@flighthq/font-formats 0.3.1-next.1041.35b950c
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/cffCharstring.d.ts +13 -0
- package/dist/cffCharstring.d.ts.map +1 -0
- package/dist/cffCharstring.js +336 -0
- package/dist/cffCharstring.js.map +1 -0
- package/dist/cffDict.d.ts +8 -0
- package/dist/cffDict.d.ts.map +1 -0
- package/dist/cffDict.js +118 -0
- package/dist/cffDict.js.map +1 -0
- package/dist/cffFdSelect.d.ts +2 -0
- package/dist/cffFdSelect.d.ts.map +1 -0
- package/dist/cffFdSelect.js +60 -0
- package/dist/cffFdSelect.js.map +1 -0
- package/dist/cffIndex.d.ts +3 -0
- package/dist/cffIndex.d.ts.map +1 -0
- package/dist/cffIndex.js +52 -0
- package/dist/cffIndex.js.map +1 -0
- package/dist/cffTable.d.ts +3 -0
- package/dist/cffTable.d.ts.map +1 -0
- package/dist/cffTable.js +134 -0
- package/dist/cffTable.js.map +1 -0
- package/dist/contract.d.ts +15 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +15 -0
- package/dist/contract.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/openTypeCmap.d.ts +5 -0
- package/dist/openTypeCmap.d.ts.map +1 -0
- package/dist/openTypeCmap.js +161 -0
- package/dist/openTypeCmap.js.map +1 -0
- package/dist/openTypeGlyf.d.ts +4 -0
- package/dist/openTypeGlyf.d.ts.map +1 -0
- package/dist/openTypeGlyf.js +229 -0
- package/dist/openTypeGlyf.js.map +1 -0
- package/dist/openTypeGlyphOutlineSource.d.ts +4 -0
- package/dist/openTypeGlyphOutlineSource.d.ts.map +1 -0
- package/dist/openTypeGlyphOutlineSource.js +168 -0
- package/dist/openTypeGlyphOutlineSource.js.map +1 -0
- package/dist/openTypeMetrics.d.ts +6 -0
- package/dist/openTypeMetrics.d.ts.map +1 -0
- package/dist/openTypeMetrics.js +74 -0
- package/dist/openTypeMetrics.js.map +1 -0
- package/dist/openTypeTestHelper.d.ts +27 -0
- package/dist/openTypeTestHelper.d.ts.map +1 -0
- package/dist/openTypeTestHelper.js +520 -0
- package/dist/openTypeTestHelper.js.map +1 -0
- package/dist/sfntAssembly.d.ts +20 -0
- package/dist/sfntAssembly.d.ts.map +1 -0
- package/dist/sfntAssembly.js +237 -0
- package/dist/sfntAssembly.js.map +1 -0
- package/dist/sfntTableDirectory.d.ts +4 -0
- package/dist/sfntTableDirectory.d.ts.map +1 -0
- package/dist/sfntTableDirectory.js +39 -0
- package/dist/sfntTableDirectory.js.map +1 -0
- package/dist/woff2Font.d.ts +6 -0
- package/dist/woff2Font.d.ts.map +1 -0
- package/dist/woff2Font.js +210 -0
- package/dist/woff2Font.js.map +1 -0
- package/dist/woff2GlyfTransform.d.ts +23 -0
- package/dist/woff2GlyfTransform.d.ts.map +1 -0
- package/dist/woff2GlyfTransform.js +437 -0
- package/dist/woff2GlyfTransform.js.map +1 -0
- package/dist/woffFont.d.ts +6 -0
- package/dist/woffFont.d.ts.map +1 -0
- package/dist/woffFont.js +122 -0
- package/dist/woffFont.js.map +1 -0
- package/package.json +51 -0
- package/src/cffCharstring.test.ts +177 -0
- package/src/cffDict.test.ts +67 -0
- package/src/cffFdSelect.test.ts +84 -0
- package/src/cffIndex.test.ts +97 -0
- package/src/cffTable.test.ts +84 -0
- package/src/openTypeCmap.test.ts +124 -0
- package/src/openTypeGlyf.test.ts +168 -0
- package/src/openTypeGlyfWinding.test.ts +80 -0
- package/src/openTypeGlyphOutlineSource.test.ts +298 -0
- package/src/openTypeMetrics.test.ts +103 -0
- package/src/sfntAssembly.test.ts +228 -0
- package/src/sfntTableDirectory.test.ts +64 -0
- package/src/woff2Font.test.ts +129 -0
- package/src/woff2GlyfTransform.test.ts +315 -0
- package/src/woffFont.test.ts +207 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// Writing a plain sfnt from tables somebody else unpacked.
|
|
2
|
+
//
|
|
3
|
+
// Both compressed wrappers end the same way: once WOFF has inflated its tables, or WOFF2 has
|
|
4
|
+
// decompressed and un-transformed its own, what is left is the identical job of laying out an sfnt.
|
|
5
|
+
// That job is the primitive, so it lives here rather than once per wrapper — an assembled font is a
|
|
6
|
+
// composition of the same parts however it arrived, and a second copy is where the two would drift.
|
|
7
|
+
const SFNT_HEADER_BYTES = 12;
|
|
8
|
+
const SFNT_DIRECTORY_ENTRY_BYTES = 16;
|
|
9
|
+
// Writes a header, a directory sorted by tag, then each table's data on a four-byte boundary.
|
|
10
|
+
//
|
|
11
|
+
// Sorting is required rather than cosmetic — the sfnt directory is defined as being in tag order, and a
|
|
12
|
+
// reader entitled to binary-search it would otherwise find the wrong table. Alignment follows the
|
|
13
|
+
// convention every real font is written with; it is not known to be enforced by consumers.
|
|
14
|
+
//
|
|
15
|
+
// `tag` is the four-character tag packed big-endian into a uint32, which is the form it is compared and
|
|
16
|
+
// sorted in, so no reader has to round-trip it through a string to order a directory.
|
|
17
|
+
export function assembleSfntFont(flavor, tables) {
|
|
18
|
+
const sorted = [...tables].sort((a, b) => a.tag - b.tag);
|
|
19
|
+
const headerBytes = SFNT_HEADER_BYTES + sorted.length * SFNT_DIRECTORY_ENTRY_BYTES;
|
|
20
|
+
let total = headerBytes;
|
|
21
|
+
for (const table of sorted)
|
|
22
|
+
total += (table.data.byteLength + 3) & ~3;
|
|
23
|
+
const out = new Uint8Array(total);
|
|
24
|
+
const view = new DataView(out.buffer);
|
|
25
|
+
view.setUint32(0, flavor);
|
|
26
|
+
view.setUint16(4, sorted.length);
|
|
27
|
+
// searchRange, entrySelector and rangeShift are derived values a reader can recompute; the reader in
|
|
28
|
+
// this package walks the directory linearly and never consults them, so they are left zero rather than
|
|
29
|
+
// written with values nothing checks.
|
|
30
|
+
let dataAt = headerBytes;
|
|
31
|
+
sorted.forEach((table, index) => {
|
|
32
|
+
const record = SFNT_HEADER_BYTES + index * SFNT_DIRECTORY_ENTRY_BYTES;
|
|
33
|
+
view.setUint32(record, table.tag);
|
|
34
|
+
// The real checksum, computed from the bytes being written. An assembled font that carried zeros
|
|
35
|
+
// here would be making a false statement about tables it holds, and any consumer that does check
|
|
36
|
+
// would read the zero as a mismatch.
|
|
37
|
+
view.setUint32(record + 4, computeSfntTableChecksum(table.data, table.tag === HEAD_TAG));
|
|
38
|
+
view.setUint32(record + 8, dataAt);
|
|
39
|
+
view.setUint32(record + 12, table.data.byteLength);
|
|
40
|
+
out.set(table.data, dataAt);
|
|
41
|
+
dataAt += (table.data.byteLength + 3) & ~3;
|
|
42
|
+
});
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
// The checksum an sfnt directory stores for a table: the sum of its bytes read as big-endian uint32
|
|
46
|
+
// words, zero-padded to a four-byte boundary, taken modulo 2^32. An interface fact about the format.
|
|
47
|
+
//
|
|
48
|
+
// ★ `head` IS THE ONE EXCEPTION AND OMITTING IT MAKES EVERY REAL FONT REPORT A MISMATCH. The table
|
|
49
|
+
// carries `checkSumAdjustment` at byte 8, a value derived from the whole font's checksum, and the
|
|
50
|
+
// format defines the table's own checksum as being computed with that field treated as ZERO —
|
|
51
|
+
// otherwise the value would have to contain a function of itself.
|
|
52
|
+
export function computeSfntTableChecksum(data, isHeadTable = false) {
|
|
53
|
+
let sum = 0;
|
|
54
|
+
for (let at = 0; at < data.byteLength; at += 4) {
|
|
55
|
+
// Bytes past the end read as zero, which is the padding the format defines rather than a guard.
|
|
56
|
+
const zeroed = isHeadTable && at === HEAD_CHECKSUM_ADJUSTMENT_OFFSET;
|
|
57
|
+
const word = zeroed
|
|
58
|
+
? 0
|
|
59
|
+
: (data[at] ?? 0) * 0x1000000 + (data[at + 1] ?? 0) * 0x10000 + (data[at + 2] ?? 0) * 0x100 + (data[at + 3] ?? 0);
|
|
60
|
+
sum = (sum + word) % 0x100000000;
|
|
61
|
+
}
|
|
62
|
+
return sum >>> 0;
|
|
63
|
+
}
|
|
64
|
+
// Packs a four-character tag into the uint32 an sfnt directory stores it as. Tags shorter than four
|
|
65
|
+
// characters are padded with spaces, which is how the format spells `cvt ` and `CFF ` — a caller
|
|
66
|
+
// Encodes one composite glyph: the header and bounds, then the component records verbatim, then the
|
|
67
|
+
// hinting instructions if any component asked for them. `components` is the slice of the WOFF2
|
|
68
|
+
// composite stream that `measureWoff2CompositeGlyph` sized, and it is copied unchanged — the transform
|
|
69
|
+
// reorders whole glyphs, it does not re-encode a component record.
|
|
70
|
+
//
|
|
71
|
+
// ★ THE CONTOUR COUNT IS A MARKER HERE, NOT A COUNT. Any negative value means "composite", and the
|
|
72
|
+
// reader switches on the sign alone before reading anything else; -1 is the conventional spelling. A
|
|
73
|
+
// caller that passed the number of components instead would write a positive count and every reader
|
|
74
|
+
// would parse the component records as an endPtsOfContours array.
|
|
75
|
+
//
|
|
76
|
+
// ★ A COMPOSITE CANNOT COMPUTE ITS OWN BOUNDS FROM WHAT IT HOLDS, which is why `bounds` is required
|
|
77
|
+
// rather than optional: it names other glyphs and places them, so its box depends on glyphs it does
|
|
78
|
+
// not carry. This is also why the WOFF2 transform always stores an explicit box for one.
|
|
79
|
+
export function encodeSfntCompositeGlyph(components, instructions, bounds, hasInstructions) {
|
|
80
|
+
// The instruction length field exists only when a component set the flag. Writing a zero length
|
|
81
|
+
// unconditionally would add two bytes no reader expects and shift every following glyph.
|
|
82
|
+
const tail = hasInstructions ? 2 + instructions.byteLength : 0;
|
|
83
|
+
const out = new Uint8Array(10 + components.byteLength + tail);
|
|
84
|
+
const view = new DataView(out.buffer);
|
|
85
|
+
view.setInt16(0, -1);
|
|
86
|
+
view.setInt16(2, bounds.xMin);
|
|
87
|
+
view.setInt16(4, bounds.yMin);
|
|
88
|
+
view.setInt16(6, bounds.xMax);
|
|
89
|
+
view.setInt16(8, bounds.yMax);
|
|
90
|
+
out.set(components, 10);
|
|
91
|
+
if (hasInstructions) {
|
|
92
|
+
view.setUint16(10 + components.byteLength, instructions.byteLength);
|
|
93
|
+
out.set(instructions, 12 + components.byteLength);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
// Builds the `loca` table from each glyph record's length, in glyph order. `loca` holds glyphCount + 1
|
|
98
|
+
// offsets, because a glyph's length is the gap to the NEXT entry — which is also how a zero-length
|
|
99
|
+
// (blank) glyph is expressed, as two equal consecutive offsets.
|
|
100
|
+
//
|
|
101
|
+
// ★ THE SHORT FORM STORES HALF THE OFFSET, WHICH MAKES EVEN PADDING A CORRECTNESS REQUIREMENT RATHER
|
|
102
|
+
// THAN A TIDINESS ONE. With `indexFormat` 0 each entry is `offset / 2` in a uint16, so an odd offset is
|
|
103
|
+
// not representable and would be silently truncated to the even one below it — pointing the reader at
|
|
104
|
+
// the previous glyph's last byte. Callers must therefore pad every record to an even length before
|
|
105
|
+
// measuring it here. Returns the null sentinel rather than truncating when an offset is odd, or when
|
|
106
|
+
// the font is too large for the short form to reach.
|
|
107
|
+
export function encodeSfntLoca(glyphLengths, indexFormat) {
|
|
108
|
+
const entries = glyphLengths.length + 1;
|
|
109
|
+
const out = new Uint8Array(indexFormat === 0 ? entries * 2 : entries * 4);
|
|
110
|
+
const view = new DataView(out.buffer);
|
|
111
|
+
let offset = 0;
|
|
112
|
+
for (let index = 0; index < entries; index += 1) {
|
|
113
|
+
if (indexFormat === 0) {
|
|
114
|
+
if (offset % 2 !== 0)
|
|
115
|
+
return null;
|
|
116
|
+
if (offset / 2 > 0xffff)
|
|
117
|
+
return null;
|
|
118
|
+
view.setUint16(index * 2, offset / 2);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
view.setUint32(index * 4, offset);
|
|
122
|
+
}
|
|
123
|
+
offset += glyphLengths[index] ?? 0;
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
// Encodes one simple glyph as the `glyf` table stores it: the contour ends, the hinting instructions,
|
|
128
|
+
// then per-point flags and the x and y deltas the flags describe. `xs` and `ys` are ABSOLUTE coordinates
|
|
129
|
+
// in font units; the deltas are computed here, because the encoding is defined over deltas and a caller
|
|
130
|
+
// holding absolute points should not have to know that.
|
|
131
|
+
//
|
|
132
|
+
// Returns an empty array for a glyph with no contours. A `glyf` entry of length zero is how the format
|
|
133
|
+
// spells "this glyph draws nothing" — a blank record with a zero contour count is NOT the same thing,
|
|
134
|
+
// and writing one gives every space character a bounding box.
|
|
135
|
+
//
|
|
136
|
+
// ★ THE ENCODING IS A COMPRESSION, AND EVERY POINT HAS SEVERAL VALID SPELLINGS. A delta of zero can be
|
|
137
|
+
// written as "same as previous" with no bytes at all; a delta within a byte can be written short with a
|
|
138
|
+
// sign bit, or long as an int16. Choosing the smallest is what a font producer does, but a font that
|
|
139
|
+
// chose differently is still correct — so a byte-for-byte comparison against a real font measures
|
|
140
|
+
// agreement with THAT producer's choices, not correctness. Compare geometry to judge correctness.
|
|
141
|
+
export function encodeSfntSimpleGlyph(endPtsOfContours, xs, ys, onCurve, instructions, bounds) {
|
|
142
|
+
if (endPtsOfContours.length === 0)
|
|
143
|
+
return new Uint8Array(0);
|
|
144
|
+
const pointCount = xs.length;
|
|
145
|
+
const flags = [];
|
|
146
|
+
const xBytes = [];
|
|
147
|
+
const yBytes = [];
|
|
148
|
+
let previousX = 0;
|
|
149
|
+
let previousY = 0;
|
|
150
|
+
for (let point = 0; point < pointCount; point += 1) {
|
|
151
|
+
const dx = xs[point] - previousX;
|
|
152
|
+
const dy = ys[point] - previousY;
|
|
153
|
+
previousX = xs[point];
|
|
154
|
+
previousY = ys[point];
|
|
155
|
+
let flag = onCurve[point] === true ? SFNT_GLYF_ON_CURVE : 0;
|
|
156
|
+
// A zero delta needs no bytes: the "same or positive" bit alone means unchanged when the matching
|
|
157
|
+
// short bit is clear, which is why these two bits cannot be read independently.
|
|
158
|
+
if (dx === 0)
|
|
159
|
+
flag |= SFNT_GLYF_X_SAME_OR_POSITIVE;
|
|
160
|
+
else if (dx >= -255 && dx <= 255) {
|
|
161
|
+
flag |= SFNT_GLYF_X_SHORT;
|
|
162
|
+
if (dx > 0)
|
|
163
|
+
flag |= SFNT_GLYF_X_SAME_OR_POSITIVE;
|
|
164
|
+
xBytes.push(Math.abs(dx));
|
|
165
|
+
}
|
|
166
|
+
else
|
|
167
|
+
xBytes.push((dx >> 8) & 0xff, dx & 0xff);
|
|
168
|
+
if (dy === 0)
|
|
169
|
+
flag |= SFNT_GLYF_Y_SAME_OR_POSITIVE;
|
|
170
|
+
else if (dy >= -255 && dy <= 255) {
|
|
171
|
+
flag |= SFNT_GLYF_Y_SHORT;
|
|
172
|
+
if (dy > 0)
|
|
173
|
+
flag |= SFNT_GLYF_Y_SAME_OR_POSITIVE;
|
|
174
|
+
yBytes.push(Math.abs(dy));
|
|
175
|
+
}
|
|
176
|
+
else
|
|
177
|
+
yBytes.push((dy >> 8) & 0xff, dy & 0xff);
|
|
178
|
+
flags.push(flag);
|
|
179
|
+
}
|
|
180
|
+
// Runs of identical flags collapse into one flag plus a repeat count. The count is a single byte, so
|
|
181
|
+
// a run longer than 256 becomes several repeat groups rather than one overflowing count.
|
|
182
|
+
const packedFlags = [];
|
|
183
|
+
for (let index = 0; index < flags.length;) {
|
|
184
|
+
const flag = flags[index];
|
|
185
|
+
let run = 1;
|
|
186
|
+
while (index + run < flags.length && flags[index + run] === flag && run < 256)
|
|
187
|
+
run += 1;
|
|
188
|
+
if (run > 1)
|
|
189
|
+
packedFlags.push(flag | SFNT_GLYF_REPEAT, run - 1);
|
|
190
|
+
else
|
|
191
|
+
packedFlags.push(flag);
|
|
192
|
+
index += run;
|
|
193
|
+
}
|
|
194
|
+
const size = 10 + endPtsOfContours.length * 2 + 2 + instructions.byteLength + packedFlags.length + xBytes.length + yBytes.length;
|
|
195
|
+
const out = new Uint8Array(size);
|
|
196
|
+
const view = new DataView(out.buffer);
|
|
197
|
+
view.setInt16(0, endPtsOfContours.length);
|
|
198
|
+
view.setInt16(2, bounds.xMin);
|
|
199
|
+
view.setInt16(4, bounds.yMin);
|
|
200
|
+
view.setInt16(6, bounds.xMax);
|
|
201
|
+
view.setInt16(8, bounds.yMax);
|
|
202
|
+
let at = 10;
|
|
203
|
+
for (const end of endPtsOfContours) {
|
|
204
|
+
view.setUint16(at, end);
|
|
205
|
+
at += 2;
|
|
206
|
+
}
|
|
207
|
+
view.setUint16(at, instructions.byteLength);
|
|
208
|
+
at += 2;
|
|
209
|
+
out.set(instructions, at);
|
|
210
|
+
at += instructions.byteLength;
|
|
211
|
+
out.set(packedFlags, at);
|
|
212
|
+
at += packedFlags.length;
|
|
213
|
+
out.set(xBytes, at);
|
|
214
|
+
at += xBytes.length;
|
|
215
|
+
out.set(yBytes, at);
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
// passing the unpadded name gets the same value the font carries rather than a silent mismatch.
|
|
219
|
+
export function packSfntTag(tag) {
|
|
220
|
+
const padded = tag.padEnd(4, ' ');
|
|
221
|
+
return (((padded.charCodeAt(0) << 24) |
|
|
222
|
+
(padded.charCodeAt(1) << 16) |
|
|
223
|
+
(padded.charCodeAt(2) << 8) |
|
|
224
|
+
padded.charCodeAt(3)) >>>
|
|
225
|
+
0);
|
|
226
|
+
}
|
|
227
|
+
const HEAD_TAG = 0x68656164;
|
|
228
|
+
const HEAD_CHECKSUM_ADJUSTMENT_OFFSET = 8;
|
|
229
|
+
// Point flag bits, as the `glyf` format defines them. The two SAME_OR_POSITIVE bits do double duty:
|
|
230
|
+
// with the matching SHORT bit set they carry the sign, and with it clear they mean the delta is zero.
|
|
231
|
+
const SFNT_GLYF_ON_CURVE = 0x01;
|
|
232
|
+
const SFNT_GLYF_REPEAT = 0x08;
|
|
233
|
+
const SFNT_GLYF_X_SAME_OR_POSITIVE = 0x10;
|
|
234
|
+
const SFNT_GLYF_X_SHORT = 0x02;
|
|
235
|
+
const SFNT_GLYF_Y_SAME_OR_POSITIVE = 0x20;
|
|
236
|
+
const SFNT_GLYF_Y_SHORT = 0x04;
|
|
237
|
+
//# sourceMappingURL=sfntAssembly.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sfntAssembly.js","sourceRoot":"","sources":["../src/sfntAssembly.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SfntTableDirectory } from '@flighthq/types/contract';
|
|
2
|
+
export declare function readSfntTableDirectory(bytes: Readonly<Uint8Array>): SfntTableDirectory | null;
|
|
3
|
+
export declare function readSfntTag(bytes: Readonly<Uint8Array>, offset: number): string;
|
|
4
|
+
//# sourceMappingURL=sfntTableDirectory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sfntTableDirectory.d.ts","sourceRoot":"","sources":["../src/sfntTableDirectory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAiBnE,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,kBAAkB,GAAG,IAAI,CAoB7F;AAKD,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/E"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// The sfnt container's table directory: a fixed 12-byte header followed by one 16-byte record per
|
|
2
|
+
// table, each record naming a four-character tag and the table's byte range within the file. Every
|
|
3
|
+
// OpenType flavor shares this layout — what differs is only which tables are present — so this is the
|
|
4
|
+
// one reader every table parser starts from.
|
|
5
|
+
//
|
|
6
|
+
// Offsets and tags are facts about the format. Nothing here interprets a table's contents.
|
|
7
|
+
const SFNT_HEADER_BYTES = 12;
|
|
8
|
+
const SFNT_TABLE_RECORD_BYTES = 16;
|
|
9
|
+
// Reads the directory and clamps every entry to the bytes actually present. A record pointing past the
|
|
10
|
+
// end of the buffer is dropped rather than trusted or thrown on: a truncated download is an ordinary
|
|
11
|
+
// thing to be handed, and the caller distinguishes "table absent" from "file damaged" by comparing
|
|
12
|
+
// `declaredTableCount` against the size of `tables` — which is exactly what `explainOpenTypeFont`
|
|
13
|
+
// reports. Returns the null sentinel only when the header itself cannot be read.
|
|
14
|
+
export function readSfntTableDirectory(bytes) {
|
|
15
|
+
if (bytes.byteLength < SFNT_HEADER_BYTES)
|
|
16
|
+
return null;
|
|
17
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
18
|
+
const declaredTableCount = view.getUint16(4);
|
|
19
|
+
const tables = new Map();
|
|
20
|
+
for (let index = 0; index < declaredTableCount; index += 1) {
|
|
21
|
+
const record = SFNT_HEADER_BYTES + index * SFNT_TABLE_RECORD_BYTES;
|
|
22
|
+
// The record itself must be inside the buffer before any field of it can be read.
|
|
23
|
+
if (record + SFNT_TABLE_RECORD_BYTES > bytes.byteLength)
|
|
24
|
+
break;
|
|
25
|
+
const offset = view.getUint32(record + 8);
|
|
26
|
+
const length = view.getUint32(record + 12);
|
|
27
|
+
if (offset + length > bytes.byteLength)
|
|
28
|
+
continue;
|
|
29
|
+
tables.set(readSfntTag(bytes, record), { length, offset });
|
|
30
|
+
}
|
|
31
|
+
return { declaredTableCount, sfntVersion: view.getUint32(0), tables };
|
|
32
|
+
}
|
|
33
|
+
// A table tag is four bytes read as characters rather than as a number, because that is how every
|
|
34
|
+
// specification, every font tool, and every error message spells it — `glyf`, `cmap`, `CFF ` with its
|
|
35
|
+
// significant trailing space. Keeping the string form means a tag never has to be decoded by a reader.
|
|
36
|
+
export function readSfntTag(bytes, offset) {
|
|
37
|
+
return String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=sfntTableDirectory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sfntTableDirectory.js","sourceRoot":"","sources":["../src/sfntTableDirectory.ts"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,mGAAmG;AACnG,sGAAsG;AACtG,6CAA6C;AAC7C,EAAE;AACF,2FAA2F;AAE3F,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAEnC,uGAAuG;AACvG,qGAAqG;AACrG,mGAAmG;AACnG,kGAAkG;AAClG,iFAAiF;AACjF,MAAM,UAAU,sBAAsB,CAAC,KAA2B;IAChE,IAAI,KAAK,CAAC,UAAU,GAAG,iBAAiB;QAAE,OAAO,IAAI,CAAC;IAEtD,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5E,MAAM,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,GAAG,EAA8C,CAAC;IAErE,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,kBAAkB,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,MAAM,GAAG,iBAAiB,GAAG,KAAK,GAAG,uBAAuB,CAAC;QACnE,kFAAkF;QAClF,IAAI,MAAM,GAAG,uBAAuB,GAAG,KAAK,CAAC,UAAU;YAAE,MAAM;QAE/D,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QAC3C,IAAI,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,UAAU;YAAE,SAAS;QAEjD,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;AACxE,CAAC;AAED,kGAAkG;AAClG,sGAAsG;AACtG,uGAAuG;AACvG,MAAM,UAAU,WAAW,CAAC,KAA2B,EAAE,MAAc;IACrE,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,CAAE,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,CAAC;AACzG,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Decompressor, Woff2TableDirectory } from '@flighthq/types/contract';
|
|
2
|
+
import { Compression } from '@flighthq/types/contract';
|
|
3
|
+
export declare const WOFF2_COMPRESSION: Compression;
|
|
4
|
+
export declare function readWoff2Font(bytes: Readonly<Uint8Array>, decompress: Decompressor | null, reverseTransform: ((tag: string, transformed: Readonly<Uint8Array>, tables: ReadonlyMap<string, Uint8Array>) => Uint8Array | null) | null): Uint8Array | null;
|
|
5
|
+
export declare function readWoff2TableDirectory(bytes: Readonly<Uint8Array>): Woff2TableDirectory | null;
|
|
6
|
+
//# sourceMappingURL=woff2Font.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"woff2Font.d.ts","sourceRoot":"","sources":["../src/woff2Font.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAmB,MAAM,0BAA0B,CAAC;AACnG,OAAO,EAAE,WAAW,EAAsB,MAAM,0BAA0B,CAAC;AA4F3E,eAAO,MAAM,iBAAiB,EAAE,WAAgC,CAAC;AAMjE,wBAAgB,aAAa,CAC3B,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,gBAAgB,EACZ,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,UAAU,GAAG,IAAI,CAAC,GAChH,IAAI,GACP,UAAU,GAAG,IAAI,CAiDnB;AAMD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,mBAAmB,GAAG,IAAI,CAqD/F"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { Compression, CompressionFraming } from '@flighthq/types/contract';
|
|
2
|
+
import { assembleSfntFont, packSfntTag } from './sfntAssembly';
|
|
3
|
+
// WOFF2 is WOFF's wrapper idea taken two steps further, and both steps are why it needs its own reader
|
|
4
|
+
// rather than a flag on the WOFF one.
|
|
5
|
+
//
|
|
6
|
+
// 1. ONE Brotli STREAM FOR THE WHOLE FONT, not one deflate stream per table. Tables are concatenated
|
|
7
|
+
// before compression, so nothing can be read until the entire stream is decompressed, and the
|
|
8
|
+
// directory carries lengths rather than offsets — there are no offsets to carry.
|
|
9
|
+
// 2. TABLES MAY BE *TRANSFORMED*, not merely compressed. A transformed table is not the sfnt table in
|
|
10
|
+
// compressed form; it is a different byte layout that must be reversed to get the table back.
|
|
11
|
+
//
|
|
12
|
+
// The container layout is an interface fact about the format. The reading is Flight's own.
|
|
13
|
+
//
|
|
14
|
+
// ★ NO DECOMPRESSOR AND NO DICTIONARY SHIP WITH THIS. Brotli's decoder needs a large static dictionary
|
|
15
|
+
// that is data rather than rules, so Flight registers nothing and the caller registers a decompressor
|
|
16
|
+
// they already have — `zlib` on Node, an ordinary package in a browser. That is the same registry seam
|
|
17
|
+
// WOFF already uses, and it keeps a `.ttf` reader from carrying a codec it never calls.
|
|
18
|
+
const WOFF2_HEADER_BYTES = 48;
|
|
19
|
+
// The 63 tags a directory entry can name by index instead of spelling out. The order is fixed by the
|
|
20
|
+
// format — index 63 means an arbitrary tag follows as four bytes instead.
|
|
21
|
+
const WOFF2_KNOWN_TAGS = [
|
|
22
|
+
'cmap',
|
|
23
|
+
'head',
|
|
24
|
+
'hhea',
|
|
25
|
+
'hmtx',
|
|
26
|
+
'maxp',
|
|
27
|
+
'name',
|
|
28
|
+
'OS/2',
|
|
29
|
+
'post',
|
|
30
|
+
'cvt ',
|
|
31
|
+
'fpgm',
|
|
32
|
+
'glyf',
|
|
33
|
+
'loca',
|
|
34
|
+
'prep',
|
|
35
|
+
'CFF ',
|
|
36
|
+
'VORG',
|
|
37
|
+
'EBDT',
|
|
38
|
+
'EBLC',
|
|
39
|
+
'gasp',
|
|
40
|
+
'hdmx',
|
|
41
|
+
'kern',
|
|
42
|
+
'LTSH',
|
|
43
|
+
'PCLT',
|
|
44
|
+
'VDMX',
|
|
45
|
+
'vhea',
|
|
46
|
+
'vmtx',
|
|
47
|
+
'BASE',
|
|
48
|
+
'GDEF',
|
|
49
|
+
'GPOS',
|
|
50
|
+
'GSUB',
|
|
51
|
+
'EBSC',
|
|
52
|
+
'JSTF',
|
|
53
|
+
'MATH',
|
|
54
|
+
'CBDT',
|
|
55
|
+
'CBLC',
|
|
56
|
+
'COLR',
|
|
57
|
+
'CPAL',
|
|
58
|
+
'SVG ',
|
|
59
|
+
'sbix',
|
|
60
|
+
'acnt',
|
|
61
|
+
'avar',
|
|
62
|
+
'bdat',
|
|
63
|
+
'bloc',
|
|
64
|
+
'bsln',
|
|
65
|
+
'cvar',
|
|
66
|
+
'fdsc',
|
|
67
|
+
'feat',
|
|
68
|
+
'fmtx',
|
|
69
|
+
'fvar',
|
|
70
|
+
'gvar',
|
|
71
|
+
'hsty',
|
|
72
|
+
'just',
|
|
73
|
+
'lcar',
|
|
74
|
+
'mort',
|
|
75
|
+
'morx',
|
|
76
|
+
'opbd',
|
|
77
|
+
'prop',
|
|
78
|
+
'trak',
|
|
79
|
+
'Zapf',
|
|
80
|
+
'Silf',
|
|
81
|
+
'Glat',
|
|
82
|
+
'Gloc',
|
|
83
|
+
'Feat',
|
|
84
|
+
'Sill',
|
|
85
|
+
];
|
|
86
|
+
// The compression this container uses. Named through the shared vocabulary rather than a local constant
|
|
87
|
+
// so a caller registering a codec and this module asking for one cannot drift apart.
|
|
88
|
+
export const WOFF2_COMPRESSION = Compression.Brotli;
|
|
89
|
+
// Rebuilds the plain sfnt a WOFF2 wraps. Returns the null sentinel for a malformed container, for a
|
|
90
|
+
// missing decompressor, and for a transform this package cannot reverse — the caller distinguishes those
|
|
91
|
+
// through `explainOpenTypeFont`, because the remedies are a repaired file, one line of registration, and
|
|
92
|
+
// a different producer respectively.
|
|
93
|
+
export function readWoff2Font(bytes, decompress, reverseTransform) {
|
|
94
|
+
const directory = readWoff2TableDirectory(bytes);
|
|
95
|
+
if (directory === null)
|
|
96
|
+
return null;
|
|
97
|
+
if (decompress === null)
|
|
98
|
+
return null;
|
|
99
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
100
|
+
const flavor = view.getUint32(4);
|
|
101
|
+
const totalCompressedSize = view.getUint32(20);
|
|
102
|
+
// The compressed stream begins immediately after the directory, whose length is only known once it has
|
|
103
|
+
// been walked. Deriving the start from the end of the file instead lands inside the format's trailing
|
|
104
|
+
// padding, which decodes as a valid but empty stream rather than failing.
|
|
105
|
+
const streamEnd = directory.streamStart + totalCompressedSize;
|
|
106
|
+
if (streamEnd > bytes.byteLength)
|
|
107
|
+
return null;
|
|
108
|
+
const stream = decompress(bytes.subarray(directory.streamStart, streamEnd), directory.totalUncompressedLength, CompressionFraming.Raw);
|
|
109
|
+
if (stream === null || stream.byteLength < directory.totalUncompressedLength)
|
|
110
|
+
return null;
|
|
111
|
+
// Tables sit end to end in the decompressed stream, in directory order, each occupying its transformed
|
|
112
|
+
// length where it was transformed and its original length where it was not.
|
|
113
|
+
const raw = new Map();
|
|
114
|
+
let at = 0;
|
|
115
|
+
for (const entry of directory.entries) {
|
|
116
|
+
const length = entry.transformed ? entry.transformLength : entry.originalLength;
|
|
117
|
+
if (at + length > stream.byteLength)
|
|
118
|
+
return null;
|
|
119
|
+
raw.set(entry.tag, stream.subarray(at, at + length));
|
|
120
|
+
at += length;
|
|
121
|
+
}
|
|
122
|
+
const tables = [];
|
|
123
|
+
for (const entry of directory.entries) {
|
|
124
|
+
const stored = raw.get(entry.tag);
|
|
125
|
+
if (!entry.transformed) {
|
|
126
|
+
tables.push({ data: stored, tag: packSfntTag(entry.tag) });
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
// A transform this package cannot reverse is refused rather than passed through. Emitting the
|
|
130
|
+
// transformed bytes under the table's own tag would produce a font whose directory says `glyf` over
|
|
131
|
+
// something that is not a `glyf` — readable, wrong, and silent.
|
|
132
|
+
if (reverseTransform === null)
|
|
133
|
+
return null;
|
|
134
|
+
const restored = reverseTransform(entry.tag, stored, raw);
|
|
135
|
+
if (restored === null)
|
|
136
|
+
return null;
|
|
137
|
+
tables.push({ data: restored, tag: packSfntTag(entry.tag) });
|
|
138
|
+
}
|
|
139
|
+
return assembleSfntFont(flavor, tables);
|
|
140
|
+
}
|
|
141
|
+
// The directory a WOFF2 carries in place of sfnt's offset table: one variable-length record per table,
|
|
142
|
+
// naming a tag, whether it was transformed, and the lengths on both sides of that transform. Returns the
|
|
143
|
+
// null sentinel rather than a partial directory, since a desynchronised walk yields entries whose tags
|
|
144
|
+
// and lengths are real values read at the wrong offsets.
|
|
145
|
+
export function readWoff2TableDirectory(bytes) {
|
|
146
|
+
if (bytes.byteLength < WOFF2_HEADER_BYTES)
|
|
147
|
+
return null;
|
|
148
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
149
|
+
const tableCount = view.getUint16(12);
|
|
150
|
+
if (tableCount === 0)
|
|
151
|
+
return null;
|
|
152
|
+
const cursor = { at: WOFF2_HEADER_BYTES };
|
|
153
|
+
const entries = [];
|
|
154
|
+
let totalUncompressedLength = 0;
|
|
155
|
+
for (let index = 0; index < tableCount; index += 1) {
|
|
156
|
+
if (cursor.at >= bytes.byteLength)
|
|
157
|
+
return null;
|
|
158
|
+
const flags = view.getUint8(cursor.at);
|
|
159
|
+
cursor.at += 1;
|
|
160
|
+
const tagIndex = flags & 0x3f;
|
|
161
|
+
const transformVersion = (flags >> 6) & 0x03;
|
|
162
|
+
let tag;
|
|
163
|
+
if (tagIndex === 0x3f) {
|
|
164
|
+
if (cursor.at + 4 > bytes.byteLength)
|
|
165
|
+
return null;
|
|
166
|
+
tag = String.fromCharCode(view.getUint8(cursor.at), view.getUint8(cursor.at + 1), view.getUint8(cursor.at + 2), view.getUint8(cursor.at + 3));
|
|
167
|
+
cursor.at += 4;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
tag = WOFF2_KNOWN_TAGS[tagIndex];
|
|
171
|
+
}
|
|
172
|
+
const originalLength = readWoff2Base128(view, cursor, bytes.byteLength);
|
|
173
|
+
if (originalLength < 0)
|
|
174
|
+
return null;
|
|
175
|
+
// The sense of `transformVersion` is INVERTED for the glyph pair, and getting this backwards is the
|
|
176
|
+
// mistake that reads a length field that is not there: for `glyf` and `loca`, version 3 means the
|
|
177
|
+
// null transform, while for every other table it is version 0 that means untransformed.
|
|
178
|
+
const isGlyphPair = tag === 'glyf' || tag === 'loca';
|
|
179
|
+
const transformed = isGlyphPair ? transformVersion !== 3 : transformVersion !== 0;
|
|
180
|
+
let transformLength = originalLength;
|
|
181
|
+
if (transformed) {
|
|
182
|
+
transformLength = readWoff2Base128(view, cursor, bytes.byteLength);
|
|
183
|
+
if (transformLength < 0)
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
entries.push({ originalLength, tag, transformLength, transformVersion, transformed });
|
|
187
|
+
totalUncompressedLength += transformed ? transformLength : originalLength;
|
|
188
|
+
}
|
|
189
|
+
return { entries, streamStart: cursor.at, totalUncompressedLength };
|
|
190
|
+
}
|
|
191
|
+
// UIntBase128: seven bits per byte, most significant first, high bit set on every byte but the last.
|
|
192
|
+
// Returns -1 for an unterminated or over-long value rather than a truncated number, so a caller cannot
|
|
193
|
+
// mistake a malformed length for a small one. Five bytes is the most a 32-bit value can occupy, and a
|
|
194
|
+
// leading zero byte is disallowed because it makes one value spellable two ways.
|
|
195
|
+
function readWoff2Base128(view, cursor, end) {
|
|
196
|
+
let value = 0;
|
|
197
|
+
for (let byte = 0; byte < 5; byte += 1) {
|
|
198
|
+
if (cursor.at >= end)
|
|
199
|
+
return -1;
|
|
200
|
+
const next = view.getUint8(cursor.at);
|
|
201
|
+
cursor.at += 1;
|
|
202
|
+
if (byte === 0 && next === 0x80)
|
|
203
|
+
return -1;
|
|
204
|
+
value = value * 128 + (next & 0x7f);
|
|
205
|
+
if ((next & 0x80) === 0)
|
|
206
|
+
return value > 0xffffffff ? -1 : value;
|
|
207
|
+
}
|
|
208
|
+
return -1;
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=woff2Font.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"woff2Font.js","sourceRoot":"","sources":["../src/woff2Font.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Woff2GlyfStreams } from '@flighthq/types/contract';
|
|
2
|
+
export declare function createWoff2TransformReverser(): (tag: string, transformed: Readonly<Uint8Array>, tables: ReadonlyMap<string, Uint8Array>) => Uint8Array | null;
|
|
3
|
+
export declare function decodeWoff2Triplet(code: number, glyphStream: Readonly<Uint8Array>, at: number): {
|
|
4
|
+
dx: number;
|
|
5
|
+
dy: number;
|
|
6
|
+
used: number;
|
|
7
|
+
} | null;
|
|
8
|
+
export declare function getWoff2BboxBitmapByteLength(glyphCount: number): number;
|
|
9
|
+
export declare function hasWoff2GlyphBbox(bboxStream: Readonly<Uint8Array>, glyphIndex: number): boolean;
|
|
10
|
+
export declare function isWoff2PointOnCurve(flag: number): boolean;
|
|
11
|
+
export declare function measureWoff2CompositeGlyph(compositeStream: Readonly<Uint8Array>, at: number): {
|
|
12
|
+
byteLength: number;
|
|
13
|
+
hasInstructions: boolean;
|
|
14
|
+
} | null;
|
|
15
|
+
export declare function readWoff2GlyfStreams(transformed: Readonly<Uint8Array>): Woff2GlyfStreams | null;
|
|
16
|
+
export declare function readWoff2Short(bytes: Readonly<Uint8Array>, cursor: {
|
|
17
|
+
at: number;
|
|
18
|
+
}, end: number): number;
|
|
19
|
+
export declare function reverseWoff2GlyfTransform(streams: Readonly<Woff2GlyfStreams>): {
|
|
20
|
+
glyf: Uint8Array;
|
|
21
|
+
loca: Uint8Array;
|
|
22
|
+
} | null;
|
|
23
|
+
//# sourceMappingURL=woff2GlyfTransform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"woff2GlyfTransform.d.ts","sourceRoot":"","sources":["../src/woff2GlyfTransform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AA8BjE,wBAAgB,4BAA4B,IAAI,CAC9C,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,EACjC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,KACpC,UAAU,GAAG,IAAI,CA2BrB;AAgBD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,EACjC,EAAE,EAAE,MAAM,GACT;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAsCjD;AAeD,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEvE;AASD,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAI/F;AAcD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD;AAmBD,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,QAAQ,CAAC,UAAU,CAAC,EACrC,EAAE,EAAE,MAAM,GACT;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAwBzD;AAUD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,gBAAgB,GAAG,IAAI,CA8C/F;AA2BD,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAwBvG;AAuCD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAClC;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,GAAG,IAAI,CA0G/C"}
|