harfbuzzjs 0.10.3 → 1.0.0-beta.2

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/dist/index.mjs ADDED
@@ -0,0 +1,1406 @@
1
+ import createHarfBuzz from "./harfbuzz.js";
2
+ //#region src/helpers.ts
3
+ let Module;
4
+ let exports;
5
+ let freeFuncPtr;
6
+ const utf8Decoder = new TextDecoder("utf8");
7
+ const utf8Encoder = new TextEncoder();
8
+ const registry = new FinalizationRegistry((cleanup) => {
9
+ cleanup();
10
+ });
11
+ function track(obj, destroy) {
12
+ const ptr = obj.ptr;
13
+ registry.register(obj, () => destroy(ptr));
14
+ }
15
+ /**
16
+ * Initialize the HarfBuzz module.
17
+ * @param module The Emscripten module instance created with {@link
18
+ * createHarfBuzz}.
19
+ */
20
+ function init(module) {
21
+ Module = module;
22
+ exports = Module.wasmExports;
23
+ freeFuncPtr = Module.addFunction((ptr) => {
24
+ exports.free(ptr);
25
+ }, "vi");
26
+ }
27
+ function hb_tag(s) {
28
+ return (s.charCodeAt(0) & 255) << 24 | (s.charCodeAt(1) & 255) << 16 | (s.charCodeAt(2) & 255) << 8 | (s.charCodeAt(3) & 255) << 0;
29
+ }
30
+ function hb_untag(tag) {
31
+ return [
32
+ String.fromCharCode(tag >> 24 & 255),
33
+ String.fromCharCode(tag >> 16 & 255),
34
+ String.fromCharCode(tag >> 8 & 255),
35
+ String.fromCharCode(tag >> 0 & 255)
36
+ ].join("");
37
+ }
38
+ function utf8_ptr_to_string(ptr, length) {
39
+ let end;
40
+ if (length == void 0) end = Module.HEAPU8.indexOf(0, ptr);
41
+ else end = ptr + length;
42
+ return utf8Decoder.decode(Module.HEAPU8.subarray(ptr, end));
43
+ }
44
+ function utf16_ptr_to_string(ptr, length) {
45
+ const end = ptr / 2 + length;
46
+ return String.fromCharCode(...Module.HEAPU16.subarray(ptr / 2, end));
47
+ }
48
+ /**
49
+ * Use when you know the input range should be ASCII.
50
+ * Faster than encoding to UTF-8
51
+ */
52
+ function string_to_ascii_ptr(text) {
53
+ const ptr = exports.malloc(text.length + 1);
54
+ for (let i = 0; i < text.length; ++i) {
55
+ const char = text.charCodeAt(i);
56
+ if (char > 127) throw new Error("Expected ASCII text");
57
+ Module.HEAPU8[ptr + i] = char;
58
+ }
59
+ Module.HEAPU8[ptr + text.length] = 0;
60
+ return {
61
+ ptr,
62
+ length: text.length,
63
+ free: function() {
64
+ exports.free(ptr);
65
+ }
66
+ };
67
+ }
68
+ function string_to_utf8_ptr(text) {
69
+ const ptr = exports.malloc(text.length);
70
+ utf8Encoder.encodeInto(text, Module.HEAPU8.subarray(ptr, ptr + text.length));
71
+ return {
72
+ ptr,
73
+ length: text.length,
74
+ free: function() {
75
+ exports.free(ptr);
76
+ }
77
+ };
78
+ }
79
+ function string_to_utf16_ptr(text) {
80
+ const ptr = exports.malloc(text.length * 2);
81
+ const words = Module.HEAPU16.subarray(ptr / 2, ptr / 2 + text.length);
82
+ for (let i = 0; i < words.length; ++i) words[i] = text.charCodeAt(i);
83
+ return {
84
+ ptr,
85
+ length: words.length,
86
+ free: function() {
87
+ exports.free(ptr);
88
+ }
89
+ };
90
+ }
91
+ function language_to_string(language) {
92
+ return utf8_ptr_to_string(exports.hb_language_to_string(language));
93
+ }
94
+ function language_from_string(str) {
95
+ const languageStr = string_to_ascii_ptr(str);
96
+ const languagePtr = exports.hb_language_from_string(languageStr.ptr, -1);
97
+ languageStr.free();
98
+ return languagePtr;
99
+ }
100
+ /**
101
+ * Return the typed array of HarfBuzz set contents.
102
+ * @param setPtr Pointer of set
103
+ * @returns Typed array instance
104
+ */
105
+ function typed_array_from_set(setPtr) {
106
+ const setCount = exports.hb_set_get_population(setPtr);
107
+ const arrayPtr = exports.malloc(setCount << 2);
108
+ const arrayOffset = arrayPtr >> 2;
109
+ exports.hb_set_next_many(setPtr, -1, arrayPtr, setCount);
110
+ return Module.HEAPU32.subarray(arrayOffset, arrayOffset + setCount);
111
+ }
112
+ //#endregion
113
+ //#region src/types.ts
114
+ const GlyphFlag = {
115
+ UNSAFE_TO_BREAK: 1,
116
+ UNSAFE_TO_CONCAT: 2,
117
+ SAFE_TO_INSERT_TATWEEL: 4,
118
+ DEFINED: 7
119
+ };
120
+ //#endregion
121
+ //#region src/blob.ts
122
+ /**
123
+ * An object representing a {@link https://harfbuzz.github.io/harfbuzz-hb-blob.html | HarfBuzz blob}.
124
+ * A blob wraps a chunk of binary data, typically the contents of a font file.
125
+ */
126
+ var Blob = class {
127
+ /**
128
+ * @param data Binary font data.
129
+ */
130
+ constructor(data) {
131
+ const blobPtr = exports.malloc(data.byteLength);
132
+ Module.HEAPU8.set(new Uint8Array(data), blobPtr);
133
+ this.ptr = exports.hb_blob_create(blobPtr, data.byteLength, 2, blobPtr, freeFuncPtr);
134
+ track(this, exports.hb_blob_destroy);
135
+ }
136
+ };
137
+ //#endregion
138
+ //#region src/face.ts
139
+ const HB_OT_NAME_ID_INVALID = 65535;
140
+ const GlyphClass = {
141
+ UNCLASSIFIED: 0,
142
+ BASE_GLYPH: 1,
143
+ LIGATURE: 2,
144
+ MARK: 3,
145
+ COMPONENT: 4
146
+ };
147
+ /**
148
+ * An object representing a {@link https://harfbuzz.github.io/harfbuzz-hb-face.html | HarfBuzz face}.
149
+ * A face represents a single face in a binary font file and is the
150
+ * foundation for creating Font objects used in text shaping.
151
+ */
152
+ var Face = class {
153
+ /**
154
+ * @param blob A Blob containing font data.
155
+ * @param index The index of the font in the blob. (0 for most files,
156
+ * or a 0-indexed font number if the `blob` came from a font collection file.)
157
+ */
158
+ constructor(blob, index = 0) {
159
+ this.ptr = exports.hb_face_create(blob.ptr, index);
160
+ this.upem = exports.hb_face_get_upem(this.ptr);
161
+ track(this, exports.hb_face_destroy);
162
+ }
163
+ /**
164
+ * Return the binary contents of an OpenType table.
165
+ * @param table Table name
166
+ * @returns A Uint8Array of the table data, or undefined if the table is not found.
167
+ */
168
+ referenceTable(table) {
169
+ const blob = exports.hb_face_reference_table(this.ptr, hb_tag(table));
170
+ const length = exports.hb_blob_get_length(blob);
171
+ if (!length) return;
172
+ const blobptr = exports.hb_blob_get_data(blob, 0);
173
+ return Module.HEAPU8.subarray(blobptr, blobptr + length);
174
+ }
175
+ /**
176
+ * Return variation axis infos.
177
+ * @returns A dictionary mapping axis tags to {min, default, max} values.
178
+ */
179
+ getAxisInfos() {
180
+ const sp = Module.stackSave();
181
+ const axis = Module.stackAlloc(2048);
182
+ const c = Module.stackAlloc(4);
183
+ Module.HEAPU32[c / 4] = 64;
184
+ exports.hb_ot_var_get_axis_infos(this.ptr, 0, c, axis);
185
+ const result = {};
186
+ Array.from({ length: Module.HEAPU32[c / 4] }).forEach((_, i) => {
187
+ result[hb_untag(Module.HEAPU32[axis / 4 + i * 8 + 1])] = {
188
+ min: Module.HEAPF32[axis / 4 + i * 8 + 4],
189
+ default: Module.HEAPF32[axis / 4 + i * 8 + 5],
190
+ max: Module.HEAPF32[axis / 4 + i * 8 + 6]
191
+ };
192
+ });
193
+ Module.stackRestore(sp);
194
+ return result;
195
+ }
196
+ /**
197
+ * Return unicodes the face supports.
198
+ * @returns A Uint32Array of supported Unicode code points.
199
+ */
200
+ collectUnicodes() {
201
+ const unicodeSetPtr = exports.hb_set_create();
202
+ exports.hb_face_collect_unicodes(this.ptr, unicodeSetPtr);
203
+ const result = typed_array_from_set(unicodeSetPtr);
204
+ exports.hb_set_destroy(unicodeSetPtr);
205
+ return result;
206
+ }
207
+ /**
208
+ * Return all scripts enumerated in the specified face's
209
+ * GSUB table or GPOS table.
210
+ * @param table The table to query, either "GSUB" or "GPOS".
211
+ * @returns An array of 4-character script tag strings.
212
+ */
213
+ getTableScriptTags(table) {
214
+ const sp = Module.stackSave();
215
+ const tableTag = hb_tag(table);
216
+ let startOffset = 0;
217
+ let scriptCount = 128;
218
+ const scriptCountPtr = Module.stackAlloc(4);
219
+ const scriptTagsPtr = Module.stackAlloc(512);
220
+ const tags = [];
221
+ while (scriptCount == 128) {
222
+ Module.HEAPU32[scriptCountPtr / 4] = scriptCount;
223
+ exports.hb_ot_layout_table_get_script_tags(this.ptr, tableTag, startOffset, scriptCountPtr, scriptTagsPtr);
224
+ scriptCount = Module.HEAPU32[scriptCountPtr / 4];
225
+ const scriptTags = Module.HEAPU32.subarray(scriptTagsPtr / 4, scriptTagsPtr / 4 + scriptCount);
226
+ tags.push(...Array.from(scriptTags).map(hb_untag));
227
+ startOffset += scriptCount;
228
+ }
229
+ Module.stackRestore(sp);
230
+ return tags;
231
+ }
232
+ /**
233
+ * Return all features enumerated in the specified face's
234
+ * GSUB table or GPOS table.
235
+ * @param table The table to query, either "GSUB" or "GPOS".
236
+ * @returns An array of 4-character feature tag strings.
237
+ */
238
+ getTableFeatureTags(table) {
239
+ const sp = Module.stackSave();
240
+ const tableTag = hb_tag(table);
241
+ let startOffset = 0;
242
+ let featureCount = 128;
243
+ const featureCountPtr = Module.stackAlloc(4);
244
+ const featureTagsPtr = Module.stackAlloc(512);
245
+ const tags = [];
246
+ while (featureCount == 128) {
247
+ Module.HEAPU32[featureCountPtr / 4] = featureCount;
248
+ exports.hb_ot_layout_table_get_feature_tags(this.ptr, tableTag, startOffset, featureCountPtr, featureTagsPtr);
249
+ featureCount = Module.HEAPU32[featureCountPtr / 4];
250
+ const featureTags = Module.HEAPU32.subarray(featureTagsPtr / 4, featureTagsPtr / 4 + featureCount);
251
+ tags.push(...Array.from(featureTags).map(hb_untag));
252
+ startOffset += featureCount;
253
+ }
254
+ Module.stackRestore(sp);
255
+ return tags;
256
+ }
257
+ /**
258
+ * Return language tags in the given face's GSUB or GPOS table, underneath
259
+ * the specified script index.
260
+ * @param table The table to query, either "GSUB" or "GPOS".
261
+ * @param scriptIndex The index of the script to query.
262
+ * @returns An array of 4-character language tag strings.
263
+ */
264
+ getScriptLanguageTags(table, scriptIndex) {
265
+ const sp = Module.stackSave();
266
+ const tableTag = hb_tag(table);
267
+ let startOffset = 0;
268
+ let languageCount = 128;
269
+ const languageCountPtr = Module.stackAlloc(4);
270
+ const languageTagsPtr = Module.stackAlloc(512);
271
+ const tags = [];
272
+ while (languageCount == 128) {
273
+ Module.HEAPU32[languageCountPtr / 4] = languageCount;
274
+ exports.hb_ot_layout_script_get_language_tags(this.ptr, tableTag, scriptIndex, startOffset, languageCountPtr, languageTagsPtr);
275
+ languageCount = Module.HEAPU32[languageCountPtr / 4];
276
+ const languageTags = Module.HEAPU32.subarray(languageTagsPtr / 4, languageTagsPtr / 4 + languageCount);
277
+ tags.push(...Array.from(languageTags).map(hb_untag));
278
+ startOffset += languageCount;
279
+ }
280
+ Module.stackRestore(sp);
281
+ return tags;
282
+ }
283
+ /**
284
+ * Return all features in the specified face's GSUB table or GPOS table,
285
+ * underneath the specified script and language.
286
+ * @param table The table to query, either "GSUB" or "GPOS".
287
+ * @param scriptIndex The index of the script to query.
288
+ * @param languageIndex The index of the language to query.
289
+ * @returns An array of 4-character feature tag strings.
290
+ */
291
+ getLanguageFeatureTags(table, scriptIndex, languageIndex) {
292
+ const sp = Module.stackSave();
293
+ const tableTag = hb_tag(table);
294
+ let startOffset = 0;
295
+ let featureCount = 128;
296
+ const featureCountPtr = Module.stackAlloc(4);
297
+ const featureTagsPtr = Module.stackAlloc(512);
298
+ const tags = [];
299
+ while (featureCount == 128) {
300
+ Module.HEAPU32[featureCountPtr / 4] = featureCount;
301
+ exports.hb_ot_layout_language_get_feature_tags(this.ptr, tableTag, scriptIndex, languageIndex, startOffset, featureCountPtr, featureTagsPtr);
302
+ featureCount = Module.HEAPU32[featureCountPtr / 4];
303
+ const featureTags = Module.HEAPU32.subarray(featureTagsPtr / 4, featureTagsPtr / 4 + featureCount);
304
+ tags.push(...Array.from(featureTags).map(hb_untag));
305
+ startOffset += featureCount;
306
+ }
307
+ Module.stackRestore(sp);
308
+ return tags;
309
+ }
310
+ /**
311
+ * Get the GDEF class of the requested glyph.
312
+ * @param glyph The glyph to get the class of.
313
+ * @returns The {@link GlyphClass} of the glyph.
314
+ */
315
+ getGlyphClass(glyph) {
316
+ return exports.hb_ot_layout_get_glyph_class(this.ptr, glyph);
317
+ }
318
+ /**
319
+ * Return all names in the specified face's name table.
320
+ * @returns An array of {nameId, language} entries.
321
+ */
322
+ listNames() {
323
+ const sp = Module.stackSave();
324
+ const numEntriesPtr = Module.stackAlloc(4);
325
+ const entriesPtr = exports.hb_ot_name_list_names(this.ptr, numEntriesPtr);
326
+ const numEntries = Module.HEAPU32[numEntriesPtr / 4];
327
+ const entries = [];
328
+ for (let i = 0; i < numEntries; i++) entries.push({
329
+ nameId: Module.HEAPU32[entriesPtr / 4 + i * 3],
330
+ language: language_to_string(Module.HEAPU32[entriesPtr / 4 + i * 3 + 2])
331
+ });
332
+ Module.stackRestore(sp);
333
+ return entries;
334
+ }
335
+ /**
336
+ * Get the name of the specified face.
337
+ * @param nameId The ID of the name to get.
338
+ * @param language The language of the name to get.
339
+ * @returns The name string.
340
+ */
341
+ getName(nameId, language) {
342
+ const sp = Module.stackSave();
343
+ const languagePtr = language_from_string(language);
344
+ const nameLen = exports.hb_ot_name_get_utf16(this.ptr, nameId, languagePtr, 0, 0) + 1;
345
+ const textSizePtr = Module.stackAlloc(4);
346
+ const textPtr = exports.malloc(nameLen * 2);
347
+ Module.HEAPU32[textSizePtr / 4] = nameLen;
348
+ exports.hb_ot_name_get_utf16(this.ptr, nameId, languagePtr, textSizePtr, textPtr);
349
+ const name = utf16_ptr_to_string(textPtr, nameLen - 1);
350
+ exports.free(textPtr);
351
+ Module.stackRestore(sp);
352
+ return name;
353
+ }
354
+ /**
355
+ * Get the name IDs of the specified feature.
356
+ * @param table The table to query, either "GSUB" or "GPOS".
357
+ * @param featureIndex The index of the feature to query.
358
+ * @returns An object with name IDs, or undefined if not found.
359
+ */
360
+ getFeatureNameIds(table, featureIndex) {
361
+ const sp = Module.stackSave();
362
+ const tableTag = hb_tag(table);
363
+ const labelIdPtr = Module.stackAlloc(4);
364
+ const tooltipIdPtr = Module.stackAlloc(4);
365
+ const sampleIdPtr = Module.stackAlloc(4);
366
+ const numNamedParametersPtr = Module.stackAlloc(4);
367
+ const firstParameterIdPtr = Module.stackAlloc(4);
368
+ const found = exports.hb_ot_layout_feature_get_name_ids(this.ptr, tableTag, featureIndex, labelIdPtr, tooltipIdPtr, sampleIdPtr, numNamedParametersPtr, firstParameterIdPtr);
369
+ let names;
370
+ if (found) {
371
+ const uiLabelNameId = Module.HEAPU32[labelIdPtr / 4];
372
+ const uiTooltipTextNameId = Module.HEAPU32[tooltipIdPtr / 4];
373
+ const sampleTextNameId = Module.HEAPU32[sampleIdPtr / 4];
374
+ const numNamedParameters = Module.HEAPU32[numNamedParametersPtr / 4];
375
+ const firstParameterId = Module.HEAPU32[firstParameterIdPtr / 4];
376
+ names = { paramUiLabelNameIds: Array.from({ length: numNamedParameters }, (_, i) => firstParameterId + i) };
377
+ if (uiLabelNameId != HB_OT_NAME_ID_INVALID) names.uiLabelNameId = uiLabelNameId;
378
+ if (uiTooltipTextNameId != HB_OT_NAME_ID_INVALID) names.uiTooltipTextNameId = uiTooltipTextNameId;
379
+ if (sampleTextNameId != HB_OT_NAME_ID_INVALID) names.sampleTextNameId = sampleTextNameId;
380
+ }
381
+ Module.stackRestore(sp);
382
+ return names;
383
+ }
384
+ };
385
+ //#endregion
386
+ //#region src/font.ts
387
+ /**
388
+ * An object representing a {@link https://harfbuzz.github.io/harfbuzz-hb-font.html | HarfBuzz font}.
389
+ * A font represents a face at a specific size and with certain other
390
+ * parameters (pixels-per-em, variation settings) specified. Fonts are the
391
+ * primary input to the shaping process.
392
+ */
393
+ var Font = class Font {
394
+ constructor(arg) {
395
+ this.drawPtrs = { pathBuffer: "" };
396
+ if (typeof arg === "number") this.ptr = exports.hb_font_reference(arg);
397
+ else this.ptr = exports.hb_font_create(arg.ptr);
398
+ const ptr = this.ptr;
399
+ const drawState = this.drawPtrs;
400
+ registry.register(this, () => {
401
+ exports.hb_font_destroy(ptr);
402
+ if (drawState.drawFuncsPtr) {
403
+ exports.hb_draw_funcs_destroy(drawState.drawFuncsPtr);
404
+ Module.removeFunction(drawState.moveToPtr);
405
+ Module.removeFunction(drawState.lineToPtr);
406
+ Module.removeFunction(drawState.cubicToPtr);
407
+ Module.removeFunction(drawState.quadToPtr);
408
+ Module.removeFunction(drawState.closePathPtr);
409
+ }
410
+ });
411
+ }
412
+ /**
413
+ * Create a sub font that inherits this font's properties.
414
+ * @returns A new Font object representing the sub font.
415
+ */
416
+ subFont() {
417
+ return new Font(exports.hb_font_create_sub_font(this.ptr));
418
+ }
419
+ /**
420
+ * Return font horizontal extents.
421
+ * @returns Object with ascender, descender, and lineGap properties.
422
+ */
423
+ hExtents() {
424
+ const sp = Module.stackSave();
425
+ const extentsPtr = Module.stackAlloc(48);
426
+ exports.hb_font_get_h_extents(this.ptr, extentsPtr);
427
+ const extents = {
428
+ ascender: Module.HEAP32[extentsPtr / 4],
429
+ descender: Module.HEAP32[extentsPtr / 4 + 1],
430
+ lineGap: Module.HEAP32[extentsPtr / 4 + 2]
431
+ };
432
+ Module.stackRestore(sp);
433
+ return extents;
434
+ }
435
+ /**
436
+ * Return font vertical extents.
437
+ * @returns Object with ascender, descender, and lineGap properties.
438
+ */
439
+ vExtents() {
440
+ const sp = Module.stackSave();
441
+ const extentsPtr = Module.stackAlloc(48);
442
+ exports.hb_font_get_v_extents(this.ptr, extentsPtr);
443
+ const extents = {
444
+ ascender: Module.HEAP32[extentsPtr / 4],
445
+ descender: Module.HEAP32[extentsPtr / 4 + 1],
446
+ lineGap: Module.HEAP32[extentsPtr / 4 + 2]
447
+ };
448
+ Module.stackRestore(sp);
449
+ return extents;
450
+ }
451
+ /**
452
+ * Return glyph name.
453
+ * @param glyphId ID of the requested glyph in the font.
454
+ * @returns The glyph name string.
455
+ */
456
+ glyphName(glyphId) {
457
+ const sp = Module.stackSave();
458
+ const strSize = 256;
459
+ const strPtr = Module.stackAlloc(strSize);
460
+ exports.hb_font_glyph_to_string(this.ptr, glyphId, strPtr, strSize);
461
+ const name = utf8_ptr_to_string(strPtr);
462
+ Module.stackRestore(sp);
463
+ return name;
464
+ }
465
+ /**
466
+ * Return a glyph as an SVG path string.
467
+ * @param glyphId ID of the requested glyph in the font.
468
+ * @returns SVG path data string.
469
+ */
470
+ glyphToPath(glyphId) {
471
+ const ds = this.drawPtrs;
472
+ if (!ds.drawFuncsPtr) {
473
+ const moveTo = (dfuncs, draw_data, draw_state, to_x, to_y, user_data) => {
474
+ ds.pathBuffer += `M${to_x},${to_y}`;
475
+ };
476
+ const lineTo = (dfuncs, draw_data, draw_state, to_x, to_y, user_data) => {
477
+ ds.pathBuffer += `L${to_x},${to_y}`;
478
+ };
479
+ const cubicTo = (dfuncs, draw_data, draw_state, c1_x, c1_y, c2_x, c2_y, to_x, to_y, user_data) => {
480
+ ds.pathBuffer += `C${c1_x},${c1_y} ${c2_x},${c2_y} ${to_x},${to_y}`;
481
+ };
482
+ const quadTo = (dfuncs, draw_data, draw_state, c_x, c_y, to_x, to_y, user_data) => {
483
+ ds.pathBuffer += `Q${c_x},${c_y} ${to_x},${to_y}`;
484
+ };
485
+ const closePath = (dfuncs, draw_data, draw_state, user_data) => {
486
+ ds.pathBuffer += "Z";
487
+ };
488
+ ds.moveToPtr = Module.addFunction(moveTo, "viiiffi");
489
+ ds.lineToPtr = Module.addFunction(lineTo, "viiiffi");
490
+ ds.cubicToPtr = Module.addFunction(cubicTo, "viiiffffffi");
491
+ ds.quadToPtr = Module.addFunction(quadTo, "viiiffffi");
492
+ ds.closePathPtr = Module.addFunction(closePath, "viiii");
493
+ ds.drawFuncsPtr = exports.hb_draw_funcs_create();
494
+ exports.hb_draw_funcs_set_move_to_func(ds.drawFuncsPtr, ds.moveToPtr, 0, 0);
495
+ exports.hb_draw_funcs_set_line_to_func(ds.drawFuncsPtr, ds.lineToPtr, 0, 0);
496
+ exports.hb_draw_funcs_set_cubic_to_func(ds.drawFuncsPtr, ds.cubicToPtr, 0, 0);
497
+ exports.hb_draw_funcs_set_quadratic_to_func(ds.drawFuncsPtr, ds.quadToPtr, 0, 0);
498
+ exports.hb_draw_funcs_set_close_path_func(ds.drawFuncsPtr, ds.closePathPtr, 0, 0);
499
+ }
500
+ ds.pathBuffer = "";
501
+ exports.hb_font_draw_glyph(this.ptr, glyphId, ds.drawFuncsPtr, 0);
502
+ return ds.pathBuffer;
503
+ }
504
+ /**
505
+ * Return glyph horizontal advance.
506
+ * @param glyphId ID of the requested glyph in the font.
507
+ * @returns The horizontal advance width.
508
+ */
509
+ glyphHAdvance(glyphId) {
510
+ return exports.hb_font_get_glyph_h_advance(this.ptr, glyphId);
511
+ }
512
+ /**
513
+ * Return glyph vertical advance.
514
+ * @param glyphId ID of the requested glyph in the font.
515
+ * @returns The vertical advance height.
516
+ */
517
+ glyphVAdvance(glyphId) {
518
+ return exports.hb_font_get_glyph_v_advance(this.ptr, glyphId);
519
+ }
520
+ /**
521
+ * Return glyph horizontal origin.
522
+ * @param glyphId ID of the requested glyph in the font.
523
+ * @returns [x, y] origin coordinates, or undefined if not available.
524
+ */
525
+ glyphHOrigin(glyphId) {
526
+ const sp = Module.stackSave();
527
+ const xPtr = Module.stackAlloc(4);
528
+ const yPtr = Module.stackAlloc(4);
529
+ let origin;
530
+ if (exports.hb_font_get_glyph_h_origin(this.ptr, glyphId, xPtr, yPtr)) origin = [Module.HEAP32[xPtr / 4], Module.HEAP32[yPtr / 4]];
531
+ Module.stackRestore(sp);
532
+ return origin;
533
+ }
534
+ /**
535
+ * Return glyph vertical origin.
536
+ * @param glyphId ID of the requested glyph in the font.
537
+ * @returns [x, y] origin coordinates, or undefined if not available.
538
+ */
539
+ glyphVOrigin(glyphId) {
540
+ const sp = Module.stackSave();
541
+ const xPtr = Module.stackAlloc(4);
542
+ const yPtr = Module.stackAlloc(4);
543
+ let origin;
544
+ if (exports.hb_font_get_glyph_v_origin(this.ptr, glyphId, xPtr, yPtr)) origin = [Module.HEAP32[xPtr / 4], Module.HEAP32[yPtr / 4]];
545
+ Module.stackRestore(sp);
546
+ return origin;
547
+ }
548
+ /**
549
+ * Return glyph extents.
550
+ * @param glyphId ID of the requested glyph in the font.
551
+ * @returns An object with xBearing, yBearing, width, and height, or undefined.
552
+ */
553
+ glyphExtents(glyphId) {
554
+ const sp = Module.stackSave();
555
+ const extentsPtr = Module.stackAlloc(16);
556
+ let extents;
557
+ if (exports.hb_font_get_glyph_extents(this.ptr, glyphId, extentsPtr)) extents = {
558
+ xBearing: Module.HEAP32[extentsPtr / 4],
559
+ yBearing: Module.HEAP32[extentsPtr / 4 + 1],
560
+ width: Module.HEAP32[extentsPtr / 4 + 2],
561
+ height: Module.HEAP32[extentsPtr / 4 + 3]
562
+ };
563
+ Module.stackRestore(sp);
564
+ return extents;
565
+ }
566
+ /**
567
+ * Return glyph ID from name.
568
+ * @param name Name of the requested glyph in the font.
569
+ * @returns The glyph ID, or undefined if not found.
570
+ */
571
+ glyphFromName(name) {
572
+ const sp = Module.stackSave();
573
+ const glyphIdPtr = Module.stackAlloc(4);
574
+ const namePtr = string_to_utf8_ptr(name);
575
+ let glyphId;
576
+ if (exports.hb_font_get_glyph_from_name(this.ptr, namePtr.ptr, namePtr.length, glyphIdPtr)) glyphId = Module.HEAPU32[glyphIdPtr / 4];
577
+ namePtr.free();
578
+ Module.stackRestore(sp);
579
+ return glyphId;
580
+ }
581
+ /**
582
+ * Return a glyph as a JSON path string
583
+ * based on format described on https://svgwg.org/specs/paths/#InterfaceSVGPathSegment
584
+ * @param glyphId ID of the requested glyph in the font.
585
+ * @returns An array of path segment objects with type and values.
586
+ */
587
+ glyphToJson(glyphId) {
588
+ return this.glyphToPath(glyphId).replace(/([MLQCZ])/g, "|$1 ").split("|").filter((x) => x.length).map((x) => {
589
+ const [type, ...values] = x.split(/[ ,]/g).filter((s) => s.length);
590
+ return {
591
+ type,
592
+ values: values.map(Number)
593
+ };
594
+ });
595
+ }
596
+ /**
597
+ * Set the font's scale factor, affecting the position values returned from
598
+ * shaping.
599
+ * @param xScale Units to scale in the X dimension.
600
+ * @param yScale Units to scale in the Y dimension.
601
+ */
602
+ setScale(xScale, yScale) {
603
+ exports.hb_font_set_scale(this.ptr, xScale, yScale);
604
+ }
605
+ /**
606
+ * Applies a list of font-variation settings to a font.
607
+ *
608
+ * Note that this overrides all existing variations set on the font.
609
+ * Axes not included in `variations` will be effectively set to their
610
+ * default values.
611
+ *
612
+ * @param variations Array of variation settings to apply.
613
+ */
614
+ setVariations(variations) {
615
+ const sp = Module.stackSave();
616
+ const vars = Module.stackAlloc(8 * variations.length);
617
+ variations.forEach((variation, i) => {
618
+ variation.writeTo(vars + i * 8);
619
+ });
620
+ exports.hb_font_set_variations(this.ptr, vars, variations.length);
621
+ Module.stackRestore(sp);
622
+ }
623
+ /** Set the font's font functions. */
624
+ setFuncs(fontFuncs) {
625
+ exports.hb_font_set_funcs(this.ptr, fontFuncs.ptr);
626
+ }
627
+ };
628
+ //#endregion
629
+ //#region src/font-funcs.ts
630
+ /**
631
+ * An object representing {@link https://harfbuzz.github.io/harfbuzz-hb-font.html | HarfBuzz font functions}.
632
+ * Font functions define the methods used by a Font for lower-level queries
633
+ * like glyph advances and extents. HarfBuzz provides built-in default
634
+ * implementations which can be selectively overridden.
635
+ */
636
+ var FontFuncs = class {
637
+ constructor() {
638
+ this.ptr = exports.hb_font_funcs_create();
639
+ track(this, exports.hb_font_funcs_destroy);
640
+ }
641
+ /**
642
+ * Set the font's glyph extents function.
643
+ * @param func The callback receives a Font and glyph ID. It should return
644
+ * an object with xBearing, yBearing, width, and height, or undefined on failure.
645
+ */
646
+ setGlyphExtentsFunc(func) {
647
+ const funcPtr = Module.addFunction((fontPtr, font_data, glyph, extentsPtr, user_data) => {
648
+ const extents = func(new Font(fontPtr), glyph);
649
+ if (extents) {
650
+ Module.HEAP32[extentsPtr / 4] = extents.xBearing;
651
+ Module.HEAP32[extentsPtr / 4 + 1] = extents.yBearing;
652
+ Module.HEAP32[extentsPtr / 4 + 2] = extents.width;
653
+ Module.HEAP32[extentsPtr / 4 + 3] = extents.height;
654
+ return 1;
655
+ }
656
+ return 0;
657
+ }, "ippipp");
658
+ exports.hb_font_funcs_set_glyph_extents_func(this.ptr, funcPtr, 0, 0);
659
+ }
660
+ /**
661
+ * Set the font's glyph from name function.
662
+ * @param func The callback receives a Font and glyph name. It should return
663
+ * the glyph ID, or undefined on failure.
664
+ */
665
+ setGlyphFromNameFunc(func) {
666
+ const funcPtr = Module.addFunction((fontPtr, font_data, namePtr, len, glyphPtr, user_data) => {
667
+ const glyph = func(new Font(fontPtr), utf8_ptr_to_string(namePtr, len));
668
+ if (glyph) {
669
+ Module.HEAPU32[glyphPtr / 4] = glyph;
670
+ return 1;
671
+ }
672
+ return 0;
673
+ }, "ipppipp");
674
+ exports.hb_font_funcs_set_glyph_from_name_func(this.ptr, funcPtr, 0, 0);
675
+ }
676
+ /**
677
+ * Set the font's glyph horizontal advance function.
678
+ * @param func The callback receives a Font and glyph ID. It should return
679
+ * the horizontal advance of the glyph.
680
+ */
681
+ setGlyphHAdvanceFunc(func) {
682
+ const funcPtr = Module.addFunction((fontPtr, font_data, glyph, user_data) => {
683
+ return func(new Font(fontPtr), glyph);
684
+ }, "ippip");
685
+ exports.hb_font_funcs_set_glyph_h_advance_func(this.ptr, funcPtr, 0, 0);
686
+ }
687
+ /**
688
+ * Set the font's glyph vertical advance function.
689
+ * @param func The callback receives a Font and glyph ID. It should return
690
+ * the vertical advance of the glyph.
691
+ */
692
+ setGlyphVAdvanceFunc(func) {
693
+ const funcPtr = Module.addFunction((fontPtr, font_data, glyph, user_data) => {
694
+ return func(new Font(fontPtr), glyph);
695
+ }, "ippip");
696
+ exports.hb_font_funcs_set_glyph_v_advance_func(this.ptr, funcPtr, 0, 0);
697
+ }
698
+ /**
699
+ * Set the font's glyph horizontal origin function.
700
+ * @param func The callback receives a Font and glyph ID. It should return
701
+ * the [x, y] horizontal origin of the glyph, or undefined on failure.
702
+ */
703
+ setGlyphHOriginFunc(func) {
704
+ const funcPtr = Module.addFunction((fontPtr, font_data, glyph, xPtr, yPtr, user_data) => {
705
+ const origin = func(new Font(fontPtr), glyph);
706
+ if (origin) {
707
+ Module.HEAP32[xPtr / 4] = origin[0];
708
+ Module.HEAP32[yPtr / 4] = origin[1];
709
+ return 1;
710
+ }
711
+ return 0;
712
+ }, "ippippp");
713
+ exports.hb_font_funcs_set_glyph_h_origin_func(this.ptr, funcPtr, 0, 0);
714
+ }
715
+ /**
716
+ * Set the font's glyph vertical origin function.
717
+ * @param func The callback receives a Font and glyph ID. It should return
718
+ * the [x, y] vertical origin of the glyph, or undefined on failure.
719
+ */
720
+ setGlyphVOriginFunc(func) {
721
+ const funcPtr = Module.addFunction((fontPtr, font_data, glyph, xPtr, yPtr, user_data) => {
722
+ const origin = func(new Font(fontPtr), glyph);
723
+ if (origin) {
724
+ Module.HEAP32[xPtr / 4] = origin[0];
725
+ Module.HEAP32[yPtr / 4] = origin[1];
726
+ return 1;
727
+ }
728
+ return 0;
729
+ }, "ippippp");
730
+ exports.hb_font_funcs_set_glyph_v_origin_func(this.ptr, funcPtr, 0, 0);
731
+ }
732
+ /**
733
+ * Set the font's glyph horizontal kerning function.
734
+ * @param func The callback receives a Font, first glyph ID, and second glyph ID.
735
+ * It should return the horizontal kerning of the glyphs.
736
+ */
737
+ setGlyphHKerningFunc(func) {
738
+ const funcPtr = Module.addFunction((fontPtr, font_data, firstGlyph, secondGlyph, user_data) => {
739
+ return func(new Font(fontPtr), firstGlyph, secondGlyph);
740
+ }, "ippiip");
741
+ exports.hb_font_funcs_set_glyph_h_kerning_func(this.ptr, funcPtr, 0, 0);
742
+ }
743
+ /**
744
+ * Set the font's glyph name function.
745
+ * @param func The callback receives a Font and glyph ID. It should return
746
+ * the name of the glyph, or undefined on failure.
747
+ */
748
+ setGlyphNameFunc(func) {
749
+ const utf8Encoder = new TextEncoder();
750
+ const funcPtr = Module.addFunction((fontPtr, font_data, glyph, namePtr, size, user_data) => {
751
+ const name = func(new Font(fontPtr), glyph);
752
+ if (name) {
753
+ utf8Encoder.encodeInto(name, Module.HEAPU8.subarray(namePtr, namePtr + size));
754
+ return 1;
755
+ }
756
+ return 0;
757
+ }, "ippipip");
758
+ exports.hb_font_funcs_set_glyph_name_func(this.ptr, funcPtr, 0, 0);
759
+ }
760
+ /**
761
+ * Set the font's nominal glyph function.
762
+ * @param func The callback receives a Font and unicode code point. It should
763
+ * return the nominal glyph of the unicode, or undefined on failure.
764
+ */
765
+ setNominalGlyphFunc(func) {
766
+ const funcPtr = Module.addFunction((fontPtr, font_data, unicode, glyphPtr, user_data) => {
767
+ const glyph = func(new Font(fontPtr), unicode);
768
+ if (glyph) {
769
+ Module.HEAPU32[glyphPtr / 4] = glyph;
770
+ return 1;
771
+ }
772
+ return 0;
773
+ }, "ippipp");
774
+ exports.hb_font_funcs_set_nominal_glyph_func(this.ptr, funcPtr, 0, 0);
775
+ }
776
+ /**
777
+ * Set the font's variation glyph function.
778
+ * @param func The callback receives a Font, unicode code point, and variation
779
+ * selector. It should return the variation glyph, or undefined on failure.
780
+ */
781
+ setVariationGlyphFunc(func) {
782
+ const funcPtr = Module.addFunction((fontPtr, font_data, unicode, variationSelector, glyphPtr, user_data) => {
783
+ const glyph = func(new Font(fontPtr), unicode, variationSelector);
784
+ if (glyph) {
785
+ Module.HEAPU32[glyphPtr / 4] = glyph;
786
+ return 1;
787
+ }
788
+ return 0;
789
+ }, "ippiipp");
790
+ exports.hb_font_funcs_set_variation_glyph_func(this.ptr, funcPtr, 0, 0);
791
+ }
792
+ /**
793
+ * Set the font's horizontal extents function.
794
+ * @param func The callback receives a Font. It should return an object with
795
+ * ascender, descender, and lineGap, or undefined on failure.
796
+ */
797
+ setFontHExtentsFunc(func) {
798
+ const funcPtr = Module.addFunction((fontPtr, font_data, extentsPtr, user_data) => {
799
+ const extents = func(new Font(fontPtr));
800
+ if (extents) {
801
+ Module.HEAP32[extentsPtr / 4] = extents.ascender;
802
+ Module.HEAP32[extentsPtr / 4 + 1] = extents.descender;
803
+ Module.HEAP32[extentsPtr / 4 + 2] = extents.lineGap;
804
+ return 1;
805
+ }
806
+ return 0;
807
+ }, "ipppp");
808
+ exports.hb_font_funcs_set_font_h_extents_func(this.ptr, funcPtr, 0, 0);
809
+ }
810
+ /**
811
+ * Set the font's vertical extents function.
812
+ * @param func The callback receives a Font. It should return an object with
813
+ * ascender, descender, and lineGap, or undefined on failure.
814
+ */
815
+ setFontVExtentsFunc(func) {
816
+ const funcPtr = Module.addFunction((fontPtr, font_data, extentsPtr, user_data) => {
817
+ const extents = func(new Font(fontPtr));
818
+ if (extents) {
819
+ Module.HEAP32[extentsPtr / 4] = extents.ascender;
820
+ Module.HEAP32[extentsPtr / 4 + 1] = extents.descender;
821
+ Module.HEAP32[extentsPtr / 4 + 2] = extents.lineGap;
822
+ return 1;
823
+ }
824
+ return 0;
825
+ }, "ipppp");
826
+ exports.hb_font_funcs_set_font_v_extents_func(this.ptr, funcPtr, 0, 0);
827
+ }
828
+ };
829
+ //#endregion
830
+ //#region src/buffer.ts
831
+ const BufferContentType = {
832
+ INVALID: 0,
833
+ UNICODE: 1,
834
+ GLYPHS: 2
835
+ };
836
+ const BufferSerializeFlag = {
837
+ DEFAULT: 0,
838
+ NO_CLUSTERS: 1,
839
+ NO_POSITIONS: 2,
840
+ NO_GLYPH_NAMES: 4,
841
+ GLYPH_EXTENTS: 8,
842
+ GLYPH_FLAGS: 16,
843
+ NO_ADVANCES: 32,
844
+ DEFINED: 63
845
+ };
846
+ const BufferFlag = {
847
+ DEFAULT: 0,
848
+ BOT: 1,
849
+ EOT: 2,
850
+ PRESERVE_DEFAULT_IGNORABLES: 4,
851
+ REMOVE_DEFAULT_IGNORABLES: 8,
852
+ DO_NOT_INSERT_DOTTED_CIRCLE: 16,
853
+ VERIFY: 32,
854
+ PRODUCE_UNSAFE_TO_CONCAT: 64,
855
+ PRODUCE_SAFE_TO_INSERT_TATWEEL: 128,
856
+ DEFINED: 255
857
+ };
858
+ const Direction = {
859
+ INVALID: 0,
860
+ LTR: 4,
861
+ RTL: 5,
862
+ TTB: 6,
863
+ BTT: 7
864
+ };
865
+ const ClusterLevel = {
866
+ MONOTONE_GRAPHEMES: 0,
867
+ MONOTONE_CHARACTERS: 1,
868
+ CHARACTERS: 2,
869
+ GRAPHEMES: 3,
870
+ DEFAULT: 0
871
+ };
872
+ const BufferSerializeFormat = {
873
+ INVALID: 0,
874
+ TEXT: hb_tag("TEXT"),
875
+ JSON: hb_tag("JSON")
876
+ };
877
+ /**
878
+ * An object representing a {@link https://harfbuzz.github.io/harfbuzz-hb-buffer.html | HarfBuzz buffer}.
879
+ * A buffer holds the input text and its properties before shaping, and the
880
+ * output glyphs and their information after shaping.
881
+ */
882
+ var Buffer = class Buffer {
883
+ /**
884
+ * @param existingPtr @internal Wrap an existing buffer pointer.
885
+ */
886
+ constructor(existingPtr) {
887
+ if (existingPtr != void 0) this.ptr = exports.hb_buffer_reference(existingPtr);
888
+ else this.ptr = exports.hb_buffer_create();
889
+ track(this, exports.hb_buffer_destroy);
890
+ }
891
+ /**
892
+ * Appends a character with the Unicode value of `codePoint` to the buffer,
893
+ * and gives it the initial cluster value of `cluster`. Clusters can be any
894
+ * thing the client wants, they are usually used to refer to the index of the
895
+ * character in the input text stream and are output in the `cluster` field
896
+ * of {@link GlyphInfo}.
897
+ *
898
+ * This function does not check the validity of `codePoint`, it is up to the
899
+ * caller to ensure it is a valid Unicode code point.
900
+ * @param codePoint A Unicode code point.
901
+ * @param cluster The cluster value of `codePoint`.
902
+ */
903
+ add(codePoint, cluster) {
904
+ exports.hb_buffer_add(this.ptr, codePoint, cluster);
905
+ }
906
+ /**
907
+ * Add text to the buffer.
908
+ * @param text Text to be added to the buffer.
909
+ * @param itemOffset The offset of the first character to add to the buffer.
910
+ * @param itemLength The number of characters to add to the buffer, or omit for the end of text.
911
+ */
912
+ addText(text, itemOffset = 0, itemLength) {
913
+ const str = string_to_utf16_ptr(text);
914
+ exports.hb_buffer_add_utf16(this.ptr, str.ptr, str.length, itemOffset, itemLength ?? str.length);
915
+ str.free();
916
+ }
917
+ /**
918
+ * Add code points to the buffer.
919
+ * @param codePoints Array of code points to be added to the buffer.
920
+ * @param itemOffset The offset of the first code point to add to the buffer.
921
+ * @param itemLength The number of code points to add to the buffer, or omit for the end of the array.
922
+ */
923
+ addCodePoints(codePoints, itemOffset = 0, itemLength) {
924
+ const codePointsPtr = exports.malloc(codePoints.length * 4);
925
+ Module.HEAPU32.subarray(codePointsPtr / 4, codePointsPtr / 4 + codePoints.length).set(codePoints);
926
+ exports.hb_buffer_add_codepoints(this.ptr, codePointsPtr, codePoints.length, itemOffset, itemLength ?? codePoints.length);
927
+ exports.free(codePointsPtr);
928
+ }
929
+ /**
930
+ * Set buffer script, language and direction.
931
+ *
932
+ * This needs to be done before shaping.
933
+ */
934
+ guessSegmentProperties() {
935
+ exports.hb_buffer_guess_segment_properties(this.ptr);
936
+ }
937
+ /**
938
+ * Set buffer direction explicitly.
939
+ * @param dir A {@link Direction} value.
940
+ */
941
+ setDirection(dir) {
942
+ exports.hb_buffer_set_direction(this.ptr, dir);
943
+ }
944
+ /**
945
+ * Set buffer flags explicitly.
946
+ * @param flags A combination of {@link BufferFlag} values (OR them together).
947
+ */
948
+ setFlags(flags) {
949
+ exports.hb_buffer_set_flags(this.ptr, flags);
950
+ }
951
+ /**
952
+ * Set buffer language explicitly.
953
+ * @param language The buffer language
954
+ */
955
+ setLanguage(language) {
956
+ const str = string_to_ascii_ptr(language);
957
+ exports.hb_buffer_set_language(this.ptr, exports.hb_language_from_string(str.ptr, -1));
958
+ str.free();
959
+ }
960
+ /**
961
+ * Set buffer script explicitly.
962
+ * @param script The buffer script
963
+ */
964
+ setScript(script) {
965
+ const str = string_to_ascii_ptr(script);
966
+ exports.hb_buffer_set_script(this.ptr, exports.hb_script_from_string(str.ptr, -1));
967
+ str.free();
968
+ }
969
+ /**
970
+ * Set the HarfBuzz clustering level.
971
+ *
972
+ * Affects the cluster values returned from shaping.
973
+ * @param level A {@link ClusterLevel} value. See the HarfBuzz manual chapter on Clusters.
974
+ */
975
+ setClusterLevel(level) {
976
+ exports.hb_buffer_set_cluster_level(this.ptr, level);
977
+ }
978
+ /** Reset the buffer to its initial status. */
979
+ reset() {
980
+ exports.hb_buffer_reset(this.ptr);
981
+ }
982
+ /**
983
+ * Similar to reset(), but does not clear the Unicode functions and the
984
+ * replacement code point.
985
+ */
986
+ clearContents() {
987
+ exports.hb_buffer_clear_contents(this.ptr);
988
+ }
989
+ /**
990
+ * Set message func.
991
+ * @param func The function to set. It receives the buffer, font, and message
992
+ * string as arguments. Returning false will skip this shaping step and move
993
+ * to the next one.
994
+ */
995
+ setMessageFunc(func) {
996
+ const traceFunc = (bufferPtr, fontPtr, messagePtr, user_data) => {
997
+ const message = utf8_ptr_to_string(messagePtr);
998
+ return func(new Buffer(bufferPtr), new Font(fontPtr), message) ? 1 : 0;
999
+ };
1000
+ const traceFuncPtr = Module.addFunction(traceFunc, "iiiii");
1001
+ exports.hb_buffer_set_message_func(this.ptr, traceFuncPtr, 0, 0);
1002
+ }
1003
+ /**
1004
+ * Get the the number of items in the buffer.
1005
+ * @returns The buffer length.
1006
+ */
1007
+ getLength() {
1008
+ return exports.hb_buffer_get_length(this.ptr);
1009
+ }
1010
+ /**
1011
+ * Get the glyph information from the buffer.
1012
+ * @returns An array of {@link GlyphInfo} objects.
1013
+ */
1014
+ getGlyphInfos() {
1015
+ const infosPtr = exports.hb_buffer_get_glyph_infos(this.ptr, 0);
1016
+ const infosArray = Module.HEAPU32.subarray(infosPtr / 4, infosPtr / 4 + this.getLength() * 5);
1017
+ const infos = [];
1018
+ for (let i = 0; i < infosArray.length; i += 5) infos.push({
1019
+ codepoint: infosArray[i],
1020
+ cluster: infosArray[i + 2],
1021
+ flags: exports.hb_glyph_info_get_glyph_flags(infosPtr + i * 4)
1022
+ });
1023
+ return infos;
1024
+ }
1025
+ /**
1026
+ * Get the glyph positions from the buffer.
1027
+ * @returns An array of {@link GlyphPosition} objects.
1028
+ */
1029
+ getGlyphPositions() {
1030
+ const positionsPtr32 = exports.hb_buffer_get_glyph_positions(this.ptr, 0) / 4;
1031
+ if (positionsPtr32 == 0) return [];
1032
+ const positionsArray = Module.HEAP32.subarray(positionsPtr32, positionsPtr32 + this.getLength() * 5);
1033
+ const positions = [];
1034
+ for (let i = 0; i < positionsArray.length; i += 5) positions.push({
1035
+ xAdvance: positionsArray[i],
1036
+ yAdvance: positionsArray[i + 1],
1037
+ xOffset: positionsArray[i + 2],
1038
+ yOffset: positionsArray[i + 3]
1039
+ });
1040
+ return positions;
1041
+ }
1042
+ /**
1043
+ * Get the glyph information and positions from the buffer.
1044
+ * @returns The glyph information and positions.
1045
+ *
1046
+ * The glyph information is returned as an array of objects with the
1047
+ * properties from getGlyphInfos and getGlyphPositions combined.
1048
+ */
1049
+ getGlyphInfosAndPositions() {
1050
+ const infosPtr = exports.hb_buffer_get_glyph_infos(this.ptr, 0);
1051
+ const infosArray = Module.HEAPU32.subarray(infosPtr / 4, infosPtr / 4 + this.getLength() * 5);
1052
+ const positionsPtr32 = exports.hb_buffer_get_glyph_positions(this.ptr, 0) / 4;
1053
+ const positionsArray = positionsPtr32 ? Module.HEAP32.subarray(positionsPtr32, positionsPtr32 + this.getLength() * 5) : void 0;
1054
+ const out = [];
1055
+ for (let i = 0; i < infosArray.length; i += 5) {
1056
+ const info = {
1057
+ codepoint: infosArray[i],
1058
+ cluster: infosArray[i + 2],
1059
+ flags: exports.hb_glyph_info_get_glyph_flags(infosPtr + i * 4)
1060
+ };
1061
+ for (const [name, idx] of [
1062
+ ["mask", 1],
1063
+ ["var1", 3],
1064
+ ["var2", 4]
1065
+ ]) Object.defineProperty(info, name, {
1066
+ value: infosArray[i + idx],
1067
+ enumerable: false
1068
+ });
1069
+ if (positionsArray) {
1070
+ info.xAdvance = positionsArray[i];
1071
+ info.yAdvance = positionsArray[i + 1];
1072
+ info.xOffset = positionsArray[i + 2];
1073
+ info.yOffset = positionsArray[i + 3];
1074
+ Object.defineProperty(info, "var", {
1075
+ value: positionsArray[i + 4],
1076
+ enumerable: false
1077
+ });
1078
+ }
1079
+ out.push(info);
1080
+ }
1081
+ return out;
1082
+ }
1083
+ /**
1084
+ * Update the glyph positions in the buffer.
1085
+ * WARNING: Do not use unless you know what you are doing.
1086
+ */
1087
+ updateGlyphPositions(positions) {
1088
+ const positionsPtr32 = exports.hb_buffer_get_glyph_positions(this.ptr, 0) / 4;
1089
+ if (positionsPtr32 == 0) return;
1090
+ const len = Math.min(positions.length, this.getLength());
1091
+ const positionsArray = Module.HEAP32.subarray(positionsPtr32, positionsPtr32 + len * 5);
1092
+ for (let i = 0; i < len; i++) {
1093
+ positionsArray[i * 5] = positions[i].xAdvance;
1094
+ positionsArray[i * 5 + 1] = positions[i].yAdvance;
1095
+ positionsArray[i * 5 + 2] = positions[i].xOffset;
1096
+ positionsArray[i * 5 + 3] = positions[i].yOffset;
1097
+ }
1098
+ }
1099
+ /**
1100
+ * Serialize the buffer contents to a string.
1101
+ * @param options Serialization options:
1102
+ * - `font`: the font to use for serialization;
1103
+ * - `start`: the starting index of the glyphs (default `0`);
1104
+ * - `end`: the ending index of the glyphs (default end of buffer);
1105
+ * - `format`: a {@link BufferSerializeFormat} value (default `TEXT`);
1106
+ * - `flags`: a combination of {@link BufferSerializeFlag} values (default `0`).
1107
+ * @returns The serialized buffer contents.
1108
+ */
1109
+ serialize(options = {}) {
1110
+ let { font, start = 0, end, format = BufferSerializeFormat.TEXT, flags = 0 } = options;
1111
+ const sp = Module.stackSave();
1112
+ const endPos = end ?? this.getLength();
1113
+ const bufLen = 32 * 1024;
1114
+ const bufPtr = exports.malloc(bufLen);
1115
+ const bufConsumedPtr = Module.stackAlloc(4);
1116
+ let result = "";
1117
+ while (start < endPos) {
1118
+ start += exports.hb_buffer_serialize(this.ptr, start, endPos, bufPtr, bufLen, bufConsumedPtr, font ? font.ptr : 0, format, flags);
1119
+ const bufConsumed = Module.HEAPU32[bufConsumedPtr / 4];
1120
+ if (bufConsumed == 0) break;
1121
+ result += utf8_ptr_to_string(bufPtr, bufConsumed);
1122
+ }
1123
+ exports.free(bufPtr);
1124
+ Module.stackRestore(sp);
1125
+ return result;
1126
+ }
1127
+ /**
1128
+ * Return the buffer content type.
1129
+ *
1130
+ * @returns The buffer content type as a {@link BufferContentType} value.
1131
+ */
1132
+ getContentType() {
1133
+ return exports.hb_buffer_get_content_type(this.ptr);
1134
+ }
1135
+ };
1136
+ //#endregion
1137
+ //#region src/feature.ts
1138
+ /**
1139
+ * A {@link https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-feature-t | HarfBuzz feature}.
1140
+ *
1141
+ * The structure that holds information about requested feature application.
1142
+ * The feature will be applied with the given value to all glyphs which are in
1143
+ * clusters between {@link Feature.start} (inclusive) and {@link Feature.end}
1144
+ * (exclusive). Setting `start` to `0` and `end` to `0xffffffff` specifies that
1145
+ * the feature always applies to the entire buffer.
1146
+ */
1147
+ var Feature = class Feature {
1148
+ static {
1149
+ this.GLOBAL_START = 0;
1150
+ }
1151
+ static {
1152
+ this.GLOBAL_END = 4294967295;
1153
+ }
1154
+ constructor(tag, value = 1, start = Feature.GLOBAL_START, end = Feature.GLOBAL_END) {
1155
+ this.tag = tag;
1156
+ this.value = value;
1157
+ this.start = start;
1158
+ this.end = end;
1159
+ }
1160
+ /**
1161
+ * Parses a string into a Feature.
1162
+ *
1163
+ * The format for specifying feature strings follows. All valid CSS
1164
+ * font-feature-settings values other than `normal` and the global values are
1165
+ * also accepted, though not documented below. CSS string escapes are not
1166
+ * supported.
1167
+ *
1168
+ * The range indices refer to the positions between Unicode characters. The
1169
+ * position before the first character is always 0.
1170
+ *
1171
+ * The format is Python-esque. Here is how it all works:
1172
+ *
1173
+ * | Syntax | Value | Start | End | Meaning |
1174
+ * | ------------- | ----- | ----- | --- | -------------------------------- |
1175
+ * | `kern` | 1 | 0 | ∞ | Turn feature on |
1176
+ * | `+kern` | 1 | 0 | ∞ | Turn feature on |
1177
+ * | `-kern` | 0 | 0 | ∞ | Turn feature off |
1178
+ * | `kern=0` | 0 | 0 | ∞ | Turn feature off |
1179
+ * | `kern=1` | 1 | 0 | ∞ | Turn feature on |
1180
+ * | `aalt=2` | 2 | 0 | ∞ | Choose 2nd alternate |
1181
+ * | `kern[]` | 1 | 0 | ∞ | Turn feature on |
1182
+ * | `kern[:]` | 1 | 0 | ∞ | Turn feature on |
1183
+ * | `kern[5:]` | 1 | 5 | ∞ | Turn feature on, partial |
1184
+ * | `kern[:5]` | 1 | 0 | 5 | Turn feature on, partial |
1185
+ * | `kern[3:5]` | 1 | 3 | 5 | Turn feature on, range |
1186
+ * | `kern[3]` | 1 | 3 | 3+1 | Turn feature on, single char |
1187
+ * | `aalt[3:5]=2` | 2 | 3 | 5 | Turn 2nd alternate on for range |
1188
+ *
1189
+ * @param str The string to parse.
1190
+ * @returns A Feature, or undefined if the string is not a valid feature.
1191
+ */
1192
+ static fromString(str) {
1193
+ const sp = Module.stackSave();
1194
+ const featurePtr = Module.stackAlloc(16);
1195
+ const strPtr = string_to_ascii_ptr(str);
1196
+ let feature;
1197
+ if (exports.hb_feature_from_string(strPtr.ptr, -1, featurePtr)) feature = new Feature(hb_untag(Module.HEAPU32[featurePtr / 4]), Module.HEAPU32[featurePtr / 4 + 1], Module.HEAPU32[featurePtr / 4 + 2], Module.HEAPU32[featurePtr / 4 + 3]);
1198
+ strPtr.free();
1199
+ Module.stackRestore(sp);
1200
+ return feature;
1201
+ }
1202
+ /**
1203
+ * Converts the feature to a string in the format understood by
1204
+ * {@link Feature.fromString}.
1205
+ *
1206
+ * Note that the feature value will be omitted if it is `1`, but the string
1207
+ * won't include any whitespace.
1208
+ *
1209
+ * @returns The feature string.
1210
+ */
1211
+ toString() {
1212
+ const sp = Module.stackSave();
1213
+ const featurePtr = Module.stackAlloc(16);
1214
+ this.writeTo(featurePtr);
1215
+ const bufLen = 128;
1216
+ const bufPtr = Module.stackAlloc(bufLen);
1217
+ exports.hb_feature_to_string(featurePtr, bufPtr, bufLen);
1218
+ const result = utf8_ptr_to_string(bufPtr);
1219
+ Module.stackRestore(sp);
1220
+ return result;
1221
+ }
1222
+ /** @internal Write this feature into the given hb_feature_t pointer. */
1223
+ writeTo(ptr) {
1224
+ Module.HEAPU32[ptr / 4] = hb_tag(this.tag);
1225
+ Module.HEAPU32[ptr / 4 + 1] = this.value;
1226
+ Module.HEAPU32[ptr / 4 + 2] = this.start;
1227
+ Module.HEAPU32[ptr / 4 + 3] = this.end;
1228
+ }
1229
+ };
1230
+ //#endregion
1231
+ //#region src/variation.ts
1232
+ /**
1233
+ * A {@link https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-variation-t | HarfBuzz variation}.
1234
+ *
1235
+ * Data type for holding variation data. Registered OpenType variation-axis
1236
+ * tags are listed in
1237
+ * {@link https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg | OpenType Axis Tag Registry}.
1238
+ */
1239
+ var Variation = class Variation {
1240
+ constructor(tag, value = 0) {
1241
+ this.tag = tag;
1242
+ this.value = value;
1243
+ }
1244
+ /**
1245
+ * Parses a string into a Variation.
1246
+ *
1247
+ * The format for specifying variation settings follows. All valid CSS
1248
+ * font-variation-settings values other than `normal` and `inherited` are
1249
+ * also accepted, though, not documented below.
1250
+ *
1251
+ * The format is a tag, optionally followed by an equals sign, followed by a
1252
+ * number. For example `wght=500`, or `slnt=-7.5`.
1253
+ *
1254
+ * @param str The string to parse.
1255
+ * @returns A Variation, or undefined if the string is not a valid variation.
1256
+ */
1257
+ static fromString(str) {
1258
+ const sp = Module.stackSave();
1259
+ const variationPtr = Module.stackAlloc(8);
1260
+ const strPtr = string_to_ascii_ptr(str);
1261
+ let variation;
1262
+ if (exports.hb_variation_from_string(strPtr.ptr, -1, variationPtr)) variation = new Variation(hb_untag(Module.HEAPU32[variationPtr / 4]), Module.HEAPF32[variationPtr / 4 + 1]);
1263
+ strPtr.free();
1264
+ Module.stackRestore(sp);
1265
+ return variation;
1266
+ }
1267
+ /**
1268
+ * Converts the variation to a string in the format understood by
1269
+ * {@link Variation.fromString}.
1270
+ *
1271
+ * Note that the string won't include any whitespace.
1272
+ *
1273
+ * @returns The variation string.
1274
+ */
1275
+ toString() {
1276
+ const sp = Module.stackSave();
1277
+ const variationPtr = Module.stackAlloc(8);
1278
+ this.writeTo(variationPtr);
1279
+ const bufLen = 128;
1280
+ const bufPtr = Module.stackAlloc(bufLen);
1281
+ exports.hb_variation_to_string(variationPtr, bufPtr, bufLen);
1282
+ const result = utf8_ptr_to_string(bufPtr);
1283
+ Module.stackRestore(sp);
1284
+ return result;
1285
+ }
1286
+ /** @internal Write this variation into the given hb_variation_t pointer. */
1287
+ writeTo(ptr) {
1288
+ Module.HEAPU32[ptr / 4] = hb_tag(this.tag);
1289
+ Module.HEAPF32[ptr / 4 + 1] = this.value;
1290
+ }
1291
+ };
1292
+ //#endregion
1293
+ //#region src/shape.ts
1294
+ const TracePhase = {
1295
+ DONT_STOP: 0,
1296
+ GSUB: 1,
1297
+ GPOS: 2
1298
+ };
1299
+ /**
1300
+ * Shape a buffer with a given font.
1301
+ *
1302
+ * Converts the Unicode text in the buffer into positioned glyphs.
1303
+ * The buffer is modified in place.
1304
+ *
1305
+ * @param font The Font to shape with.
1306
+ * @param buffer The Buffer containing text to shape, suitably prepared
1307
+ * (text added, segment properties set).
1308
+ * @param features An array of {@link Feature} values to apply.
1309
+ */
1310
+ function shape(font, buffer, features) {
1311
+ const featuresLen = features?.length ?? 0;
1312
+ const sp = Module.stackSave();
1313
+ let featuresPtr = 0;
1314
+ if (featuresLen) {
1315
+ featuresPtr = Module.stackAlloc(16 * featuresLen);
1316
+ features.forEach((feature, i) => {
1317
+ feature.writeTo(featuresPtr + i * 16);
1318
+ });
1319
+ }
1320
+ exports.hb_shape(font.ptr, buffer.ptr, featuresPtr, featuresLen);
1321
+ Module.stackRestore(sp);
1322
+ }
1323
+ /**
1324
+ * Shape a buffer with a given font, returning a JSON trace of the shaping process.
1325
+ *
1326
+ * This function supports "partial shaping", where the shaping process is
1327
+ * terminated after a given lookup ID is reached.
1328
+ *
1329
+ * @param font The Font to shape with.
1330
+ * @param buffer The Buffer containing text to shape, suitably prepared.
1331
+ * @param features An array of {@link Feature} values to apply.
1332
+ * @param stop_at A lookup ID at which to terminate shaping.
1333
+ * @param stop_phase The {@link TracePhase} at which to stop shaping.
1334
+ * @returns An array of trace entries, each with a message, serialized glyphs, and phase info.
1335
+ */
1336
+ function shapeWithTrace(font, buffer, features, stop_at, stop_phase) {
1337
+ const trace = [];
1338
+ let currentPhase = TracePhase.DONT_STOP;
1339
+ let stopping = false;
1340
+ buffer.setMessageFunc((buffer, font, message) => {
1341
+ if (message.startsWith("start table GSUB")) currentPhase = TracePhase.GSUB;
1342
+ else if (message.startsWith("start table GPOS")) currentPhase = TracePhase.GPOS;
1343
+ if (currentPhase != stop_phase) stopping = false;
1344
+ if (stop_phase != TracePhase.DONT_STOP && currentPhase == stop_phase && message.startsWith("end lookup " + stop_at)) stopping = true;
1345
+ if (stopping) return false;
1346
+ const traceBuf = buffer.serialize({
1347
+ font,
1348
+ format: BufferSerializeFormat.JSON,
1349
+ flags: BufferSerializeFlag.NO_GLYPH_NAMES
1350
+ });
1351
+ trace.push({
1352
+ m: message,
1353
+ t: JSON.parse(traceBuf),
1354
+ glyphs: buffer.getContentType() == BufferContentType.GLYPHS
1355
+ });
1356
+ return true;
1357
+ });
1358
+ shape(font, buffer, features);
1359
+ return trace;
1360
+ }
1361
+ /**
1362
+ * Return the HarfBuzz version.
1363
+ * @returns An object with major, minor, and micro version numbers.
1364
+ */
1365
+ function version() {
1366
+ const sp = Module.stackSave();
1367
+ const versionPtr = Module.stackAlloc(12);
1368
+ exports.hb_version(versionPtr, versionPtr + 4, versionPtr + 8);
1369
+ const ver = {
1370
+ major: Module.HEAPU32[versionPtr / 4],
1371
+ minor: Module.HEAPU32[(versionPtr + 4) / 4],
1372
+ micro: Module.HEAPU32[(versionPtr + 8) / 4]
1373
+ };
1374
+ Module.stackRestore(sp);
1375
+ return ver;
1376
+ }
1377
+ /**
1378
+ * Return the HarfBuzz version as a string.
1379
+ * @returns A version string in the form "major.minor.micro".
1380
+ */
1381
+ function versionString() {
1382
+ return utf8_ptr_to_string(exports.hb_version_string());
1383
+ }
1384
+ /**
1385
+ * Convert an OpenType script tag to HarfBuzz script.
1386
+ * @param tag The tag to convert.
1387
+ * @returns The script.
1388
+ */
1389
+ function otTagToScript(tag) {
1390
+ const hbTag = hb_tag(tag);
1391
+ return hb_untag(exports.hb_ot_tag_to_script(hbTag));
1392
+ }
1393
+ /**
1394
+ * Convert an OpenType language tag to HarfBuzz language.
1395
+ * @param tag The tag to convert.
1396
+ * @returns The language.
1397
+ */
1398
+ function otTagToLanguage(tag) {
1399
+ const hbTag = hb_tag(tag);
1400
+ return language_to_string(exports.hb_ot_tag_to_language(hbTag));
1401
+ }
1402
+ //#endregion
1403
+ //#region src/index.ts
1404
+ init(await createHarfBuzz());
1405
+ //#endregion
1406
+ export { Blob, Buffer, BufferContentType, BufferFlag, BufferSerializeFlag, BufferSerializeFormat, ClusterLevel, Direction, Face, Feature, Font, FontFuncs, GlyphClass, GlyphFlag, TracePhase, Variation, otTagToLanguage, otTagToScript, shape, shapeWithTrace, version, versionString };