@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,437 @@
|
|
|
1
|
+
import { encodeSfntCompositeGlyph, encodeSfntLoca, encodeSfntSimpleGlyph } from './sfntAssembly';
|
|
2
|
+
// The transformed `glyf` table: seven parallel sub-streams instead of one array of glyphs.
|
|
3
|
+
//
|
|
4
|
+
// WHY THE TRANSFORM EXISTS, WHICH IS ALSO WHY IT MUST BE REVERSED RATHER THAN DECOMPRESSED: a `glyf`
|
|
5
|
+
// table interleaves contour counts, flags, coordinates and hinting bytecode per glyph, so similar values
|
|
6
|
+
// end up far apart and compress badly. The transform SEPARATES them — every glyph's contour count in one
|
|
7
|
+
// stream, every flag in another, every coordinate in a third — so like sits beside like. It is a
|
|
8
|
+
// reordering, not a compression, and Brotli is applied over the result.
|
|
9
|
+
//
|
|
10
|
+
// So the reversal is a re-interleave: walk the streams in step and rebuild each glyph.
|
|
11
|
+
//
|
|
12
|
+
// The stream layout and header fields are interface facts about the format. The reading is Flight's own.
|
|
13
|
+
const WOFF2_GLYF_HEADER_BYTES = 36;
|
|
14
|
+
// Builds the `reverseTransform` callback `readWoff2Font` takes. Create one per font: it holds the
|
|
15
|
+
// reversal's second output between the two calls that need it, so it is not reusable across fonts.
|
|
16
|
+
//
|
|
17
|
+
// ★ ONE REVERSAL PRODUCES TWO TABLES, BUT THE SEAM ASKS FOR ONE TABLE AT A TIME. Reversing the `glyf`
|
|
18
|
+
// transform necessarily rebuilds `loca` as well — the offsets are only knowable once every record has
|
|
19
|
+
// been laid out — yet the callback is invoked once per tag. A stateless implementation would therefore
|
|
20
|
+
// walk all seven streams TWICE per font, once to answer `glyf` and again to answer `loca`, which is the
|
|
21
|
+
// most expensive part of opening the file. Holding the pair is what avoids that.
|
|
22
|
+
//
|
|
23
|
+
// A WOFF2 whose `glyf` is transformed always marks `loca` transformed too, with a transformed length of
|
|
24
|
+
// zero, because its contents are entirely derived. Asking for `loca` first is handled: the reversal runs
|
|
25
|
+
// from the `glyf` bytes in `tables` whichever tag arrives first.
|
|
26
|
+
export function createWoff2TransformReverser() {
|
|
27
|
+
let reversed = null;
|
|
28
|
+
const reverse = (glyfBytes) => {
|
|
29
|
+
if (reversed !== null)
|
|
30
|
+
return true;
|
|
31
|
+
if (glyfBytes === undefined)
|
|
32
|
+
return false;
|
|
33
|
+
const streams = readWoff2GlyfStreams(glyfBytes);
|
|
34
|
+
if (streams === null)
|
|
35
|
+
return false;
|
|
36
|
+
reversed = reverseWoff2GlyfTransform(streams);
|
|
37
|
+
return reversed !== null;
|
|
38
|
+
};
|
|
39
|
+
return (tag, transformed, tables) => {
|
|
40
|
+
if (tag === 'glyf')
|
|
41
|
+
return reverse(transformed) ? reversed.glyf : null;
|
|
42
|
+
if (tag === 'loca')
|
|
43
|
+
return reverse(tables.get('glyf')) ? reversed.loca : null;
|
|
44
|
+
// Any other transformed table is a transform this package does not implement, and refusing is what
|
|
45
|
+
// stops a font being assembled with transformed bytes under an untransformed tag.
|
|
46
|
+
//
|
|
47
|
+
// ★ THIS REFUSAL IS NOT A KNOWN GAP, AND THE DISTINCTION IS WORTH THE COMMENT. The container also
|
|
48
|
+
// defines a transform for `hmtx`, so a reader that declines it reads as incomplete against the
|
|
49
|
+
// format. In practice producers emit the `glyf`/`loca` pair and nothing else, because that pair is
|
|
50
|
+
// where the compression is; the others are permitted but unused. Implementing one would therefore
|
|
51
|
+
// add a branch no font reaches AND that no font can test — trading a loud refusal for an untested
|
|
52
|
+
// path. `censusWoff2Transforms` in the reversal oracle is what measures this, and it is the check
|
|
53
|
+
// to re-run before deciding the situation has changed.
|
|
54
|
+
return null;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// One point's coordinate delta, decoded from the flag's low seven bits and the bytes that follow it in
|
|
58
|
+
// the glyph stream. `used` is how many glyph-stream bytes this point consumed.
|
|
59
|
+
//
|
|
60
|
+
// The 128 codes partition as 10 + 10 + 64 + 36 + 4 + 4, and each block fixes a byte count, a bit width
|
|
61
|
+
// per axis, a base to add to the raw value, and a sign pair. Those are interface facts about the
|
|
62
|
+
// format — what a published format exists to state — and the decoding below is Flight's own.
|
|
63
|
+
//
|
|
64
|
+
// ★ TWO DETAILS THAT A PLAUSIBLE-LOOKING GUESS GETS WRONG, AND NEITHER FAILS LOUDLY:
|
|
65
|
+
// 1. WITHIN EVERY FOUR-CODE GROUP THE ORDER IS (-,-) (+,-) (-,+) (+,+) — so bit 0 of the group index
|
|
66
|
+
// is the X sign and bit 1 is the Y sign. Swapping them MIRRORS every diagonal delta, and a
|
|
67
|
+
// mirrored glyph is still a glyph.
|
|
68
|
+
// 2. THE 12-BIT AND 16-BIT BLOCKS ADD NO BASE. The 4-bit and 8-bit blocks add 1, 17, 33, 49 and
|
|
69
|
+
// 1, 257, 513 respectively; the two widest add nothing. An off-by-one there shifts only the
|
|
70
|
+
// largest deltas, so most glyphs still look right.
|
|
71
|
+
export function decodeWoff2Triplet(code, glyphStream, at) {
|
|
72
|
+
const used = code < 84 ? 1 : code < 120 ? 2 : code < 124 ? 3 : 4;
|
|
73
|
+
if (at + used > glyphStream.byteLength)
|
|
74
|
+
return null;
|
|
75
|
+
const b0 = glyphStream[at];
|
|
76
|
+
const b1 = glyphStream[at + 1] ?? 0;
|
|
77
|
+
const b2 = glyphStream[at + 2] ?? 0;
|
|
78
|
+
const b3 = glyphStream[at + 3] ?? 0;
|
|
79
|
+
const signX = (group) => ((group & 1) !== 0 ? 1 : -1);
|
|
80
|
+
const signY = (group) => ((group & 2) !== 0 ? 1 : -1);
|
|
81
|
+
if (code < 10)
|
|
82
|
+
return { dx: 0, dy: ((code & 1) !== 0 ? 1 : -1) * ((code >> 1) * 256 + b0), used };
|
|
83
|
+
if (code < 20) {
|
|
84
|
+
const i = code - 10;
|
|
85
|
+
return { dx: ((i & 1) !== 0 ? 1 : -1) * ((i >> 1) * 256 + b0), dy: 0, used };
|
|
86
|
+
}
|
|
87
|
+
if (code < 84) {
|
|
88
|
+
// Four bits per axis packed into one byte, X in the high nibble.
|
|
89
|
+
const i = code - 20;
|
|
90
|
+
return {
|
|
91
|
+
dx: signX(i) * (1 + (i >> 4) * 16 + (b0 >> 4)),
|
|
92
|
+
dy: signY(i) * (1 + ((i >> 2) & 3) * 16 + (b0 & 15)),
|
|
93
|
+
used,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (code < 120) {
|
|
97
|
+
const i = code - 84;
|
|
98
|
+
return {
|
|
99
|
+
dx: signX(i) * (1 + Math.floor(i / 12) * 256 + b0),
|
|
100
|
+
dy: signY(i) * (1 + Math.floor((i % 12) / 4) * 256 + b1),
|
|
101
|
+
used,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
if (code < 124) {
|
|
105
|
+
const i = code - 120;
|
|
106
|
+
return { dx: signX(i) * ((b0 << 4) | (b1 >> 4)), dy: signY(i) * (((b1 & 15) << 8) | b2), used };
|
|
107
|
+
}
|
|
108
|
+
const i = code - 124;
|
|
109
|
+
return { dx: signX(i) * ((b0 << 8) | b1), dy: signY(i) * ((b2 << 8) | b3), used };
|
|
110
|
+
}
|
|
111
|
+
// How many bytes of `bboxStream` the presence bitmap occupies, before the explicit bounding boxes
|
|
112
|
+
// begin. One bit per glyph, but the bitmap is padded to a 32-BIT boundary rather than to a byte.
|
|
113
|
+
//
|
|
114
|
+
// ★ THE PADDING IS THE WHOLE REASON THIS IS A FUNCTION AND NOT AN INLINE `>> 3`. Rounding to a byte
|
|
115
|
+
// gives the right answer whenever the glyph count happens to land in the same 4-byte cell, and the
|
|
116
|
+
// wrong answer by 1-3 bytes otherwise. Those bytes are the SEAM between the bitmap and the first
|
|
117
|
+
// bounding box, so being short by two shifts every box by one int16 — each glyph then reads three of
|
|
118
|
+
// its own values plus one belonging to its neighbour, which still looks like a plausible box.
|
|
119
|
+
//
|
|
120
|
+
// The coincidence is what makes it dangerous: a font whose glyph count rounds the same way under both
|
|
121
|
+
// rules cannot distinguish them, so byte-rounding reads such a font perfectly and the neighbouring
|
|
122
|
+
// weight of the same family not at all. Any check of this seam needs a glyph count that is NOT a
|
|
123
|
+
// multiple of 32.
|
|
124
|
+
export function getWoff2BboxBitmapByteLength(glyphCount) {
|
|
125
|
+
return 4 * Math.ceil(glyphCount / 32);
|
|
126
|
+
}
|
|
127
|
+
// Whether a glyph carries an explicit bounding box in `bboxStream`, rather than one to be computed
|
|
128
|
+
// from its points. Composite glyphs always do, since they hold no points of their own.
|
|
129
|
+
//
|
|
130
|
+
// Bit order is most-significant-first: glyph 0 is the HIGH bit of byte 0. Reading it the other way
|
|
131
|
+
// round is the more dangerous of the two mistakes, because it is neither right nor obviously wrong —
|
|
132
|
+
// the two orders agree on any byte that is symmetric, so a least-significant-first reader recovers a
|
|
133
|
+
// scattered subset of the boxes and mis-assigns the rest to the wrong glyphs.
|
|
134
|
+
export function hasWoff2GlyphBbox(bboxStream, glyphIndex) {
|
|
135
|
+
const byte = bboxStream[glyphIndex >> 3];
|
|
136
|
+
if (byte === undefined)
|
|
137
|
+
return false;
|
|
138
|
+
return (byte & (0x80 >> (glyphIndex & 7))) !== 0;
|
|
139
|
+
}
|
|
140
|
+
// Whether a point is on the curve, from its `flagStream` byte. The low seven bits are the triplet
|
|
141
|
+
// code; the high bit carries this.
|
|
142
|
+
//
|
|
143
|
+
// ★ THE SENSE IS INVERTED RELATIVE TO `glyf`, AND ASSUMING OTHERWISE IS SILENT. In an sfnt `glyf`
|
|
144
|
+
// table the on-curve flag is bit 0 SET meaning on-curve. Here the high bit SET means the point is
|
|
145
|
+
// OFF the curve, and CLEAR means on-curve. Anyone carrying the `glyf` convention across will invert
|
|
146
|
+
// every point in the font — and an inverted outline still draws a glyph, with corners where curves
|
|
147
|
+
// belong, so nothing fails loudly. Same silent class as the sign order and the missing base above.
|
|
148
|
+
//
|
|
149
|
+
// The mistake is unfalsifiable by eye, which is why the sense is pinned by a named function rather
|
|
150
|
+
// than an inline mask: an outline with every on/off decision inverted is still a closed, plausible
|
|
151
|
+
// outline, so it renders as a glyph rather than as damage.
|
|
152
|
+
export function isWoff2PointOnCurve(flag) {
|
|
153
|
+
return (flag & WOFF2_POINT_OFF_CURVE) === 0;
|
|
154
|
+
}
|
|
155
|
+
// How many `compositeStream` bytes one composite glyph's component records occupy, and whether any
|
|
156
|
+
// component asks for hinting instructions. Returns the null sentinel when the records run past the end
|
|
157
|
+
// of the stream.
|
|
158
|
+
//
|
|
159
|
+
// A composite glyph names other glyphs and places them, so it carries no points of its own — which is
|
|
160
|
+
// why a reversal walking the streams is tempted to skip it entirely.
|
|
161
|
+
//
|
|
162
|
+
// ★ SKIPPING IT DESYNCHRONISES THE GLYPH STREAM, AND NOT THROUGH THE STREAM YOU WOULD EXPECT. A
|
|
163
|
+
// composite consumes no points, so the flag and point streams are genuinely untouched. But when any
|
|
164
|
+
// component sets `WE_HAVE_INSTRUCTIONS`, the glyph's instruction length is stored in the GLYPH stream,
|
|
165
|
+
// exactly as a simple glyph's is. Miss that read and every SIMPLE glyph after this one decodes from a
|
|
166
|
+
// position one length-field too early — so the failure surfaces far from its cause, in glyphs that are
|
|
167
|
+
// themselves fine, and the first symptom is usually a decoded outline that overruns the font's own
|
|
168
|
+
// declared bounding box.
|
|
169
|
+
//
|
|
170
|
+
// `hasInstructions` is therefore the field a caller must not ignore; `byteLength` alone looks like the
|
|
171
|
+
// complete answer and is not.
|
|
172
|
+
export function measureWoff2CompositeGlyph(compositeStream, at) {
|
|
173
|
+
const start = at;
|
|
174
|
+
let cursor = at;
|
|
175
|
+
let hasInstructions = false;
|
|
176
|
+
let more = true;
|
|
177
|
+
while (more) {
|
|
178
|
+
// Flags and glyph index, then the placement arguments and the optional transform.
|
|
179
|
+
if (cursor + 4 > compositeStream.byteLength)
|
|
180
|
+
return null;
|
|
181
|
+
const flags = (compositeStream[cursor] << 8) | compositeStream[cursor + 1];
|
|
182
|
+
cursor += 4;
|
|
183
|
+
cursor += (flags & WOFF2_COMPONENT_ARGS_ARE_WORDS) !== 0 ? 4 : 2;
|
|
184
|
+
// The three transform forms are mutually exclusive, widest first: a single scale, one per axis, or
|
|
185
|
+
// a full 2x2. Adding them instead of choosing would overcount every transformed component.
|
|
186
|
+
if ((flags & WOFF2_COMPONENT_HAS_SCALE) !== 0)
|
|
187
|
+
cursor += 2;
|
|
188
|
+
else if ((flags & WOFF2_COMPONENT_HAS_XY_SCALE) !== 0)
|
|
189
|
+
cursor += 4;
|
|
190
|
+
else if ((flags & WOFF2_COMPONENT_HAS_TWO_BY_TWO) !== 0)
|
|
191
|
+
cursor += 8;
|
|
192
|
+
if ((flags & WOFF2_COMPONENT_HAS_INSTRUCTIONS) !== 0)
|
|
193
|
+
hasInstructions = true;
|
|
194
|
+
more = (flags & WOFF2_COMPONENT_MORE_COMPONENTS) !== 0;
|
|
195
|
+
}
|
|
196
|
+
if (cursor > compositeStream.byteLength)
|
|
197
|
+
return null;
|
|
198
|
+
return { byteLength: cursor - start, hasInstructions };
|
|
199
|
+
}
|
|
200
|
+
// Carves the seven sub-streams out of a transformed `glyf` table. Returns the null sentinel when the
|
|
201
|
+
// declared sizes do not fit the table, rather than clamped streams: a stream that is short by a few bytes
|
|
202
|
+
// still decodes into real-looking contour counts and coordinates, so a partial carve is the silent-
|
|
203
|
+
// wrongness case rather than a visible one.
|
|
204
|
+
//
|
|
205
|
+
// Kept separate from the re-interleave so the split is checkable on its own — the seven sizes plus the
|
|
206
|
+
// header must account for the table exactly, which is a property a real font can be tested against
|
|
207
|
+
// without reconstructing a single glyph.
|
|
208
|
+
export function readWoff2GlyfStreams(transformed) {
|
|
209
|
+
if (transformed.byteLength < WOFF2_GLYF_HEADER_BYTES)
|
|
210
|
+
return null;
|
|
211
|
+
const view = new DataView(transformed.buffer, transformed.byteOffset, transformed.byteLength);
|
|
212
|
+
const glyphCount = view.getUint16(4);
|
|
213
|
+
const indexFormat = view.getUint16(6);
|
|
214
|
+
const sizes = [];
|
|
215
|
+
for (let index = 0; index < 7; index += 1)
|
|
216
|
+
sizes.push(view.getUint32(8 + index * 4));
|
|
217
|
+
let total = WOFF2_GLYF_HEADER_BYTES;
|
|
218
|
+
for (const size of sizes)
|
|
219
|
+
total += size;
|
|
220
|
+
// The sizes must account for the table exactly. A table longer than its streams claim carries bytes
|
|
221
|
+
// nothing will read; one shorter means at least one stream is truncated.
|
|
222
|
+
if (total !== transformed.byteLength)
|
|
223
|
+
return null;
|
|
224
|
+
let at = WOFF2_GLYF_HEADER_BYTES;
|
|
225
|
+
const slice = (size) => {
|
|
226
|
+
const part = transformed.subarray(at, at + size);
|
|
227
|
+
at += size;
|
|
228
|
+
return part;
|
|
229
|
+
};
|
|
230
|
+
// Carved into locals in STREAM order before the object is built. The returned fields are alphabetized
|
|
231
|
+
// to match the rest of the package, and object literal properties evaluate in source order — so
|
|
232
|
+
// slicing inside the literal would consume the streams alphabetically and hand every field the right
|
|
233
|
+
// LENGTH with the wrong BYTES. Lengths alone cannot see that, which is why the order lives here.
|
|
234
|
+
const nContourStream = slice(sizes[0]);
|
|
235
|
+
const nPointsStream = slice(sizes[1]);
|
|
236
|
+
const flagStream = slice(sizes[2]);
|
|
237
|
+
const glyphStream = slice(sizes[3]);
|
|
238
|
+
const compositeStream = slice(sizes[4]);
|
|
239
|
+
const bboxStream = slice(sizes[5]);
|
|
240
|
+
const instructionStream = slice(sizes[6]);
|
|
241
|
+
return {
|
|
242
|
+
bboxStream,
|
|
243
|
+
compositeStream,
|
|
244
|
+
flagStream,
|
|
245
|
+
glyphCount,
|
|
246
|
+
glyphStream,
|
|
247
|
+
indexFormat,
|
|
248
|
+
instructionStream,
|
|
249
|
+
nContourStream,
|
|
250
|
+
nPointsStream,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// The high bit of a `flagStream` byte. Named rather than inlined because the value is unremarkable
|
|
254
|
+
// and the SENSE is not: set means off-curve, which is the opposite of the `glyf` convention.
|
|
255
|
+
const WOFF2_POINT_OFF_CURVE = 0x80;
|
|
256
|
+
// Composite component flags. These are interface facts about the `glyf` format, which a composite
|
|
257
|
+
// glyph's records are written in unchanged — the transform reorders whole glyphs, it does not re-encode
|
|
258
|
+
// a component record.
|
|
259
|
+
const WOFF2_COMPONENT_ARGS_ARE_WORDS = 0x0001;
|
|
260
|
+
const WOFF2_COMPONENT_HAS_INSTRUCTIONS = 0x0100;
|
|
261
|
+
const WOFF2_COMPONENT_HAS_SCALE = 0x0008;
|
|
262
|
+
const WOFF2_COMPONENT_HAS_TWO_BY_TWO = 0x0080;
|
|
263
|
+
const WOFF2_COMPONENT_HAS_XY_SCALE = 0x0040;
|
|
264
|
+
const WOFF2_COMPONENT_MORE_COMPONENTS = 0x0020;
|
|
265
|
+
const WOFF2_SHORT_WORD = 253;
|
|
266
|
+
const WOFF2_SHORT_ONE_MORE_BYTE_2 = 254;
|
|
267
|
+
const WOFF2_SHORT_ONE_MORE_BYTE_1 = 255;
|
|
268
|
+
const WOFF2_SHORT_LOWEST = 253;
|
|
269
|
+
// 255UInt16: a variable-length count used for point-per-contour and instruction lengths. Three escape
|
|
270
|
+
// codes extend a single byte's range, and reading one with the wrong escape yields a plausible small
|
|
271
|
+
// number rather than an error — which is why the codes are named rather than inlined.
|
|
272
|
+
//
|
|
273
|
+
// Advances `cursor.at`. Returns -1 when the value runs past `end`, so a caller can refuse rather than
|
|
274
|
+
// treat a truncated stream as a short glyph.
|
|
275
|
+
export function readWoff2Short(bytes, cursor, end) {
|
|
276
|
+
if (cursor.at >= end)
|
|
277
|
+
return -1;
|
|
278
|
+
const code = bytes[cursor.at];
|
|
279
|
+
cursor.at += 1;
|
|
280
|
+
if (code === WOFF2_SHORT_WORD) {
|
|
281
|
+
if (cursor.at + 2 > end)
|
|
282
|
+
return -1;
|
|
283
|
+
const value = (bytes[cursor.at] << 8) | bytes[cursor.at + 1];
|
|
284
|
+
cursor.at += 2;
|
|
285
|
+
return value;
|
|
286
|
+
}
|
|
287
|
+
if (code === WOFF2_SHORT_ONE_MORE_BYTE_2) {
|
|
288
|
+
if (cursor.at >= end)
|
|
289
|
+
return -1;
|
|
290
|
+
const value = bytes[cursor.at] + WOFF2_SHORT_LOWEST * 2;
|
|
291
|
+
cursor.at += 1;
|
|
292
|
+
return value;
|
|
293
|
+
}
|
|
294
|
+
if (code === WOFF2_SHORT_ONE_MORE_BYTE_1) {
|
|
295
|
+
if (cursor.at >= end)
|
|
296
|
+
return -1;
|
|
297
|
+
const value = bytes[cursor.at] + WOFF2_SHORT_LOWEST;
|
|
298
|
+
cursor.at += 1;
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
return code;
|
|
302
|
+
}
|
|
303
|
+
const EMPTY_BYTES = new Uint8Array(0);
|
|
304
|
+
function measurePointBounds(xs, ys) {
|
|
305
|
+
let xMax = xs[0] ?? 0;
|
|
306
|
+
let xMin = xs[0] ?? 0;
|
|
307
|
+
let yMax = ys[0] ?? 0;
|
|
308
|
+
let yMin = ys[0] ?? 0;
|
|
309
|
+
for (let index = 1; index < xs.length; index += 1) {
|
|
310
|
+
if (xs[index] < xMin)
|
|
311
|
+
xMin = xs[index];
|
|
312
|
+
if (xs[index] > xMax)
|
|
313
|
+
xMax = xs[index];
|
|
314
|
+
if (ys[index] < yMin)
|
|
315
|
+
yMin = ys[index];
|
|
316
|
+
if (ys[index] > yMax)
|
|
317
|
+
yMax = ys[index];
|
|
318
|
+
}
|
|
319
|
+
return { xMax, xMin, yMax, yMin };
|
|
320
|
+
}
|
|
321
|
+
function padToEven(record) {
|
|
322
|
+
if (record.byteLength % 2 === 0)
|
|
323
|
+
return record;
|
|
324
|
+
const padded = new Uint8Array(record.byteLength + 1);
|
|
325
|
+
padded.set(record);
|
|
326
|
+
return padded;
|
|
327
|
+
}
|
|
328
|
+
// Re-interleaves the seven sub-streams back into a `glyf` table and the `loca` that indexes it. This is
|
|
329
|
+
// the reversal the whole transform exists to be undone by: every other export here reads one piece, and
|
|
330
|
+
// this walks them in step.
|
|
331
|
+
//
|
|
332
|
+
// Returns the null sentinel the moment any stream runs short, rather than a partial table. A truncated
|
|
333
|
+
// walk yields real-looking glyphs for every index before the break, so a partial result is the silent
|
|
334
|
+
// failure and a refusal is the visible one.
|
|
335
|
+
//
|
|
336
|
+
// ★ EVERY RECORD IS PADDED TO AN EVEN LENGTH, AND THAT IS CORRECTNESS RATHER THAN TIDINESS. With the
|
|
337
|
+
// short `loca` format each offset is stored halved, so an odd offset cannot be represented; see
|
|
338
|
+
// `encodeSfntLoca`, which refuses rather than truncating.
|
|
339
|
+
export function reverseWoff2GlyfTransform(streams) {
|
|
340
|
+
if (streams.nContourStream.byteLength < streams.glyphCount * 2)
|
|
341
|
+
return null;
|
|
342
|
+
const contourView = new DataView(streams.nContourStream.buffer, streams.nContourStream.byteOffset, streams.nContourStream.byteLength);
|
|
343
|
+
const points = { at: 0 };
|
|
344
|
+
const glyph = { at: 0 };
|
|
345
|
+
let compositeAt = 0;
|
|
346
|
+
let flagAt = 0;
|
|
347
|
+
let instructionAt = 0;
|
|
348
|
+
let bboxAt = getWoff2BboxBitmapByteLength(streams.glyphCount);
|
|
349
|
+
const records = [];
|
|
350
|
+
for (let index = 0; index < streams.glyphCount; index += 1) {
|
|
351
|
+
const contours = contourView.getInt16(index * 2);
|
|
352
|
+
// A glyph carrying an explicit box consumes one from the stream whether or not it needs it, so the
|
|
353
|
+
// read happens here rather than only where a box is wanted.
|
|
354
|
+
let stored = null;
|
|
355
|
+
if (hasWoff2GlyphBbox(streams.bboxStream, index)) {
|
|
356
|
+
if (bboxAt + 8 > streams.bboxStream.byteLength)
|
|
357
|
+
return null;
|
|
358
|
+
const box = new DataView(streams.bboxStream.buffer, streams.bboxStream.byteOffset + bboxAt, 8);
|
|
359
|
+
stored = { xMax: box.getInt16(4), xMin: box.getInt16(0), yMax: box.getInt16(6), yMin: box.getInt16(2) };
|
|
360
|
+
bboxAt += 8;
|
|
361
|
+
}
|
|
362
|
+
if (contours === 0) {
|
|
363
|
+
records.push(EMPTY_BYTES);
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
if (contours < 0) {
|
|
367
|
+
const measured = measureWoff2CompositeGlyph(streams.compositeStream, compositeAt);
|
|
368
|
+
// A composite cannot compute its own box, so a missing one is unrecoverable rather than a default.
|
|
369
|
+
if (measured === null || stored === null)
|
|
370
|
+
return null;
|
|
371
|
+
const components = streams.compositeStream.subarray(compositeAt, compositeAt + measured.byteLength);
|
|
372
|
+
compositeAt += measured.byteLength;
|
|
373
|
+
let instructions = EMPTY_BYTES;
|
|
374
|
+
if (measured.hasInstructions) {
|
|
375
|
+
const length = readWoff2Short(streams.glyphStream, glyph, streams.glyphStream.byteLength);
|
|
376
|
+
if (length < 0 || instructionAt + length > streams.instructionStream.byteLength)
|
|
377
|
+
return null;
|
|
378
|
+
instructions = streams.instructionStream.subarray(instructionAt, instructionAt + length);
|
|
379
|
+
instructionAt += length;
|
|
380
|
+
}
|
|
381
|
+
records.push(padToEven(encodeSfntCompositeGlyph(components, instructions, stored, measured.hasInstructions)));
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const endPtsOfContours = [];
|
|
385
|
+
let pointCount = 0;
|
|
386
|
+
for (let contour = 0; contour < contours; contour += 1) {
|
|
387
|
+
const count = readWoff2Short(streams.nPointsStream, points, streams.nPointsStream.byteLength);
|
|
388
|
+
if (count < 0)
|
|
389
|
+
return null;
|
|
390
|
+
pointCount += count;
|
|
391
|
+
endPtsOfContours.push(pointCount - 1);
|
|
392
|
+
}
|
|
393
|
+
if (flagAt + pointCount > streams.flagStream.byteLength)
|
|
394
|
+
return null;
|
|
395
|
+
const xs = [];
|
|
396
|
+
const ys = [];
|
|
397
|
+
const onCurve = [];
|
|
398
|
+
let x = 0;
|
|
399
|
+
let y = 0;
|
|
400
|
+
for (let point = 0; point < pointCount; point += 1) {
|
|
401
|
+
const flag = streams.flagStream[flagAt + point];
|
|
402
|
+
const delta = decodeWoff2Triplet(flag & 0x7f, streams.glyphStream, glyph.at);
|
|
403
|
+
if (delta === null)
|
|
404
|
+
return null;
|
|
405
|
+
glyph.at += delta.used;
|
|
406
|
+
x += delta.dx;
|
|
407
|
+
y += delta.dy;
|
|
408
|
+
xs.push(x);
|
|
409
|
+
ys.push(y);
|
|
410
|
+
onCurve.push(isWoff2PointOnCurve(flag));
|
|
411
|
+
}
|
|
412
|
+
flagAt += pointCount;
|
|
413
|
+
const instructionLength = readWoff2Short(streams.glyphStream, glyph, streams.glyphStream.byteLength);
|
|
414
|
+
if (instructionLength < 0 || instructionAt + instructionLength > streams.instructionStream.byteLength)
|
|
415
|
+
return null;
|
|
416
|
+
const instructions = streams.instructionStream.subarray(instructionAt, instructionAt + instructionLength);
|
|
417
|
+
instructionAt += instructionLength;
|
|
418
|
+
// A simple glyph without a stored box gets one measured from its own points, which is the only
|
|
419
|
+
// place the box can come from once the transform has dropped it.
|
|
420
|
+
const bounds = stored ?? measurePointBounds(xs, ys);
|
|
421
|
+
records.push(padToEven(encodeSfntSimpleGlyph(endPtsOfContours, xs, ys, onCurve, instructions, bounds)));
|
|
422
|
+
}
|
|
423
|
+
const loca = encodeSfntLoca(records.map((record) => record.byteLength), streams.indexFormat);
|
|
424
|
+
if (loca === null)
|
|
425
|
+
return null;
|
|
426
|
+
let total = 0;
|
|
427
|
+
for (const record of records)
|
|
428
|
+
total += record.byteLength;
|
|
429
|
+
const glyf = new Uint8Array(total);
|
|
430
|
+
let at = 0;
|
|
431
|
+
for (const record of records) {
|
|
432
|
+
glyf.set(record, at);
|
|
433
|
+
at += record.byteLength;
|
|
434
|
+
}
|
|
435
|
+
return { glyf, loca };
|
|
436
|
+
}
|
|
437
|
+
//# sourceMappingURL=woff2GlyfTransform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"woff2GlyfTransform.js","sourceRoot":"","sources":["../src/woff2GlyfTransform.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Decompressor, ImportDiagnostic, WoffChecksumMismatch } from '@flighthq/types/contract';
|
|
2
|
+
import { Compression } from '@flighthq/types/contract';
|
|
3
|
+
export declare function readWoffChecksumMismatches(bytes: Readonly<Uint8Array>, decompress: Decompressor | null): readonly WoffChecksumMismatch[];
|
|
4
|
+
export declare const WOFF_COMPRESSION: Compression;
|
|
5
|
+
export declare function readWoffFont(bytes: Readonly<Uint8Array>, decompress: Decompressor | null, diagnostics?: ImportDiagnostic[]): Uint8Array | null;
|
|
6
|
+
//# sourceMappingURL=woffFont.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"woffFont.d.ts","sourceRoot":"","sources":["../src/woffFont.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrG,OAAO,EAAE,WAAW,EAAgD,MAAM,0BAA0B,CAAC;AA8BrG,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,UAAU,EAAE,YAAY,GAAG,IAAI,GAC9B,SAAS,oBAAoB,EAAE,CAgCjC;AAID,eAAO,MAAM,gBAAgB,EAAE,WAAiC,CAAC;AAKjE,wBAAgB,YAAY,CAC1B,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,WAAW,CAAC,EAAE,gBAAgB,EAAE,GAC/B,UAAU,GAAG,IAAI,CAmEnB"}
|
package/dist/woffFont.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { reportImportDiagnostic } from '@flighthq/importdiagnostics/contract';
|
|
2
|
+
import { Compression, CompressionFraming, ImportDiagnosticSeverity } from '@flighthq/types/contract';
|
|
3
|
+
import { assembleSfntFont, computeSfntTableChecksum } from './sfntAssembly';
|
|
4
|
+
// WOFF is a wrapper, not a font format: the same sfnt tables, each optionally deflated, behind a header
|
|
5
|
+
// that says where they went. So the whole job is to REBUILD THE SFNT and hand it to the reader that
|
|
6
|
+
// already exists — no new outline code, no new seam, and `glyf`, `CFF ` and CID all work through it
|
|
7
|
+
// unchanged because they never learn the bytes arrived wrapped.
|
|
8
|
+
//
|
|
9
|
+
// The container layout is an interface fact about the format. The reconstruction is Flight's own.
|
|
10
|
+
//
|
|
11
|
+
// ★ THE DECOMPRESSOR IS NOT BUNDLED HERE, DELIBERATELY. It is fetched from `@flighthq/compression`'s
|
|
12
|
+
// registry, which a caller opts into with `registerDeflateDecompressor()`. Importing the codec directly
|
|
13
|
+
// would drag DEFLATE into every bundle that reads a `.ttf`, which is the bundle invariant this repository
|
|
14
|
+
// enforces — an assembly never inflates the bundle cost of a primitive. The cost of that choice is that
|
|
15
|
+
// an unregistered decompressor is a real outcome, so it gets its own reported reason rather than being
|
|
16
|
+
// folded into "unsupported container".
|
|
17
|
+
const WOFF_HEADER_BYTES = 44;
|
|
18
|
+
const WOFF_DIRECTORY_ENTRY_BYTES = 20;
|
|
19
|
+
// Which tables' stored checksums disagree with their own bytes. Returns an empty array when every
|
|
20
|
+
// table agrees, and for a container this reader cannot open at all — a caller distinguishes those by
|
|
21
|
+
// whether `readWoffFont` returned a font.
|
|
22
|
+
//
|
|
23
|
+
// ★ REPORTED, NEVER ENFORCED. A mismatch is bad data rather than API misuse, so it takes a sentinel
|
|
24
|
+
// and not a throw, and the font still loads: deciding that a font is unacceptable belongs to the
|
|
25
|
+
// caller, and a reader that refused one which would otherwise work would have taken that decision
|
|
26
|
+
// away with no way to opt out. Kept as a separate query so a caller who never asks does not link the
|
|
27
|
+
// arithmetic — the same shape as `explainOpenTypeFont`, for the same reason.
|
|
28
|
+
export function readWoffChecksumMismatches(bytes, decompress) {
|
|
29
|
+
if (bytes.byteLength < WOFF_HEADER_BYTES)
|
|
30
|
+
return [];
|
|
31
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
32
|
+
const tableCount = view.getUint16(12);
|
|
33
|
+
const directoryEnd = WOFF_HEADER_BYTES + tableCount * WOFF_DIRECTORY_ENTRY_BYTES;
|
|
34
|
+
if (tableCount === 0 || directoryEnd > bytes.byteLength)
|
|
35
|
+
return [];
|
|
36
|
+
const mismatches = [];
|
|
37
|
+
for (let index = 0; index < tableCount; index += 1) {
|
|
38
|
+
const record = WOFF_HEADER_BYTES + index * WOFF_DIRECTORY_ENTRY_BYTES;
|
|
39
|
+
const tag = view.getUint32(record);
|
|
40
|
+
const offset = view.getUint32(record + 4);
|
|
41
|
+
const compressedLength = view.getUint32(record + 8);
|
|
42
|
+
const originalLength = view.getUint32(record + 12);
|
|
43
|
+
const stored = view.getUint32(record + 16);
|
|
44
|
+
if (offset + compressedLength > bytes.byteLength)
|
|
45
|
+
continue;
|
|
46
|
+
const raw = bytes.subarray(offset, offset + compressedLength);
|
|
47
|
+
let data = raw;
|
|
48
|
+
if (compressedLength !== originalLength) {
|
|
49
|
+
if (decompress === null)
|
|
50
|
+
continue;
|
|
51
|
+
data = decompress(raw, originalLength, CompressionFraming.Rfc1950);
|
|
52
|
+
if (data === null || data.byteLength !== originalLength)
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const computed = computeSfntTableChecksum(data, tag === HEAD_TAG);
|
|
56
|
+
if (computed !== stored) {
|
|
57
|
+
mismatches.push({ computed, stored, tag: readWoffTagText(view, record) });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return mismatches;
|
|
61
|
+
}
|
|
62
|
+
// The compression this container uses. Named through the shared vocabulary rather than a local constant so
|
|
63
|
+
// a caller registering a codec and this module asking for one cannot drift apart.
|
|
64
|
+
export const WOFF_COMPRESSION = Compression.Deflate;
|
|
65
|
+
// Rebuilds the plain sfnt a WOFF wraps. Returns the null sentinel for a malformed container, and for a
|
|
66
|
+
// deflated table when no decompressor is registered — the caller distinguishes those through
|
|
67
|
+
// `explainOpenTypeFont`, since one wants a repaired file and the other wants one line of registration.
|
|
68
|
+
export function readWoffFont(bytes, decompress, diagnostics) {
|
|
69
|
+
if (bytes.byteLength < WOFF_HEADER_BYTES)
|
|
70
|
+
return null;
|
|
71
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
72
|
+
const tableCount = view.getUint16(12);
|
|
73
|
+
if (tableCount === 0)
|
|
74
|
+
return null;
|
|
75
|
+
const directoryEnd = WOFF_HEADER_BYTES + tableCount * WOFF_DIRECTORY_ENTRY_BYTES;
|
|
76
|
+
if (directoryEnd > bytes.byteLength)
|
|
77
|
+
return null;
|
|
78
|
+
// The wrapper carries the sfnt version the tables belonged to, so the rebuilt font declares the flavor
|
|
79
|
+
// it actually is rather than one inferred from which tables happen to be present.
|
|
80
|
+
const flavor = view.getUint32(4);
|
|
81
|
+
const tables = [];
|
|
82
|
+
for (let index = 0; index < tableCount; index += 1) {
|
|
83
|
+
const record = WOFF_HEADER_BYTES + index * WOFF_DIRECTORY_ENTRY_BYTES;
|
|
84
|
+
const tag = view.getUint32(record);
|
|
85
|
+
const offset = view.getUint32(record + 4);
|
|
86
|
+
const compressedLength = view.getUint32(record + 8);
|
|
87
|
+
const originalLength = view.getUint32(record + 12);
|
|
88
|
+
if (offset + compressedLength > bytes.byteLength)
|
|
89
|
+
return null;
|
|
90
|
+
const stored = bytes.subarray(offset, offset + compressedLength);
|
|
91
|
+
// A table is stored uncompressed when the two lengths match — the format's own way of saying
|
|
92
|
+
// "compressing this one did not pay", so it is a normal case rather than an edge one.
|
|
93
|
+
if (compressedLength === originalLength) {
|
|
94
|
+
tables.push({ data: stored, tag });
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (decompress === null) {
|
|
98
|
+
reportImportDiagnostic(diagnostics, ImportDiagnosticSeverity.Reject, 'woff.no-decompressor-registered', 'readWoffFont', { table: readWoffTagText(view, record) });
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const inflated = decompress(stored, originalLength, CompressionFraming.Rfc1950);
|
|
102
|
+
// A decompressor that returns the wrong length has produced something that is not this table, and
|
|
103
|
+
// reassembling it would yield a font whose directory lengths lie about its own contents.
|
|
104
|
+
if (inflated === null || inflated.byteLength !== originalLength) {
|
|
105
|
+
reportImportDiagnostic(diagnostics, ImportDiagnosticSeverity.Reject, 'woff.decompression-failed', 'readWoffFont', {
|
|
106
|
+
compressedLength,
|
|
107
|
+
originalLength,
|
|
108
|
+
outputLength: inflated?.byteLength ?? -1,
|
|
109
|
+
table: readWoffTagText(view, record),
|
|
110
|
+
});
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
tables.push({ data: inflated, tag });
|
|
114
|
+
}
|
|
115
|
+
return assembleSfntFont(flavor, tables);
|
|
116
|
+
}
|
|
117
|
+
// The four-character tag as text, for a caller that will show it or key on it.
|
|
118
|
+
function readWoffTagText(view, record) {
|
|
119
|
+
return String.fromCharCode(view.getUint8(record), view.getUint8(record + 1), view.getUint8(record + 2), view.getUint8(record + 3));
|
|
120
|
+
}
|
|
121
|
+
const HEAD_TAG = 0x68656164;
|
|
122
|
+
//# sourceMappingURL=woffFont.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"woffFont.js","sourceRoot":"","sources":["../src/woffFont.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAE9E,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAErG,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAE5E,wGAAwG;AACxG,oGAAoG;AACpG,oGAAoG;AACpG,gEAAgE;AAChE,EAAE;AACF,kGAAkG;AAClG,EAAE;AACF,qGAAqG;AACrG,wGAAwG;AACxG,0GAA0G;AAC1G,wGAAwG;AACxG,uGAAuG;AACvG,uCAAuC;AAEvC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAEtC,kGAAkG;AAClG,qGAAqG;AACrG,0CAA0C;AAC1C,EAAE;AACF,oGAAoG;AACpG,iGAAiG;AACjG,kGAAkG;AAClG,qGAAqG;AACrG,6EAA6E;AAC7E,MAAM,UAAU,0BAA0B,CACxC,KAA2B,EAC3B,UAA+B;IAE/B,IAAI,KAAK,CAAC,UAAU,GAAG,iBAAiB;QAAE,OAAO,EAAE,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAE5E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACtC,MAAM,YAAY,GAAG,iBAAiB,GAAG,UAAU,GAAG,0BAA0B,CAAC;IACjF,IAAI,UAAU,KAAK,CAAC,IAAI,YAAY,GAAG,KAAK,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IAEnE,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,iBAAiB,GAAG,KAAK,GAAG,0BAA0B,CAAC;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QAC3C,IAAI,MAAM,GAAG,gBAAgB,GAAG,KAAK,CAAC,UAAU;YAAE,SAAS;QAE3D,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC;QAC9D,IAAI,IAAI,GAAsB,GAAiB,CAAC;QAChD,IAAI,gBAAgB,KAAK,cAAc,EAAE,CAAC;YACxC,IAAI,UAAU,KAAK,IAAI;gBAAE,SAAS;YAClC,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACnE,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,cAAc;gBAAE,SAAS;QACpE,CAAC;QAED,MAAM,QAAQ,GAAG,wBAAwB,CAAC,IAAI,EAAE,GAAG,KAAK,QAAQ,CAAC,CAAC;QAClE,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,UAAU,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,2GAA2G;AAC3G,kFAAkF;AAClF,MAAM,CAAC,MAAM,gBAAgB,GAAgB,WAAW,CAAC,OAAO,CAAC;AAEjE,uGAAuG;AACvG,6FAA6F;AAC7F,uGAAuG;AACvG,MAAM,UAAU,YAAY,CAC1B,KAA2B,EAC3B,UAA+B,EAC/B,WAAgC;IAEhC,IAAI,KAAK,CAAC,UAAU,GAAG,iBAAiB;QAAE,OAAO,IAAI,CAAC;IACtD,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAE5E,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACtC,IAAI,UAAU,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,YAAY,GAAG,iBAAiB,GAAG,UAAU,GAAG,0BAA0B,CAAC;IACjF,IAAI,YAAY,GAAG,KAAK,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAEjD,uGAAuG;IACvG,kFAAkF;IAClF,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAMjC,MAAM,MAAM,GAAgB,EAAE,CAAC;IAE/B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,iBAAiB,GAAG,KAAK,GAAG,0BAA0B,CAAC;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;QACnD,IAAI,MAAM,GAAG,gBAAgB,GAAG,KAAK,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAE9D,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,CAAC,CAAC;QACjE,6FAA6F;QAC7F,sFAAsF;QACtF,IAAI,gBAAgB,KAAK,cAAc,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;YACjD,SAAS;QACX,CAAC;QAED,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,sBAAsB,CACpB,WAAW,EACX,wBAAwB,CAAC,MAAM,EAC/B,iCAAiC,EACjC,cAAc,EACd,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CACzC,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAChF,kGAAkG;QAClG,yFAAyF;QACzF,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,KAAK,cAAc,EAAE,CAAC;YAChE,sBAAsB,CACpB,WAAW,EACX,wBAAwB,CAAC,MAAM,EAC/B,2BAA2B,EAC3B,cAAc,EACd;gBACE,gBAAgB;gBAChB,cAAc;gBACd,YAAY,EAAE,QAAQ,EAAE,UAAU,IAAI,CAAC,CAAC;gBACxC,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC;aACrC,CACF,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC;AAED,+EAA+E;AAC/E,SAAS,eAAe,CAAC,IAAwB,EAAE,MAAc;IAC/D,OAAO,MAAM,CAAC,YAAY,CACxB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EACzB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,EACzB,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAC1B,CAAC;AACJ,CAAC;AAED,MAAM,QAAQ,GAAG,UAAU,CAAC"}
|