pdf-codec 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/README.md +75 -12
  2. package/dist/cff-bounds.cjs +432 -0
  3. package/dist/cff-bounds.d.cts +9 -0
  4. package/dist/cff-bounds.d.ts +9 -0
  5. package/dist/cff-bounds.js +431 -0
  6. package/dist/cff-probe.cjs +8 -106
  7. package/dist/cff-probe.js +9 -107
  8. package/dist/cff.cjs +158 -0
  9. package/dist/cff.d.cts +17 -0
  10. package/dist/cff.d.ts +17 -0
  11. package/dist/cff.js +150 -0
  12. package/dist/filters.cjs +45 -2
  13. package/dist/filters.d.cts +4 -3
  14. package/dist/filters.d.ts +4 -3
  15. package/dist/filters.js +45 -2
  16. package/dist/formula.d.cts +1 -1
  17. package/dist/formula.d.ts +1 -1
  18. package/dist/glyf.cjs +62 -6
  19. package/dist/glyf.d.cts +2 -0
  20. package/dist/glyf.d.ts +2 -0
  21. package/dist/glyf.js +62 -6
  22. package/dist/glyph-bounds-BV_Z40KS.d.cts +10 -0
  23. package/dist/glyph-bounds-BV_Z40KS.d.ts +10 -0
  24. package/dist/glyph-bounds.cjs +12 -0
  25. package/dist/glyph-bounds.d.cts +2 -0
  26. package/dist/glyph-bounds.d.ts +2 -0
  27. package/dist/glyph-bounds.js +11 -0
  28. package/dist/image/jbig2-arith.cjs +432 -0
  29. package/dist/image/jbig2-arith.d.cts +23 -0
  30. package/dist/image/jbig2-arith.d.ts +23 -0
  31. package/dist/image/jbig2-arith.js +426 -0
  32. package/dist/image/jbig2-bitmap.cjs +80 -0
  33. package/dist/image/jbig2-bitmap.d.cts +20 -0
  34. package/dist/image/jbig2-bitmap.d.ts +20 -0
  35. package/dist/image/jbig2-bitmap.js +72 -0
  36. package/dist/image/jbig2-errors.cjs +17 -0
  37. package/dist/image/jbig2-errors.d.cts +2 -0
  38. package/dist/image/jbig2-errors.d.ts +2 -0
  39. package/dist/image/jbig2-errors.js +15 -0
  40. package/dist/image/jbig2-generic.cjs +242 -0
  41. package/dist/image/jbig2-generic.d.cts +27 -0
  42. package/dist/image/jbig2-generic.d.ts +27 -0
  43. package/dist/image/jbig2-generic.js +237 -0
  44. package/dist/image/jbig2-text.cjs +175 -0
  45. package/dist/image/jbig2-text.d.cts +58 -0
  46. package/dist/image/jbig2-text.d.ts +58 -0
  47. package/dist/image/jbig2-text.js +170 -0
  48. package/dist/image/jbig2.cjs +333 -0
  49. package/dist/image/jbig2.d.cts +15 -0
  50. package/dist/image/jbig2.d.ts +15 -0
  51. package/dist/image/jbig2.js +332 -0
  52. package/dist/image/jp2-boxes.cjs +148 -0
  53. package/dist/image/jp2-boxes.d.cts +26 -0
  54. package/dist/image/jp2-boxes.d.ts +26 -0
  55. package/dist/image/jp2-boxes.js +146 -0
  56. package/dist/image/jpeg2000-codestream.cjs +309 -0
  57. package/dist/image/jpeg2000-codestream.d.cts +78 -0
  58. package/dist/image/jpeg2000-codestream.d.ts +78 -0
  59. package/dist/image/jpeg2000-codestream.js +308 -0
  60. package/dist/image/jpeg2000-dwt.cjs +148 -0
  61. package/dist/image/jpeg2000-dwt.d.cts +34 -0
  62. package/dist/image/jpeg2000-dwt.d.ts +34 -0
  63. package/dist/image/jpeg2000-dwt.js +145 -0
  64. package/dist/image/jpeg2000-errors.cjs +17 -0
  65. package/dist/image/jpeg2000-errors.d.cts +9 -0
  66. package/dist/image/jpeg2000-errors.d.ts +9 -0
  67. package/dist/image/jpeg2000-errors.js +15 -0
  68. package/dist/image/jpeg2000-t1.cjs +254 -0
  69. package/dist/image/jpeg2000-t1.d.cts +18 -0
  70. package/dist/image/jpeg2000-t1.d.ts +18 -0
  71. package/dist/image/jpeg2000-t1.js +253 -0
  72. package/dist/image/jpeg2000-t2.cjs +316 -0
  73. package/dist/image/jpeg2000-t2.d.cts +79 -0
  74. package/dist/image/jpeg2000-t2.d.ts +79 -0
  75. package/dist/image/jpeg2000-t2.js +311 -0
  76. package/dist/image/jpeg2000-tagtree.cjs +105 -0
  77. package/dist/image/jpeg2000-tagtree.d.cts +29 -0
  78. package/dist/image/jpeg2000-tagtree.d.ts +29 -0
  79. package/dist/image/jpeg2000-tagtree.js +103 -0
  80. package/dist/image/jpeg2000.cjs +322 -0
  81. package/dist/image/jpeg2000.d.cts +54 -0
  82. package/dist/image/jpeg2000.d.ts +54 -0
  83. package/dist/image/jpeg2000.js +320 -0
  84. package/dist/images-read.cjs +78 -1
  85. package/dist/images-read.js +78 -1
  86. package/dist/index.cjs +17 -0
  87. package/dist/index.d.cts +11 -2
  88. package/dist/index.d.ts +11 -2
  89. package/dist/index.js +7 -1
  90. package/dist/jbig2-errors-Bj6MPxrx.d.cts +9 -0
  91. package/dist/jbig2-errors-Bj6MPxrx.d.ts +9 -0
  92. package/dist/math-content-write.cjs +37 -1
  93. package/dist/math-content-write.d.cts +1 -1
  94. package/dist/math-content-write.d.ts +1 -1
  95. package/dist/math-content-write.js +38 -2
  96. package/dist/math-font-write.cjs +6 -1
  97. package/dist/math-font-write.d.cts +1 -1
  98. package/dist/math-font-write.d.ts +1 -1
  99. package/dist/math-font-write.js +6 -1
  100. package/dist/math-font.cjs +91 -18
  101. package/dist/math-font.d.cts +8 -1
  102. package/dist/math-font.d.ts +8 -1
  103. package/dist/math-font.js +91 -18
  104. package/dist/math-stretch-Bwk_bxh1.d.ts +24 -0
  105. package/dist/math-stretch-DXWjs8gL.d.cts +24 -0
  106. package/dist/math-stretch.cjs +96 -0
  107. package/dist/math-stretch.d.cts +2 -0
  108. package/dist/math-stretch.d.ts +2 -0
  109. package/dist/math-stretch.js +94 -0
  110. package/dist/math-table-DhPrNoPa.d.ts +70 -0
  111. package/dist/math-table-gFNB8DmQ.d.cts +70 -0
  112. package/dist/math-table.cjs +69 -1
  113. package/dist/math-table.d.cts +2 -45
  114. package/dist/math-table.d.ts +2 -45
  115. package/dist/math-table.js +69 -1
  116. package/dist/{math-types-Ba8qAf1p.d.ts → math-types-BZkWO5Ow.d.cts} +30 -2
  117. package/dist/{math-types-Ba8qAf1p.d.cts → math-types-Bq7tyV4g.d.ts} +30 -2
  118. package/dist/math-types.d.cts +3 -2
  119. package/dist/math-types.d.ts +3 -2
  120. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ import { crc32 } from "./bytes/crc32.js";
3
3
  import { DeflateLevel, InflateResult, MAX_INFLATE_OUTPUT_BYTES, deflate, inflate, inflateTolerant } from "./bytes/flate.js";
4
4
  import { ByteReader, isAsciiWhitespace } from "./bytes/reader.js";
5
5
  import { ByteWriter, concatBytes } from "./bytes/writer.js";
6
+ import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.js";
6
7
  import { NOOP_DIAGNOSTIC_SINK, PdfDiagnostic, PdfDiagnosticSeverity, PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError } from "./diagnostics.js";
7
8
  import { PdfBytesSchema, pdfCodec } from "./codec.js";
8
9
  import { n as EmbeddedFaceMetrics, r as EmbeddedFaceSubstitution, t as EmbeddedFace } from "./embedded-font-CbqkKgBl.js";
@@ -11,10 +12,18 @@ import { DEFAULT_VERTICAL_METRIC_POLICY, FontMeasurerOptions, StandardFontMeasur
11
12
  import { WinAnsiSubstitution } from "./winansi.js";
12
13
  import { i as Point, u as rotatePointAboutCenter } from "./matrix-BHzJESll.js";
13
14
  import { ResolvedFont, resolveStandardFont } from "./fonts.js";
14
- import { a as MathGlyphRun, c as MathStroke, i as MathGlyphMetrics, n as MathColor, o as MathLayoutItem, r as MathFontMetrics, s as MathRule, t as MathBox } from "./math-types-Ba8qAf1p.js";
15
+ import { a as MathGlyphPart, c as MathVariants, n as MathGlyphAssembly, o as MathGlyphVariant, r as MathGlyphConstruction } from "./math-table-DhPrNoPa.js";
16
+ import { a as assembleStretchyGlyph, i as MathStretchPlacement, n as MathStretchConstruction, o as scaleMathStretchConstruction, r as MathStretchOptions, t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
17
+ import { a as MathGlyphMetrics, c as MathLayoutItem, d as MathStretchResult, f as MathStroke, i as MathFontMetrics, l as MathRule, n as MathBox, o as MathGlyphPlacement, r as MathColor, s as MathGlyphRun, t as MathAssembledGlyphs, u as MathStretchGlyph } from "./math-types-Bq7tyV4g.js";
15
18
  import { PositionedFormula } from "./formula.js";
16
19
  import { CcittFaxImage, CcittFaxOptions, decodeCcittFax } from "./image/ccitt.js";
20
+ import { n as Jbig2UnsupportedError, t as Jbig2ParseError } from "./jbig2-errors-Bj6MPxrx.js";
21
+ import { Jbig2DecodeOptions, Jbig2Image, decodeJbig2Embedded } from "./image/jbig2.js";
22
+ import { Jp2ChannelDefinition, Jp2ColourSpace, Jp2Container, Jp2ImageHeader, looksLikeBareCodestream, parseJp2Container } from "./image/jp2-boxes.js";
17
23
  import { JpegInfo, readJpegInfo } from "./image/jpeg-info.js";
24
+ import { Jpeg2000ProgressionOrder, Jpeg2000QuantizationStyle, Jpeg2000Transform } from "./image/jpeg2000-codestream.js";
25
+ import { Jpeg2000ParseError, Jpeg2000UnsupportedError } from "./image/jpeg2000-errors.js";
26
+ import { Jpeg2000ComponentMetadata, Jpeg2000DecodeOptions, Jpeg2000Image, Jpeg2000Metadata, decodeJpeg2000, readJpeg2000Metadata } from "./image/jpeg2000.js";
18
27
  import { PngDecodeOptions, RawImage, decodePng } from "./image/png-decode.js";
19
28
  import { PngEncodeOptions, encodePng } from "./image/png-encode.js";
20
29
  import { PngFilterType, filterScanlines, unfilterScanlines } from "./image/png-filter.js";
@@ -22,4 +31,4 @@ import { ReadPdfOptions, readPdf } from "./read.js";
22
31
  import { WritePdfOptions, writePdf } from "./write.js";
23
32
  import { LoadedMathFont, MathFont, MathFontDescriptorMetrics, loadMathFont } from "./math-font.js";
24
33
  import { StyledFragment, StyledRun, WrapOptions, WrappedLine, wrapRunsToWidth } from "./text-layout.js";
25
- export { ByteReader, ByteWriter, type CcittFaxImage, type CcittFaxOptions, DEFAULT_VERTICAL_METRIC_POLICY, type DeflateLevel, type EmbeddedFace, type EmbeddedFaceMetrics, type EmbeddedFaceSubstitution, type FontMeasurerOptions, type FontMetrics, type FontRegistry, type FontRegistryOptions, type FontSubstitution, type InflateResult, type JpegInfo, type LoadedMathFont, MAX_INFLATE_OUTPUT_BYTES, type MathBox, type MathColor, type MathFont, type MathFontDescriptorMetrics, type MathFontMetrics, type MathGlyphMetrics, type MathGlyphRun, type MathLayoutItem, type MathRule, type MathStroke, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, type PngDecodeOptions, type PngEncodeOptions, type PngFilterType, type Point, type PositionedFormula, type ProvidedFont, type RawImage, type ReadPdfOptions, type ResolvedFace, type ResolvedFont, STANDARD_METRICS, type StandardFontMeasurerOptions, type StandardFontName, type StyledFragment, type StyledRun, type TextMeasurer, type UnderlineMetrics, type VerticalMetricPolicy, type WinAnsiSubstitution, type WrapOptions, type WrappedLine, type WritePdfOptions, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, pdfCodec, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, unfilterScanlines, wrapRunsToWidth, writePdf };
34
+ export { ByteReader, ByteWriter, type CcittFaxImage, type CcittFaxOptions, DEFAULT_VERTICAL_METRIC_POLICY, type DeflateLevel, type EmbeddedFace, type EmbeddedFaceMetrics, type EmbeddedFaceSubstitution, type FontMeasurerOptions, type FontMetrics, type FontRegistry, type FontRegistryOptions, type FontSubstitution, type GlyphInkBounds, type InflateResult, type Jbig2DecodeOptions, type Jbig2Image, Jbig2ParseError, Jbig2UnsupportedError, type Jp2ChannelDefinition, type Jp2ColourSpace, type Jp2Container, type Jp2ImageHeader, type Jpeg2000ComponentMetadata, type Jpeg2000DecodeOptions, type Jpeg2000Image, type Jpeg2000Metadata, Jpeg2000ParseError, type Jpeg2000ProgressionOrder, type Jpeg2000QuantizationStyle, type Jpeg2000Transform, Jpeg2000UnsupportedError, type JpegInfo, type LoadedMathFont, MAX_INFLATE_OUTPUT_BYTES, type MathAssembledGlyphs, type MathBox, type MathColor, type MathFont, type MathFontDescriptorMetrics, type MathFontMetrics, type MathGlyphAssembly, type MathGlyphConstruction, type MathGlyphMetrics, type MathGlyphPart, type MathGlyphPlacement, type MathGlyphRun, type MathGlyphVariant, type MathLayoutItem, type MathRule, type MathStretchAxis, type MathStretchConstruction, type MathStretchGlyph, type MathStretchOptions, type MathStretchPlacement, type MathStretchResult, type MathStroke, type MathVariants, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, type PdfDiagnostic, type PdfDiagnosticSeverity, type PdfDiagnosticSink, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, type PngDecodeOptions, type PngEncodeOptions, type PngFilterType, type Point, type PositionedFormula, type ProvidedFont, type RawImage, type ReadPdfOptions, type ResolvedFace, type ResolvedFont, STANDARD_METRICS, type StandardFontMeasurerOptions, type StandardFontName, type StyledFragment, type StyledRun, type TextMeasurer, type UnderlineMetrics, type VerticalMetricPolicy, type WinAnsiSubstitution, type WrapOptions, type WrappedLine, type WritePdfOptions, assembleStretchyGlyph, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodeJbig2Embedded, decodeJpeg2000, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, looksLikeBareCodestream, parseJp2Container, pdfCodec, readJpeg2000Metadata, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, scaleMathStretchConstruction, unfilterScanlines, wrapRunsToWidth, writePdf };
package/dist/index.js CHANGED
@@ -5,17 +5,23 @@ import { ByteWriter, concatBytes } from "./bytes/writer.js";
5
5
  import { NOOP_DIAGNOSTIC_SINK, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError } from "./diagnostics.js";
6
6
  import { MAX_INFLATE_OUTPUT_BYTES, deflate, inflate, inflateTolerant } from "./bytes/flate.js";
7
7
  import { decodeCcittFax } from "./image/ccitt.js";
8
+ import { Jbig2ParseError, Jbig2UnsupportedError } from "./image/jbig2-errors.js";
9
+ import { decodeJbig2Embedded } from "./image/jbig2.js";
8
10
  import { filterScanlines, unfilterScanlines } from "./image/png-filter.js";
9
11
  import { resolveStandardFont } from "./fonts.js";
10
12
  import { encodePng } from "./image/png-encode.js";
11
13
  import { readJpegInfo } from "./image/jpeg-info.js";
14
+ import { Jpeg2000ParseError, Jpeg2000UnsupportedError } from "./image/jpeg2000-errors.js";
15
+ import { looksLikeBareCodestream, parseJp2Container } from "./image/jp2-boxes.js";
16
+ import { decodeJpeg2000, readJpeg2000Metadata } from "./image/jpeg2000.js";
12
17
  import { rotatePointAboutCenter } from "./matrix.js";
13
18
  import { decodePng } from "./image/png-decode.js";
14
19
  import { createFontRegistry, resolveFaceWithRegistry } from "./font-registry.js";
20
+ import { assembleStretchyGlyph, scaleMathStretchConstruction } from "./math-stretch.js";
15
21
  import { loadMathFont } from "./math-font.js";
16
22
  import { DEFAULT_VERTICAL_METRIC_POLICY, createFontMeasurer, createStandardFontMeasurer } from "./measure.js";
17
23
  import { writePdf } from "./write.js";
18
24
  import { readPdf } from "./read.js";
19
25
  import { PdfBytesSchema, pdfCodec } from "./codec.js";
20
26
  import { wrapRunsToWidth } from "./text-layout.js";
21
- export { ByteReader, ByteWriter, DEFAULT_VERTICAL_METRIC_POLICY, MAX_INFLATE_OUTPUT_BYTES, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, STANDARD_METRICS, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, pdfCodec, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, unfilterScanlines, wrapRunsToWidth, writePdf };
27
+ export { ByteReader, ByteWriter, DEFAULT_VERTICAL_METRIC_POLICY, Jbig2ParseError, Jbig2UnsupportedError, Jpeg2000ParseError, Jpeg2000UnsupportedError, MAX_INFLATE_OUTPUT_BYTES, NOOP_DIAGNOSTIC_SINK, PdfBytesSchema, PdfEncryptedError, PdfParseError, PdfPasswordRequiredError, STANDARD_METRICS, assembleStretchyGlyph, concatBytes, crc32, createFontMeasurer, createFontRegistry, createStandardFontMeasurer, decodeCcittFax, decodeJbig2Embedded, decodeJpeg2000, decodePng, deflate, encodePng, filterScanlines, inflate, inflateTolerant, isAsciiWhitespace, loadMathFont, looksLikeBareCodestream, parseJp2Container, pdfCodec, readJpeg2000Metadata, readJpegInfo, readPdf, resolveFaceWithRegistry, resolveStandardFont, rotatePointAboutCenter, scaleMathStretchConstruction, unfilterScanlines, wrapRunsToWidth, writePdf };
@@ -0,0 +1,9 @@
1
+ //#region src/image/jbig2-errors.d.ts
2
+ declare class Jbig2ParseError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ declare class Jbig2UnsupportedError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ //#endregion
9
+ export { Jbig2UnsupportedError as n, Jbig2ParseError as t };
@@ -0,0 +1,9 @@
1
+ //#region src/image/jbig2-errors.d.ts
2
+ declare class Jbig2ParseError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ declare class Jbig2UnsupportedError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ //#endregion
9
+ export { Jbig2UnsupportedError as n, Jbig2ParseError as t };
@@ -40,6 +40,37 @@ function writeGlyphRun(writer, positioned, item, ctx) {
40
40
  writer.writeAscii(" Tj\n");
41
41
  writer.writeAscii("ET\n");
42
42
  }
43
+ function cidBytes(glyphId) {
44
+ return new Uint8Array([glyphId >> 8 & 255, glyphId & 255]);
45
+ }
46
+ function utf16BeWithBom(text) {
47
+ const bytes = new Uint8Array(2 + text.length * 2);
48
+ bytes[0] = 254;
49
+ bytes[1] = 255;
50
+ for (let i = 0; i < text.length; i++) {
51
+ const unit = text.charCodeAt(i);
52
+ bytes[2 + i * 2] = unit >> 8 & 255;
53
+ bytes[3 + i * 2] = unit & 255;
54
+ }
55
+ return bytes;
56
+ }
57
+ function writeAssembledGlyphs(writer, positioned, item, ctx) {
58
+ if (item.placements.length === 0) return;
59
+ require_serialize.writeObject(writer, require_objects.pdfName("Span"));
60
+ writer.writeAscii(" ");
61
+ require_serialize.writeObject(writer, require_objects.pdfDict({ ActualText: require_objects.pdfHexString(utf16BeWithBom(item.text)) }));
62
+ writer.writeAscii(" BDC\n");
63
+ for (const placement of item.placements) {
64
+ writer.writeAscii("BT\n");
65
+ writer.writeAscii(`/${ctx.resourceName} ${require_serialize.formatNumber(item.sizePt)} Tf\n`);
66
+ writeRgbOperator(writer, item.color, "rg");
67
+ writer.writeAscii(`1 0 0 1 ${require_serialize.formatNumber(toPdfX(positioned, placement.xPt))} ${require_serialize.formatNumber(toPdfY(positioned, placement.yPt))} Tm\n`);
68
+ require_serialize.writeObject(writer, require_objects.pdfHexString(cidBytes(placement.glyphId)));
69
+ writer.writeAscii(" Tj\n");
70
+ writer.writeAscii("ET\n");
71
+ }
72
+ writer.writeAscii("EMC\n");
73
+ }
43
74
  function writeRule(writer, positioned, item) {
44
75
  const x = toPdfX(positioned, item.xPt);
45
76
  const topY = toPdfY(positioned, item.yPt);
@@ -62,18 +93,23 @@ function writeFormulaContentStream(formulas, ctx) {
62
93
  const writer = new require_bytes_writer.ByteWriter();
63
94
  for (const positioned of formulas) for (const item of positioned.box.items) if (item.kind === "glyphs") writeGlyphRun(writer, positioned, item, ctx);
64
95
  else if (item.kind === "rule") writeRule(writer, positioned, item);
96
+ else if (item.kind === "assembled-glyphs") writeAssembledGlyphs(writer, positioned, item, ctx);
65
97
  else writeStroke(writer, positioned, item);
66
98
  return writer.toBytes();
67
99
  }
68
100
  function collectUsedGlyphs(formulas, font) {
69
101
  const used = /* @__PURE__ */ new Map();
70
102
  for (const positioned of formulas) for (const item of positioned.box.items) {
103
+ if (item.kind === "assembled-glyphs") {
104
+ for (const placement of item.placements) if (!used.has(placement.glyphId)) used.set(placement.glyphId, void 0);
105
+ continue;
106
+ }
71
107
  if (item.kind !== "glyphs") continue;
72
108
  for (const ch of item.text) {
73
109
  const codePoint = ch.codePointAt(0);
74
110
  if (codePoint === void 0) continue;
75
111
  const glyphId = font.glyphId(codePoint);
76
- if (glyphId !== void 0 && !used.has(glyphId)) used.set(glyphId, codePoint);
112
+ if (glyphId !== void 0 && used.get(glyphId) === void 0) used.set(glyphId, codePoint);
77
113
  }
78
114
  }
79
115
  return used;
@@ -6,6 +6,6 @@ interface MathContentWriteContext {
6
6
  readonly resourceName: string;
7
7
  }
8
8
  declare function writeFormulaContentStream(formulas: readonly PositionedFormula[], ctx: MathContentWriteContext): Uint8Array<ArrayBuffer>;
9
- declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number>;
9
+ declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number | undefined>;
10
10
  //#endregion
11
11
  export { MathContentWriteContext, collectUsedGlyphs, writeFormulaContentStream };
@@ -6,6 +6,6 @@ interface MathContentWriteContext {
6
6
  readonly resourceName: string;
7
7
  }
8
8
  declare function writeFormulaContentStream(formulas: readonly PositionedFormula[], ctx: MathContentWriteContext): Uint8Array<ArrayBuffer>;
9
- declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number>;
9
+ declare function collectUsedGlyphs(formulas: readonly PositionedFormula[], font: MathFont): ReadonlyMap<number, number | undefined>;
10
10
  //#endregion
11
11
  export { MathContentWriteContext, collectUsedGlyphs, writeFormulaContentStream };
@@ -1,5 +1,5 @@
1
1
  import { ByteWriter } from "./bytes/writer.js";
2
- import { pdfHexString } from "./objects.js";
2
+ import { pdfDict, pdfHexString, pdfName } from "./objects.js";
3
3
  import { formatNumber, writeObject } from "./serialize.js";
4
4
  //#region src/math-content-write.ts
5
5
  function toPdfX(positioned, itemXPt) {
@@ -39,6 +39,37 @@ function writeGlyphRun(writer, positioned, item, ctx) {
39
39
  writer.writeAscii(" Tj\n");
40
40
  writer.writeAscii("ET\n");
41
41
  }
42
+ function cidBytes(glyphId) {
43
+ return new Uint8Array([glyphId >> 8 & 255, glyphId & 255]);
44
+ }
45
+ function utf16BeWithBom(text) {
46
+ const bytes = new Uint8Array(2 + text.length * 2);
47
+ bytes[0] = 254;
48
+ bytes[1] = 255;
49
+ for (let i = 0; i < text.length; i++) {
50
+ const unit = text.charCodeAt(i);
51
+ bytes[2 + i * 2] = unit >> 8 & 255;
52
+ bytes[3 + i * 2] = unit & 255;
53
+ }
54
+ return bytes;
55
+ }
56
+ function writeAssembledGlyphs(writer, positioned, item, ctx) {
57
+ if (item.placements.length === 0) return;
58
+ writeObject(writer, pdfName("Span"));
59
+ writer.writeAscii(" ");
60
+ writeObject(writer, pdfDict({ ActualText: pdfHexString(utf16BeWithBom(item.text)) }));
61
+ writer.writeAscii(" BDC\n");
62
+ for (const placement of item.placements) {
63
+ writer.writeAscii("BT\n");
64
+ writer.writeAscii(`/${ctx.resourceName} ${formatNumber(item.sizePt)} Tf\n`);
65
+ writeRgbOperator(writer, item.color, "rg");
66
+ writer.writeAscii(`1 0 0 1 ${formatNumber(toPdfX(positioned, placement.xPt))} ${formatNumber(toPdfY(positioned, placement.yPt))} Tm\n`);
67
+ writeObject(writer, pdfHexString(cidBytes(placement.glyphId)));
68
+ writer.writeAscii(" Tj\n");
69
+ writer.writeAscii("ET\n");
70
+ }
71
+ writer.writeAscii("EMC\n");
72
+ }
42
73
  function writeRule(writer, positioned, item) {
43
74
  const x = toPdfX(positioned, item.xPt);
44
75
  const topY = toPdfY(positioned, item.yPt);
@@ -61,18 +92,23 @@ function writeFormulaContentStream(formulas, ctx) {
61
92
  const writer = new ByteWriter();
62
93
  for (const positioned of formulas) for (const item of positioned.box.items) if (item.kind === "glyphs") writeGlyphRun(writer, positioned, item, ctx);
63
94
  else if (item.kind === "rule") writeRule(writer, positioned, item);
95
+ else if (item.kind === "assembled-glyphs") writeAssembledGlyphs(writer, positioned, item, ctx);
64
96
  else writeStroke(writer, positioned, item);
65
97
  return writer.toBytes();
66
98
  }
67
99
  function collectUsedGlyphs(formulas, font) {
68
100
  const used = /* @__PURE__ */ new Map();
69
101
  for (const positioned of formulas) for (const item of positioned.box.items) {
102
+ if (item.kind === "assembled-glyphs") {
103
+ for (const placement of item.placements) if (!used.has(placement.glyphId)) used.set(placement.glyphId, void 0);
104
+ continue;
105
+ }
70
106
  if (item.kind !== "glyphs") continue;
71
107
  for (const ch of item.text) {
72
108
  const codePoint = ch.codePointAt(0);
73
109
  if (codePoint === void 0) continue;
74
110
  const glyphId = font.glyphId(codePoint);
75
- if (glyphId !== void 0 && !used.has(glyphId)) used.set(glyphId, codePoint);
111
+ if (glyphId !== void 0 && used.get(glyphId) === void 0) used.set(glyphId, codePoint);
76
112
  }
77
113
  }
78
114
  return used;
@@ -38,6 +38,11 @@ function buildFontFileStream(font, compress) {
38
38
  } : { Subtype: require_objects.pdfName("CIDFontType0C") });
39
39
  return require_objects.pdfStream(dict, compress ? require_bytes_flate.deflate(font.cffBytes) : font.cffBytes);
40
40
  }
41
+ function toUnicodeEntries(usedGlyphs) {
42
+ const entries = /* @__PURE__ */ new Map();
43
+ for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, codePoint);
44
+ return entries;
45
+ }
41
46
  function buildMathFontObjects(font, usedGlyphs, refs, compress) {
42
47
  const cidFont = require_objects.pdfDict({
43
48
  Type: require_objects.pdfName("Font"),
@@ -64,7 +69,7 @@ function buildMathFontObjects(font, usedGlyphs, refs, compress) {
64
69
  cidFont,
65
70
  descriptor: buildFontDescriptor(font, refs.fontFileRef),
66
71
  fontFile: buildFontFileStream(font, compress),
67
- toUnicode: require_tounicode.buildToUnicodeCMap(usedGlyphs)
72
+ toUnicode: require_tounicode.buildToUnicodeCMap(toUnicodeEntries(usedGlyphs))
68
73
  };
69
74
  }
70
75
  //#endregion
@@ -14,6 +14,6 @@ interface MathFontObjects {
14
14
  readonly fontFile: PdfObject;
15
15
  readonly toUnicode: PdfObject;
16
16
  }
17
- declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
17
+ declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number | undefined>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
18
18
  //#endregion
19
19
  export { MathFontObjectRefs, MathFontObjects, buildMathFontObjects };
@@ -14,6 +14,6 @@ interface MathFontObjects {
14
14
  readonly fontFile: PdfObject;
15
15
  readonly toUnicode: PdfObject;
16
16
  }
17
- declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
17
+ declare function buildMathFontObjects(font: MathFont, usedGlyphs: ReadonlyMap<number, number | undefined>, refs: MathFontObjectRefs, compress: boolean): MathFontObjects;
18
18
  //#endregion
19
19
  export { MathFontObjectRefs, MathFontObjects, buildMathFontObjects };
@@ -37,6 +37,11 @@ function buildFontFileStream(font, compress) {
37
37
  } : { Subtype: pdfName("CIDFontType0C") });
38
38
  return pdfStream(dict, compress ? deflate(font.cffBytes) : font.cffBytes);
39
39
  }
40
+ function toUnicodeEntries(usedGlyphs) {
41
+ const entries = /* @__PURE__ */ new Map();
42
+ for (const [glyphId, codePoint] of usedGlyphs) if (codePoint !== void 0) entries.set(glyphId, codePoint);
43
+ return entries;
44
+ }
40
45
  function buildMathFontObjects(font, usedGlyphs, refs, compress) {
41
46
  const cidFont = pdfDict({
42
47
  Type: pdfName("Font"),
@@ -63,7 +68,7 @@ function buildMathFontObjects(font, usedGlyphs, refs, compress) {
63
68
  cidFont,
64
69
  descriptor: buildFontDescriptor(font, refs.fontFileRef),
65
70
  fontFile: buildFontFileStream(font, compress),
66
- toUnicode: buildToUnicodeCMap(usedGlyphs)
71
+ toUnicode: buildToUnicodeCMap(toUnicodeEntries(usedGlyphs))
67
72
  };
68
73
  }
69
74
  //#endregion
@@ -1,15 +1,62 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_sfnt = require("./sfnt.cjs");
3
+ const require_cff_bounds = require("./cff-bounds.cjs");
3
4
  const require_cmap_table = require("./cmap-table.cjs");
4
5
  const require_util_base64 = require("./util/base64.cjs");
5
6
  const require_hmtx_table = require("./hmtx-table.cjs");
6
7
  const require_assets_stix_two_math_font = require("./assets/stix-two-math-font.cjs");
8
+ const require_math_stretch = require("./math-stretch.cjs");
7
9
  const require_math_table = require("./math-table.cjs");
8
10
  //#region src/math-font.ts
9
11
  function toPt(designUnits, unitsPerEm, sizePt) {
10
12
  return designUnits / unitsPerEm * sizePt;
11
13
  }
12
- function metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt) {
14
+ function measureConstruction(placements, axis, inkBounds, hmtx) {
15
+ let inkAscent = Number.NEGATIVE_INFINITY;
16
+ let inkDescent = Number.NEGATIVE_INFINITY;
17
+ let advanceWidth = 0;
18
+ for (const placement of placements) {
19
+ advanceWidth = Math.max(advanceWidth, hmtx.advanceWidth(placement.glyphId));
20
+ const ink = inkBounds?.bounds(placement.glyphId);
21
+ if (ink === void 0) continue;
22
+ const alongY = axis === "vertical" ? placement.offset : 0;
23
+ inkAscent = Math.max(inkAscent, alongY + ink.yMax);
24
+ inkDescent = Math.max(inkDescent, -(alongY + ink.yMin));
25
+ }
26
+ return inkAscent === Number.NEGATIVE_INFINITY ? void 0 : {
27
+ inkAscent,
28
+ inkDescent,
29
+ advanceWidth
30
+ };
31
+ }
32
+ function stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, sizePt) {
33
+ const glyphId = cmap(codePoint);
34
+ if (glyphId === void 0) return;
35
+ const construction = (axis === "vertical" ? math.variants.vertical : math.variants.horizontal).get(glyphId);
36
+ if (construction === void 0) return;
37
+ const designUnitsPerPt = unitsPerEm / sizePt;
38
+ const assembled = require_math_stretch.assembleStretchyGlyph(construction, {
39
+ axis,
40
+ targetSize: targetSizePt * designUnitsPerPt,
41
+ minConnectorOverlap: math.variants.minConnectorOverlap
42
+ });
43
+ if (assembled === void 0) return;
44
+ const measured = measureConstruction(assembled.placements, axis, inkBounds, hmtx);
45
+ if (measured === void 0) return;
46
+ const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
47
+ return {
48
+ kind: assembled.kind,
49
+ sizePt: pt(assembled.size),
50
+ advanceWidthPt: pt(measured.advanceWidth),
51
+ inkAscentPt: pt(measured.inkAscent),
52
+ inkDescentPt: pt(measured.inkDescent),
53
+ placements: assembled.placements.map((placement) => ({
54
+ glyphId: placement.glyphId,
55
+ offsetPt: pt(placement.offset)
56
+ }))
57
+ };
58
+ }
59
+ function metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt) {
13
60
  const c = math.constants;
14
61
  const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
15
62
  return {
@@ -52,11 +99,17 @@ function metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentD
52
99
  const advanceWidthPt = toPt(hmtx.advanceWidth(glyphId), unitsPerEm, glyphSizePt);
53
100
  const italicCorrectionDesignUnits = math.glyphInfo.italicsCorrection.get(glyphId) ?? 0;
54
101
  const topAccentDesignUnits = math.glyphInfo.topAccentAttachment.get(glyphId);
102
+ const ink = inkBounds?.bounds(glyphId);
55
103
  return {
56
104
  advanceWidthPt,
57
105
  italicCorrectionPt: toPt(italicCorrectionDesignUnits, unitsPerEm, glyphSizePt),
58
- topAccentXPt: topAccentDesignUnits === void 0 ? void 0 : toPt(topAccentDesignUnits, unitsPerEm, glyphSizePt)
106
+ topAccentXPt: topAccentDesignUnits === void 0 ? void 0 : toPt(topAccentDesignUnits, unitsPerEm, glyphSizePt),
107
+ inkAscentPt: ink === void 0 ? void 0 : toPt(ink.yMax, unitsPerEm, glyphSizePt),
108
+ inkDescentPt: ink === void 0 ? void 0 : toPt(-ink.yMin, unitsPerEm, glyphSizePt)
59
109
  };
110
+ },
111
+ stretch(codePoint, axis, targetSizePt, glyphSizePt) {
112
+ return stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, glyphSizePt);
60
113
  }
61
114
  };
62
115
  }
@@ -81,23 +134,43 @@ function loadMathFont() {
81
134
  if (cmap === void 0) throw new Error("embedded math font has no readable cmap subtable");
82
135
  const hmtx = require_hmtx_table.parseHmtx(sfnt);
83
136
  const math = require_math_table.parseMathTable(sfnt);
84
- cached = {
85
- font: {
86
- metrics: metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentDesignUnits, unitsPerEm),
87
- cffBytes,
88
- descriptor: {
89
- unitsPerEm,
90
- ascent: ascentDesignUnits,
91
- descent: descentDesignUnits,
92
- capHeight,
93
- bboxMin,
94
- bboxMax,
95
- italicAngle: 0
96
- },
97
- glyphId: (codePoint) => cmap(codePoint),
98
- glyphSpaceWidth: (glyphId) => hmtx.advanceWidth(glyphId) * 1e3 / unitsPerEm
137
+ const inkBounds = require_cff_bounds.parseCffGlyphBounds(cffBytes);
138
+ const font = {
139
+ metrics: metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, unitsPerEm),
140
+ cffBytes,
141
+ descriptor: {
142
+ unitsPerEm,
143
+ ascent: ascentDesignUnits,
144
+ descent: descentDesignUnits,
145
+ capHeight,
146
+ bboxMin,
147
+ bboxMax,
148
+ italicAngle: 0
99
149
  },
100
- metricsAt: (sizePt) => metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt)
150
+ glyphId: (codePoint) => cmap(codePoint),
151
+ glyphSpaceWidth: (glyphId) => hmtx.advanceWidth(glyphId) * 1e3 / unitsPerEm,
152
+ glyphInkBounds: (glyphId) => inkBounds?.bounds(glyphId),
153
+ minConnectorOverlap: math.variants.minConnectorOverlap,
154
+ stretchyConstruction: (codePoint, axis) => {
155
+ const glyphId = cmap(codePoint);
156
+ if (glyphId === void 0) return;
157
+ return (axis === "vertical" ? math.variants.vertical : math.variants.horizontal).get(glyphId);
158
+ }
159
+ };
160
+ cached = {
161
+ font,
162
+ metricsAt: (sizePt) => metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt),
163
+ stretchGlyph: (codePoint, axis, targetSizePt, sizePt) => {
164
+ const construction = font.stretchyConstruction(codePoint, axis);
165
+ if (construction === void 0) return;
166
+ const designUnitsPerPt = unitsPerEm / sizePt;
167
+ const assembled = require_math_stretch.assembleStretchyGlyph(construction, {
168
+ axis,
169
+ targetSize: targetSizePt * designUnitsPerPt,
170
+ minConnectorOverlap: math.variants.minConnectorOverlap
171
+ });
172
+ return assembled === void 0 ? void 0 : require_math_stretch.scaleMathStretchConstruction(assembled, 1 / designUnitsPerPt);
173
+ }
101
174
  };
102
175
  return cached;
103
176
  }
@@ -1,4 +1,7 @@
1
- import { r as MathFontMetrics } from "./math-types-Ba8qAf1p.cjs";
1
+ import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.cjs";
2
+ import { r as MathGlyphConstruction } from "./math-table-gFNB8DmQ.cjs";
3
+ import { n as MathStretchConstruction, t as MathStretchAxis } from "./math-stretch-DXWjs8gL.cjs";
4
+ import { i as MathFontMetrics } from "./math-types-BZkWO5Ow.cjs";
2
5
  //#region src/math-font.d.ts
3
6
  interface MathFontDescriptorMetrics {
4
7
  readonly unitsPerEm: number;
@@ -15,10 +18,14 @@ interface MathFont {
15
18
  readonly descriptor: MathFontDescriptorMetrics;
16
19
  glyphId(codePoint: number): number | undefined;
17
20
  glyphSpaceWidth(glyphId: number): number;
21
+ glyphInkBounds(glyphId: number): GlyphInkBounds | undefined;
22
+ readonly minConnectorOverlap: number;
23
+ stretchyConstruction(codePoint: number, axis: MathStretchAxis): MathGlyphConstruction | undefined;
18
24
  }
19
25
  interface LoadedMathFont {
20
26
  readonly font: MathFont;
21
27
  readonly metricsAt: (sizePt: number) => MathFontMetrics;
28
+ readonly stretchGlyph: (codePoint: number, axis: MathStretchAxis, targetSizePt: number, sizePt: number) => MathStretchConstruction | undefined;
22
29
  }
23
30
  declare function loadMathFont(): LoadedMathFont;
24
31
  //#endregion
@@ -1,4 +1,7 @@
1
- import { r as MathFontMetrics } from "./math-types-Ba8qAf1p.js";
1
+ import { t as GlyphInkBounds } from "./glyph-bounds-BV_Z40KS.js";
2
+ import { r as MathGlyphConstruction } from "./math-table-DhPrNoPa.js";
3
+ import { n as MathStretchConstruction, t as MathStretchAxis } from "./math-stretch-Bwk_bxh1.js";
4
+ import { i as MathFontMetrics } from "./math-types-Bq7tyV4g.js";
2
5
  //#region src/math-font.d.ts
3
6
  interface MathFontDescriptorMetrics {
4
7
  readonly unitsPerEm: number;
@@ -15,10 +18,14 @@ interface MathFont {
15
18
  readonly descriptor: MathFontDescriptorMetrics;
16
19
  glyphId(codePoint: number): number | undefined;
17
20
  glyphSpaceWidth(glyphId: number): number;
21
+ glyphInkBounds(glyphId: number): GlyphInkBounds | undefined;
22
+ readonly minConnectorOverlap: number;
23
+ stretchyConstruction(codePoint: number, axis: MathStretchAxis): MathGlyphConstruction | undefined;
18
24
  }
19
25
  interface LoadedMathFont {
20
26
  readonly font: MathFont;
21
27
  readonly metricsAt: (sizePt: number) => MathFontMetrics;
28
+ readonly stretchGlyph: (codePoint: number, axis: MathStretchAxis, targetSizePt: number, sizePt: number) => MathStretchConstruction | undefined;
22
29
  }
23
30
  declare function loadMathFont(): LoadedMathFont;
24
31
  //#endregion
package/dist/math-font.js CHANGED
@@ -1,14 +1,61 @@
1
1
  import { i16, parseSfnt, sfntTableBytes, u16 } from "./sfnt.js";
2
+ import { parseCffGlyphBounds } from "./cff-bounds.js";
2
3
  import { buildCmapLookup } from "./cmap-table.js";
3
4
  import { base64ToBytes } from "./util/base64.js";
4
5
  import { parseHmtx } from "./hmtx-table.js";
5
6
  import { STIX_TWO_MATH_FONT_BASE64 } from "./assets/stix-two-math-font.js";
7
+ import { assembleStretchyGlyph, scaleMathStretchConstruction } from "./math-stretch.js";
6
8
  import { parseMathTable } from "./math-table.js";
7
9
  //#region src/math-font.ts
8
10
  function toPt(designUnits, unitsPerEm, sizePt) {
9
11
  return designUnits / unitsPerEm * sizePt;
10
12
  }
11
- function metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt) {
13
+ function measureConstruction(placements, axis, inkBounds, hmtx) {
14
+ let inkAscent = Number.NEGATIVE_INFINITY;
15
+ let inkDescent = Number.NEGATIVE_INFINITY;
16
+ let advanceWidth = 0;
17
+ for (const placement of placements) {
18
+ advanceWidth = Math.max(advanceWidth, hmtx.advanceWidth(placement.glyphId));
19
+ const ink = inkBounds?.bounds(placement.glyphId);
20
+ if (ink === void 0) continue;
21
+ const alongY = axis === "vertical" ? placement.offset : 0;
22
+ inkAscent = Math.max(inkAscent, alongY + ink.yMax);
23
+ inkDescent = Math.max(inkDescent, -(alongY + ink.yMin));
24
+ }
25
+ return inkAscent === Number.NEGATIVE_INFINITY ? void 0 : {
26
+ inkAscent,
27
+ inkDescent,
28
+ advanceWidth
29
+ };
30
+ }
31
+ function stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, sizePt) {
32
+ const glyphId = cmap(codePoint);
33
+ if (glyphId === void 0) return;
34
+ const construction = (axis === "vertical" ? math.variants.vertical : math.variants.horizontal).get(glyphId);
35
+ if (construction === void 0) return;
36
+ const designUnitsPerPt = unitsPerEm / sizePt;
37
+ const assembled = assembleStretchyGlyph(construction, {
38
+ axis,
39
+ targetSize: targetSizePt * designUnitsPerPt,
40
+ minConnectorOverlap: math.variants.minConnectorOverlap
41
+ });
42
+ if (assembled === void 0) return;
43
+ const measured = measureConstruction(assembled.placements, axis, inkBounds, hmtx);
44
+ if (measured === void 0) return;
45
+ const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
46
+ return {
47
+ kind: assembled.kind,
48
+ sizePt: pt(assembled.size),
49
+ advanceWidthPt: pt(measured.advanceWidth),
50
+ inkAscentPt: pt(measured.inkAscent),
51
+ inkDescentPt: pt(measured.inkDescent),
52
+ placements: assembled.placements.map((placement) => ({
53
+ glyphId: placement.glyphId,
54
+ offsetPt: pt(placement.offset)
55
+ }))
56
+ };
57
+ }
58
+ function metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt) {
12
59
  const c = math.constants;
13
60
  const pt = (designUnits) => toPt(designUnits, unitsPerEm, sizePt);
14
61
  return {
@@ -51,11 +98,17 @@ function metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentD
51
98
  const advanceWidthPt = toPt(hmtx.advanceWidth(glyphId), unitsPerEm, glyphSizePt);
52
99
  const italicCorrectionDesignUnits = math.glyphInfo.italicsCorrection.get(glyphId) ?? 0;
53
100
  const topAccentDesignUnits = math.glyphInfo.topAccentAttachment.get(glyphId);
101
+ const ink = inkBounds?.bounds(glyphId);
54
102
  return {
55
103
  advanceWidthPt,
56
104
  italicCorrectionPt: toPt(italicCorrectionDesignUnits, unitsPerEm, glyphSizePt),
57
- topAccentXPt: topAccentDesignUnits === void 0 ? void 0 : toPt(topAccentDesignUnits, unitsPerEm, glyphSizePt)
105
+ topAccentXPt: topAccentDesignUnits === void 0 ? void 0 : toPt(topAccentDesignUnits, unitsPerEm, glyphSizePt),
106
+ inkAscentPt: ink === void 0 ? void 0 : toPt(ink.yMax, unitsPerEm, glyphSizePt),
107
+ inkDescentPt: ink === void 0 ? void 0 : toPt(-ink.yMin, unitsPerEm, glyphSizePt)
58
108
  };
109
+ },
110
+ stretch(codePoint, axis, targetSizePt, glyphSizePt) {
111
+ return stretchAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, codePoint, axis, targetSizePt, glyphSizePt);
59
112
  }
60
113
  };
61
114
  }
@@ -80,23 +133,43 @@ function loadMathFont() {
80
133
  if (cmap === void 0) throw new Error("embedded math font has no readable cmap subtable");
81
134
  const hmtx = parseHmtx(sfnt);
82
135
  const math = parseMathTable(sfnt);
83
- cached = {
84
- font: {
85
- metrics: metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentDesignUnits, unitsPerEm),
86
- cffBytes,
87
- descriptor: {
88
- unitsPerEm,
89
- ascent: ascentDesignUnits,
90
- descent: descentDesignUnits,
91
- capHeight,
92
- bboxMin,
93
- bboxMax,
94
- italicAngle: 0
95
- },
96
- glyphId: (codePoint) => cmap(codePoint),
97
- glyphSpaceWidth: (glyphId) => hmtx.advanceWidth(glyphId) * 1e3 / unitsPerEm
136
+ const inkBounds = parseCffGlyphBounds(cffBytes);
137
+ const font = {
138
+ metrics: metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, unitsPerEm),
139
+ cffBytes,
140
+ descriptor: {
141
+ unitsPerEm,
142
+ ascent: ascentDesignUnits,
143
+ descent: descentDesignUnits,
144
+ capHeight,
145
+ bboxMin,
146
+ bboxMax,
147
+ italicAngle: 0
98
148
  },
99
- metricsAt: (sizePt) => metricsAtSize(cmap, hmtx, math, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt)
149
+ glyphId: (codePoint) => cmap(codePoint),
150
+ glyphSpaceWidth: (glyphId) => hmtx.advanceWidth(glyphId) * 1e3 / unitsPerEm,
151
+ glyphInkBounds: (glyphId) => inkBounds?.bounds(glyphId),
152
+ minConnectorOverlap: math.variants.minConnectorOverlap,
153
+ stretchyConstruction: (codePoint, axis) => {
154
+ const glyphId = cmap(codePoint);
155
+ if (glyphId === void 0) return;
156
+ return (axis === "vertical" ? math.variants.vertical : math.variants.horizontal).get(glyphId);
157
+ }
158
+ };
159
+ cached = {
160
+ font,
161
+ metricsAt: (sizePt) => metricsAtSize(cmap, hmtx, math, inkBounds, unitsPerEm, ascentDesignUnits, descentDesignUnits, sizePt),
162
+ stretchGlyph: (codePoint, axis, targetSizePt, sizePt) => {
163
+ const construction = font.stretchyConstruction(codePoint, axis);
164
+ if (construction === void 0) return;
165
+ const designUnitsPerPt = unitsPerEm / sizePt;
166
+ const assembled = assembleStretchyGlyph(construction, {
167
+ axis,
168
+ targetSize: targetSizePt * designUnitsPerPt,
169
+ minConnectorOverlap: math.variants.minConnectorOverlap
170
+ });
171
+ return assembled === void 0 ? void 0 : scaleMathStretchConstruction(assembled, 1 / designUnitsPerPt);
172
+ }
100
173
  };
101
174
  return cached;
102
175
  }