postext-pdf 1.14.0 → 1.15.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 (100) hide show
  1. package/README.md +13 -1
  2. package/dist/__bench__/arabicShaping.bench.test.d.ts +2 -0
  3. package/dist/__bench__/arabicShaping.bench.test.d.ts.map +1 -0
  4. package/dist/__bench__/arabicShaping.bench.test.js +53 -0
  5. package/dist/__bench__/arabicShaping.bench.test.js.map +1 -0
  6. package/dist/__tests__/arabicShaping.test.d.ts +2 -0
  7. package/dist/__tests__/arabicShaping.test.d.ts.map +1 -0
  8. package/dist/__tests__/arabicShaping.test.js +261 -0
  9. package/dist/__tests__/arabicShaping.test.js.map +1 -0
  10. package/dist/__tests__/complexShaping.test.d.ts +2 -0
  11. package/dist/__tests__/complexShaping.test.d.ts.map +1 -0
  12. package/dist/__tests__/complexShaping.test.js +145 -0
  13. package/dist/__tests__/complexShaping.test.js.map +1 -0
  14. package/dist/__tests__/designTextRtl.test.d.ts +2 -0
  15. package/dist/__tests__/designTextRtl.test.d.ts.map +1 -0
  16. package/dist/__tests__/designTextRtl.test.js +136 -0
  17. package/dist/__tests__/designTextRtl.test.js.map +1 -0
  18. package/dist/__tests__/harfbuzz.test.d.ts +2 -0
  19. package/dist/__tests__/harfbuzz.test.d.ts.map +1 -0
  20. package/dist/__tests__/harfbuzz.test.js +103 -0
  21. package/dist/__tests__/harfbuzz.test.js.map +1 -0
  22. package/dist/__tests__/measuredLines.test.js +13 -5
  23. package/dist/__tests__/measuredLines.test.js.map +1 -1
  24. package/dist/__tests__/mirroredPdf.test.d.ts +2 -0
  25. package/dist/__tests__/mirroredPdf.test.d.ts.map +1 -0
  26. package/dist/__tests__/mirroredPdf.test.js +104 -0
  27. package/dist/__tests__/mirroredPdf.test.js.map +1 -0
  28. package/dist/__tests__/rtlPdf.test.d.ts +2 -0
  29. package/dist/__tests__/rtlPdf.test.d.ts.map +1 -0
  30. package/dist/__tests__/rtlPdf.test.js +312 -0
  31. package/dist/__tests__/rtlPdf.test.js.map +1 -0
  32. package/dist/__tests__/verticalText.test.js +4 -4
  33. package/dist/__tests__/verticalText.test.js.map +1 -1
  34. package/dist/complexShaping.d.ts +113 -0
  35. package/dist/complexShaping.d.ts.map +1 -0
  36. package/dist/complexShaping.js +188 -0
  37. package/dist/complexShaping.js.map +1 -0
  38. package/dist/faceFiles.d.ts +9 -1
  39. package/dist/faceFiles.d.ts.map +1 -1
  40. package/dist/faceFiles.js +47 -5
  41. package/dist/faceFiles.js.map +1 -1
  42. package/dist/harfbuzz.d.ts +119 -0
  43. package/dist/harfbuzz.d.ts.map +1 -0
  44. package/dist/harfbuzz.js +280 -0
  45. package/dist/harfbuzz.js.map +1 -0
  46. package/dist/harfbuzz.wasm +0 -0
  47. package/dist/index.d.ts +2 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/pdf-backend/blockRender.d.ts.map +1 -1
  51. package/dist/pdf-backend/blockRender.js +113 -40
  52. package/dist/pdf-backend/blockRender.js.map +1 -1
  53. package/dist/pdf-backend/chip.d.ts.map +1 -1
  54. package/dist/pdf-backend/chip.js +11 -2
  55. package/dist/pdf-backend/chip.js.map +1 -1
  56. package/dist/pdf-backend/directedLine.d.ts +38 -0
  57. package/dist/pdf-backend/directedLine.d.ts.map +1 -0
  58. package/dist/pdf-backend/directedLine.js +103 -0
  59. package/dist/pdf-backend/directedLine.js.map +1 -0
  60. package/dist/pdf-backend/fontHelpers.d.ts.map +1 -1
  61. package/dist/pdf-backend/fontHelpers.js +6 -0
  62. package/dist/pdf-backend/fontHelpers.js.map +1 -1
  63. package/dist/pdf-backend/headerFooter.d.ts.map +1 -1
  64. package/dist/pdf-backend/headerFooter.js +11 -3
  65. package/dist/pdf-backend/headerFooter.js.map +1 -1
  66. package/dist/pdf-backend/index.d.ts +32 -3
  67. package/dist/pdf-backend/index.d.ts.map +1 -1
  68. package/dist/pdf-backend/index.js +40 -6
  69. package/dist/pdf-backend/index.js.map +1 -1
  70. package/dist/pdf-backend/links.d.ts +7 -2
  71. package/dist/pdf-backend/links.d.ts.map +1 -1
  72. package/dist/pdf-backend/links.js +9 -3
  73. package/dist/pdf-backend/links.js.map +1 -1
  74. package/dist/pdf-backend/outlines.js +2 -2
  75. package/dist/pdf-backend/outlines.js.map +1 -1
  76. package/dist/pdf-backend/primitives.d.ts +46 -2
  77. package/dist/pdf-backend/primitives.d.ts.map +1 -1
  78. package/dist/pdf-backend/primitives.js +67 -5
  79. package/dist/pdf-backend/primitives.js.map +1 -1
  80. package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -1
  81. package/dist/pdf-backend/renderResourceBlock.js +48 -14
  82. package/dist/pdf-backend/renderResourceBlock.js.map +1 -1
  83. package/dist/pdf-backend/rtlRun.d.ts +12 -0
  84. package/dist/pdf-backend/rtlRun.d.ts.map +1 -0
  85. package/dist/pdf-backend/rtlRun.js +31 -0
  86. package/dist/pdf-backend/rtlRun.js.map +1 -0
  87. package/dist/pdf-backend/shapedText.d.ts +122 -0
  88. package/dist/pdf-backend/shapedText.d.ts.map +1 -0
  89. package/dist/pdf-backend/shapedText.js +635 -0
  90. package/dist/pdf-backend/shapedText.js.map +1 -0
  91. package/dist/pdf-backend/svgVector.d.ts +9 -2
  92. package/dist/pdf-backend/svgVector.d.ts.map +1 -1
  93. package/dist/pdf-backend/svgVector.js +42 -18
  94. package/dist/pdf-backend/svgVector.js.map +1 -1
  95. package/dist/worker/client.d.ts.map +1 -1
  96. package/dist/worker/client.js +10 -1
  97. package/dist/worker/client.js.map +1 -1
  98. package/dist/worker/protocol.d.ts +5 -1
  99. package/dist/worker/protocol.d.ts.map +1 -1
  100. package/package.json +6 -5
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Complex-script shaping with HarfBuzz (issue #380).
3
+ *
4
+ * pdf-lib shapes through fontkit, which joins Arabic letters but places
5
+ * none of their marks: every `yOffset` is dropped, so a shadda and its
6
+ * fatha land on each other, Noto Naskh's dots and kasras merge, and Amiri
7
+ * loses the contextual lookups of a vocalised ٱللَّه. It also reverses a
8
+ * right-to-left run whole, digits and Latin included, and picks the script
9
+ * from the run's first letters, so a line that opens in Latin gets no
10
+ * Arabic shaping at all. The browser that measured the layout shapes with
11
+ * HarfBuzz; so does this module, glyph for glyph the same.
12
+ *
13
+ * HarfBuzz is a WebAssembly build (harfbuzzjs's `harfbuzz.wasm`, about
14
+ * 430 KB, 145 KB brotli), bound in `harfbuzz.ts` without the harfbuzzjs
15
+ * glue. It is loaded only for a document that sets text needing it
16
+ * ({@link needsComplexShaping}), once, before the pages are drawn
17
+ * ({@link loadComplexShaper}); shaping itself is then synchronous, as the
18
+ * page painters are.
19
+ *
20
+ * Fonts are identified by their bytes (the file pdf-lib embeds): one
21
+ * HarfBuzz face per file, and per face the runs already shaped, since the
22
+ * same words recur through a book.
23
+ */
24
+ import { type HarfBuzzWasmSource } from './harfbuzz';
25
+ /** Why HarfBuzz could not be loaded, for the `complexShapingUnavailable`
26
+ * warning. */
27
+ export interface ComplexShaperFailure {
28
+ reason: string;
29
+ }
30
+ /**
31
+ * Load HarfBuzz, once. Resolves true when it is ready; when it could not
32
+ * be loaded (no WebAssembly, the binary found nowhere), false, and
33
+ * `onFailure` hears why: the painters then shape with fontkit, as they did
34
+ * before, and the text keeps its joining but not its marks or its order.
35
+ * A failed load is tried again on the next call, which may bring a
36
+ * `source` (`RenderToPdfOptions.harfbuzzWasm`) the first did not; a call
37
+ * without one (an SVG's text, shaped while the resources are embedded)
38
+ * uses the last given. Once loaded, `source` is not looked at.
39
+ */
40
+ export declare function loadComplexShaper(source?: HarfBuzzWasmSource, onFailure?: (failure: ComplexShaperFailure) => void): Promise<boolean>;
41
+ /** Whether {@link loadComplexShaper} has finished loading HarfBuzz. */
42
+ export declare function complexShaperReady(): boolean;
43
+ /**
44
+ * Whether a code point is shaped with HarfBuzz: a letter or mark of a
45
+ * right-to-left script (Hebrew, Arabic, Syriac, Thaana, N'Ko, Samaritan,
46
+ * Mandaic and the Arabic extensions up to U+08FF; their presentation forms;
47
+ * the right-to-left blocks of the supplementary planes, Adlam and Hanifi
48
+ * Rohingya among them). Every right-to-left run needs it, not only the
49
+ * joining ones: fontkit turns a run around whole, so a pointed Hebrew word
50
+ * loses its mark positions and a number inside a Hebrew phrase reads
51
+ * backwards. The Indic scripts are shaped well enough by fontkit for now
52
+ * and stay with it.
53
+ */
54
+ export declare function codePointNeedsComplexShaping(cp: number): boolean;
55
+ /** Whether `text` holds a character {@link codePointNeedsComplexShaping}. */
56
+ export declare function needsComplexShaping(text: string): boolean;
57
+ /**
58
+ * Whether `text` holds a letter of a joining script (Arabic and its
59
+ * extensions, Syriac, N'Ko, Mandaic, Hanifi Rohingya, Sogdian, Adlam):
60
+ * letters that connect to their neighbours, which character spacing (`Tc`)
61
+ * would pull apart. Hebrew and Thaana do not join and may be tracked.
62
+ */
63
+ export declare function joinsLetters(text: string): boolean;
64
+ /** One glyph of a shaped run, in font units. `gid` is the glyph's id in
65
+ * the font file; `cluster` the UTF-16 offset in the run's text of the
66
+ * first character it stands for. Glyphs come in visual order (left to
67
+ * right), so a right-to-left run lists its clusters descending. */
68
+ export interface ShapedGlyph {
69
+ gid: number;
70
+ cluster: number;
71
+ xAdvance: number;
72
+ yAdvance: number;
73
+ xOffset: number;
74
+ yOffset: number;
75
+ }
76
+ /** A run shaped by {@link shapeRun}: its glyphs and the face's units per em. */
77
+ export interface ShapedRun {
78
+ glyphs: readonly ShapedGlyph[];
79
+ upem: number;
80
+ }
81
+ /** OpenType features to shape with: tags turned on (`['ss01']`), or tags
82
+ * with their values (`{ liga: false, salt: 2 }`), as pdf-lib takes them. */
83
+ export type ShapeFeatures = readonly string[] | Readonly<Record<string, boolean | number>>;
84
+ export interface ShapeOptions {
85
+ /** The run's direction: a right-to-left run comes out reversed, its
86
+ * brackets mirrored. The text must be one bidi run (see `bidiRuns.ts`):
87
+ * HarfBuzz applies no bidi algorithm, and reverses the digits inside
88
+ * an Arabic run with the letters. */
89
+ direction: 'ltr' | 'rtl';
90
+ /** ISO 15924 script tag (`Arab`); guessed from the text when absent. */
91
+ script?: string;
92
+ /** BCP 47 language tag (`ar`, `fa`, `ur`): selects the font's `locl`
93
+ * forms (Persian and Urdu digits, Sindhi letters). */
94
+ language?: string;
95
+ features?: ShapeFeatures;
96
+ }
97
+ /**
98
+ * Shape `text` in the font file `fontBytes` with HarfBuzz. Undefined when
99
+ * HarfBuzz is not loaded ({@link loadComplexShaper}). Cached per face,
100
+ * text, direction, script, language and features; the result must not be
101
+ * changed.
102
+ *
103
+ * Clusters are graphemes (`MONOTONE_GRAPHEMES`): a letter and its marks
104
+ * are one cluster, which text extraction reads as one unit.
105
+ */
106
+ export declare function shapeRun(fontBytes: Uint8Array, text: string, options: ShapeOptions): ShapedRun | undefined;
107
+ /** The text each glyph of `run` stands for, for text extraction: the
108
+ * first glyph met of each cluster carries the cluster's characters
109
+ * (`text` from its offset up to the next cluster's), every other glyph of
110
+ * it (a mark a decomposition added, the second glyph of a split vowel)
111
+ * none. */
112
+ export declare function clusterTexts(run: ShapedRun, text: string): string[];
113
+ //# sourceMappingURL=complexShaping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complexShaping.d.ts","sourceRoot":"","sources":["../src/complexShaping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAA+B,KAAK,kBAAkB,EAAqB,MAAM,YAAY,CAAC;AAMrG;eACe;AACf,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,CAAC,EAAE,kBAAkB,EAAE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAc1I;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAOhE;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAYzD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAWlD;AAED;;;oEAGoE;AACpE,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gFAAgF;AAChF,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;6EAC6E;AAC7E,MAAM,MAAM,aAAa,GAAG,SAAS,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC;AAE3F,MAAM,WAAW,YAAY;IAC3B;;;0CAGsC;IACtC,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC;IACzB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;2DACuD;IACvD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,CAgB1G;AAED;;;;YAIY;AACZ,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUnE"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Complex-script shaping with HarfBuzz (issue #380).
3
+ *
4
+ * pdf-lib shapes through fontkit, which joins Arabic letters but places
5
+ * none of their marks: every `yOffset` is dropped, so a shadda and its
6
+ * fatha land on each other, Noto Naskh's dots and kasras merge, and Amiri
7
+ * loses the contextual lookups of a vocalised ٱللَّه. It also reverses a
8
+ * right-to-left run whole, digits and Latin included, and picks the script
9
+ * from the run's first letters, so a line that opens in Latin gets no
10
+ * Arabic shaping at all. The browser that measured the layout shapes with
11
+ * HarfBuzz; so does this module, glyph for glyph the same.
12
+ *
13
+ * HarfBuzz is a WebAssembly build (harfbuzzjs's `harfbuzz.wasm`, about
14
+ * 430 KB, 145 KB brotli), bound in `harfbuzz.ts` without the harfbuzzjs
15
+ * glue. It is loaded only for a document that sets text needing it
16
+ * ({@link needsComplexShaping}), once, before the pages are drawn
17
+ * ({@link loadComplexShaper}); shaping itself is then synchronous, as the
18
+ * page painters are.
19
+ *
20
+ * Fonts are identified by their bytes (the file pdf-lib embeds): one
21
+ * HarfBuzz face per file, and per face the runs already shaped, since the
22
+ * same words recur through a book.
23
+ */
24
+ import { loadHarfBuzz } from './harfbuzz';
25
+ let hb;
26
+ let loading;
27
+ let lastSource;
28
+ /**
29
+ * Load HarfBuzz, once. Resolves true when it is ready; when it could not
30
+ * be loaded (no WebAssembly, the binary found nowhere), false, and
31
+ * `onFailure` hears why: the painters then shape with fontkit, as they did
32
+ * before, and the text keeps its joining but not its marks or its order.
33
+ * A failed load is tried again on the next call, which may bring a
34
+ * `source` (`RenderToPdfOptions.harfbuzzWasm`) the first did not; a call
35
+ * without one (an SVG's text, shaped while the resources are embedded)
36
+ * uses the last given. Once loaded, `source` is not looked at.
37
+ */
38
+ export async function loadComplexShaper(source, onFailure) {
39
+ if (hb)
40
+ return true;
41
+ if (source !== undefined)
42
+ lastSource = source;
43
+ if (!loading) {
44
+ loading = loadHarfBuzz(lastSource);
45
+ loading.catch(() => { loading = undefined; });
46
+ }
47
+ try {
48
+ hb = await loading;
49
+ return true;
50
+ }
51
+ catch (err) {
52
+ onFailure?.({ reason: err instanceof Error ? err.message : String(err) });
53
+ return false;
54
+ }
55
+ }
56
+ /** Whether {@link loadComplexShaper} has finished loading HarfBuzz. */
57
+ export function complexShaperReady() {
58
+ return hb !== undefined;
59
+ }
60
+ /**
61
+ * Whether a code point is shaped with HarfBuzz: a letter or mark of a
62
+ * right-to-left script (Hebrew, Arabic, Syriac, Thaana, N'Ko, Samaritan,
63
+ * Mandaic and the Arabic extensions up to U+08FF; their presentation forms;
64
+ * the right-to-left blocks of the supplementary planes, Adlam and Hanifi
65
+ * Rohingya among them). Every right-to-left run needs it, not only the
66
+ * joining ones: fontkit turns a run around whole, so a pointed Hebrew word
67
+ * loses its mark positions and a number inside a Hebrew phrase reads
68
+ * backwards. The Indic scripts are shaped well enough by fontkit for now
69
+ * and stay with it.
70
+ */
71
+ export function codePointNeedsComplexShaping(cp) {
72
+ if (cp < 0x0590)
73
+ return false;
74
+ return cp <= 0x08ff
75
+ || (cp >= 0xfb1d && cp <= 0xfdff)
76
+ || (cp >= 0xfe70 && cp <= 0xfefe)
77
+ || (cp >= 0x10800 && cp <= 0x10fff)
78
+ || (cp >= 0x1e800 && cp <= 0x1efff);
79
+ }
80
+ /** Whether `text` holds a character {@link codePointNeedsComplexShaping}. */
81
+ export function needsComplexShaping(text) {
82
+ for (let i = 0; i < text.length; i++) {
83
+ const c = text.charCodeAt(i);
84
+ if (c < 0x0590)
85
+ continue;
86
+ if (c >= 0xd800 && c <= 0xdbff) {
87
+ if (codePointNeedsComplexShaping(text.codePointAt(i)))
88
+ return true;
89
+ i++;
90
+ continue;
91
+ }
92
+ if (codePointNeedsComplexShaping(c))
93
+ return true;
94
+ }
95
+ return false;
96
+ }
97
+ /**
98
+ * Whether `text` holds a letter of a joining script (Arabic and its
99
+ * extensions, Syriac, N'Ko, Mandaic, Hanifi Rohingya, Sogdian, Adlam):
100
+ * letters that connect to their neighbours, which character spacing (`Tc`)
101
+ * would pull apart. Hebrew and Thaana do not join and may be tracked.
102
+ */
103
+ export function joinsLetters(text) {
104
+ for (const ch of text) {
105
+ const cp = ch.codePointAt(0);
106
+ if (cp < 0x0600)
107
+ continue;
108
+ if ((cp <= 0x074f) || (cp >= 0x0750 && cp <= 0x077f) || (cp >= 0x07c0 && cp <= 0x07ff)
109
+ || (cp >= 0x0840 && cp <= 0x08ff) || (cp >= 0xfb50 && cp <= 0xfdff) || (cp >= 0xfe70 && cp <= 0xfefe)
110
+ || (cp >= 0x10d00 && cp <= 0x10d3f) || (cp >= 0x10f30 && cp <= 0x10f6f) || (cp >= 0x1e900 && cp <= 0x1e95f)) {
111
+ return true;
112
+ }
113
+ }
114
+ return false;
115
+ }
116
+ /** HarfBuzz faces by font file. */
117
+ const faces = new WeakMap();
118
+ /** Shaped runs kept per face before the cache is emptied. */
119
+ const RUN_CACHE_SLOTS = 50_000;
120
+ function faceOf(bytes) {
121
+ let entry = faces.get(bytes);
122
+ if (!entry) {
123
+ const runs = new Map();
124
+ entry = { font: hb.openFont(bytes, runs), runs };
125
+ faces.set(bytes, entry);
126
+ }
127
+ return entry;
128
+ }
129
+ function featureList(features) {
130
+ if (!features)
131
+ return undefined;
132
+ if (Array.isArray(features))
133
+ return features.map((tag) => [tag, 1]);
134
+ return Object.entries(features).map(([tag, value]) => [tag, typeof value === 'number' ? value : value ? 1 : 0]);
135
+ }
136
+ function featureKey(features) {
137
+ if (!features)
138
+ return '';
139
+ return Array.isArray(features) ? features.join(',') : Object.entries(features).map(([t, v]) => `${t}=${Number(v)}`).join(',');
140
+ }
141
+ /**
142
+ * Shape `text` in the font file `fontBytes` with HarfBuzz. Undefined when
143
+ * HarfBuzz is not loaded ({@link loadComplexShaper}). Cached per face,
144
+ * text, direction, script, language and features; the result must not be
145
+ * changed.
146
+ *
147
+ * Clusters are graphemes (`MONOTONE_GRAPHEMES`): a letter and its marks
148
+ * are one cluster, which text extraction reads as one unit.
149
+ */
150
+ export function shapeRun(fontBytes, text, options) {
151
+ if (!hb)
152
+ return undefined;
153
+ const face = faceOf(fontBytes);
154
+ const key = `${options.direction}|${options.script ?? ''}|${options.language ?? ''}|${featureKey(options.features)}|${text}`;
155
+ const hit = face.runs.get(key);
156
+ if (hit)
157
+ return hit;
158
+ const glyphs = hb.shape(face.font, text, {
159
+ direction: options.direction,
160
+ ...(options.script ? { script: options.script } : {}),
161
+ ...(options.language ? { language: options.language } : {}),
162
+ ...(options.features ? { features: featureList(options.features) } : {}),
163
+ });
164
+ const run = { glyphs, upem: face.font.upem };
165
+ if (face.runs.size >= RUN_CACHE_SLOTS)
166
+ face.runs.clear();
167
+ face.runs.set(key, run);
168
+ return run;
169
+ }
170
+ /** The text each glyph of `run` stands for, for text extraction: the
171
+ * first glyph met of each cluster carries the cluster's characters
172
+ * (`text` from its offset up to the next cluster's), every other glyph of
173
+ * it (a mark a decomposition added, the second glyph of a split vowel)
174
+ * none. */
175
+ export function clusterTexts(run, text) {
176
+ const starts = [...new Set(run.glyphs.map((g) => g.cluster))].sort((a, b) => a - b);
177
+ const endOf = new Map();
178
+ for (let i = 0; i < starts.length; i++)
179
+ endOf.set(starts[i], starts[i + 1] ?? text.length);
180
+ const seen = new Set();
181
+ return run.glyphs.map((g) => {
182
+ if (seen.has(g.cluster))
183
+ return '';
184
+ seen.add(g.cluster);
185
+ return text.slice(g.cluster, endOf.get(g.cluster));
186
+ });
187
+ }
188
+ //# sourceMappingURL=complexShaping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complexShaping.js","sourceRoot":"","sources":["../src/complexShaping.ts"],"names":[],"mappings":"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"}
@@ -52,8 +52,16 @@ export interface FileRun {
52
52
  * invisible one (a joiner, a variation selector), stays in the run before
53
53
  * it: it is drawn (or dropped) as that file's fallback, and a printing one
54
54
  * is reported as missing when shaped.
55
+ *
56
+ * With `rtl` (a run HarfBuzz shapes right to left) a mirrored character
57
+ * goes by the glyph that run will show: HarfBuzz sets `(` as `)` only when
58
+ * the file has a `)`, and keeps the `(` otherwise. Fontsource's `arabic`
59
+ * file of Amiri holds `(` and not `)`, so an opening bracket cut into it
60
+ * printed unmirrored in an Arabic line (#401). Such a character is set in
61
+ * the first file with its mirror (the `latin` one), or by its own glyph
62
+ * when no file has the mirror.
55
63
  */
56
- export declare function fileRuns(font: PDFFont, text: string): FileRun[];
64
+ export declare function fileRuns(font: PDFFont, text: string, rtl?: boolean): FileRun[];
57
65
  /** `text`'s width at `size` (points), each run measured in its file. */
58
66
  export declare function widthOfTextAtSize(font: PDFFont, text: string, size: number): number;
59
67
  /** Record the characters of `text` that `font` has no glyph for (it draws
@@ -1 +1 @@
1
- {"version":3,"file":"faceFiles.d.ts","sourceRoot":"","sources":["../src/faceFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAoBvC,sEAAsE;AACtE,qBAAa,SAAS;IACpB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;gBAE/C,KAAK,EAAE,SAAS,OAAO,EAAE;IAKrC;uBACmB;IACnB,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAQxB,2CAA2C;IAC3C,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO;IAI1C,uEAAuE;IACvE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;CAapC;AAID;;;oDAGoD;AACpD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CASxF;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAGhE;AAED,+CAA+C;AAC/C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAmB/D;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnF;AAQD;;;6EAG6E;AAC7E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAanE;AAED;yEACyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAEtF;AAED;4BAC4B;AAC5B,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9C"}
1
+ {"version":3,"file":"faceFiles.d.ts","sourceRoot":"","sources":["../src/faceFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAqBvC,sEAAsE;AACtE,qBAAa,SAAS;IACpB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgD;IACtE,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;gBAE/C,KAAK,EAAE,SAAS,OAAO,EAAE;IAKrC;uBACmB;IACnB,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAQxB,2CAA2C;IAC3C,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO;IAI1C,uEAAuE;IACvE,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;CAapC;AAID;;;oDAGoD;AACpD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,CASxF;AAED,6EAA6E;AAC7E,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAGhE;AAED,+CAA+C;AAC/C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,UAAQ,GAAG,OAAO,EAAE,CAwC5E;AAcD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnF;AAQD;;;6EAG6E;AAC7E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAanE;AAED;yEACyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAEtF;AAED;4BAC4B;AAC5B,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9C"}
package/dist/faceFiles.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { mirroredCodePoint } from 'postext';
1
2
  import { isDefaultIgnorable, isFallbackHandled, substituteGlyph } from './pdf-backend/fallbackSpaces';
2
3
  function coverageFace(font) {
3
4
  const face = font.embedder?.font;
@@ -82,29 +83,70 @@ export function faceFilesOf(font) {
82
83
  * invisible one (a joiner, a variation selector), stays in the run before
83
84
  * it: it is drawn (or dropped) as that file's fallback, and a printing one
84
85
  * is reported as missing when shaped.
86
+ *
87
+ * With `rtl` (a run HarfBuzz shapes right to left) a mirrored character
88
+ * goes by the glyph that run will show: HarfBuzz sets `(` as `)` only when
89
+ * the file has a `)`, and keeps the `(` otherwise. Fontsource's `arabic`
90
+ * file of Amiri holds `(` and not `)`, so an opening bracket cut into it
91
+ * printed unmirrored in an Arabic line (#401). Such a character is set in
92
+ * the first file with its mirror (the `latin` one), or by its own glyph
93
+ * when no file has the mirror.
85
94
  */
86
- export function fileRuns(font, text) {
95
+ export function fileRuns(font, text, rtl = false) {
87
96
  const list = faceFilesOf(font);
88
97
  if (!list)
89
98
  return [{ font, text }];
90
99
  const runs = [];
91
100
  let current;
101
+ // Joining controls waiting for the letter after them (see below).
102
+ let pending = '';
103
+ let previous = 0;
92
104
  for (const ch of text) {
93
105
  const cp = ch.codePointAt(0);
106
+ // A zero width joiner or non-joiner shapes with the letters it sits
107
+ // between (HarfBuzz reads it only inside one run): it stays with the
108
+ // letter before it, and one with no letter before it (opening the
109
+ // text, after a space) goes with the letter after it. Fontsource
110
+ // serves U+2000–206F from the `latin` file, so the file that covers it
111
+ // first is rarely the Arabic letters' one.
112
+ if (isJoiningControl(cp) && (!current || !joinsOnto(previous))) {
113
+ pending += ch;
114
+ continue;
115
+ }
116
+ const mirror = rtl ? mirroredCodePoint(cp) : cp;
117
+ const shown = mirror !== cp && list.fileFor(mirror) ? mirror : cp;
94
118
  let file = current?.font;
95
- if (!file || (!list.covers(file, cp) && !isDefaultIgnorable(cp))) {
96
- file = list.fileFor(cp) ?? current?.font ?? font;
119
+ if (!file || (!list.covers(file, shown) && !isDefaultIgnorable(cp))) {
120
+ file = list.fileFor(shown) ?? current?.font ?? font;
97
121
  }
98
122
  if (current && current.font === file) {
99
- current.text += ch;
123
+ current.text += pending + ch;
100
124
  }
101
125
  else {
102
- current = { font: file, text: ch };
126
+ current = { font: file, text: pending + ch };
103
127
  runs.push(current);
104
128
  }
129
+ pending = '';
130
+ previous = cp;
131
+ }
132
+ if (pending) {
133
+ if (current)
134
+ current.text += pending;
135
+ else
136
+ runs.push({ font, text: pending });
105
137
  }
106
138
  return runs.length > 0 ? runs : [{ font, text }];
107
139
  }
140
+ /** ZWNJ (U+200C) and ZWJ (U+200D): they choose the joining form of the
141
+ * letters either side of them. */
142
+ function isJoiningControl(cp) {
143
+ return cp === 0x200c || cp === 0x200d;
144
+ }
145
+ /** Whether a joining control after `cp` belongs with it: anything but a
146
+ * space or a control (a letter, a mark, a digit, punctuation). */
147
+ function joinsOnto(cp) {
148
+ return cp > 0x20 && !(cp >= 0x7f && cp < 0xa0) && !/\s/u.test(String.fromCodePoint(cp)) && !isJoiningControl(cp);
149
+ }
108
150
  /** `text`'s width at `size` (points), each run measured in its file. */
109
151
  export function widthOfTextAtSize(font, text, size) {
110
152
  const runs = fileRuns(font, text);
@@ -1 +1 @@
1
- {"version":3,"file":"faceFiles.js","sourceRoot":"","sources":["../src/faceFiles.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAOtG,SAAS,YAAY,CAAC,IAAa;IACjC,MAAM,IAAI,GAAI,IAA0D,CAAC,QAAQ,EAAE,IAAI,CAAC;IACxF,OAAO,IAAI,IAAI,OAAO,IAAI,CAAC,oBAAoB,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AACpF,CAAC;AAED;;iCAEiC;AACjC,SAAS,YAAY,CAAC,EAAU;IAC9B,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,iBAAiB,CAAC,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,sEAAsE;AACtE,MAAM,OAAO,SAAS;IACX,KAAK,CAAY;IACT,KAAK,GAAG,IAAI,GAAG,EAAqC,CAAC;IACtE,4DAA4D;IAC3C,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE3D,YAAY,KAAyB;QACnC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED;uBACmB;IACnB,GAAG,CAAC,IAAa;QACf,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QACjC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;QACzC,+CAA+C;QAC/C,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,GAAG,KAAK,IAAI;gBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,2CAA2C;IAC3C,MAAM,CAAC,IAAa,EAAE,EAAU;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC;IACjE,CAAC;IAED,uEAAuE;IACvE,OAAO,CAAC,EAAU;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,GAAG,CAAC;QAClC,IAAI,KAAK,GAAmB,IAAI,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC;gBAC1B,KAAK,GAAG,IAAI,CAAC;gBACb,MAAM;YACR,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,MAAM,SAAS,GAAG,IAAI,OAAO,EAAsB,CAAC;AAEpD;;;oDAGoD;AACpD,MAAM,UAAU,iBAAiB,CAAC,OAAgB,EAAE,KAAyB;IAC3E,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;IAChD,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,WAAW,CAAC,IAAa;IACvC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAQD;;;;;;;;;GASG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAa,EAAE,IAAY;IAClD,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IACnC,MAAM,IAAI,GAAc,EAAE,CAAC;IAC3B,IAAI,OAA4B,CAAC;IACjC,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;QAC9B,IAAI,IAAI,GAAG,OAAO,EAAE,IAAI,CAAC;QACzB,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACjE,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;QACnD,CAAC;QACD,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACrC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,IAAa,EAAE,IAAY,EAAE,IAAY;IACzE,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5E,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;4DAE4D;AAC5D,MAAM,aAAa,GAAG,IAAI,OAAO,EAAgC,CAAC;AAClE,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB;;;6EAG6E;AAC7E,MAAM,UAAU,iBAAiB,CAAC,IAAa,EAAE,IAAY;IAC3D,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;QAC9B,IAAI,YAAY,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,oBAAoB,CAAC,EAAE,CAAC,IAAI,eAAe,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,SAAS;YAAE,SAAS;QAC3G,IAAI,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;YACjB,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED;yEACyE;AACzE,MAAM,UAAU,eAAe,CAAC,IAAa;IAC3C,OAAO,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;4BAC4B;AAC5B,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"faceFiles.js","sourceRoot":"","sources":["../src/faceFiles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * HarfBuzz from its WebAssembly binary, without the Emscripten glue
3
+ * (issue #380).
4
+ *
5
+ * harfbuzzjs ships `harfbuzz.wasm` with a JavaScript module that loads it,
6
+ * and that module works out where it runs from `process`: in Node it
7
+ * imports `module` to read the file. A CDN that compiles packages for the
8
+ * browser (esm.sh) defines a `process` of its own, so in a page that
9
+ * imports postext-pdf from it the glue took the Node path and threw, and
10
+ * every Arabic PDF fell back to fontkit, its marks unplaced.
11
+ *
12
+ * The binary needs very little from its host: five imports (a heap that
13
+ * grows, an abort, a timer and an exit Emscripten never calls for
14
+ * shaping), and the static constructors run once. This module provides
15
+ * them and binds the dozen `hb_*` functions postext-pdf shapes with, so
16
+ * HarfBuzz loads the same way in Node, a page, a Worker and a bundle.
17
+ *
18
+ * The binary is taken from, in order: the source the caller gave
19
+ * (`RenderToPdfOptions.harfbuzzWasm`); `harfbuzz.wasm` beside this module
20
+ * (the build copies it into `dist`; a bundler sees the literal
21
+ * `new URL(…, import.meta.url)` and emits it as an asset; Node reads the
22
+ * file); in the source tree, the harfbuzzjs package itself; and, for a
23
+ * page whose CDN rebuilt the module somewhere else (esm.sh puts it under
24
+ * `/es2022/`, where no `.wasm` sits beside it), the same harfbuzzjs
25
+ * release from jsDelivr, then from esm.sh.
26
+ */
27
+ /** The harfbuzzjs release whose `harfbuzz.wasm` this binding is written
28
+ * for, and fetched from a CDN when no copy sits beside the module. A test
29
+ * keeps it equal to the installed package. */
30
+ export declare const HARFBUZZ_VERSION = "1.6.2";
31
+ /** Where the binary can come from: its URL, or its bytes. */
32
+ export type HarfBuzzWasmSource = string | URL | ArrayBuffer | ArrayBufferView;
33
+ /** One shaped glyph, as `hb_glyph_info_t` and `hb_glyph_position_t` give it. */
34
+ export interface HbGlyph {
35
+ gid: number;
36
+ cluster: number;
37
+ xAdvance: number;
38
+ yAdvance: number;
39
+ xOffset: number;
40
+ yOffset: number;
41
+ }
42
+ /** A face made from a font file: the `hb_font_t` to shape with and its
43
+ * units per em. */
44
+ export interface HbFontHandle {
45
+ readonly font: number;
46
+ readonly upem: number;
47
+ }
48
+ export interface HbShapeRequest {
49
+ direction: 'ltr' | 'rtl';
50
+ /** ISO 15924 tag; HarfBuzz guesses it from the text when absent. */
51
+ script?: string;
52
+ /** BCP 47 tag. */
53
+ language?: string;
54
+ /** OpenType features and their values. */
55
+ features?: readonly (readonly [tag: string, value: number])[];
56
+ }
57
+ interface HbExports {
58
+ memory: WebAssembly.Memory;
59
+ __wasm_call_ctors(): void;
60
+ malloc(size: number): number;
61
+ free(ptr: number): void;
62
+ hb_blob_create(data: number, length: number, mode: number, userData: number, destroy: number): number;
63
+ hb_blob_destroy(blob: number): void;
64
+ hb_face_create(blob: number, index: number): number;
65
+ hb_face_destroy(face: number): void;
66
+ hb_face_get_upem(face: number): number;
67
+ hb_font_create(face: number): number;
68
+ hb_font_destroy(font: number): void;
69
+ hb_buffer_create(): number;
70
+ hb_buffer_reset(buffer: number): void;
71
+ hb_buffer_set_cluster_level(buffer: number, level: number): void;
72
+ hb_buffer_add_utf16(buffer: number, text: number, textLength: number, itemOffset: number, itemLength: number): void;
73
+ hb_buffer_guess_segment_properties(buffer: number): void;
74
+ hb_buffer_set_direction(buffer: number, direction: number): void;
75
+ hb_buffer_set_script(buffer: number, script: number): void;
76
+ hb_buffer_set_language(buffer: number, language: number): void;
77
+ hb_script_from_string(str: number, length: number): number;
78
+ hb_language_from_string(str: number, length: number): number;
79
+ hb_buffer_get_length(buffer: number): number;
80
+ hb_buffer_get_glyph_infos(buffer: number, length: number): number;
81
+ hb_buffer_get_glyph_positions(buffer: number, length: number): number;
82
+ hb_shape(font: number, buffer: number, features: number, numFeatures: number): void;
83
+ }
84
+ /** A running HarfBuzz: one WebAssembly instance and one shaping buffer. */
85
+ export declare class HarfBuzz {
86
+ private readonly hb;
87
+ private readonly buffer;
88
+ /** Frees a face's memory once the font file it was made from is
89
+ * collected (the caller keys faces by the file's bytes). */
90
+ private readonly faces;
91
+ constructor(hb: HbExports);
92
+ /** The heap as bytes. A fresh view each time: growing the memory
93
+ * detaches the old one. */
94
+ private get u8();
95
+ /** Copy `str` (ASCII: a script or language tag) into the heap, NUL
96
+ * terminated; the caller frees it. */
97
+ private ascii;
98
+ /**
99
+ * A face for the font file `bytes` (its first face). The bytes are
100
+ * copied into the heap and freed, with the face, when `owner` (the
101
+ * caller's handle for this face) is collected.
102
+ */
103
+ openFont(bytes: Uint8Array, owner: object): HbFontHandle;
104
+ /** Shape `text` (one bidi run) with `font`. Glyphs in visual order;
105
+ * clusters are UTF-16 offsets, a letter and its marks one cluster. */
106
+ shape(font: HbFontHandle, text: string, request: HbShapeRequest): HbGlyph[];
107
+ }
108
+ /** Instantiate HarfBuzz from its binary. */
109
+ export declare function instantiateHarfBuzz(wasm: BufferSource): Promise<HarfBuzz>;
110
+ /** What a relative `source` resolves against: the page's (or worker's)
111
+ * location, as a `fetch` would; this module's URL where there is none. */
112
+ export declare function sourceBase(): string;
113
+ /**
114
+ * Load HarfBuzz from `source`, or from the default locations in turn.
115
+ * Rejects with every place tried and why it failed.
116
+ */
117
+ export declare function loadHarfBuzz(source?: HarfBuzzWasmSource): Promise<HarfBuzz>;
118
+ export {};
119
+ //# sourceMappingURL=harfbuzz.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harfbuzz.d.ts","sourceRoot":"","sources":["../src/harfbuzz.ts"],"names":[],"mappings":"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"}