nuxt-og-image 6.7.6 → 6.7.7

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 (32) hide show
  1. package/LICENSE.md +6 -0
  2. package/dist/chunks/decode.mjs +1087 -0
  3. package/dist/chunks/tw4.mjs +1 -1
  4. package/dist/chunks/uno.mjs +2 -2
  5. package/dist/module.d.ts +1 -1
  6. package/dist/module.json +1 -1
  7. package/dist/module.mjs +1 -1
  8. package/dist/runtime/server/og-image/bindings/font-assets/dev-prerender.js +5 -6
  9. package/dist/runtime/server/og-image/bindings/font-assets/node.d.ts +1 -1
  10. package/dist/runtime/server/og-image/bindings/font-assets/node.js +2 -3
  11. package/dist/runtime/server/og-image/browser/screenshot.js +2 -1
  12. package/dist/runtime/server/og-image/font-source.d.ts +3 -12
  13. package/dist/runtime/server/og-image/font-source.js +1 -4
  14. package/dist/runtime/server/og-image/fonts.d.ts +0 -7
  15. package/dist/runtime/server/og-image/fonts.js +1 -1
  16. package/dist/runtime/server/og-image/takumi/renderer.js +2 -2
  17. package/dist/runtime/server/routes/resolve.js +2 -1
  18. package/dist/runtime/server/util/fetchLocalAsset.d.ts +1 -1
  19. package/dist/runtime/server/util/fetchLocalAsset.js +2 -1
  20. package/dist/runtime/types.d.ts +1 -1
  21. package/dist/shared/{nuxt-og-image.BIbfn5xQ.mjs → nuxt-og-image.BMHzg1Vz.mjs} +227 -76
  22. package/package.json +21 -22
  23. package/dist/chunks/tw4.cjs +0 -493
  24. package/dist/chunks/uno.cjs +0 -249
  25. package/dist/cli.cjs +0 -1345
  26. package/dist/cli.d.cts +0 -1
  27. package/dist/content.cjs +0 -21
  28. package/dist/content.d.cts +0 -16
  29. package/dist/module.cjs +0 -39
  30. package/dist/module.d.cts +0 -219
  31. package/dist/shared/nuxt-og-image.CMYbz66P.cjs +0 -193
  32. package/dist/shared/nuxt-og-image.CdpC3njh.cjs +0 -5898
@@ -0,0 +1,1087 @@
1
+ import { brotliDecompressSync } from 'node:zlib';
2
+
3
+ function computeChecksum(data, offset, length) {
4
+ let sum = 0;
5
+ const end = offset + length;
6
+ const view = new DataView(data.buffer, data.byteOffset);
7
+ const alignedEnd = offset + (length & -4);
8
+ for (let index = offset; index < alignedEnd; index += 4)
9
+ sum = sum + view.getUint32(index) >>> 0;
10
+ if (end > alignedEnd) {
11
+ let last = 0;
12
+ for (let index = alignedEnd; index < end; index++)
13
+ last = last << 8 | data[index];
14
+ last <<= (4 - (end - alignedEnd)) * 8;
15
+ sum = sum + last >>> 0;
16
+ }
17
+ return sum;
18
+ }
19
+ function pad4(value) {
20
+ return value + 3 & -4;
21
+ }
22
+
23
+ const KNOWN_TAGS = [
24
+ 1668112752,
25
+ 1751474532,
26
+ 1751672161,
27
+ 1752003704,
28
+ 1835104368,
29
+ 1851878757,
30
+ 1330851634,
31
+ 1886352244,
32
+ 1668707360,
33
+ 1718642541,
34
+ 1735162214,
35
+ 1819239265,
36
+ 1886545264,
37
+ 1128678944,
38
+ 1448038983,
39
+ 1161970772,
40
+ 1161972803,
41
+ 1734439792,
42
+ 1751412088,
43
+ 1801810542,
44
+ 1280594760,
45
+ 1346587732,
46
+ 1447316824,
47
+ 1986553185,
48
+ 1986884728,
49
+ 1111577413,
50
+ 1195656518,
51
+ 1196445523,
52
+ 1196643650,
53
+ 1161974595,
54
+ 1246975046,
55
+ 1296127048,
56
+ 1128416340,
57
+ 1128418371,
58
+ 1129270354,
59
+ 1129333068,
60
+ 1398163232,
61
+ 1935829368,
62
+ 1633906292,
63
+ 1635148146,
64
+ 1650745716,
65
+ 1651273571,
66
+ 1651731566,
67
+ 1668702578,
68
+ 1717859171,
69
+ 1717920116,
70
+ 1718449272,
71
+ 1719034226,
72
+ 1735811442,
73
+ 1752396921,
74
+ 1786082164,
75
+ 1818452338,
76
+ 1836020340,
77
+ 1836020344,
78
+ 1869636196,
79
+ 1886547824,
80
+ 1953653099,
81
+ 1516335206,
82
+ 1399417958,
83
+ 1198285172,
84
+ 1198288739,
85
+ 1181049204,
86
+ 1399417964
87
+ ];
88
+ const TAG_GLYF = 1735162214;
89
+ const TAG_LOCA = 1819239265;
90
+ const TAG_HMTX = 1752003704;
91
+ const TAG_HHEA = 1751672161;
92
+ const TAG_HEAD = 1751474532;
93
+ const TTC_FLAVOR = 1953784678;
94
+ const WOFF2_SIGNATURE = 2001684018;
95
+ const WOFF2_FLAGS_TRANSFORM = 1 << 5;
96
+ function tagToString(tag) {
97
+ return String.fromCharCode(
98
+ tag >> 24 & 255,
99
+ tag >> 16 & 255,
100
+ tag >> 8 & 255,
101
+ tag & 255
102
+ );
103
+ }
104
+
105
+ function createReadBuffer(input) {
106
+ const data = input instanceof Uint8Array ? input : new Uint8Array(input);
107
+ let offset = 0;
108
+ return {
109
+ get offset() {
110
+ return offset;
111
+ },
112
+ skip(length) {
113
+ if (length < 0 || offset + length > data.byteLength)
114
+ return false;
115
+ offset += length;
116
+ return true;
117
+ },
118
+ readU8() {
119
+ if (offset + 1 > data.byteLength)
120
+ return null;
121
+ return data[offset++];
122
+ },
123
+ readU16() {
124
+ if (offset + 2 > data.byteLength)
125
+ return null;
126
+ const value = data[offset] << 8 | data[offset + 1];
127
+ offset += 2;
128
+ return value;
129
+ },
130
+ readU32() {
131
+ if (offset + 4 > data.byteLength)
132
+ return null;
133
+ const value = data[offset] * 16777216 + (data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
134
+ offset += 4;
135
+ return value;
136
+ }
137
+ };
138
+ }
139
+
140
+ function read255UShort(buffer) {
141
+ const code = buffer.readU8();
142
+ if (code === null)
143
+ return null;
144
+ if (code === 253)
145
+ return buffer.readU16();
146
+ if (code === 255) {
147
+ const next = buffer.readU8();
148
+ return next === null ? null : 253 + next;
149
+ }
150
+ if (code === 254) {
151
+ const next = buffer.readU8();
152
+ return next === null ? null : 506 + next;
153
+ }
154
+ return code;
155
+ }
156
+ function readBase128(buffer) {
157
+ let result = 0;
158
+ for (let index = 0; index < 5; index++) {
159
+ const code = buffer.readU8();
160
+ if (code === null || index === 0 && code === 128 || (result & 4261412864) !== 0)
161
+ return null;
162
+ result = result << 7 | code & 127;
163
+ if ((code & 128) === 0)
164
+ return result;
165
+ }
166
+ return null;
167
+ }
168
+
169
+ const SFNT_HEADER_SIZE = 12;
170
+ const SFNT_ENTRY_SIZE = 16;
171
+ const FLAG_ON_CURVE = 1;
172
+ const FLAG_X_SHORT = 1 << 1;
173
+ const FLAG_Y_SHORT = 1 << 2;
174
+ const FLAG_REPEAT = 1 << 3;
175
+ const FLAG_X_SAME = 1 << 4;
176
+ const FLAG_Y_SAME = 1 << 5;
177
+ const FLAG_OVERLAP_SIMPLE = 1 << 6;
178
+ function woff2Decode(data) {
179
+ const input = data instanceof Uint8Array ? data : new Uint8Array(data);
180
+ const buf = createReadBuffer(input);
181
+ const header = readHeader(buf, input.byteLength);
182
+ if (!header) {
183
+ throw new Error("Failed to read WOFF2 header");
184
+ }
185
+ const compressedData = input.subarray(
186
+ header.compressedOffset,
187
+ header.compressedOffset + header.compressedLength
188
+ );
189
+ const brotli = brotliDecompressSync(compressedData);
190
+ const decompressed = new Uint8Array(brotli.buffer, brotli.byteOffset, brotli.byteLength);
191
+ if (decompressed.byteLength !== header.uncompressedSize) {
192
+ throw new Error(
193
+ `Brotli decompression failed: expected ${header.uncompressedSize} bytes, got ${decompressed.byteLength}`
194
+ );
195
+ }
196
+ const firstTableOffset = computeOffsetToFirstTable(header);
197
+ let outputSize = firstTableOffset;
198
+ for (const table of header.tables) {
199
+ outputSize += table.origLength;
200
+ outputSize += (4 - table.origLength % 4) % 4;
201
+ }
202
+ const output = new Uint8Array(outputSize);
203
+ const outView = new DataView(output.buffer);
204
+ const fontInfos = writeHeaders(header, output, outView);
205
+ const writtenTables = /* @__PURE__ */ new Map();
206
+ let nextTableOffset = computeOffsetToFirstTable(header);
207
+ if (header.ttcFonts.length > 0) {
208
+ for (let i = 0; i < header.ttcFonts.length; i++) {
209
+ nextTableOffset = reconstructFont(
210
+ decompressed,
211
+ header,
212
+ i,
213
+ fontInfos[i],
214
+ output,
215
+ outView,
216
+ writtenTables,
217
+ nextTableOffset
218
+ );
219
+ }
220
+ } else {
221
+ reconstructFont(
222
+ decompressed,
223
+ header,
224
+ 0,
225
+ fontInfos[0],
226
+ output,
227
+ outView,
228
+ writtenTables,
229
+ nextTableOffset
230
+ );
231
+ }
232
+ return output;
233
+ }
234
+ function readHeader(buf, totalLength) {
235
+ const signature = buf.readU32();
236
+ if (signature !== WOFF2_SIGNATURE) {
237
+ return null;
238
+ }
239
+ const flavor = buf.readU32();
240
+ if (flavor === null)
241
+ return null;
242
+ const length = buf.readU32();
243
+ if (length === null || length !== totalLength)
244
+ return null;
245
+ const numTables = buf.readU16();
246
+ if (numTables === null || numTables === 0)
247
+ return null;
248
+ if (!buf.skip(2))
249
+ return null;
250
+ if (!buf.skip(4))
251
+ return null;
252
+ const compressedLength = buf.readU32();
253
+ if (compressedLength === null)
254
+ return null;
255
+ if (!buf.skip(4))
256
+ return null;
257
+ const metaOffset = buf.readU32();
258
+ const metaLength = buf.readU32();
259
+ const metaOrigLength = buf.readU32();
260
+ if (metaOffset === null || metaLength === null || metaOrigLength === null)
261
+ return null;
262
+ if (metaOffset !== 0) {
263
+ if (metaOffset >= totalLength || totalLength - metaOffset < metaLength) {
264
+ return null;
265
+ }
266
+ }
267
+ const privOffset = buf.readU32();
268
+ const privLength = buf.readU32();
269
+ if (privOffset === null || privLength === null)
270
+ return null;
271
+ if (privOffset !== 0) {
272
+ if (privOffset >= totalLength || totalLength - privOffset < privLength) {
273
+ return null;
274
+ }
275
+ }
276
+ const tables = readTableDirectory(buf, numTables);
277
+ if (!tables)
278
+ return null;
279
+ const lastTable = tables[tables.length - 1];
280
+ const uncompressedSize = lastTable.srcOffset + lastTable.srcLength;
281
+ let headerVersion = 0;
282
+ const ttcFonts = [];
283
+ if (flavor === TTC_FLAVOR) {
284
+ headerVersion = buf.readU32() ?? 0;
285
+ if (headerVersion !== 65536 && headerVersion !== 131072) {
286
+ return null;
287
+ }
288
+ const numFonts = read255UShort(buf);
289
+ if (numFonts === null || numFonts === 0)
290
+ return null;
291
+ for (let i = 0; i < numFonts; i++) {
292
+ const fontNumTables = read255UShort(buf);
293
+ if (fontNumTables === null || fontNumTables === 0)
294
+ return null;
295
+ const fontFlavor = buf.readU32();
296
+ if (fontFlavor === null)
297
+ return null;
298
+ const tableIndices = [];
299
+ for (let j = 0; j < fontNumTables; j++) {
300
+ const idx = read255UShort(buf);
301
+ if (idx === null || idx >= tables.length)
302
+ return null;
303
+ tableIndices.push(idx);
304
+ }
305
+ ttcFonts.push({
306
+ flavor: fontFlavor,
307
+ dstOffset: 0,
308
+ headerChecksum: 0,
309
+ tableIndices
310
+ });
311
+ }
312
+ }
313
+ return {
314
+ flavor,
315
+ headerVersion,
316
+ numTables,
317
+ compressedOffset: buf.offset,
318
+ compressedLength,
319
+ uncompressedSize,
320
+ tables,
321
+ ttcFonts
322
+ };
323
+ }
324
+ function readTableDirectory(buf, numTables) {
325
+ const tables = [];
326
+ let srcOffset = 0;
327
+ for (let i = 0; i < numTables; i++) {
328
+ const flagByte = buf.readU8();
329
+ if (flagByte === null)
330
+ return null;
331
+ let tag;
332
+ if ((flagByte & 63) === 63) {
333
+ tag = buf.readU32() ?? 0;
334
+ if (tag === 0)
335
+ return null;
336
+ } else {
337
+ tag = KNOWN_TAGS[flagByte & 63];
338
+ }
339
+ const xformVersion = flagByte >> 6 & 3;
340
+ let flags = 0;
341
+ if (tag === TAG_GLYF || tag === TAG_LOCA) {
342
+ if (xformVersion === 0) {
343
+ flags |= WOFF2_FLAGS_TRANSFORM;
344
+ }
345
+ } else if (xformVersion !== 0) {
346
+ flags |= WOFF2_FLAGS_TRANSFORM;
347
+ }
348
+ flags |= xformVersion;
349
+ const origLength = readBase128(buf);
350
+ if (origLength === null)
351
+ return null;
352
+ let transformLength = origLength;
353
+ if ((flags & WOFF2_FLAGS_TRANSFORM) !== 0) {
354
+ transformLength = readBase128(buf) ?? 0;
355
+ if (transformLength === 0 && tag !== TAG_LOCA)
356
+ return null;
357
+ if (tag === TAG_LOCA && transformLength !== 0)
358
+ return null;
359
+ }
360
+ tables.push({
361
+ tag,
362
+ flags,
363
+ origLength,
364
+ transformLength,
365
+ srcOffset,
366
+ srcLength: transformLength,
367
+ dstOffset: 0,
368
+ dstLength: origLength,
369
+ key: `${tag}:${srcOffset}`
370
+ });
371
+ srcOffset += transformLength;
372
+ }
373
+ return tables;
374
+ }
375
+ function computeOffsetToFirstTable(header) {
376
+ if (header.ttcFonts.length === 0) {
377
+ return SFNT_HEADER_SIZE + SFNT_ENTRY_SIZE * header.numTables;
378
+ }
379
+ let offset = 12;
380
+ offset += 4 * header.ttcFonts.length;
381
+ if (header.headerVersion === 131072) {
382
+ offset += 12;
383
+ }
384
+ for (const ttcFont of header.ttcFonts) {
385
+ offset += SFNT_HEADER_SIZE;
386
+ offset += SFNT_ENTRY_SIZE * ttcFont.tableIndices.length;
387
+ }
388
+ return offset;
389
+ }
390
+ function writeHeaders(header, output, outView) {
391
+ const fontInfos = [];
392
+ let offset = 0;
393
+ if (header.ttcFonts.length > 0) {
394
+ outView.setUint32(offset, header.flavor);
395
+ offset += 4;
396
+ outView.setUint32(offset, header.headerVersion);
397
+ offset += 4;
398
+ outView.setUint32(offset, header.ttcFonts.length);
399
+ offset += 4;
400
+ const offsetTableStart = offset;
401
+ offset += 4 * header.ttcFonts.length;
402
+ if (header.headerVersion === 131072) {
403
+ offset += 12;
404
+ }
405
+ for (let i = 0; i < header.ttcFonts.length; i++) {
406
+ const ttcFont = header.ttcFonts[i];
407
+ outView.setUint32(offsetTableStart + i * 4, offset);
408
+ ttcFont.dstOffset = offset;
409
+ const numTables = ttcFont.tableIndices.length;
410
+ offset = writeOffsetTable(outView, offset, ttcFont.flavor, numTables);
411
+ const sortedIndices = [...ttcFont.tableIndices].sort(
412
+ (a, b) => header.tables[a].tag - header.tables[b].tag
413
+ );
414
+ const tableEntryByTag = /* @__PURE__ */ new Map();
415
+ for (const tableIdx of sortedIndices) {
416
+ const table = header.tables[tableIdx];
417
+ tableEntryByTag.set(table.tag, offset);
418
+ offset = writeTableEntry(outView, offset, table.tag);
419
+ }
420
+ ttcFont.tableIndices = sortedIndices;
421
+ ttcFont.headerChecksum = computeChecksum(
422
+ output,
423
+ ttcFont.dstOffset,
424
+ offset - ttcFont.dstOffset
425
+ );
426
+ fontInfos.push({
427
+ numGlyphs: 0,
428
+ indexFormat: 0,
429
+ numHMetrics: 0,
430
+ xMins: new Int16Array(0),
431
+ tableEntryByTag
432
+ });
433
+ }
434
+ } else {
435
+ offset = writeOffsetTable(outView, offset, header.flavor, header.numTables);
436
+ const sortedTables = [...header.tables].sort((a, b) => a.tag - b.tag);
437
+ const tableEntryByTag = /* @__PURE__ */ new Map();
438
+ for (const table of sortedTables) {
439
+ tableEntryByTag.set(table.tag, offset);
440
+ offset = writeTableEntry(outView, offset, table.tag);
441
+ }
442
+ fontInfos.push({
443
+ numGlyphs: 0,
444
+ indexFormat: 0,
445
+ numHMetrics: 0,
446
+ xMins: new Int16Array(0),
447
+ tableEntryByTag
448
+ });
449
+ }
450
+ return fontInfos;
451
+ }
452
+ function writeOffsetTable(view, offset, flavor, numTables) {
453
+ view.setUint32(offset, flavor);
454
+ view.setUint16(offset + 4, numTables);
455
+ let maxPow2 = 0;
456
+ while (1 << maxPow2 + 1 <= numTables) {
457
+ maxPow2++;
458
+ }
459
+ const searchRange = (1 << maxPow2) * 16;
460
+ view.setUint16(offset + 6, searchRange);
461
+ view.setUint16(offset + 8, maxPow2);
462
+ view.setUint16(offset + 10, numTables * 16 - searchRange);
463
+ return offset + SFNT_HEADER_SIZE;
464
+ }
465
+ function writeTableEntry(view, offset, tag) {
466
+ view.setUint32(offset, tag);
467
+ view.setUint32(offset + 4, 0);
468
+ view.setUint32(offset + 8, 0);
469
+ view.setUint32(offset + 12, 0);
470
+ return offset + SFNT_ENTRY_SIZE;
471
+ }
472
+ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outView, writtenTables, dstOffset) {
473
+ const tables = header.ttcFonts.length > 0 ? header.ttcFonts[fontIndex].tableIndices.map((i) => header.tables[i]) : header.tables;
474
+ const sortedTables = [...tables].sort((a, b) => a.tag - b.tag);
475
+ const glyfTable = sortedTables.find((t) => t.tag === TAG_GLYF);
476
+ const locaTable = sortedTables.find((t) => t.tag === TAG_LOCA);
477
+ const hheaTable = sortedTables.find((t) => t.tag === TAG_HHEA);
478
+ if (hheaTable) {
479
+ const hheaData = decompressed.subarray(
480
+ hheaTable.srcOffset,
481
+ hheaTable.srcOffset + hheaTable.srcLength
482
+ );
483
+ if (hheaData.byteLength >= 36) {
484
+ const hheaView = new DataView(hheaData.buffer, hheaData.byteOffset);
485
+ fontInfo.numHMetrics = hheaView.getUint16(34);
486
+ }
487
+ }
488
+ let fontChecksum = header.ttcFonts.length > 0 ? header.ttcFonts[fontIndex].headerChecksum : 0;
489
+ const isTTC = header.ttcFonts.length > 0;
490
+ for (const table of sortedTables) {
491
+ const entryOffset = fontInfo.tableEntryByTag.get(table.tag);
492
+ if (entryOffset === void 0)
493
+ continue;
494
+ const tKey = table.key;
495
+ const existing = writtenTables.get(tKey);
496
+ if (existing) {
497
+ updateTableEntry(outView, entryOffset, existing.checksum, existing.dstOffset, existing.dstLength);
498
+ if (isTTC) {
499
+ fontChecksum = fontChecksum + existing.checksum >>> 0;
500
+ fontChecksum = fontChecksum + computeTableEntryChecksum(existing.checksum, existing.dstOffset, existing.dstLength) >>> 0;
501
+ }
502
+ continue;
503
+ }
504
+ table.dstOffset = dstOffset;
505
+ let tableData;
506
+ let checksum;
507
+ if ((table.flags & WOFF2_FLAGS_TRANSFORM) !== 0) {
508
+ if (table.tag === TAG_GLYF && glyfTable && locaTable) {
509
+ const result = reconstructGlyf(
510
+ decompressed,
511
+ glyfTable,
512
+ locaTable,
513
+ fontInfo
514
+ );
515
+ tableData = result.glyfData;
516
+ glyfTable.dstLength = result.glyfData.byteLength;
517
+ locaTable.dstOffset = dstOffset + pad4(result.glyfData.byteLength);
518
+ locaTable.dstLength = result.locaData.byteLength;
519
+ output.set(tableData, dstOffset);
520
+ checksum = computeChecksum(output, dstOffset, tableData.byteLength);
521
+ updateTableEntry(outView, entryOffset, checksum, dstOffset, tableData.byteLength);
522
+ if (isTTC) {
523
+ fontChecksum = fontChecksum + checksum >>> 0;
524
+ fontChecksum = fontChecksum + computeTableEntryChecksum(checksum, dstOffset, tableData.byteLength) >>> 0;
525
+ }
526
+ writtenTables.set(tKey, {
527
+ dstOffset,
528
+ dstLength: tableData.byteLength,
529
+ checksum
530
+ });
531
+ dstOffset += pad4(tableData.byteLength);
532
+ const locaEntryOffset = fontInfo.tableEntryByTag.get(TAG_LOCA);
533
+ if (locaEntryOffset !== void 0) {
534
+ output.set(result.locaData, dstOffset);
535
+ const locaChecksum = computeChecksum(output, dstOffset, result.locaData.byteLength);
536
+ updateTableEntry(outView, locaEntryOffset, locaChecksum, dstOffset, result.locaData.byteLength);
537
+ if (isTTC) {
538
+ fontChecksum = fontChecksum + locaChecksum >>> 0;
539
+ fontChecksum = fontChecksum + computeTableEntryChecksum(locaChecksum, dstOffset, result.locaData.byteLength) >>> 0;
540
+ }
541
+ writtenTables.set(locaTable.key, {
542
+ dstOffset,
543
+ dstLength: result.locaData.byteLength,
544
+ checksum: locaChecksum
545
+ });
546
+ dstOffset += pad4(result.locaData.byteLength);
547
+ }
548
+ continue;
549
+ } else if (table.tag === TAG_LOCA) {
550
+ continue;
551
+ } else if (table.tag === TAG_HMTX) {
552
+ tableData = reconstructHmtx(
553
+ decompressed,
554
+ table,
555
+ fontInfo.numGlyphs,
556
+ fontInfo.numHMetrics,
557
+ fontInfo.xMins
558
+ );
559
+ } else {
560
+ throw new Error(`Unknown transform for table ${tagToString(table.tag)}`);
561
+ }
562
+ } else {
563
+ tableData = decompressed.subarray(
564
+ table.srcOffset,
565
+ table.srcOffset + table.srcLength
566
+ );
567
+ if (table.tag === TAG_HEAD && tableData.byteLength >= 12) {
568
+ tableData = new Uint8Array(tableData);
569
+ const headView = new DataView(tableData.buffer, tableData.byteOffset);
570
+ headView.setUint32(8, 0);
571
+ }
572
+ }
573
+ output.set(tableData, dstOffset);
574
+ checksum = computeChecksum(output, dstOffset, tableData.byteLength);
575
+ table.dstLength = tableData.byteLength;
576
+ updateTableEntry(outView, entryOffset, checksum, dstOffset, tableData.byteLength);
577
+ if (isTTC) {
578
+ fontChecksum = fontChecksum + checksum >>> 0;
579
+ fontChecksum = fontChecksum + computeTableEntryChecksum(checksum, dstOffset, tableData.byteLength) >>> 0;
580
+ }
581
+ writtenTables.set(tKey, {
582
+ dstOffset,
583
+ dstLength: tableData.byteLength,
584
+ checksum
585
+ });
586
+ dstOffset += pad4(tableData.byteLength);
587
+ }
588
+ const headTable = sortedTables.find((t) => t.tag === TAG_HEAD);
589
+ if (headTable) {
590
+ const headEntry = writtenTables.get(headTable.key);
591
+ if (headEntry && headEntry.dstLength >= 12) {
592
+ const finalChecksum = isTTC ? fontChecksum : computeChecksum(output, 0, dstOffset);
593
+ outView.setUint32(headEntry.dstOffset + 8, 2981146554 - finalChecksum >>> 0);
594
+ }
595
+ }
596
+ return dstOffset;
597
+ }
598
+ function computeTableEntryChecksum(checksum, offset, length) {
599
+ return checksum + offset + length >>> 0;
600
+ }
601
+ function makeByteStream(data, start, length) {
602
+ return { data, pos: start, end: start + length };
603
+ }
604
+ function bsReadU8(stream) {
605
+ if (stream.pos >= stream.end)
606
+ throw new Error("Stream overflow");
607
+ return stream.data[stream.pos++];
608
+ }
609
+ function bsReadU16(stream) {
610
+ if (stream.pos + 2 > stream.end)
611
+ throw new Error("Stream overflow");
612
+ const idx = stream.pos;
613
+ stream.pos = idx + 2;
614
+ return stream.data[idx] << 8 | stream.data[idx + 1];
615
+ }
616
+ function bsReadS16(stream) {
617
+ if (stream.pos + 2 > stream.end)
618
+ throw new Error("Stream overflow");
619
+ const idx = stream.pos;
620
+ stream.pos = idx + 2;
621
+ const val = stream.data[idx] << 8 | stream.data[idx + 1];
622
+ return (val & 32768) !== 0 ? val - 65536 : val;
623
+ }
624
+ function fsReadU32(stream) {
625
+ if (stream.pos + 4 > stream.end)
626
+ throw new Error("Stream overflow");
627
+ const idx = stream.pos;
628
+ stream.pos = idx + 4;
629
+ return stream.data[idx] * 16777216 + (stream.data[idx + 1] << 16 | stream.data[idx + 2] << 8 | stream.data[idx + 3]) >>> 0;
630
+ }
631
+ function bsSkip(stream, n) {
632
+ if (stream.pos + n > stream.end || n < 0)
633
+ throw new Error("Stream overflow");
634
+ stream.pos += n;
635
+ }
636
+ function fsReadBytes(stream, n) {
637
+ if (stream.pos + n > stream.end || n < 0)
638
+ throw new Error("Stream overflow");
639
+ const start = stream.pos;
640
+ stream.pos += n;
641
+ return stream.data.subarray(start, start + n);
642
+ }
643
+ function bsRead255UShort(stream) {
644
+ const code = bsReadU8(stream);
645
+ if (code === 253) {
646
+ return bsReadU16(stream);
647
+ } else if (code === 255) {
648
+ return 253 + bsReadU8(stream);
649
+ } else if (code === 254) {
650
+ return 253 * 2 + bsReadU8(stream);
651
+ }
652
+ return code;
653
+ }
654
+ function reconstructGlyf(data, glyfTable, _locaTable, fontInfo) {
655
+ const headerStream = makeByteStream(
656
+ data,
657
+ glyfTable.srcOffset,
658
+ glyfTable.transformLength
659
+ );
660
+ bsReadU16(headerStream);
661
+ const optionFlags = bsReadU16(headerStream);
662
+ const numGlyphs = bsReadU16(headerStream);
663
+ const indexFormat = bsReadU16(headerStream);
664
+ fontInfo.numGlyphs = numGlyphs;
665
+ fontInfo.indexFormat = indexFormat;
666
+ const nContourStreamSize = fsReadU32(headerStream);
667
+ const nPointsStreamSize = fsReadU32(headerStream);
668
+ const flagStreamSize = fsReadU32(headerStream);
669
+ const glyphStreamSize = fsReadU32(headerStream);
670
+ const compositeStreamSize = fsReadU32(headerStream);
671
+ const bboxStreamSize = fsReadU32(headerStream);
672
+ const instructionStreamSize = fsReadU32(headerStream);
673
+ let offset = headerStream.pos;
674
+ const nContourStream = makeByteStream(data, offset, nContourStreamSize);
675
+ offset += nContourStreamSize;
676
+ const nPointsStream = makeByteStream(data, offset, nPointsStreamSize);
677
+ offset += nPointsStreamSize;
678
+ const flagStream = makeByteStream(data, offset, flagStreamSize);
679
+ offset += flagStreamSize;
680
+ const glyphStream = makeByteStream(data, offset, glyphStreamSize);
681
+ offset += glyphStreamSize;
682
+ const compositeStream = makeByteStream(data, offset, compositeStreamSize);
683
+ offset += compositeStreamSize;
684
+ const bboxStream = makeByteStream(data, offset, bboxStreamSize);
685
+ offset += bboxStreamSize;
686
+ const instructionStream = makeByteStream(data, offset, instructionStreamSize);
687
+ const hasOverlapBitmap = (optionFlags & 1) !== 0;
688
+ let overlapBitmap = null;
689
+ if (hasOverlapBitmap) {
690
+ const overlapBitmapLength = numGlyphs + 7 >> 3;
691
+ overlapBitmap = data.subarray(
692
+ offset + instructionStreamSize,
693
+ offset + instructionStreamSize + overlapBitmapLength
694
+ );
695
+ }
696
+ const bboxBitmapLength = numGlyphs + 31 >> 5 << 2;
697
+ const bboxBitmap = fsReadBytes(bboxStream, bboxBitmapLength);
698
+ let glyfOutput = new Uint8Array(glyfTable.origLength * 2);
699
+ let glyfOffset = 0;
700
+ const locaValues = new Uint32Array(numGlyphs + 1);
701
+ fontInfo.xMins = new Int16Array(numGlyphs);
702
+ let contourEndsScratch = new Uint16Array(128);
703
+ let flagsScratch = new Uint8Array(512);
704
+ let xScratch = new Uint8Array(512);
705
+ let yScratch = new Uint8Array(512);
706
+ for (let glyphId = 0; glyphId < numGlyphs; glyphId++) {
707
+ locaValues[glyphId] = glyfOffset;
708
+ const nContours = bsReadS16(nContourStream);
709
+ const haveBbox = (bboxBitmap[glyphId >> 3] & 128 >> (glyphId & 7)) !== 0;
710
+ if (nContours === 0) {
711
+ if (haveBbox) {
712
+ throw new Error(`Empty glyph ${glyphId} has bbox`);
713
+ }
714
+ continue;
715
+ }
716
+ if (nContours === -1) {
717
+ if (!haveBbox) {
718
+ throw new Error(`Composite glyph ${glyphId} missing bbox`);
719
+ }
720
+ const { compositeData, haveInstructions } = readCompositeGlyph(compositeStream);
721
+ let instructionSize = 0;
722
+ if (haveInstructions) {
723
+ instructionSize = bsRead255UShort(glyphStream);
724
+ }
725
+ const glyphSize = 10 + compositeData.byteLength + (haveInstructions ? 2 + instructionSize : 0);
726
+ ensureCapacity(glyphSize);
727
+ writeInt16BE(glyfOutput, glyfOffset, -1);
728
+ const bbox = fsReadBytes(bboxStream, 8);
729
+ glyfOutput.set(bbox, glyfOffset + 2);
730
+ fontInfo.xMins[glyphId] = readInt16BE(bbox, 0);
731
+ glyfOutput.set(compositeData, glyfOffset + 10);
732
+ if (haveInstructions) {
733
+ const instrOffset = glyfOffset + 10 + compositeData.byteLength;
734
+ writeUint16BE(glyfOutput, instrOffset, instructionSize);
735
+ const instructions = fsReadBytes(instructionStream, instructionSize);
736
+ glyfOutput.set(instructions, instrOffset + 2);
737
+ }
738
+ glyfOffset += glyphSize;
739
+ glyfOffset = pad4(glyfOffset);
740
+ } else {
741
+ if (nContours > contourEndsScratch.length) {
742
+ contourEndsScratch = new Uint16Array(nContours * 2);
743
+ }
744
+ let totalPoints = 0;
745
+ let endPoint = -1;
746
+ for (let i = 0; i < nContours; i++) {
747
+ const n = bsRead255UShort(nPointsStream);
748
+ totalPoints += n;
749
+ endPoint += n;
750
+ contourEndsScratch[i] = endPoint;
751
+ }
752
+ const scratchSize = totalPoints * 2;
753
+ if (scratchSize > flagsScratch.length) {
754
+ flagsScratch = new Uint8Array(scratchSize);
755
+ }
756
+ if (scratchSize > xScratch.length) {
757
+ xScratch = new Uint8Array(scratchSize);
758
+ }
759
+ if (scratchSize > yScratch.length) {
760
+ yScratch = new Uint8Array(scratchSize);
761
+ }
762
+ const encoded = encodeTripletsToScratch(
763
+ flagStream,
764
+ glyphStream,
765
+ totalPoints,
766
+ ((overlapBitmap?.[glyphId >> 3] ?? 0) & 128 >> (glyphId & 7)) !== 0,
767
+ flagsScratch,
768
+ xScratch,
769
+ yScratch
770
+ );
771
+ const instructionSize = bsRead255UShort(glyphStream);
772
+ const glyphSize = 10 + 2 * nContours + 2 + instructionSize + encoded.flagsLen + encoded.xLen + encoded.yLen;
773
+ ensureCapacity(glyphSize);
774
+ writeInt16BE(glyfOutput, glyfOffset, nContours);
775
+ let xMin = 0;
776
+ if (haveBbox) {
777
+ const bbox = fsReadBytes(bboxStream, 8);
778
+ glyfOutput.set(bbox, glyfOffset + 2);
779
+ xMin = readInt16BE(bbox, 0);
780
+ } else {
781
+ writeInt16BE(glyfOutput, glyfOffset + 2, encoded.xMin);
782
+ writeInt16BE(glyfOutput, glyfOffset + 4, encoded.yMin);
783
+ writeInt16BE(glyfOutput, glyfOffset + 6, encoded.xMax);
784
+ writeInt16BE(glyfOutput, glyfOffset + 8, encoded.yMax);
785
+ xMin = encoded.xMin;
786
+ }
787
+ let writeOffset = glyfOffset + 10;
788
+ for (let i = 0; i < nContours; i++) {
789
+ writeUint16BE(glyfOutput, writeOffset, contourEndsScratch[i]);
790
+ writeOffset += 2;
791
+ }
792
+ writeUint16BE(glyfOutput, writeOffset, instructionSize);
793
+ writeOffset += 2;
794
+ if (instructionSize > 0) {
795
+ const instructions = fsReadBytes(instructionStream, instructionSize);
796
+ glyfOutput.set(instructions, writeOffset);
797
+ writeOffset += instructionSize;
798
+ }
799
+ glyfOutput.set(flagsScratch.subarray(0, encoded.flagsLen), writeOffset);
800
+ writeOffset += encoded.flagsLen;
801
+ glyfOutput.set(xScratch.subarray(0, encoded.xLen), writeOffset);
802
+ writeOffset += encoded.xLen;
803
+ glyfOutput.set(yScratch.subarray(0, encoded.yLen), writeOffset);
804
+ fontInfo.xMins[glyphId] = xMin;
805
+ glyfOffset += glyphSize;
806
+ glyfOffset = pad4(glyfOffset);
807
+ }
808
+ }
809
+ locaValues[numGlyphs] = glyfOffset;
810
+ const locaSize = indexFormat ? (numGlyphs + 1) * 4 : (numGlyphs + 1) * 2;
811
+ const locaData = new Uint8Array(locaSize);
812
+ const locaView = new DataView(locaData.buffer);
813
+ for (let i = 0; i <= numGlyphs; i++) {
814
+ if (indexFormat) {
815
+ locaView.setUint32(i * 4, locaValues[i]);
816
+ } else {
817
+ locaView.setUint16(i * 2, locaValues[i] >> 1);
818
+ }
819
+ }
820
+ return {
821
+ glyfData: glyfOutput.subarray(0, glyfOffset),
822
+ locaData
823
+ };
824
+ function ensureCapacity(needed) {
825
+ if (glyfOffset + needed > glyfOutput.byteLength) {
826
+ const newOutput = new Uint8Array((glyfOffset + needed) * 2);
827
+ newOutput.set(glyfOutput);
828
+ glyfOutput = newOutput;
829
+ }
830
+ }
831
+ }
832
+ function readCompositeGlyph(stream) {
833
+ const FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
834
+ const FLAG_WE_HAVE_A_SCALE = 1 << 3;
835
+ const FLAG_MORE_COMPONENTS = 1 << 5;
836
+ const FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
837
+ const FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
838
+ const FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
839
+ const startOffset = stream.pos;
840
+ let haveInstructions = false;
841
+ let flags = FLAG_MORE_COMPONENTS;
842
+ while (flags & FLAG_MORE_COMPONENTS) {
843
+ flags = bsReadU16(stream);
844
+ haveInstructions = haveInstructions || (flags & FLAG_WE_HAVE_INSTRUCTIONS) !== 0;
845
+ let argSize = 2;
846
+ if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
847
+ argSize += 4;
848
+ } else {
849
+ argSize += 2;
850
+ }
851
+ if (flags & FLAG_WE_HAVE_A_SCALE) {
852
+ argSize += 2;
853
+ } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
854
+ argSize += 4;
855
+ } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
856
+ argSize += 8;
857
+ }
858
+ bsSkip(stream, argSize);
859
+ }
860
+ const compositeData = stream.data.subarray(startOffset, stream.pos);
861
+ return { compositeData, haveInstructions };
862
+ }
863
+ function encodeTripletsToScratch(flagStream, glyphStream, nPoints, hasOverlapBit, flagsOut, xOut, yOut) {
864
+ if (nPoints === 0) {
865
+ return {
866
+ flagsLen: 0,
867
+ xLen: 0,
868
+ yLen: 0,
869
+ xMin: 0,
870
+ yMin: 0,
871
+ xMax: 0,
872
+ yMax: 0
873
+ };
874
+ }
875
+ let flagsLen = 0;
876
+ let xLen = 0;
877
+ let yLen = 0;
878
+ let x = 0;
879
+ let y = 0;
880
+ let xMin = 0;
881
+ let yMin = 0;
882
+ let xMax = 0;
883
+ let yMax = 0;
884
+ let lastFlag = -1;
885
+ let repeatCount = 0;
886
+ const flagData = flagStream.data;
887
+ let flagPos = flagStream.pos;
888
+ const flagEnd = flagStream.end;
889
+ const glyphData = glyphStream.data;
890
+ let glyphPos = glyphStream.pos;
891
+ const glyphEnd = glyphStream.end;
892
+ for (let i = 0; i < nPoints; i++) {
893
+ if (flagPos >= flagEnd)
894
+ throw new Error("Stream overflow");
895
+ const flag = flagData[flagPos++];
896
+ const onCurve = (flag & 128) === 0;
897
+ const flagLow = flag & 127;
898
+ let dx;
899
+ let dy;
900
+ if (flagLow < 10) {
901
+ dx = 0;
902
+ if (glyphPos >= glyphEnd)
903
+ throw new Error("Stream overflow");
904
+ const b = glyphData[glyphPos++];
905
+ dy = ((flagLow & 14) << 7) + b;
906
+ if ((flagLow & 1) === 0)
907
+ dy = -dy;
908
+ } else if (flagLow < 20) {
909
+ if (glyphPos >= glyphEnd)
910
+ throw new Error("Stream overflow");
911
+ const b = glyphData[glyphPos++];
912
+ dx = ((flagLow - 10 & 14) << 7) + b;
913
+ if ((flagLow & 1) === 0)
914
+ dx = -dx;
915
+ dy = 0;
916
+ } else if (flagLow < 84) {
917
+ if (glyphPos >= glyphEnd)
918
+ throw new Error("Stream overflow");
919
+ const b = glyphData[glyphPos++];
920
+ const b0 = flagLow - 20;
921
+ dx = 1 + (b0 & 48) + (b >> 4);
922
+ dy = 1 + ((b0 & 12) << 2) + (b & 15);
923
+ if ((flagLow & 1) === 0)
924
+ dx = -dx;
925
+ if ((flagLow & 2) === 0)
926
+ dy = -dy;
927
+ } else if (flagLow < 120) {
928
+ if (glyphPos + 1 >= glyphEnd)
929
+ throw new Error("Stream overflow");
930
+ const b0 = glyphData[glyphPos++];
931
+ const b1 = glyphData[glyphPos++];
932
+ const idx = flagLow - 84;
933
+ dx = 1 + ((idx / 12 | 0) << 8) + b0;
934
+ dy = 1 + (idx % 12 >> 2 << 8) + b1;
935
+ if ((flagLow & 1) === 0)
936
+ dx = -dx;
937
+ if ((flagLow & 2) === 0)
938
+ dy = -dy;
939
+ } else if (flagLow < 124) {
940
+ if (glyphPos + 2 >= glyphEnd)
941
+ throw new Error("Stream overflow");
942
+ const b0 = glyphData[glyphPos++];
943
+ const b1 = glyphData[glyphPos++];
944
+ const b2 = glyphData[glyphPos++];
945
+ dx = (b0 << 4) + (b1 >> 4);
946
+ dy = ((b1 & 15) << 8) + b2;
947
+ if ((flagLow & 1) === 0)
948
+ dx = -dx;
949
+ if ((flagLow & 2) === 0)
950
+ dy = -dy;
951
+ } else {
952
+ if (glyphPos + 3 >= glyphEnd)
953
+ throw new Error("Stream overflow");
954
+ const b0 = glyphData[glyphPos++];
955
+ const b1 = glyphData[glyphPos++];
956
+ const b2 = glyphData[glyphPos++];
957
+ const b3 = glyphData[glyphPos++];
958
+ dx = (b0 << 8) + b1;
959
+ dy = (b2 << 8) + b3;
960
+ if ((flagLow & 1) === 0)
961
+ dx = -dx;
962
+ if ((flagLow & 2) === 0)
963
+ dy = -dy;
964
+ }
965
+ x += dx;
966
+ y += dy;
967
+ if (i === 0) {
968
+ xMin = xMax = x;
969
+ yMin = yMax = y;
970
+ } else {
971
+ if (x < xMin)
972
+ xMin = x;
973
+ if (x > xMax)
974
+ xMax = x;
975
+ if (y < yMin)
976
+ yMin = y;
977
+ if (y > yMax)
978
+ yMax = y;
979
+ }
980
+ let outFlag = onCurve ? FLAG_ON_CURVE : 0;
981
+ if (hasOverlapBit && i === 0)
982
+ outFlag |= FLAG_OVERLAP_SIMPLE;
983
+ if (dx === 0) {
984
+ outFlag |= FLAG_X_SAME;
985
+ } else if (dx >= -255 && dx <= 255) {
986
+ outFlag |= FLAG_X_SHORT;
987
+ if (dx > 0)
988
+ outFlag |= FLAG_X_SAME;
989
+ xOut[xLen++] = dx > 0 ? dx : -dx;
990
+ } else {
991
+ xOut[xLen++] = dx >> 8 & 255;
992
+ xOut[xLen++] = dx & 255;
993
+ }
994
+ if (dy === 0) {
995
+ outFlag |= FLAG_Y_SAME;
996
+ } else if (dy >= -255 && dy <= 255) {
997
+ outFlag |= FLAG_Y_SHORT;
998
+ if (dy > 0)
999
+ outFlag |= FLAG_Y_SAME;
1000
+ yOut[yLen++] = dy > 0 ? dy : -dy;
1001
+ } else {
1002
+ yOut[yLen++] = dy >> 8 & 255;
1003
+ yOut[yLen++] = dy & 255;
1004
+ }
1005
+ if (outFlag === lastFlag && repeatCount < 255) {
1006
+ flagsOut[flagsLen - 1] |= FLAG_REPEAT;
1007
+ repeatCount++;
1008
+ } else {
1009
+ if (repeatCount > 0) {
1010
+ flagsOut[flagsLen++] = repeatCount;
1011
+ repeatCount = 0;
1012
+ }
1013
+ flagsOut[flagsLen++] = outFlag;
1014
+ lastFlag = outFlag;
1015
+ }
1016
+ }
1017
+ if (repeatCount > 0) {
1018
+ flagsOut[flagsLen++] = repeatCount;
1019
+ }
1020
+ flagStream.pos = flagPos;
1021
+ glyphStream.pos = glyphPos;
1022
+ return {
1023
+ flagsLen,
1024
+ xLen,
1025
+ yLen,
1026
+ xMin,
1027
+ yMin,
1028
+ xMax,
1029
+ yMax
1030
+ };
1031
+ }
1032
+ function reconstructHmtx(data, table, numGlyphs, numHMetrics, xMins) {
1033
+ const hmtxStream = makeByteStream(data, table.srcOffset, table.srcLength);
1034
+ const hmtxFlags = bsReadU8(hmtxStream);
1035
+ const hasProportionalLsbs = (hmtxFlags & 1) === 0;
1036
+ const hasMonospaceLsbs = (hmtxFlags & 2) === 0;
1037
+ const advanceWidths = new Uint16Array(numHMetrics);
1038
+ for (let i = 0; i < numHMetrics; i++) {
1039
+ advanceWidths[i] = bsReadU16(hmtxStream);
1040
+ }
1041
+ const lsbs = new Int16Array(numGlyphs);
1042
+ for (let i = 0; i < numHMetrics; i++) {
1043
+ if (hasProportionalLsbs) {
1044
+ lsbs[i] = bsReadS16(hmtxStream);
1045
+ } else {
1046
+ lsbs[i] = xMins[i];
1047
+ }
1048
+ }
1049
+ for (let i = numHMetrics; i < numGlyphs; i++) {
1050
+ if (hasMonospaceLsbs) {
1051
+ lsbs[i] = bsReadS16(hmtxStream);
1052
+ } else {
1053
+ lsbs[i] = xMins[i];
1054
+ }
1055
+ }
1056
+ const outputSize = numHMetrics * 4 + (numGlyphs - numHMetrics) * 2;
1057
+ const output = new Uint8Array(outputSize);
1058
+ let offset = 0;
1059
+ for (let i = 0; i < numGlyphs; i++) {
1060
+ if (i < numHMetrics) {
1061
+ writeUint16BE(output, offset, advanceWidths[i]);
1062
+ offset += 2;
1063
+ }
1064
+ writeInt16BE(output, offset, lsbs[i]);
1065
+ offset += 2;
1066
+ }
1067
+ return output;
1068
+ }
1069
+ function updateTableEntry(view, entryOffset, checksum, offset, length) {
1070
+ view.setUint32(entryOffset + 4, checksum);
1071
+ view.setUint32(entryOffset + 8, offset);
1072
+ view.setUint32(entryOffset + 12, length);
1073
+ }
1074
+ function readInt16BE(data, offset) {
1075
+ const val = data[offset] << 8 | data[offset + 1];
1076
+ return (val & 32768) !== 0 ? val - 65536 : val;
1077
+ }
1078
+ function writeInt16BE(data, offset, value) {
1079
+ data[offset] = value >> 8 & 255;
1080
+ data[offset + 1] = value & 255;
1081
+ }
1082
+ function writeUint16BE(data, offset, value) {
1083
+ data[offset] = value >> 8 & 255;
1084
+ data[offset + 1] = value & 255;
1085
+ }
1086
+
1087
+ export { woff2Decode };