@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.
Files changed (84) hide show
  1. package/dist/cffCharstring.d.ts +13 -0
  2. package/dist/cffCharstring.d.ts.map +1 -0
  3. package/dist/cffCharstring.js +336 -0
  4. package/dist/cffCharstring.js.map +1 -0
  5. package/dist/cffDict.d.ts +8 -0
  6. package/dist/cffDict.d.ts.map +1 -0
  7. package/dist/cffDict.js +118 -0
  8. package/dist/cffDict.js.map +1 -0
  9. package/dist/cffFdSelect.d.ts +2 -0
  10. package/dist/cffFdSelect.d.ts.map +1 -0
  11. package/dist/cffFdSelect.js +60 -0
  12. package/dist/cffFdSelect.js.map +1 -0
  13. package/dist/cffIndex.d.ts +3 -0
  14. package/dist/cffIndex.d.ts.map +1 -0
  15. package/dist/cffIndex.js +52 -0
  16. package/dist/cffIndex.js.map +1 -0
  17. package/dist/cffTable.d.ts +3 -0
  18. package/dist/cffTable.d.ts.map +1 -0
  19. package/dist/cffTable.js +134 -0
  20. package/dist/cffTable.js.map +1 -0
  21. package/dist/contract.d.ts +15 -0
  22. package/dist/contract.d.ts.map +1 -0
  23. package/dist/contract.js +15 -0
  24. package/dist/contract.js.map +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +2 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/openTypeCmap.d.ts +5 -0
  30. package/dist/openTypeCmap.d.ts.map +1 -0
  31. package/dist/openTypeCmap.js +161 -0
  32. package/dist/openTypeCmap.js.map +1 -0
  33. package/dist/openTypeGlyf.d.ts +4 -0
  34. package/dist/openTypeGlyf.d.ts.map +1 -0
  35. package/dist/openTypeGlyf.js +229 -0
  36. package/dist/openTypeGlyf.js.map +1 -0
  37. package/dist/openTypeGlyphOutlineSource.d.ts +4 -0
  38. package/dist/openTypeGlyphOutlineSource.d.ts.map +1 -0
  39. package/dist/openTypeGlyphOutlineSource.js +168 -0
  40. package/dist/openTypeGlyphOutlineSource.js.map +1 -0
  41. package/dist/openTypeMetrics.d.ts +6 -0
  42. package/dist/openTypeMetrics.d.ts.map +1 -0
  43. package/dist/openTypeMetrics.js +74 -0
  44. package/dist/openTypeMetrics.js.map +1 -0
  45. package/dist/openTypeTestHelper.d.ts +27 -0
  46. package/dist/openTypeTestHelper.d.ts.map +1 -0
  47. package/dist/openTypeTestHelper.js +520 -0
  48. package/dist/openTypeTestHelper.js.map +1 -0
  49. package/dist/sfntAssembly.d.ts +20 -0
  50. package/dist/sfntAssembly.d.ts.map +1 -0
  51. package/dist/sfntAssembly.js +237 -0
  52. package/dist/sfntAssembly.js.map +1 -0
  53. package/dist/sfntTableDirectory.d.ts +4 -0
  54. package/dist/sfntTableDirectory.d.ts.map +1 -0
  55. package/dist/sfntTableDirectory.js +39 -0
  56. package/dist/sfntTableDirectory.js.map +1 -0
  57. package/dist/woff2Font.d.ts +6 -0
  58. package/dist/woff2Font.d.ts.map +1 -0
  59. package/dist/woff2Font.js +210 -0
  60. package/dist/woff2Font.js.map +1 -0
  61. package/dist/woff2GlyfTransform.d.ts +23 -0
  62. package/dist/woff2GlyfTransform.d.ts.map +1 -0
  63. package/dist/woff2GlyfTransform.js +437 -0
  64. package/dist/woff2GlyfTransform.js.map +1 -0
  65. package/dist/woffFont.d.ts +6 -0
  66. package/dist/woffFont.d.ts.map +1 -0
  67. package/dist/woffFont.js +122 -0
  68. package/dist/woffFont.js.map +1 -0
  69. package/package.json +51 -0
  70. package/src/cffCharstring.test.ts +177 -0
  71. package/src/cffDict.test.ts +67 -0
  72. package/src/cffFdSelect.test.ts +84 -0
  73. package/src/cffIndex.test.ts +97 -0
  74. package/src/cffTable.test.ts +84 -0
  75. package/src/openTypeCmap.test.ts +124 -0
  76. package/src/openTypeGlyf.test.ts +168 -0
  77. package/src/openTypeGlyfWinding.test.ts +80 -0
  78. package/src/openTypeGlyphOutlineSource.test.ts +298 -0
  79. package/src/openTypeMetrics.test.ts +103 -0
  80. package/src/sfntAssembly.test.ts +228 -0
  81. package/src/sfntTableDirectory.test.ts +64 -0
  82. package/src/woff2Font.test.ts +129 -0
  83. package/src/woff2GlyfTransform.test.ts +315 -0
  84. 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"}
@@ -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":"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"}