postext-pdf 1.14.1 → 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,280 @@
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 const HARFBUZZ_VERSION = '1.6.2';
31
+ // hb-common.h, hb-buffer.h, hb-blob.h.
32
+ const HB_DIRECTION_LTR = 4;
33
+ const HB_DIRECTION_RTL = 5;
34
+ const HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = 0;
35
+ const HB_MEMORY_MODE_READONLY = 1;
36
+ /** `hb_feature_t`: tag, value, start, end, four `uint32`. */
37
+ const FEATURE_BYTES = 16;
38
+ const FEATURE_GLOBAL_END = 0xffffffff;
39
+ /** `hb_glyph_info_t` and `hb_glyph_position_t` are five 32-bit words each. */
40
+ const GLYPH_WORDS = 5;
41
+ /** The heap's ceiling, as Emscripten built it (`getHeapMax`). */
42
+ const HEAP_MAX = 2 ** 31;
43
+ const WASM_PAGE = 65536;
44
+ function hbTag(tag) {
45
+ return ((tag.charCodeAt(0) & 0xff) << 24 | (tag.charCodeAt(1) & 0xff) << 16 | (tag.charCodeAt(2) & 0xff) << 8 | (tag.charCodeAt(3) & 0xff)) >>> 0;
46
+ }
47
+ /** A running HarfBuzz: one WebAssembly instance and one shaping buffer. */
48
+ export class HarfBuzz {
49
+ hb;
50
+ buffer;
51
+ /** Frees a face's memory once the font file it was made from is
52
+ * collected (the caller keys faces by the file's bytes). */
53
+ faces = new FinalizationRegistry((f) => {
54
+ this.hb.hb_font_destroy(f.font);
55
+ this.hb.hb_face_destroy(f.face);
56
+ this.hb.free(f.data);
57
+ });
58
+ constructor(hb) {
59
+ this.hb = hb;
60
+ this.buffer = hb.hb_buffer_create();
61
+ }
62
+ /** The heap as bytes. A fresh view each time: growing the memory
63
+ * detaches the old one. */
64
+ get u8() {
65
+ return new Uint8Array(this.hb.memory.buffer);
66
+ }
67
+ /** Copy `str` (ASCII: a script or language tag) into the heap, NUL
68
+ * terminated; the caller frees it. */
69
+ ascii(str) {
70
+ const ptr = this.hb.malloc(str.length + 1);
71
+ const u8 = this.u8;
72
+ for (let i = 0; i < str.length; i++)
73
+ u8[ptr + i] = str.charCodeAt(i) & 0x7f;
74
+ u8[ptr + str.length] = 0;
75
+ return ptr;
76
+ }
77
+ /**
78
+ * A face for the font file `bytes` (its first face). The bytes are
79
+ * copied into the heap and freed, with the face, when `owner` (the
80
+ * caller's handle for this face) is collected.
81
+ */
82
+ openFont(bytes, owner) {
83
+ const hb = this.hb;
84
+ const data = hb.malloc(bytes.byteLength);
85
+ this.u8.set(bytes, data);
86
+ // Read-only: HarfBuzz copies a table it must patch, and never frees
87
+ // the data (no destroy callback); the registry does.
88
+ const blob = hb.hb_blob_create(data, bytes.byteLength, HB_MEMORY_MODE_READONLY, 0, 0);
89
+ const face = hb.hb_face_create(blob, 0);
90
+ hb.hb_blob_destroy(blob);
91
+ const font = hb.hb_font_create(face);
92
+ const handle = { font, upem: hb.hb_face_get_upem(face) };
93
+ this.faces.register(owner, { data, face, font });
94
+ return handle;
95
+ }
96
+ /** Shape `text` (one bidi run) with `font`. Glyphs in visual order;
97
+ * clusters are UTF-16 offsets, a letter and its marks one cluster. */
98
+ shape(font, text, request) {
99
+ const hb = this.hb;
100
+ const buf = this.buffer;
101
+ hb.hb_buffer_reset(buf);
102
+ hb.hb_buffer_set_cluster_level(buf, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES);
103
+ const textPtr = hb.malloc(text.length * 2 || 2);
104
+ const u16 = new Uint16Array(hb.memory.buffer, textPtr, text.length);
105
+ for (let i = 0; i < text.length; i++)
106
+ u16[i] = text.charCodeAt(i);
107
+ hb.hb_buffer_add_utf16(buf, textPtr, text.length, 0, text.length);
108
+ hb.free(textPtr);
109
+ hb.hb_buffer_guess_segment_properties(buf);
110
+ hb.hb_buffer_set_direction(buf, request.direction === 'rtl' ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
111
+ if (request.script) {
112
+ const s = this.ascii(request.script);
113
+ hb.hb_buffer_set_script(buf, hb.hb_script_from_string(s, -1));
114
+ hb.free(s);
115
+ }
116
+ if (request.language) {
117
+ const s = this.ascii(request.language);
118
+ hb.hb_buffer_set_language(buf, hb.hb_language_from_string(s, -1));
119
+ hb.free(s);
120
+ }
121
+ const features = request.features ?? [];
122
+ let featuresPtr = 0;
123
+ if (features.length > 0) {
124
+ featuresPtr = hb.malloc(features.length * FEATURE_BYTES);
125
+ const words = new Uint32Array(hb.memory.buffer, featuresPtr, features.length * 4);
126
+ features.forEach(([tag, value], i) => {
127
+ words[i * 4] = hbTag(tag);
128
+ words[i * 4 + 1] = value >>> 0;
129
+ words[i * 4 + 2] = 0;
130
+ words[i * 4 + 3] = FEATURE_GLOBAL_END;
131
+ });
132
+ }
133
+ hb.hb_shape(font.font, buf, featuresPtr, features.length);
134
+ if (featuresPtr)
135
+ hb.free(featuresPtr);
136
+ const n = hb.hb_buffer_get_length(buf);
137
+ const infos = hb.hb_buffer_get_glyph_infos(buf, 0) >>> 2;
138
+ const positions = hb.hb_buffer_get_glyph_positions(buf, 0) >>> 2;
139
+ const u32 = new Uint32Array(hb.memory.buffer);
140
+ const i32 = new Int32Array(hb.memory.buffer);
141
+ const glyphs = new Array(n);
142
+ for (let i = 0; i < n; i++) {
143
+ const info = infos + i * GLYPH_WORDS;
144
+ const pos = positions + i * GLYPH_WORDS;
145
+ glyphs[i] = {
146
+ gid: u32[info],
147
+ cluster: u32[info + 2],
148
+ xAdvance: i32[pos],
149
+ yAdvance: i32[pos + 1],
150
+ xOffset: i32[pos + 2],
151
+ yOffset: i32[pos + 3],
152
+ };
153
+ }
154
+ return glyphs;
155
+ }
156
+ }
157
+ /** Instantiate HarfBuzz from its binary. */
158
+ export async function instantiateHarfBuzz(wasm) {
159
+ // The heap is the module's own export, known once it is instantiated.
160
+ const heap = {};
161
+ const abort = (what) => {
162
+ throw new WebAssembly.RuntimeError(`HarfBuzz aborted (${what})`);
163
+ };
164
+ const imports = {
165
+ env: {
166
+ _abort_js: () => abort('abort'),
167
+ // Emscripten's event loop: nothing here keeps it alive or sets a
168
+ // timer (`alarm`, `setitimer`), and shaping never asks for one.
169
+ _emscripten_runtime_keepalive_clear: () => { },
170
+ _setitimer_js: () => 0,
171
+ // Grow the heap to hold `requested` bytes: double it, as Emscripten
172
+ // does, up to its ceiling. 1 on success, 0 when it cannot.
173
+ emscripten_resize_heap: (requested) => {
174
+ const mem = heap.memory;
175
+ const old = mem.buffer.byteLength;
176
+ requested >>>= 0;
177
+ if (requested > HEAP_MAX)
178
+ return 0;
179
+ const target = Math.min(HEAP_MAX, Math.max(requested, old * 2));
180
+ try {
181
+ mem.grow(Math.ceil((target - old) / WASM_PAGE));
182
+ return 1;
183
+ }
184
+ catch {
185
+ try {
186
+ mem.grow(Math.ceil((requested - old) / WASM_PAGE));
187
+ return 1;
188
+ }
189
+ catch {
190
+ return 0;
191
+ }
192
+ }
193
+ },
194
+ },
195
+ wasi_snapshot_preview1: {
196
+ proc_exit: (code) => abort(`exit ${code}`),
197
+ },
198
+ };
199
+ const { instance } = await WebAssembly.instantiate(wasm, imports);
200
+ const hb = instance.exports;
201
+ heap.memory = hb.memory;
202
+ hb.__wasm_call_ctors();
203
+ return new HarfBuzz(hb);
204
+ }
205
+ /** The literal, so a bundler emits the binary beside the chunk. */
206
+ function besideThisModule() {
207
+ return new URL('./harfbuzz.wasm', import.meta.url);
208
+ }
209
+ /** Whether `bytes` start as a WebAssembly module (`\0asm`): a server that
210
+ * answers a missing file with a page must not reach `instantiate`. */
211
+ function isWasm(bytes) {
212
+ return bytes.length > 8 && bytes[0] === 0 && bytes[1] === 0x61 && bytes[2] === 0x73 && bytes[3] === 0x6d;
213
+ }
214
+ /** Read a `file:` URL. `node:fs` is named through a variable, so a
215
+ * bundler or a CDN leaves it alone, and only a host that runs from files
216
+ * (Node, Deno, Bun) ever imports it. */
217
+ async function readFileUrl(url) {
218
+ const fsModule = 'node:fs/promises';
219
+ const fs = (await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ /* @vite-ignore */ fsModule));
220
+ return new Uint8Array(await fs.readFile(url));
221
+ }
222
+ async function fetchBytes(url) {
223
+ if (url.protocol === 'file:')
224
+ return readFileUrl(url);
225
+ const response = await fetch(url);
226
+ if (!response.ok)
227
+ throw new Error(`HTTP ${response.status}`);
228
+ return new Uint8Array(await response.arrayBuffer());
229
+ }
230
+ /** What a relative `source` resolves against: the page's (or worker's)
231
+ * location, as a `fetch` would; this module's URL where there is none. */
232
+ export function sourceBase() {
233
+ return globalThis.location?.href ?? import.meta.url;
234
+ }
235
+ /** The places the binary is looked for when the caller gave none. */
236
+ function defaultLocations() {
237
+ const beside = besideThisModule();
238
+ if (beside.protocol === 'file:') {
239
+ // From `src` (tests) or a `dist` built without the copy: the package
240
+ // this binding is written against. Resolved against `beside`, not
241
+ // `import.meta.url`, so no bundler takes it for an asset to emit.
242
+ return [beside, new URL('../node_modules/harfbuzzjs/dist/harfbuzz.wasm', beside)];
243
+ }
244
+ return [
245
+ beside,
246
+ new URL(`https://cdn.jsdelivr.net/npm/harfbuzzjs@${HARFBUZZ_VERSION}/dist/harfbuzz.wasm`),
247
+ new URL(`https://esm.sh/harfbuzzjs@${HARFBUZZ_VERSION}/dist/harfbuzz.wasm`),
248
+ ];
249
+ }
250
+ /**
251
+ * Load HarfBuzz from `source`, or from the default locations in turn.
252
+ * Rejects with every place tried and why it failed.
253
+ */
254
+ export async function loadHarfBuzz(source) {
255
+ if (source !== undefined && typeof source !== 'string' && !(source instanceof URL)) {
256
+ const bytes = ArrayBuffer.isView(source)
257
+ ? new Uint8Array(source.buffer, source.byteOffset, source.byteLength)
258
+ : new Uint8Array(source);
259
+ return instantiateHarfBuzz(bytes);
260
+ }
261
+ const locations = source !== undefined ? [new URL(source, sourceBase())] : defaultLocations();
262
+ const failures = [];
263
+ for (const url of locations) {
264
+ let bytes;
265
+ try {
266
+ bytes = await fetchBytes(url);
267
+ }
268
+ catch (err) {
269
+ failures.push(`${url.href}: ${err instanceof Error ? err.message : String(err)}`);
270
+ continue;
271
+ }
272
+ if (!isWasm(bytes)) {
273
+ failures.push(`${url.href}: not a WebAssembly file`);
274
+ continue;
275
+ }
276
+ return instantiateHarfBuzz(bytes);
277
+ }
278
+ throw new Error(failures.join('; '));
279
+ }
280
+ //# sourceMappingURL=harfbuzz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harfbuzz.js","sourceRoot":"","sources":["../src/harfbuzz.ts"],"names":[],"mappings":"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"}
Binary file
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { renderToPdf } from './pdf-backend';
2
- export type { RenderToPdfOptions, RenderProgress, PdfFontProvider, PdfFontRequest, PdfWarning, PdfFontWarning, PdfFontFallbackWarning, PdfMissingGlyphWarning, PdfVariableFontWarning, PdfCffEmbeddedWholeWarning, ResourceBytesProvider, } from './pdf-backend';
2
+ export type { RenderToPdfOptions, RenderProgress, PdfFontProvider, PdfFontRequest, PdfWarning, PdfFontWarning, PdfFontFallbackWarning, PdfMissingGlyphWarning, PdfVariableFontWarning, PdfCffEmbeddedWholeWarning, PdfComplexShapingWarning, ResourceBytesProvider, } from './pdf-backend';
3
3
  export { decompressWoff2 } from './woff2';
4
+ export type { HarfBuzzWasmSource } from './harfbuzz';
4
5
  export { svgToVectorDrawing, type VectorDrawing } from './pdf-backend/svgVector';
5
6
  export { sniffBytes, rasterizeSvgWithDom, type SvgRasterizer } from './pdf-backend/renderResourceBlock';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,UAAU,EACV,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,cAAc,EACd,UAAU,EACV,cAAc,EACd,sBAAsB,EACtB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,mCAAmC,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAc5C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAsB,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAe5C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAsB,MAAM,mCAAmC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"blockRender.d.ts","sourceRoot":"","sources":["../../src/pdf-backend/blockRender.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAuC,MAAM,SAAS,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,KAAK,OAAO,EAAkN,MAAM,cAAc,CAAC;AAI5P,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAA8B,MAAM,SAAS,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAIrD,mFAAmF;AACnF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,4EAA4E;IAC5E,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AA+eD,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,qBAAqB,GAClC,IAAI,CAoEN"}
1
+ {"version":3,"file":"blockRender.d.ts","sourceRoot":"","sources":["../../src/pdf-backend/blockRender.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAuC,MAAM,SAAS,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,KAAK,OAAO,EAAiO,MAAM,cAAc,CAAC;AAI3Q,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAA8B,MAAM,SAAS,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAOrD,mFAAmF;AACnF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,4EAA4E;IAC5E,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AAwjBD,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,qBAAqB,GAClC,IAAI,CAoEN"}
@@ -1,7 +1,7 @@
1
1
  import { popGraphicsState, pushGraphicsState } from 'pdf-lib';
2
- import { segmentOrientation } from 'postext';
2
+ import { lineTextAlign, segmentOrientation } from 'postext';
3
3
  import { parseFontString } from '../fontString';
4
- import { alphaOf, alphaStateOp, beginActualTextSpan, cjkLineText, compressedMarkSpacingPx, drawLinePx, drawMeasuredTextPx, drawSwatchPx, drawTextPx, colorFromHex, endActualTextSpan, setTrackingPx } from './primitives';
4
+ import { alphaOf, alphaStateOp, beginActualTextSpan, counterFlipPx, cjkLineText, compressedMarkSpacingPx, drawLinePx, drawMeasuredTextPx, drawSwatchPx, drawTextPx, colorFromHex, endActualTextSpan, setTrackingPx } from './primitives';
5
5
  import { paintChip } from './chip';
6
6
  import { pickSegmentColor, pickSegmentFont } from './fontHelpers';
7
7
  import { renderHeaderFooterSlot } from './headerFooter';
@@ -10,6 +10,9 @@ import { RefRun, refTarget, UriRuns } from './links';
10
10
  import { tagArtifact, tagContent } from './tagging';
11
11
  import { paintLineMarks, paintRuby, paintWarichu } from './annotations';
12
12
  import { inkScaleOperators } from './inkScale';
13
+ import { drawShapedTextPx, drawStyledWordPx } from './shapedText';
14
+ import { segmentLanguages, segmentOffsets, wordParts } from './directedLine';
15
+ import { needsComplexShaping } from '../complexShaping';
13
16
  /** The link destination of a footnote of the document being drawn
14
17
  * (`LinkRegistry.documentIndex`: note ids repeat from chapter to chapter).
15
18
  * A key no resource id takes: it opens with a NUL. */
@@ -24,6 +27,10 @@ function renderMathRender(ctx, render, topLeftXPx, topLeftYPx, fallbackColor) {
24
27
  const S = pxPerVb * pxToPt;
25
28
  const x = topLeftXPx * pxToPt - render.viewBox.minX * S;
26
29
  const y = pageHeightPt - topLeftYPx * pxToPt + render.viewBox.minY * S;
30
+ // A formula on a mirrored page reads unmirrored in its box.
31
+ counterFlipPx(ctx, topLeftXPx, render.widthPx, () => paintMathPaths(ctx, render, x, y, S, fallbackColor));
32
+ }
33
+ function paintMathPaths(ctx, render, x, y, S, fallbackColor) {
27
34
  for (const path of render.paths) {
28
35
  // MathJax fills are `currentColor` or a hex; an unpainted path (`none`,
29
36
  // as a stroke-only rule leaves after flattening) draws nothing, and any
@@ -99,6 +106,21 @@ function paintComposedText(ctx, seg, x, baseline, font, size, color, colorHex, a
99
106
  * `/ActualText`. Any other line was set word by word and carries none of
100
107
  * them: its segments are painted as every line was before the CJK
101
108
  * features, with no further look at each one.
109
+ *
110
+ * A line that carries directions ({@link isDirected}: a right-to-left run
111
+ * on it) is laid out in `line.order`, left to right on the sheet (flow
112
+ * order on a mirrored page), each right-to-left segment shaped as one run
113
+ * by HarfBuzz (`shapedText.ts`), its glyphs shown in visual order, as every
114
+ * right-to-left PDF shows them. The segments are then painted, and tagged,
115
+ * in logical order, each at the place `order` gave it: the content stream,
116
+ * the marked-content sequences and the structure tree read the line as it
117
+ * was written, and readers that order text by position (Poppler) place it
118
+ * by its glyphs. A run of such a line in another language than the
119
+ * document's ({@link segmentLanguages}) is a `Span` with its own `/Lang`.
120
+ *
121
+ * A word set in several styles (`VDTLineSegment.runs`, a bold letter in an
122
+ * Arabic word) is shaped whole and each glyph painted in its run's style
123
+ * (`drawStyledWordPx`).
102
124
  */
103
125
  function renderSegments(ctx, segments, startX, baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, justifiedSpaceWidth,
104
126
  /** The character spacing the line is painted with (block + line, px);
@@ -109,6 +131,24 @@ tracking = 0) {
109
131
  const uris = new UriRuns(ctx, line, linkRegistry, elem);
110
132
  const repeatedAt = repeatedHyphenSegment(line, segments);
111
133
  const composed = line.cjkComposed === true || ctx.vertical !== undefined;
134
+ const directed = isDirected(line);
135
+ // The order segments are laid out in, left to right (by default
136
+ // theirs), and the x it gives each: they are painted in logical order.
137
+ const order = directed && line.order && line.order.length === segments.length ? line.order : undefined;
138
+ const xs = order ? segmentOffsets(segments, order, startX, (seg) => (seg.kind === 'space' ? (composed && seg.autospace ? seg.width : justifiedSpaceWidth ?? seg.width) : seg.width)) : undefined;
139
+ // Runs in another language than the document's (tagged render only).
140
+ const langs = elem && directed ? segmentLanguages(segments, elem.tree.options.lang) : undefined;
141
+ let langSpan;
142
+ const textElemOf = (i) => {
143
+ const lang = langs?.[i];
144
+ if (!lang) {
145
+ langSpan = undefined;
146
+ return elem;
147
+ }
148
+ if (langSpan?.lang !== lang)
149
+ langSpan = { lang, elem: elem.child('Span', { lang }) };
150
+ return langSpan.elem;
151
+ };
112
152
  // A composed CJK line (spread characters, Han–Latin spaces) reads as
113
153
  // written, not with the gaps between its pieces.
114
154
  // A vertical line is painted in runs and cells down the column: it reads
@@ -129,11 +169,16 @@ tracking = 0) {
129
169
  }
130
170
  for (let i = 0; i < segments.length; i++) {
131
171
  const seg = segments[i];
172
+ if (xs)
173
+ x = xs[i];
174
+ const textElem = langs ? textElemOf(i) : elem;
132
175
  if (seg.kind === 'space') {
133
176
  const inLink = uris.space(seg.text);
134
177
  if (ctx.tags && seg.text) {
135
- tagContent(ctx, inLink ?? elem);
136
- drawTextPx(ctx, seg.text, x, baseline, blockFont, blockSize, blockColor);
178
+ tagContent(ctx, inLink ?? textElem);
179
+ // The gap of a poem's bayt holds the tab of its plain text (#378),
180
+ // which no face draws: it reads as a space.
181
+ drawTextPx(ctx, seg.text.replace(/\t/g, ' '), x, baseline, blockFont, blockSize, blockColor);
137
182
  }
138
183
  // A Han–Latin space keeps the width the composer set.
139
184
  x += composed && seg.autospace ? seg.width : justifiedSpaceWidth ?? seg.width;
@@ -189,16 +234,24 @@ tracking = 0) {
189
234
  // A footnote marker links to its note, like a `:ref` to its resource
190
235
  // and a cross-reference to its anchor (#264).
191
236
  const target = refTarget(seg) ?? (seg.footnoteId !== undefined ? footnoteDestination(linkRegistry, seg.footnoteId) : undefined);
192
- const link = refRun.enter(seg, x, elem, target);
237
+ const link = refRun.enter(seg, x, textElem, target, seg.width);
193
238
  // A page number of the index links to its page.
194
239
  const pageElem = seg.pageLink !== undefined && elem && !link ? elem.child('Link') : undefined;
195
240
  // A ruby base is the `RB` of a `Ruby` whose `RT` holds its reading (#194).
196
- const holder = link ?? pageElem ?? uriElem ?? elem;
241
+ const holder = link ?? pageElem ?? uriElem ?? textElem;
197
242
  const rubyElem = composed && seg.ruby && holder ? holder.child('Ruby') : undefined;
198
243
  tagContent(ctx, rubyElem ? rubyElem.child('RB') : holder);
199
244
  // The hyphen repeated from the line before is painted but not read.
200
245
  const actualText = i === repeatedAt ? seg.text.slice(1) : undefined;
201
- if (!composed)
246
+ // On a line with directions each segment is one run: HarfBuzz shapes a
247
+ // right-to-left one (and any complex text), and a word set in several
248
+ // styles. The kashidas justification inserted are painted, not read.
249
+ const shaped = (seg.runs !== undefined || (directed && (seg.rtl || needsComplexShaping(seg.text))))
250
+ && paintShapedSegment(ctx, seg, x, baseline + (seg.baselineShift ?? 0), font, size, color, block, fontCache, actualText, kashidaOf(seg, line));
251
+ if (shaped) {
252
+ // Painted by HarfBuzz.
253
+ }
254
+ else if (!composed)
202
255
  drawTextPx(ctx, seg.text, x, baseline + (seg.baselineShift ?? 0), font, size, color, undefined, actualText);
203
256
  else
204
257
  paintComposedText(ctx, seg, x, baseline, font, size, color, colorHex, actualText, tracking, fontCache, blockFont, rubyElem);
@@ -209,8 +262,8 @@ tracking = 0) {
209
262
  const ref = refRun.leave(seg, segments[i + 1], target);
210
263
  if (ref && linkRegistry) {
211
264
  const { scale, pageHeightPt } = ctx;
212
- const x1 = ref.startX * scale;
213
- const x2 = (x + seg.width) * scale;
265
+ const x1 = ref.left * scale;
266
+ const x2 = Math.max(ref.right, x + seg.width) * scale;
214
267
  const y2 = pageHeightPt - line.bbox.y * scale;
215
268
  const y1 = pageHeightPt - (line.bbox.y + line.bbox.height) * scale;
216
269
  linkRegistry.addLink(ctx.page, sheetRect(ctx, [x1, y1, x2, y2]), ref.resourceId, link ? { elem: link, contents: ref.text } : undefined);
@@ -221,6 +274,18 @@ tracking = 0) {
221
274
  if (lineState)
222
275
  endActualTextSpan(ctx, lineState);
223
276
  }
277
+ /**
278
+ * Paint a segment HarfBuzz shapes: a word set in several styles
279
+ * (`runs`), each glyph in its run's face and colour, else the segment as
280
+ * one run in its direction. False when HarfBuzz is not loaded: the caller
281
+ * paints it the fontkit way.
282
+ */
283
+ function paintShapedSegment(ctx, seg, x, baseline, font, size, color, block, fontCache, actualText, hideTatweel) {
284
+ const direction = seg.rtl ? 'rtl' : 'ltr';
285
+ if (seg.runs && drawStyledWordPx(ctx, seg.text, x, baseline, font, size, color, wordParts(seg, font, color, ctx, (bold, italic) => ({ font: fontCache.get(pickSegmentFont(bold, italic, block)) ?? undefined, color: colorFromHex(pickSegmentColor(bold, italic, block), ctx.colorSpace) })), { direction, actualText, hideTatweel }))
286
+ return true;
287
+ return drawShapedTextPx(ctx, seg.text, x, baseline, font, size, color, { direction, actualText, hideTatweel });
288
+ }
224
289
  /** Tracking: the block (column balancing; negative for a runt set short)
225
290
  * and the line (justification tracking) were measured with extra advance
226
291
  * after every glyph, so paint the line with the matching character
@@ -257,8 +322,15 @@ function renderLineText(ctx, line, block, columnWidth, columnX, fontCache, linkR
257
322
  return;
258
323
  const blockSize = parseFontString(block.fontString)?.sizePx ?? 0;
259
324
  const blockColor = colorFromHex(block.color, ctx.colorSpace);
260
- const lineIndent = line.bbox.x - columnX;
261
- const effectiveWidth = columnWidth - lineIndent;
325
+ // A line whose block runs against its frame (a right-to-left paragraph
326
+ // on a left-to-right page, an English quotation in an Arabic book)
327
+ // carries its span (`measure`): it is justified across it and set ragged
328
+ // from its start side, the right, as the canvas sets it.
329
+ const span = line.measure;
330
+ const lineX = span ? span.x : line.bbox.x;
331
+ const align = lineTextAlign(line, block.textAlign);
332
+ const lineIndent = lineX - columnX;
333
+ const effectiveWidth = span ? span.width : columnWidth - lineIndent;
262
334
  const segments = line.segments;
263
335
  // Only a line of the CJK composer (or down a vertical page) has hung
264
336
  // marks and Han–Latin spaces (see `renderSegments`).
@@ -284,18 +356,18 @@ function renderLineText(ctx, line, block, columnWidth, columnX, fontCache, linkR
284
356
  }
285
357
  if (spaceCount > 0 && ((!line.isLastLine && !line.ragged) || naturalWidth > effectiveWidth)) {
286
358
  const justifiedSpaceWidth = (effectiveWidth - wordWidth) / spaceCount;
287
- renderSegments(ctx, segments, line.bbox.x, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, justifiedSpaceWidth, tracking);
359
+ renderSegments(ctx, segments, lineX, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, justifiedSpaceWidth, tracking);
288
360
  return;
289
361
  }
290
362
  }
291
- if ((block.textAlign === 'center' || block.textAlign === 'right') && segments) {
363
+ if ((align === 'center' || align === 'right') && segments) {
292
364
  // Hung marks stay out of the alignment, as trailing tracking does.
293
365
  let contentWidth = 0;
294
366
  for (const seg of segments)
295
367
  if (!(composed && seg.hangs))
296
368
  contentWidth += seg.width;
297
369
  const slack = Math.max(0, effectiveWidth - (contentWidth - trailing));
298
- const startX = line.bbox.x + (block.textAlign === 'center' ? slack / 2 : slack);
370
+ const startX = lineX + (align === 'center' ? slack / 2 : slack);
299
371
  renderSegments(ctx, segments, startX, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, undefined, tracking);
300
372
  return;
301
373
  }
@@ -303,29 +375,35 @@ function renderLineText(ctx, line, block, columnWidth, columnX, fontCache, linkR
303
375
  // blocks. Segments are needed when any of them styles differently from the
304
376
  // block (bold/italic/math/ref/own font or colour); otherwise one text
305
377
  // object paints the line.
306
- if (segments && segments.some(composed ? composedSegmentIsStyled : segmentIsStyled)) {
307
- renderSegments(ctx, segments, line.bbox.x, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, undefined, tracking);
378
+ if (segments && (isDirected(line) || segments.some(composed ? composedSegmentIsStyled : segmentIsStyled))) {
379
+ renderSegments(ctx, segments, lineX, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, undefined, tracking);
308
380
  return;
309
381
  }
310
382
  tagContent(ctx, elem);
311
383
  const plainSlack = Math.max(0, effectiveWidth - (line.bbox.width - trailing));
312
- const plainX = line.bbox.x + (block.textAlign === 'right' ? plainSlack : block.textAlign === 'center' ? plainSlack / 2 : 0);
384
+ const plainX = lineX + (align === 'right' ? plainSlack : align === 'center' ? plainSlack / 2 : 0);
313
385
  // Each word where the layout measured it (EF-137): the embedded face's
314
386
  // own widths could differ, most of all for a character it has no glyph
315
- // for, and would carry the rest of the line along. A line with
316
- // right-to-left letters stays one run, which the shaper turns around.
387
+ // for, and would carry the rest of the line along.
317
388
  // The hyphen repeated from the line before is painted but not read.
318
389
  const actualText = line.repeatedHyphen && line.text.startsWith('-') ? line.text.slice(1) : undefined;
319
- if (segments && segments.length > 0 && !hasRightToLeft(line.text)
390
+ // A line with right-to-left or joining letters and no directions (a VDT
391
+ // from before the engine resolved bidi levels) is set as one text, cut
392
+ // into bidi runs and shaped by HarfBuzz; with fontkit when HarfBuzz is
393
+ // not loaded, which turns the whole line around.
394
+ const complex = needsComplexShaping(line.text);
395
+ if (segments && segments.length > 0 && !complex
320
396
  && drawMeasuredTextPx(ctx, withLineEndSpace(segments, line.text), plainX, line.baseline, blockFont, blockSize, blockColor, tracking, actualText))
321
397
  return;
398
+ if (complex && drawShapedTextPx(ctx, line.text, plainX, line.baseline, blockFont, blockSize, blockColor, { base: block.direction, actualText }))
399
+ return;
322
400
  drawTextPx(ctx, line.text, plainX, line.baseline, blockFont, blockSize, blockColor, undefined, actualText);
323
401
  }
324
402
  /** Whether a segment of a line set word by word paints differently from
325
403
  * the block's plain text, or is linked; an orientation mark (`:tcy`,
326
404
  * `:upright`, `:sideways`) keeps its segment apart. */
327
405
  function segmentIsStyled(s) {
328
- return s.bold || s.italic || s.kind === 'math' || s.kind === 'swatch' || s.kind === 'chip' || s.refResourceId !== undefined || s.href !== undefined || s.pageLink !== undefined || s.fontString !== undefined || s.color !== undefined || s.baselineShift !== undefined
406
+ return s.bold || s.italic || s.runs !== undefined || s.kind === 'math' || s.kind === 'swatch' || s.kind === 'chip' || s.refResourceId !== undefined || s.href !== undefined || s.pageLink !== undefined || s.fontString !== undefined || s.color !== undefined || s.baselineShift !== undefined
329
407
  || s.tcy !== undefined || s.orientation !== undefined || s.labelTab !== undefined;
330
408
  }
331
409
  /** {@link segmentIsStyled} for a line of the CJK composer or one down a
@@ -359,25 +437,11 @@ function withLineEndSpace(segments, text) {
359
437
  const rest = text.slice(shown.length);
360
438
  return /^\s+$/.test(rest) ? [...segments, { text: rest, width: 0 }] : segments;
361
439
  }
362
- /** Whether `text` holds a right-to-left letter: Hebrew, Arabic, Syriac,
363
- * Thaana, N'Ko and the scripts after them up to U+08FF, their
364
- * presentation forms, and the right-to-left blocks of the supplementary
365
- * planes. */
366
- function hasRightToLeft(text) {
367
- for (let i = 0; i < text.length; i++) {
368
- const c = text.charCodeAt(i);
369
- if (c < 0x0590)
370
- continue;
371
- if (c <= 0x08ff || (c >= 0xfb1d && c <= 0xfdff) || (c >= 0xfe70 && c <= 0xfefe))
372
- return true;
373
- if (c >= 0xd800 && c <= 0xdbff) {
374
- const cp = text.codePointAt(i);
375
- if ((cp >= 0x10800 && cp <= 0x10fff) || (cp >= 0x1e800 && cp <= 0x1efff))
376
- return true;
377
- i++;
378
- }
379
- }
380
- return false;
440
+ /** Whether a line carries the engine's directions: an order to paint its
441
+ * segments in, or a right-to-left segment. Absent on every left-to-right
442
+ * line, which is painted as it always was. */
443
+ function isDirected(line) {
444
+ return line.order !== undefined || (line.segments?.some((s) => s.rtl) ?? false);
381
445
  }
382
446
  function renderBullet(ctx, block, fontCache, elem) {
383
447
  if (!block.bulletText ||
@@ -503,4 +567,13 @@ export function renderBlock(ctx, block, columnWidth, columnX, fontCache, resourc
503
567
  renderStrikethrough(ctx, block);
504
568
  }
505
569
  }
570
+ /** The tatweels of a segment its text read leaves out: the ones kashida
571
+ * justification inserted (`VDTLineSegment.kashida`), so one the author
572
+ * typed stays; every one on a line of a VDT that only counts them
573
+ * (`VDTLine.kashida`, before the per-segment offsets). */
574
+ function kashidaOf(seg, line) {
575
+ if (seg.kashida)
576
+ return seg.kashida.length;
577
+ return line.kashida !== undefined && !line.segments?.some((s) => s.kashida);
578
+ }
506
579
  //# sourceMappingURL=blockRender.js.map