woff2-decode 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/dist/buffer.d.ts +1 -0
- package/dist/buffer.d.ts.map +1 -1
- package/dist/decode.d.ts.map +1 -1
- package/dist/index.cjs +306 -288
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +303 -285
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import brotliDecompress from "brotli/decompress";
|
|
1
|
+
import brotliDecompress from "brotli/decompress.js";
|
|
2
2
|
|
|
3
3
|
//#region \0rolldown/runtime.js
|
|
4
4
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) {
|
|
@@ -38,9 +38,11 @@ var Buffer$1 = class {
|
|
|
38
38
|
this.pos = 0;
|
|
39
39
|
if (data instanceof Uint8Array) {
|
|
40
40
|
const len = length ?? data.byteLength - offset;
|
|
41
|
+
this.u8 = data.subarray(offset, offset + len);
|
|
41
42
|
this.view = new DataView(data.buffer, data.byteOffset + offset, len);
|
|
42
43
|
} else {
|
|
43
44
|
const len = length ?? data.byteLength - offset;
|
|
45
|
+
this.u8 = new Uint8Array(data, offset, len);
|
|
44
46
|
this.view = new DataView(data, offset, len);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
@@ -48,66 +50,67 @@ var Buffer$1 = class {
|
|
|
48
50
|
return this.pos;
|
|
49
51
|
}
|
|
50
52
|
get length() {
|
|
51
|
-
return this.
|
|
53
|
+
return this.u8.byteLength;
|
|
52
54
|
}
|
|
53
55
|
get remaining() {
|
|
54
|
-
return this.
|
|
56
|
+
return this.u8.byteLength - this.pos;
|
|
55
57
|
}
|
|
56
58
|
get buffer() {
|
|
57
59
|
return this.view;
|
|
58
60
|
}
|
|
59
61
|
skip(n) {
|
|
60
|
-
if (this.pos + n > this.
|
|
62
|
+
if (this.pos + n > this.u8.byteLength || this.pos + n < this.pos) return false;
|
|
61
63
|
this.pos += n;
|
|
62
64
|
return true;
|
|
63
65
|
}
|
|
64
66
|
seek(offset) {
|
|
65
|
-
if (offset > this.
|
|
67
|
+
if (offset > this.u8.byteLength || offset < 0) return false;
|
|
66
68
|
this.pos = offset;
|
|
67
69
|
return true;
|
|
68
70
|
}
|
|
69
71
|
readU8() {
|
|
70
|
-
if (this.pos + 1 > this.
|
|
71
|
-
return this.
|
|
72
|
+
if (this.pos + 1 > this.u8.byteLength) return null;
|
|
73
|
+
return this.u8[this.pos++];
|
|
72
74
|
}
|
|
73
75
|
readU16() {
|
|
74
|
-
if (this.pos + 2 > this.
|
|
75
|
-
const
|
|
76
|
-
this.pos
|
|
77
|
-
return
|
|
76
|
+
if (this.pos + 2 > this.u8.byteLength) return null;
|
|
77
|
+
const idx = this.pos;
|
|
78
|
+
this.pos = idx + 2;
|
|
79
|
+
return this.u8[idx] << 8 | this.u8[idx + 1];
|
|
78
80
|
}
|
|
79
81
|
readS16() {
|
|
80
|
-
if (this.pos + 2 > this.
|
|
81
|
-
const
|
|
82
|
-
this.pos
|
|
83
|
-
|
|
82
|
+
if (this.pos + 2 > this.u8.byteLength) return null;
|
|
83
|
+
const idx = this.pos;
|
|
84
|
+
this.pos = idx + 2;
|
|
85
|
+
const val = this.u8[idx] << 8 | this.u8[idx + 1];
|
|
86
|
+
return (val & 32768) !== 0 ? val - 65536 : val;
|
|
84
87
|
}
|
|
85
88
|
readU32() {
|
|
86
|
-
if (this.pos + 4 > this.
|
|
87
|
-
const
|
|
88
|
-
this.pos
|
|
89
|
-
return
|
|
89
|
+
if (this.pos + 4 > this.u8.byteLength) return null;
|
|
90
|
+
const idx = this.pos;
|
|
91
|
+
this.pos = idx + 4;
|
|
92
|
+
return this.u8[idx] * 16777216 + (this.u8[idx + 1] << 16 | this.u8[idx + 2] << 8 | this.u8[idx + 3]) >>> 0;
|
|
90
93
|
}
|
|
91
94
|
readS32() {
|
|
92
|
-
if (this.pos + 4 > this.
|
|
93
|
-
const
|
|
94
|
-
this.pos
|
|
95
|
-
return
|
|
95
|
+
if (this.pos + 4 > this.u8.byteLength) return null;
|
|
96
|
+
const idx = this.pos;
|
|
97
|
+
this.pos = idx + 4;
|
|
98
|
+
return this.u8[idx] << 24 | this.u8[idx + 1] << 16 | this.u8[idx + 2] << 8 | this.u8[idx + 3];
|
|
96
99
|
}
|
|
97
100
|
readBytes(n) {
|
|
98
|
-
if (this.pos + n > this.
|
|
99
|
-
const result =
|
|
101
|
+
if (this.pos + n > this.u8.byteLength || n < 0) return null;
|
|
102
|
+
const result = this.u8.subarray(this.pos, this.pos + n);
|
|
100
103
|
this.pos += n;
|
|
101
104
|
return result;
|
|
102
105
|
}
|
|
103
106
|
peekU8(offset = 0) {
|
|
104
107
|
const idx = this.pos + offset;
|
|
105
|
-
if (idx >= this.
|
|
106
|
-
return this.
|
|
108
|
+
if (idx >= this.u8.byteLength || idx < 0) return null;
|
|
109
|
+
return this.u8[idx];
|
|
107
110
|
}
|
|
108
111
|
subarray(offset, length) {
|
|
109
|
-
if (offset + length > this.
|
|
110
|
-
return
|
|
112
|
+
if (offset + length > this.u8.byteLength || offset < 0 || length < 0) return null;
|
|
113
|
+
return this.u8.subarray(offset, offset + length);
|
|
111
114
|
}
|
|
112
115
|
};
|
|
113
116
|
|
|
@@ -223,6 +226,13 @@ function readBase128(buf) {
|
|
|
223
226
|
//#region src/decode.ts
|
|
224
227
|
const SFNT_HEADER_SIZE = 12;
|
|
225
228
|
const SFNT_ENTRY_SIZE = 16;
|
|
229
|
+
const FLAG_ON_CURVE = 1;
|
|
230
|
+
const FLAG_X_SHORT = 2;
|
|
231
|
+
const FLAG_Y_SHORT = 4;
|
|
232
|
+
const FLAG_REPEAT = 8;
|
|
233
|
+
const FLAG_X_SAME = 16;
|
|
234
|
+
const FLAG_Y_SAME = 32;
|
|
235
|
+
const FLAG_OVERLAP_SIMPLE = 64;
|
|
226
236
|
function decode(data, options) {
|
|
227
237
|
const input = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
228
238
|
const header = readHeader(new Buffer$1(input), input.byteLength);
|
|
@@ -344,7 +354,8 @@ function readTableDirectory(buf, numTables) {
|
|
|
344
354
|
srcOffset,
|
|
345
355
|
srcLength: transformLength,
|
|
346
356
|
dstOffset: 0,
|
|
347
|
-
dstLength: origLength
|
|
357
|
+
dstLength: origLength,
|
|
358
|
+
key: `${tag}:${srcOffset}`
|
|
348
359
|
});
|
|
349
360
|
srcOffset += transformLength;
|
|
350
361
|
}
|
|
@@ -447,8 +458,8 @@ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outV
|
|
|
447
458
|
for (const table of sortedTables) {
|
|
448
459
|
const entryOffset = fontInfo.tableEntryByTag.get(table.tag);
|
|
449
460
|
if (entryOffset === void 0) continue;
|
|
450
|
-
const
|
|
451
|
-
const existing = writtenTables.get(
|
|
461
|
+
const tKey = table.key;
|
|
462
|
+
const existing = writtenTables.get(tKey);
|
|
452
463
|
if (existing) {
|
|
453
464
|
updateTableEntry(outView, entryOffset, existing.checksum, existing.dstOffset, existing.dstLength);
|
|
454
465
|
if (isTTC) {
|
|
@@ -473,7 +484,7 @@ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outV
|
|
|
473
484
|
fontChecksum = fontChecksum + checksum >>> 0;
|
|
474
485
|
fontChecksum = fontChecksum + computeTableEntryChecksum(checksum, dstOffset, tableData.byteLength) >>> 0;
|
|
475
486
|
}
|
|
476
|
-
writtenTables.set(
|
|
487
|
+
writtenTables.set(tKey, {
|
|
477
488
|
dstOffset,
|
|
478
489
|
dstLength: tableData.byteLength,
|
|
479
490
|
checksum
|
|
@@ -488,8 +499,7 @@ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outV
|
|
|
488
499
|
fontChecksum = fontChecksum + locaChecksum >>> 0;
|
|
489
500
|
fontChecksum = fontChecksum + computeTableEntryChecksum(locaChecksum, dstOffset, result.locaData.byteLength) >>> 0;
|
|
490
501
|
}
|
|
491
|
-
|
|
492
|
-
writtenTables.set(locaKey, {
|
|
502
|
+
writtenTables.set(locaTable.key, {
|
|
493
503
|
dstOffset,
|
|
494
504
|
dstLength: result.locaData.byteLength,
|
|
495
505
|
checksum: locaChecksum
|
|
@@ -515,7 +525,7 @@ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outV
|
|
|
515
525
|
fontChecksum = fontChecksum + checksum >>> 0;
|
|
516
526
|
fontChecksum = fontChecksum + computeTableEntryChecksum(checksum, dstOffset, tableData.byteLength) >>> 0;
|
|
517
527
|
}
|
|
518
|
-
writtenTables.set(
|
|
528
|
+
writtenTables.set(tKey, {
|
|
519
529
|
dstOffset,
|
|
520
530
|
dstLength: tableData.byteLength,
|
|
521
531
|
checksum
|
|
@@ -524,7 +534,7 @@ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outV
|
|
|
524
534
|
}
|
|
525
535
|
const headTable = sortedTables.find((t) => t.tag === TAG_HEAD);
|
|
526
536
|
if (headTable) {
|
|
527
|
-
const headEntry = writtenTables.get(
|
|
537
|
+
const headEntry = writtenTables.get(headTable.key);
|
|
528
538
|
if (headEntry && headEntry.dstLength >= 12) {
|
|
529
539
|
const finalChecksum = isTTC ? fontChecksum : computeChecksum(output, 0, dstOffset);
|
|
530
540
|
outView.setUint32(headEntry.dstOffset + 8, 2981146554 - finalChecksum >>> 0);
|
|
@@ -535,54 +545,100 @@ function reconstructFont(decompressed, header, fontIndex, fontInfo, output, outV
|
|
|
535
545
|
function computeTableEntryChecksum(checksum, offset, length) {
|
|
536
546
|
return checksum + offset + length >>> 0;
|
|
537
547
|
}
|
|
548
|
+
function makeByteStream(data, start, length) {
|
|
549
|
+
return {
|
|
550
|
+
data,
|
|
551
|
+
pos: start,
|
|
552
|
+
end: start + length
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function bsReadU8(stream) {
|
|
556
|
+
if (stream.pos >= stream.end) throw new Error("Stream overflow");
|
|
557
|
+
return stream.data[stream.pos++];
|
|
558
|
+
}
|
|
559
|
+
function bsReadU16(stream) {
|
|
560
|
+
if (stream.pos + 2 > stream.end) throw new Error("Stream overflow");
|
|
561
|
+
const idx = stream.pos;
|
|
562
|
+
stream.pos = idx + 2;
|
|
563
|
+
return stream.data[idx] << 8 | stream.data[idx + 1];
|
|
564
|
+
}
|
|
565
|
+
function bsReadS16(stream) {
|
|
566
|
+
if (stream.pos + 2 > stream.end) throw new Error("Stream overflow");
|
|
567
|
+
const idx = stream.pos;
|
|
568
|
+
stream.pos = idx + 2;
|
|
569
|
+
const val = stream.data[idx] << 8 | stream.data[idx + 1];
|
|
570
|
+
return (val & 32768) !== 0 ? val - 65536 : val;
|
|
571
|
+
}
|
|
572
|
+
function fsReadU32(stream) {
|
|
573
|
+
if (stream.pos + 4 > stream.end) throw new Error("Stream overflow");
|
|
574
|
+
const idx = stream.pos;
|
|
575
|
+
stream.pos = idx + 4;
|
|
576
|
+
return stream.data[idx] * 16777216 + (stream.data[idx + 1] << 16 | stream.data[idx + 2] << 8 | stream.data[idx + 3]) >>> 0;
|
|
577
|
+
}
|
|
578
|
+
function bsSkip(stream, n) {
|
|
579
|
+
if (stream.pos + n > stream.end || n < 0) throw new Error("Stream overflow");
|
|
580
|
+
stream.pos += n;
|
|
581
|
+
}
|
|
582
|
+
function fsReadBytes(stream, n) {
|
|
583
|
+
if (stream.pos + n > stream.end || n < 0) throw new Error("Stream overflow");
|
|
584
|
+
const start = stream.pos;
|
|
585
|
+
stream.pos += n;
|
|
586
|
+
return stream.data.subarray(start, start + n);
|
|
587
|
+
}
|
|
588
|
+
function bsRead255UShort(stream) {
|
|
589
|
+
const code = bsReadU8(stream);
|
|
590
|
+
if (code === 253) return bsReadU16(stream);
|
|
591
|
+
else if (code === 255) return 253 + bsReadU8(stream);
|
|
592
|
+
else if (code === 254) return 506 + bsReadU8(stream);
|
|
593
|
+
return code;
|
|
594
|
+
}
|
|
538
595
|
function reconstructGlyf(data, glyfTable, locaTable, fontInfo) {
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
const optionFlags =
|
|
542
|
-
const numGlyphs =
|
|
543
|
-
const indexFormat =
|
|
544
|
-
if (version === null || optionFlags === null || numGlyphs === null || indexFormat === null) throw new Error("Invalid glyf transform header");
|
|
596
|
+
const headerStream = makeByteStream(data, glyfTable.srcOffset, glyfTable.transformLength);
|
|
597
|
+
bsReadU16(headerStream);
|
|
598
|
+
const optionFlags = bsReadU16(headerStream);
|
|
599
|
+
const numGlyphs = bsReadU16(headerStream);
|
|
600
|
+
const indexFormat = bsReadU16(headerStream);
|
|
545
601
|
fontInfo.numGlyphs = numGlyphs;
|
|
546
602
|
fontInfo.indexFormat = indexFormat;
|
|
547
|
-
const nContourStreamSize =
|
|
548
|
-
const nPointsStreamSize =
|
|
549
|
-
const flagStreamSize =
|
|
550
|
-
const glyphStreamSize =
|
|
551
|
-
const compositeStreamSize =
|
|
552
|
-
const bboxStreamSize =
|
|
553
|
-
const instructionStreamSize =
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const nContourStream = new Buffer$1(data, glyfTable.srcOffset + offset, nContourStreamSize);
|
|
603
|
+
const nContourStreamSize = fsReadU32(headerStream);
|
|
604
|
+
const nPointsStreamSize = fsReadU32(headerStream);
|
|
605
|
+
const flagStreamSize = fsReadU32(headerStream);
|
|
606
|
+
const glyphStreamSize = fsReadU32(headerStream);
|
|
607
|
+
const compositeStreamSize = fsReadU32(headerStream);
|
|
608
|
+
const bboxStreamSize = fsReadU32(headerStream);
|
|
609
|
+
const instructionStreamSize = fsReadU32(headerStream);
|
|
610
|
+
let offset = headerStream.pos;
|
|
611
|
+
const nContourStream = makeByteStream(data, offset, nContourStreamSize);
|
|
557
612
|
offset += nContourStreamSize;
|
|
558
|
-
const nPointsStream =
|
|
613
|
+
const nPointsStream = makeByteStream(data, offset, nPointsStreamSize);
|
|
559
614
|
offset += nPointsStreamSize;
|
|
560
|
-
const flagStream =
|
|
615
|
+
const flagStream = makeByteStream(data, offset, flagStreamSize);
|
|
561
616
|
offset += flagStreamSize;
|
|
562
|
-
const glyphStream =
|
|
617
|
+
const glyphStream = makeByteStream(data, offset, glyphStreamSize);
|
|
563
618
|
offset += glyphStreamSize;
|
|
564
|
-
const compositeStream =
|
|
619
|
+
const compositeStream = makeByteStream(data, offset, compositeStreamSize);
|
|
565
620
|
offset += compositeStreamSize;
|
|
566
|
-
const bboxStream =
|
|
621
|
+
const bboxStream = makeByteStream(data, offset, bboxStreamSize);
|
|
567
622
|
offset += bboxStreamSize;
|
|
568
|
-
const instructionStream =
|
|
623
|
+
const instructionStream = makeByteStream(data, offset, instructionStreamSize);
|
|
569
624
|
const hasOverlapBitmap = (optionFlags & 1) !== 0;
|
|
570
625
|
let overlapBitmap = null;
|
|
571
626
|
if (hasOverlapBitmap) {
|
|
572
627
|
const overlapBitmapLength = numGlyphs + 7 >> 3;
|
|
573
|
-
overlapBitmap = data.subarray(
|
|
628
|
+
overlapBitmap = data.subarray(offset + instructionStreamSize, offset + instructionStreamSize + overlapBitmapLength);
|
|
574
629
|
}
|
|
575
|
-
const
|
|
576
|
-
const bboxBitmap = bboxStream.readBytes(bboxBitmapLength);
|
|
577
|
-
if (!bboxBitmap) throw new Error("Failed to read bbox bitmap");
|
|
630
|
+
const bboxBitmap = fsReadBytes(bboxStream, numGlyphs + 31 >> 5 << 2);
|
|
578
631
|
let glyfOutput = new Uint8Array(glyfTable.origLength * 2);
|
|
579
632
|
let glyfOffset = 0;
|
|
580
|
-
const locaValues =
|
|
633
|
+
const locaValues = new Uint32Array(numGlyphs + 1);
|
|
581
634
|
fontInfo.xMins = new Int16Array(numGlyphs);
|
|
635
|
+
let contourEndsScratch = new Uint16Array(128);
|
|
636
|
+
let flagsScratch = new Uint8Array(512);
|
|
637
|
+
let xScratch = new Uint8Array(512);
|
|
638
|
+
let yScratch = new Uint8Array(512);
|
|
582
639
|
for (let glyphId = 0; glyphId < numGlyphs; glyphId++) {
|
|
583
|
-
locaValues
|
|
584
|
-
const nContours = nContourStream
|
|
585
|
-
if (nContours === null) throw new Error(`Failed to read nContours for glyph ${glyphId}`);
|
|
640
|
+
locaValues[glyphId] = glyfOffset;
|
|
641
|
+
const nContours = bsReadS16(nContourStream);
|
|
586
642
|
const haveBbox = (bboxBitmap[glyphId >> 3] & 128 >> (glyphId & 7)) !== 0;
|
|
587
643
|
if (nContours === 0) {
|
|
588
644
|
if (haveBbox) throw new Error(`Empty glyph ${glyphId} has bbox`);
|
|
@@ -592,34 +648,76 @@ function reconstructGlyf(data, glyfTable, locaTable, fontInfo) {
|
|
|
592
648
|
if (!haveBbox) throw new Error(`Composite glyph ${glyphId} missing bbox`);
|
|
593
649
|
const { compositeData, haveInstructions } = readCompositeGlyph(compositeStream);
|
|
594
650
|
let instructionSize = 0;
|
|
595
|
-
if (haveInstructions) instructionSize =
|
|
651
|
+
if (haveInstructions) instructionSize = bsRead255UShort(glyphStream);
|
|
596
652
|
const glyphSize = 10 + compositeData.byteLength + (haveInstructions ? 2 + instructionSize : 0);
|
|
597
653
|
ensureCapacity(glyphSize);
|
|
598
|
-
|
|
599
|
-
const bbox = bboxStream
|
|
600
|
-
if (!bbox) throw new Error("Failed to read bbox");
|
|
654
|
+
writeInt16BE(glyfOutput, glyfOffset, -1);
|
|
655
|
+
const bbox = fsReadBytes(bboxStream, 8);
|
|
601
656
|
glyfOutput.set(bbox, glyfOffset + 2);
|
|
602
|
-
fontInfo.xMins[glyphId] =
|
|
657
|
+
fontInfo.xMins[glyphId] = readInt16BE(bbox, 0);
|
|
603
658
|
glyfOutput.set(compositeData, glyfOffset + 10);
|
|
604
659
|
if (haveInstructions) {
|
|
605
660
|
const instrOffset = glyfOffset + 10 + compositeData.byteLength;
|
|
606
|
-
|
|
607
|
-
const instructions = instructionStream
|
|
608
|
-
if (!instructions) throw new Error("Failed to read instructions");
|
|
661
|
+
writeUint16BE(glyfOutput, instrOffset, instructionSize);
|
|
662
|
+
const instructions = fsReadBytes(instructionStream, instructionSize);
|
|
609
663
|
glyfOutput.set(instructions, instrOffset + 2);
|
|
610
664
|
}
|
|
611
665
|
glyfOffset += glyphSize;
|
|
612
666
|
glyfOffset = pad4(glyfOffset);
|
|
613
667
|
} else {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
668
|
+
if (nContours > contourEndsScratch.length) contourEndsScratch = new Uint16Array(nContours * 2);
|
|
669
|
+
let totalPoints = 0;
|
|
670
|
+
let endPoint = -1;
|
|
671
|
+
for (let i = 0; i < nContours; i++) {
|
|
672
|
+
const n = bsRead255UShort(nPointsStream);
|
|
673
|
+
totalPoints += n;
|
|
674
|
+
endPoint += n;
|
|
675
|
+
contourEndsScratch[i] = endPoint;
|
|
676
|
+
}
|
|
677
|
+
const scratchSize = totalPoints * 2;
|
|
678
|
+
if (scratchSize > flagsScratch.length) flagsScratch = new Uint8Array(scratchSize);
|
|
679
|
+
if (scratchSize > xScratch.length) xScratch = new Uint8Array(scratchSize);
|
|
680
|
+
if (scratchSize > yScratch.length) yScratch = new Uint8Array(scratchSize);
|
|
681
|
+
const encoded = encodeTripletsToScratch(flagStream, glyphStream, totalPoints, ((overlapBitmap?.[glyphId >> 3] ?? 0) & 128 >> (glyphId & 7)) !== 0, flagsScratch, xScratch, yScratch);
|
|
682
|
+
const instructionSize = bsRead255UShort(glyphStream);
|
|
683
|
+
const glyphSize = 10 + 2 * nContours + 2 + instructionSize + encoded.flagsLen + encoded.xLen + encoded.yLen;
|
|
684
|
+
ensureCapacity(glyphSize);
|
|
685
|
+
writeInt16BE(glyfOutput, glyfOffset, nContours);
|
|
686
|
+
let xMin = 0;
|
|
687
|
+
if (haveBbox) {
|
|
688
|
+
const bbox = fsReadBytes(bboxStream, 8);
|
|
689
|
+
glyfOutput.set(bbox, glyfOffset + 2);
|
|
690
|
+
xMin = readInt16BE(bbox, 0);
|
|
691
|
+
} else {
|
|
692
|
+
writeInt16BE(glyfOutput, glyfOffset + 2, encoded.xMin);
|
|
693
|
+
writeInt16BE(glyfOutput, glyfOffset + 4, encoded.yMin);
|
|
694
|
+
writeInt16BE(glyfOutput, glyfOffset + 6, encoded.xMax);
|
|
695
|
+
writeInt16BE(glyfOutput, glyfOffset + 8, encoded.yMax);
|
|
696
|
+
xMin = encoded.xMin;
|
|
697
|
+
}
|
|
698
|
+
let writeOffset = glyfOffset + 10;
|
|
699
|
+
for (let i = 0; i < nContours; i++) {
|
|
700
|
+
writeUint16BE(glyfOutput, writeOffset, contourEndsScratch[i]);
|
|
701
|
+
writeOffset += 2;
|
|
702
|
+
}
|
|
703
|
+
writeUint16BE(glyfOutput, writeOffset, instructionSize);
|
|
704
|
+
writeOffset += 2;
|
|
705
|
+
if (instructionSize > 0) {
|
|
706
|
+
const instructions = fsReadBytes(instructionStream, instructionSize);
|
|
707
|
+
glyfOutput.set(instructions, writeOffset);
|
|
708
|
+
writeOffset += instructionSize;
|
|
709
|
+
}
|
|
710
|
+
glyfOutput.set(flagsScratch.subarray(0, encoded.flagsLen), writeOffset);
|
|
711
|
+
writeOffset += encoded.flagsLen;
|
|
712
|
+
glyfOutput.set(xScratch.subarray(0, encoded.xLen), writeOffset);
|
|
713
|
+
writeOffset += encoded.xLen;
|
|
714
|
+
glyfOutput.set(yScratch.subarray(0, encoded.yLen), writeOffset);
|
|
715
|
+
fontInfo.xMins[glyphId] = xMin;
|
|
716
|
+
glyfOffset += glyphSize;
|
|
619
717
|
glyfOffset = pad4(glyfOffset);
|
|
620
718
|
}
|
|
621
719
|
}
|
|
622
|
-
locaValues
|
|
720
|
+
locaValues[numGlyphs] = glyfOffset;
|
|
623
721
|
const locaSize = indexFormat ? (numGlyphs + 1) * 4 : (numGlyphs + 1) * 2;
|
|
624
722
|
const locaData = new Uint8Array(locaSize);
|
|
625
723
|
const locaView = new DataView(locaData.buffer);
|
|
@@ -644,11 +742,11 @@ function readCompositeGlyph(stream) {
|
|
|
644
742
|
const FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 64;
|
|
645
743
|
const FLAG_WE_HAVE_A_TWO_BY_TWO = 128;
|
|
646
744
|
const FLAG_WE_HAVE_INSTRUCTIONS = 256;
|
|
647
|
-
const startOffset = stream.
|
|
745
|
+
const startOffset = stream.pos;
|
|
648
746
|
let haveInstructions = false;
|
|
649
747
|
let flags = FLAG_MORE_COMPONENTS;
|
|
650
748
|
while (flags & FLAG_MORE_COMPONENTS) {
|
|
651
|
-
flags = stream
|
|
749
|
+
flags = bsReadU16(stream);
|
|
652
750
|
haveInstructions = haveInstructions || (flags & FLAG_WE_HAVE_INSTRUCTIONS) !== 0;
|
|
653
751
|
let argSize = 2;
|
|
654
752
|
if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) argSize += 4;
|
|
@@ -656,126 +754,91 @@ function readCompositeGlyph(stream) {
|
|
|
656
754
|
if (flags & FLAG_WE_HAVE_A_SCALE) argSize += 2;
|
|
657
755
|
else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) argSize += 4;
|
|
658
756
|
else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) argSize += 8;
|
|
659
|
-
stream
|
|
757
|
+
bsSkip(stream, argSize);
|
|
660
758
|
}
|
|
661
|
-
const compositeData = stream.subarray(startOffset, stream.offset - startOffset);
|
|
662
|
-
if (!compositeData) throw new Error("Failed to read composite glyph data");
|
|
663
759
|
return {
|
|
664
|
-
compositeData,
|
|
760
|
+
compositeData: stream.data.subarray(startOffset, stream.pos),
|
|
665
761
|
haveInstructions
|
|
666
762
|
};
|
|
667
763
|
}
|
|
668
|
-
function
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
const output = new Uint8Array(glyphSize);
|
|
682
|
-
const view = new DataView(output.buffer);
|
|
683
|
-
let offset = 0;
|
|
684
|
-
view.setInt16(offset, nContours);
|
|
685
|
-
offset += 2;
|
|
686
|
-
if (haveBbox) {
|
|
687
|
-
const bbox = bboxStream.readBytes(8);
|
|
688
|
-
if (!bbox) throw new Error("Failed to read bbox");
|
|
689
|
-
output.set(bbox, offset);
|
|
690
|
-
} else {
|
|
691
|
-
let xMin = 0, yMin = 0, xMax = 0, yMax = 0;
|
|
692
|
-
if (points.length > 0) {
|
|
693
|
-
xMin = xMax = points[0].x;
|
|
694
|
-
yMin = yMax = points[0].y;
|
|
695
|
-
for (const p of points) {
|
|
696
|
-
xMin = Math.min(xMin, p.x);
|
|
697
|
-
xMax = Math.max(xMax, p.x);
|
|
698
|
-
yMin = Math.min(yMin, p.y);
|
|
699
|
-
yMax = Math.max(yMax, p.y);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
view.setInt16(offset, xMin);
|
|
703
|
-
view.setInt16(offset + 2, yMin);
|
|
704
|
-
view.setInt16(offset + 4, xMax);
|
|
705
|
-
view.setInt16(offset + 6, yMax);
|
|
706
|
-
}
|
|
707
|
-
offset += 8;
|
|
708
|
-
let endPoint = -1;
|
|
709
|
-
for (let i = 0; i < nContours; i++) {
|
|
710
|
-
endPoint += pointsPerContour[i];
|
|
711
|
-
view.setUint16(offset, endPoint);
|
|
712
|
-
offset += 2;
|
|
713
|
-
}
|
|
714
|
-
view.setUint16(offset, instructionSize);
|
|
715
|
-
offset += 2;
|
|
716
|
-
if (instructionSize > 0) {
|
|
717
|
-
const instructions = instructionStream.readBytes(instructionSize);
|
|
718
|
-
if (!instructions) throw new Error("Failed to read instructions");
|
|
719
|
-
output.set(instructions, offset);
|
|
720
|
-
offset += instructionSize;
|
|
721
|
-
}
|
|
722
|
-
output.set(flagsAndCoords, offset);
|
|
723
|
-
return output;
|
|
724
|
-
}
|
|
725
|
-
function decodeTriplets(flagStream, glyphStream, nPoints) {
|
|
726
|
-
const points = [];
|
|
764
|
+
function encodeTripletsToScratch(flagStream, glyphStream, nPoints, hasOverlapBit, flagsOut, xOut, yOut) {
|
|
765
|
+
if (nPoints === 0) return {
|
|
766
|
+
flagsLen: 0,
|
|
767
|
+
xLen: 0,
|
|
768
|
+
yLen: 0,
|
|
769
|
+
xMin: 0,
|
|
770
|
+
yMin: 0,
|
|
771
|
+
xMax: 0,
|
|
772
|
+
yMax: 0
|
|
773
|
+
};
|
|
774
|
+
let flagsLen = 0;
|
|
775
|
+
let xLen = 0;
|
|
776
|
+
let yLen = 0;
|
|
727
777
|
let x = 0;
|
|
728
778
|
let y = 0;
|
|
779
|
+
let xMin = 0;
|
|
780
|
+
let yMin = 0;
|
|
781
|
+
let xMax = 0;
|
|
782
|
+
let yMax = 0;
|
|
783
|
+
let lastFlag = -1;
|
|
784
|
+
let repeatCount = 0;
|
|
785
|
+
const flagData = flagStream.data;
|
|
786
|
+
let flagPos = flagStream.pos;
|
|
787
|
+
const flagEnd = flagStream.end;
|
|
788
|
+
const glyphData = glyphStream.data;
|
|
789
|
+
let glyphPos = glyphStream.pos;
|
|
790
|
+
const glyphEnd = glyphStream.end;
|
|
729
791
|
for (let i = 0; i < nPoints; i++) {
|
|
730
|
-
|
|
731
|
-
|
|
792
|
+
if (flagPos >= flagEnd) throw new Error("Stream overflow");
|
|
793
|
+
const flag = flagData[flagPos++];
|
|
732
794
|
const onCurve = (flag & 128) === 0;
|
|
733
795
|
const flagLow = flag & 127;
|
|
734
|
-
let dx
|
|
796
|
+
let dx;
|
|
797
|
+
let dy;
|
|
735
798
|
if (flagLow < 10) {
|
|
736
799
|
dx = 0;
|
|
737
|
-
|
|
738
|
-
|
|
800
|
+
if (glyphPos >= glyphEnd) throw new Error("Stream overflow");
|
|
801
|
+
const b = glyphData[glyphPos++];
|
|
739
802
|
dy = ((flagLow & 14) << 7) + b;
|
|
740
803
|
if ((flagLow & 1) === 0) dy = -dy;
|
|
741
804
|
} else if (flagLow < 20) {
|
|
742
|
-
|
|
743
|
-
|
|
805
|
+
if (glyphPos >= glyphEnd) throw new Error("Stream overflow");
|
|
806
|
+
const b = glyphData[glyphPos++];
|
|
744
807
|
dx = ((flagLow - 10 & 14) << 7) + b;
|
|
745
808
|
if ((flagLow & 1) === 0) dx = -dx;
|
|
746
809
|
dy = 0;
|
|
747
810
|
} else if (flagLow < 84) {
|
|
748
|
-
|
|
749
|
-
|
|
811
|
+
if (glyphPos >= glyphEnd) throw new Error("Stream overflow");
|
|
812
|
+
const b = glyphData[glyphPos++];
|
|
750
813
|
const b0 = flagLow - 20;
|
|
751
814
|
dx = 1 + (b0 & 48) + (b >> 4);
|
|
752
815
|
dy = 1 + ((b0 & 12) << 2) + (b & 15);
|
|
753
816
|
if ((flagLow & 1) === 0) dx = -dx;
|
|
754
817
|
if ((flagLow & 2) === 0) dy = -dy;
|
|
755
818
|
} else if (flagLow < 120) {
|
|
756
|
-
|
|
757
|
-
const
|
|
758
|
-
|
|
819
|
+
if (glyphPos + 1 >= glyphEnd) throw new Error("Stream overflow");
|
|
820
|
+
const b0 = glyphData[glyphPos++];
|
|
821
|
+
const b1 = glyphData[glyphPos++];
|
|
759
822
|
const idx = flagLow - 84;
|
|
760
|
-
dx = 1 + (
|
|
823
|
+
dx = 1 + ((idx / 12 | 0) << 8) + b0;
|
|
761
824
|
dy = 1 + (idx % 12 >> 2 << 8) + b1;
|
|
762
825
|
if ((flagLow & 1) === 0) dx = -dx;
|
|
763
826
|
if ((flagLow & 2) === 0) dy = -dy;
|
|
764
827
|
} else if (flagLow < 124) {
|
|
765
|
-
|
|
766
|
-
const
|
|
767
|
-
const
|
|
768
|
-
|
|
828
|
+
if (glyphPos + 2 >= glyphEnd) throw new Error("Stream overflow");
|
|
829
|
+
const b0 = glyphData[glyphPos++];
|
|
830
|
+
const b1 = glyphData[glyphPos++];
|
|
831
|
+
const b2 = glyphData[glyphPos++];
|
|
769
832
|
dx = (b0 << 4) + (b1 >> 4);
|
|
770
833
|
dy = ((b1 & 15) << 8) + b2;
|
|
771
834
|
if ((flagLow & 1) === 0) dx = -dx;
|
|
772
835
|
if ((flagLow & 2) === 0) dy = -dy;
|
|
773
836
|
} else {
|
|
774
|
-
|
|
775
|
-
const
|
|
776
|
-
const
|
|
777
|
-
const
|
|
778
|
-
|
|
837
|
+
if (glyphPos + 3 >= glyphEnd) throw new Error("Stream overflow");
|
|
838
|
+
const b0 = glyphData[glyphPos++];
|
|
839
|
+
const b1 = glyphData[glyphPos++];
|
|
840
|
+
const b2 = glyphData[glyphPos++];
|
|
841
|
+
const b3 = glyphData[glyphPos++];
|
|
779
842
|
dx = (b0 << 8) + b1;
|
|
780
843
|
dy = (b2 << 8) + b3;
|
|
781
844
|
if ((flagLow & 1) === 0) dx = -dx;
|
|
@@ -783,138 +846,81 @@ function decodeTriplets(flagStream, glyphStream, nPoints) {
|
|
|
783
846
|
}
|
|
784
847
|
x += dx;
|
|
785
848
|
y += dy;
|
|
786
|
-
|
|
787
|
-
x
|
|
788
|
-
y
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
const FLAG_REPEAT = 8;
|
|
799
|
-
const FLAG_X_SAME = 16;
|
|
800
|
-
const FLAG_Y_SAME = 32;
|
|
801
|
-
const FLAG_OVERLAP_SIMPLE = 64;
|
|
802
|
-
if (points.length === 0) return new Uint8Array(0);
|
|
803
|
-
const flags = [];
|
|
804
|
-
const xCoords = [];
|
|
805
|
-
const yCoords = [];
|
|
806
|
-
let lastX = 0;
|
|
807
|
-
let lastY = 0;
|
|
808
|
-
for (let i = 0; i < points.length; i++) {
|
|
809
|
-
const p = points[i];
|
|
810
|
-
let flag = p.onCurve ? FLAG_ON_CURVE : 0;
|
|
811
|
-
if (hasOverlapBit && i === 0) flag |= FLAG_OVERLAP_SIMPLE;
|
|
812
|
-
const dx = p.x - lastX;
|
|
813
|
-
const dy = p.y - lastY;
|
|
814
|
-
if (dx === 0) flag |= FLAG_X_SAME;
|
|
849
|
+
if (i === 0) {
|
|
850
|
+
xMin = xMax = x;
|
|
851
|
+
yMin = yMax = y;
|
|
852
|
+
} else {
|
|
853
|
+
if (x < xMin) xMin = x;
|
|
854
|
+
if (x > xMax) xMax = x;
|
|
855
|
+
if (y < yMin) yMin = y;
|
|
856
|
+
if (y > yMax) yMax = y;
|
|
857
|
+
}
|
|
858
|
+
let outFlag = onCurve ? FLAG_ON_CURVE : 0;
|
|
859
|
+
if (hasOverlapBit && i === 0) outFlag |= FLAG_OVERLAP_SIMPLE;
|
|
860
|
+
if (dx === 0) outFlag |= FLAG_X_SAME;
|
|
815
861
|
else if (dx >= -255 && dx <= 255) {
|
|
816
|
-
|
|
817
|
-
if (dx > 0)
|
|
818
|
-
|
|
819
|
-
} else xCoords.push(dx);
|
|
820
|
-
if (dy === 0) flag |= FLAG_Y_SAME;
|
|
821
|
-
else if (dy >= -255 && dy <= 255) {
|
|
822
|
-
flag |= FLAG_Y_SHORT;
|
|
823
|
-
if (dy > 0) flag |= FLAG_Y_SAME;
|
|
824
|
-
yCoords.push(Math.abs(dy));
|
|
825
|
-
} else yCoords.push(dy);
|
|
826
|
-
flags.push(flag);
|
|
827
|
-
lastX = p.x;
|
|
828
|
-
lastY = p.y;
|
|
829
|
-
}
|
|
830
|
-
const encodedFlags = [];
|
|
831
|
-
let lastFlag = -1;
|
|
832
|
-
let repeatCount = 0;
|
|
833
|
-
for (let i = 0; i < flags.length; i++) {
|
|
834
|
-
const flag = flags[i];
|
|
835
|
-
if (flag === lastFlag && repeatCount < 255) {
|
|
836
|
-
encodedFlags[encodedFlags.length - 1] |= FLAG_REPEAT;
|
|
837
|
-
repeatCount++;
|
|
862
|
+
outFlag |= FLAG_X_SHORT;
|
|
863
|
+
if (dx > 0) outFlag |= FLAG_X_SAME;
|
|
864
|
+
xOut[xLen++] = dx > 0 ? dx : -dx;
|
|
838
865
|
} else {
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
repeatCount = 0;
|
|
866
|
+
xOut[xLen++] = dx >> 8 & 255;
|
|
867
|
+
xOut[xLen++] = dx & 255;
|
|
842
868
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
if ((flag & FLAG_X_SHORT) !== 0) {
|
|
852
|
-
xSize += 1;
|
|
853
|
-
xIdx++;
|
|
854
|
-
} else if ((flag & FLAG_X_SAME) === 0) {
|
|
855
|
-
xSize += 2;
|
|
856
|
-
xIdx++;
|
|
869
|
+
if (dy === 0) outFlag |= FLAG_Y_SAME;
|
|
870
|
+
else if (dy >= -255 && dy <= 255) {
|
|
871
|
+
outFlag |= FLAG_Y_SHORT;
|
|
872
|
+
if (dy > 0) outFlag |= FLAG_Y_SAME;
|
|
873
|
+
yOut[yLen++] = dy > 0 ? dy : -dy;
|
|
874
|
+
} else {
|
|
875
|
+
yOut[yLen++] = dy >> 8 & 255;
|
|
876
|
+
yOut[yLen++] = dy & 255;
|
|
857
877
|
}
|
|
858
|
-
if (
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
} else
|
|
862
|
-
|
|
863
|
-
|
|
878
|
+
if (outFlag === lastFlag && repeatCount < 255) {
|
|
879
|
+
flagsOut[flagsLen - 1] |= FLAG_REPEAT;
|
|
880
|
+
repeatCount++;
|
|
881
|
+
} else {
|
|
882
|
+
if (repeatCount > 0) {
|
|
883
|
+
flagsOut[flagsLen++] = repeatCount;
|
|
884
|
+
repeatCount = 0;
|
|
885
|
+
}
|
|
886
|
+
flagsOut[flagsLen++] = outFlag;
|
|
887
|
+
lastFlag = outFlag;
|
|
864
888
|
}
|
|
865
889
|
}
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
else if ((flag & FLAG_Y_SAME) === 0) {
|
|
879
|
-
const val = yCoords[yIdx++];
|
|
880
|
-
output[offset++] = val >> 8 & 255;
|
|
881
|
-
output[offset++] = val & 255;
|
|
882
|
-
}
|
|
883
|
-
return output;
|
|
890
|
+
if (repeatCount > 0) flagsOut[flagsLen++] = repeatCount;
|
|
891
|
+
flagStream.pos = flagPos;
|
|
892
|
+
glyphStream.pos = glyphPos;
|
|
893
|
+
return {
|
|
894
|
+
flagsLen,
|
|
895
|
+
xLen,
|
|
896
|
+
yLen,
|
|
897
|
+
xMin,
|
|
898
|
+
yMin,
|
|
899
|
+
xMax,
|
|
900
|
+
yMax
|
|
901
|
+
};
|
|
884
902
|
}
|
|
885
903
|
function reconstructHmtx(data, table, numGlyphs, numHMetrics, xMins) {
|
|
886
|
-
const
|
|
887
|
-
const hmtxFlags =
|
|
888
|
-
if (hmtxFlags === null) throw new Error("Failed to read hmtx flags");
|
|
904
|
+
const hmtxStream = makeByteStream(data, table.srcOffset, table.srcLength);
|
|
905
|
+
const hmtxFlags = bsReadU8(hmtxStream);
|
|
889
906
|
const hasProportionalLsbs = (hmtxFlags & 1) === 0;
|
|
890
907
|
const hasMonospaceLsbs = (hmtxFlags & 2) === 0;
|
|
891
|
-
const advanceWidths =
|
|
892
|
-
for (let i = 0; i < numHMetrics; i++)
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
for (let i = 0; i < numHMetrics; i++) if (hasProportionalLsbs) {
|
|
899
|
-
const lsb = buf.readS16();
|
|
900
|
-
if (lsb === null) throw new Error("Failed to read proportional LSB");
|
|
901
|
-
lsbs.push(lsb);
|
|
902
|
-
} else lsbs.push(xMins[i]);
|
|
903
|
-
for (let i = numHMetrics; i < numGlyphs; i++) if (hasMonospaceLsbs) {
|
|
904
|
-
const lsb = buf.readS16();
|
|
905
|
-
if (lsb === null) throw new Error("Failed to read monospace LSB");
|
|
906
|
-
lsbs.push(lsb);
|
|
907
|
-
} else lsbs.push(xMins[i]);
|
|
908
|
+
const advanceWidths = new Uint16Array(numHMetrics);
|
|
909
|
+
for (let i = 0; i < numHMetrics; i++) advanceWidths[i] = bsReadU16(hmtxStream);
|
|
910
|
+
const lsbs = new Int16Array(numGlyphs);
|
|
911
|
+
for (let i = 0; i < numHMetrics; i++) if (hasProportionalLsbs) lsbs[i] = bsReadS16(hmtxStream);
|
|
912
|
+
else lsbs[i] = xMins[i];
|
|
913
|
+
for (let i = numHMetrics; i < numGlyphs; i++) if (hasMonospaceLsbs) lsbs[i] = bsReadS16(hmtxStream);
|
|
914
|
+
else lsbs[i] = xMins[i];
|
|
908
915
|
const outputSize = numHMetrics * 4 + (numGlyphs - numHMetrics) * 2;
|
|
909
916
|
const output = new Uint8Array(outputSize);
|
|
910
|
-
const view = new DataView(output.buffer);
|
|
911
917
|
let offset = 0;
|
|
912
918
|
for (let i = 0; i < numGlyphs; i++) {
|
|
913
919
|
if (i < numHMetrics) {
|
|
914
|
-
|
|
920
|
+
writeUint16BE(output, offset, advanceWidths[i]);
|
|
915
921
|
offset += 2;
|
|
916
922
|
}
|
|
917
|
-
|
|
923
|
+
writeInt16BE(output, offset, lsbs[i]);
|
|
918
924
|
offset += 2;
|
|
919
925
|
}
|
|
920
926
|
return output;
|
|
@@ -924,12 +930,24 @@ function updateTableEntry(view, entryOffset, checksum, offset, length) {
|
|
|
924
930
|
view.setUint32(entryOffset + 8, offset);
|
|
925
931
|
view.setUint32(entryOffset + 12, length);
|
|
926
932
|
}
|
|
933
|
+
function readInt16BE(data, offset) {
|
|
934
|
+
const val = data[offset] << 8 | data[offset + 1];
|
|
935
|
+
return (val & 32768) !== 0 ? val - 65536 : val;
|
|
936
|
+
}
|
|
937
|
+
function writeInt16BE(data, offset, value) {
|
|
938
|
+
data[offset] = value >> 8 & 255;
|
|
939
|
+
data[offset + 1] = value & 255;
|
|
940
|
+
}
|
|
941
|
+
function writeUint16BE(data, offset, value) {
|
|
942
|
+
data[offset] = value >> 8 & 255;
|
|
943
|
+
data[offset + 1] = value & 255;
|
|
944
|
+
}
|
|
927
945
|
function computeChecksum(data, offset, length) {
|
|
928
946
|
let sum = 0;
|
|
929
947
|
const end = offset + length;
|
|
930
|
-
const
|
|
948
|
+
const dataView = new DataView(data.buffer, data.byteOffset);
|
|
931
949
|
const alignedEnd = offset + (length & -4);
|
|
932
|
-
for (let i = offset; i < alignedEnd; i += 4) sum = sum +
|
|
950
|
+
for (let i = offset; i < alignedEnd; i += 4) sum = sum + dataView.getUint32(i) >>> 0;
|
|
933
951
|
if (end > alignedEnd) {
|
|
934
952
|
let last = 0;
|
|
935
953
|
for (let i = alignedEnd; i < end; i++) last = last << 8 | data[i];
|