postext-pdf 1.14.1 → 1.15.1
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.
- package/README.md +13 -1
- package/dist/__bench__/arabicShaping.bench.test.d.ts +2 -0
- package/dist/__bench__/arabicShaping.bench.test.d.ts.map +1 -0
- package/dist/__bench__/arabicShaping.bench.test.js +53 -0
- package/dist/__bench__/arabicShaping.bench.test.js.map +1 -0
- package/dist/__tests__/arabicShaping.test.d.ts +2 -0
- package/dist/__tests__/arabicShaping.test.d.ts.map +1 -0
- package/dist/__tests__/arabicShaping.test.js +261 -0
- package/dist/__tests__/arabicShaping.test.js.map +1 -0
- package/dist/__tests__/complexShaping.test.d.ts +2 -0
- package/dist/__tests__/complexShaping.test.d.ts.map +1 -0
- package/dist/__tests__/complexShaping.test.js +145 -0
- package/dist/__tests__/complexShaping.test.js.map +1 -0
- package/dist/__tests__/designTextRtl.test.d.ts +2 -0
- package/dist/__tests__/designTextRtl.test.d.ts.map +1 -0
- package/dist/__tests__/designTextRtl.test.js +136 -0
- package/dist/__tests__/designTextRtl.test.js.map +1 -0
- package/dist/__tests__/harfbuzz.test.d.ts +2 -0
- package/dist/__tests__/harfbuzz.test.d.ts.map +1 -0
- package/dist/__tests__/harfbuzz.test.js +103 -0
- package/dist/__tests__/harfbuzz.test.js.map +1 -0
- package/dist/__tests__/measuredLines.test.js +13 -5
- package/dist/__tests__/measuredLines.test.js.map +1 -1
- package/dist/__tests__/mirroredPdf.test.d.ts +2 -0
- package/dist/__tests__/mirroredPdf.test.d.ts.map +1 -0
- package/dist/__tests__/mirroredPdf.test.js +104 -0
- package/dist/__tests__/mirroredPdf.test.js.map +1 -0
- package/dist/__tests__/rtlPdf.test.d.ts +2 -0
- package/dist/__tests__/rtlPdf.test.d.ts.map +1 -0
- package/dist/__tests__/rtlPdf.test.js +312 -0
- package/dist/__tests__/rtlPdf.test.js.map +1 -0
- package/dist/__tests__/verticalText.test.js +4 -4
- package/dist/__tests__/verticalText.test.js.map +1 -1
- package/dist/complexShaping.d.ts +113 -0
- package/dist/complexShaping.d.ts.map +1 -0
- package/dist/complexShaping.js +188 -0
- package/dist/complexShaping.js.map +1 -0
- package/dist/faceFiles.d.ts +9 -1
- package/dist/faceFiles.d.ts.map +1 -1
- package/dist/faceFiles.js +47 -5
- package/dist/faceFiles.js.map +1 -1
- package/dist/harfbuzz.d.ts +119 -0
- package/dist/harfbuzz.d.ts.map +1 -0
- package/dist/harfbuzz.js +280 -0
- package/dist/harfbuzz.js.map +1 -0
- package/dist/harfbuzz.wasm +0 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pdf-backend/blockRender.d.ts.map +1 -1
- package/dist/pdf-backend/blockRender.js +113 -40
- package/dist/pdf-backend/blockRender.js.map +1 -1
- package/dist/pdf-backend/chip.d.ts.map +1 -1
- package/dist/pdf-backend/chip.js +11 -2
- package/dist/pdf-backend/chip.js.map +1 -1
- package/dist/pdf-backend/directedLine.d.ts +38 -0
- package/dist/pdf-backend/directedLine.d.ts.map +1 -0
- package/dist/pdf-backend/directedLine.js +103 -0
- package/dist/pdf-backend/directedLine.js.map +1 -0
- package/dist/pdf-backend/fontHelpers.d.ts.map +1 -1
- package/dist/pdf-backend/fontHelpers.js +6 -0
- package/dist/pdf-backend/fontHelpers.js.map +1 -1
- package/dist/pdf-backend/headerFooter.d.ts.map +1 -1
- package/dist/pdf-backend/headerFooter.js +11 -3
- package/dist/pdf-backend/headerFooter.js.map +1 -1
- package/dist/pdf-backend/index.d.ts +32 -3
- package/dist/pdf-backend/index.d.ts.map +1 -1
- package/dist/pdf-backend/index.js +40 -6
- package/dist/pdf-backend/index.js.map +1 -1
- package/dist/pdf-backend/links.d.ts +7 -2
- package/dist/pdf-backend/links.d.ts.map +1 -1
- package/dist/pdf-backend/links.js +9 -3
- package/dist/pdf-backend/links.js.map +1 -1
- package/dist/pdf-backend/outlines.js +2 -2
- package/dist/pdf-backend/outlines.js.map +1 -1
- package/dist/pdf-backend/primitives.d.ts +46 -2
- package/dist/pdf-backend/primitives.d.ts.map +1 -1
- package/dist/pdf-backend/primitives.js +67 -5
- package/dist/pdf-backend/primitives.js.map +1 -1
- package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -1
- package/dist/pdf-backend/renderResourceBlock.js +48 -14
- package/dist/pdf-backend/renderResourceBlock.js.map +1 -1
- package/dist/pdf-backend/rtlRun.d.ts +12 -0
- package/dist/pdf-backend/rtlRun.d.ts.map +1 -0
- package/dist/pdf-backend/rtlRun.js +31 -0
- package/dist/pdf-backend/rtlRun.js.map +1 -0
- package/dist/pdf-backend/shapedText.d.ts +122 -0
- package/dist/pdf-backend/shapedText.d.ts.map +1 -0
- package/dist/pdf-backend/shapedText.js +635 -0
- package/dist/pdf-backend/shapedText.js.map +1 -0
- package/dist/pdf-backend/svgVector.d.ts +9 -2
- package/dist/pdf-backend/svgVector.d.ts.map +1 -1
- package/dist/pdf-backend/svgVector.js +42 -18
- package/dist/pdf-backend/svgVector.js.map +1 -1
- package/dist/worker/client.d.ts.map +1 -1
- package/dist/worker/client.js +10 -1
- package/dist/worker/client.js.map +1 -1
- package/dist/worker/protocol.d.ts +5 -1
- package/dist/worker/protocol.d.ts.map +1 -1
- 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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"}
|
package/dist/faceFiles.d.ts
CHANGED
|
@@ -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
|
package/dist/faceFiles.d.ts.map
CHANGED
|
@@ -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;
|
|
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,
|
|
96
|
-
file = list.fileFor(
|
|
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);
|
package/dist/faceFiles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"faceFiles.js","sourceRoot":"","sources":["../src/faceFiles.ts"],"names":[],"mappings":"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
|
|
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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"}
|