@flighthq/font-formats 0.3.1-next.209.43ef1bc

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 (83) 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 +26 -0
  46. package/dist/openTypeTestHelper.d.ts.map +1 -0
  47. package/dist/openTypeTestHelper.js +494 -0
  48. package/dist/openTypeTestHelper.js.map +1 -0
  49. package/dist/sfntAssembly.d.ts +7 -0
  50. package/dist/sfntAssembly.d.ts.map +1 -0
  51. package/dist/sfntAssembly.js +77 -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 +6 -0
  62. package/dist/woff2GlyfTransform.d.ts.map +1 -0
  63. package/dist/woff2GlyfTransform.js +104 -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 +112 -0
  68. package/dist/woffFont.js.map +1 -0
  69. package/package.json +50 -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/openTypeGlyphOutlineSource.test.ts +298 -0
  78. package/src/openTypeMetrics.test.ts +103 -0
  79. package/src/sfntAssembly.test.ts +92 -0
  80. package/src/sfntTableDirectory.test.ts +64 -0
  81. package/src/woff2Font.test.ts +125 -0
  82. package/src/woff2GlyfTransform.test.ts +88 -0
  83. package/src/woffFont.test.ts +167 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cffIndex.js","sourceRoot":"","sources":["../src/cffIndex.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,EAAE;AACF,uGAAuG;AACvG,iGAAiG;AACjG,yGAAyG;AACzG,EAAE;AACF,6EAA6E;AAC7E,EAAE;AACF,qGAAqG;AACrG,yGAAyG;AAEzG,yGAAyG;AACzG,wGAAwG;AACxG,iEAAiE;AACjE,MAAM,UAAU,YAAY,CAAC,KAA2B,EAAE,MAAc;IACtE,IAAI,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC/C,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAErC,qGAAqG;IACrG,qFAAqF;IACrF,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAE/D,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1C,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5C,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,SAAS,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;IACrD,IAAI,MAAM,IAAI,KAAK,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE5C,MAAM,UAAU,GAAG,CAAC,KAAa,EAAU,EAAE;QAC3C,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,CAAC;YAC1C,KAAK,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,IAAI,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC7B,uGAAuG;IACvG,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEhC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACnC,oGAAoG;QACpG,gGAAgG;QAChG,IAAI,IAAI,GAAG,QAAQ,IAAI,MAAM,GAAG,IAAI,GAAG,KAAK,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC;QAC/D,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE,OAAO,EAAE,CAAC;AACnD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CffTable, SfntTableDirectory } from '@flighthq/types/contract';
2
+ export declare function readCffTable(bytes: Readonly<Uint8Array>, directory: Readonly<SfntTableDirectory>): CffTable | null;
3
+ //# sourceMappingURL=cffTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cffTable.d.ts","sourceRoot":"","sources":["../src/cffTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,QAAQ,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAoG5F,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,QAAQ,GAAG,IAAI,CAmDlH"}
@@ -0,0 +1,134 @@
1
+ import { CFF_OPERATOR_CHARSTRINGS, CFF_OPERATOR_FD_ARRAY, CFF_OPERATOR_FD_SELECT, CFF_OPERATOR_PRIVATE, CFF_OPERATOR_SUBRS, readCffDict, } from './cffDict';
2
+ import { readCffFdSelect } from './cffFdSelect';
3
+ import { readCffIndex } from './cffIndex';
4
+ // Assembles the parts of a `CFF ` table an outline reader needs: the charstrings, and the two subroutine
5
+ // pools they call into.
6
+ //
7
+ // The walk is fixed by the format — header, then name / top DICT / string / global subroutine INDEXes in
8
+ // that order — and everything after is reached by offsets read from the top DICT. Offsets in the top DICT
9
+ // are from the start of the TABLE; the local subroutine offset is from the start of the PRIVATE DICT.
10
+ // Mixing those two bases is the mistake that yields a real-but-wrong subroutine pool, which draws
11
+ // plausible garbage instead of failing.
12
+ // Local subroutines are optional: a font whose glyphs call none simply omits the operator, and an empty
13
+ // pool is the correct answer rather than a failure. Returned as an empty array so a caller never has to
14
+ // distinguish "absent" from "present but empty" — the biasing arithmetic treats them identically.
15
+ function readCffLocalSubrs(bytes, top, tableOffset, tableEnd) {
16
+ const privateEntry = top.get(CFF_OPERATOR_PRIVATE);
17
+ if (privateEntry === undefined || privateEntry.length < 2)
18
+ return [];
19
+ const [privateSize, privateOffset] = privateEntry;
20
+ const privateAt = tableOffset + privateOffset;
21
+ if (privateAt < tableOffset || privateAt + privateSize > tableEnd)
22
+ return [];
23
+ const privateDict = readCffDict(bytes, privateAt, privateAt + privateSize);
24
+ const subrsOffset = privateDict?.get(CFF_OPERATOR_SUBRS)?.[0];
25
+ if (subrsOffset === undefined)
26
+ return [];
27
+ // Relative to the PRIVATE dict, not the table. This is the base that is easy to get wrong.
28
+ const subrs = readCffIndex(bytes, privateAt + subrsOffset);
29
+ return subrs === null ? [] : subrs.entries;
30
+ }
31
+ // One local-subroutine pool per glyph, resolved through FDSelect into the FDArray. Returns the null
32
+ // sentinel when either structure is unreadable, because a partial answer here binds some glyphs to the
33
+ // wrong pool — which draws something rather than failing, and is the reason CID fonts were refused until
34
+ // this landed.
35
+ function readCffCidSubrs(bytes, top, tableOffset, tableEnd, glyphCount) {
36
+ const fdArrayOffset = top.get(CFF_OPERATOR_FD_ARRAY)?.[0];
37
+ const fdSelectOffset = top.get(CFF_OPERATOR_FD_SELECT)?.[0];
38
+ if (fdArrayOffset === undefined || fdSelectOffset === undefined)
39
+ return null;
40
+ const fdArray = readCffIndex(bytes, tableOffset + fdArrayOffset);
41
+ if (fdArray === null || fdArray.entries.length === 0)
42
+ return null;
43
+ // Each FDArray entry is a font DICT whose private DICT is read exactly as the non-CID top DICT's is —
44
+ // same operator, same table-relative base — so the two paths cannot drift apart in how they resolve it.
45
+ const pools = [];
46
+ for (const entry of fdArray.entries) {
47
+ const fontDict = readCffDict(bytes, entry.start, entry.end);
48
+ if (fontDict === null)
49
+ return null;
50
+ pools.push(readCffLocalSubrs(bytes, fontDict, tableOffset, tableEnd));
51
+ }
52
+ const select = readCffFdSelect(bytes, tableOffset + fdSelectOffset, glyphCount);
53
+ if (select === null)
54
+ return null;
55
+ const byGlyph = [];
56
+ for (let glyph = 0; glyph < glyphCount; glyph += 1) {
57
+ const pool = pools[select[glyph]];
58
+ // An FDSelect naming an FD the FDArray does not have is malformed. Defaulting to pool 0 would be the
59
+ // wrong-pool outcome wearing a reasonable-looking fallback.
60
+ if (pool === undefined)
61
+ return null;
62
+ byGlyph.push(pool);
63
+ }
64
+ return byGlyph;
65
+ }
66
+ // Returns the null sentinel for anything this package cannot read, INCLUDING a CID-keyed font. That is a
67
+ // deliberate refusal rather than a gap: a CID font reaches its charstrings through an FDSelect/FDArray
68
+ // indirection this package does not implement, so each glyph has its own private DICT and its own local
69
+ // subroutines, and the single-private-DICT read below is not reading what it assumes it is.
70
+ //
71
+ // WHAT THE REFUSAL IS **NOT** JUSTIFIED BY, since the first version of this comment claimed it: it is not
72
+ // established that such a font would fail silently. Measured instead of predicted — with no local
73
+ // subroutine pool, a charstring that calls one returns false, which is a VISIBLE failure rather than
74
+ // plausible garbage. Whether a given CID font lands there depends on whether its top DICT happens to
75
+ // carry a private entry at all, and that is not something this reader can know in advance.
76
+ // ⇒ SO THE REASON TO REFUSE IS THAT THE OUTCOME IS UNPREDICTABLE PER FONT, NOT THAT IT IS KNOWN TO BE
77
+ // SILENT. That is the narrower claim and the one the evidence supports.
78
+ export function readCffTable(bytes, directory) {
79
+ const table = directory.tables.get('CFF ');
80
+ if (table === undefined || table.length < 4)
81
+ return null;
82
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
83
+ // The header states its own size, so a future revision with extra header fields still parses.
84
+ const headerSize = view.getUint8(table.offset + 2);
85
+ const tableEnd = table.offset + table.length;
86
+ const names = readCffIndex(bytes, table.offset + headerSize);
87
+ if (names === null)
88
+ return null;
89
+ const topDicts = readCffIndex(bytes, names.endOffset);
90
+ if (topDicts === null || topDicts.entries.length === 0)
91
+ return null;
92
+ const strings = readCffIndex(bytes, topDicts.endOffset);
93
+ if (strings === null)
94
+ return null;
95
+ const globals = readCffIndex(bytes, strings.endOffset);
96
+ if (globals === null)
97
+ return null;
98
+ const top = readCffDict(bytes, topDicts.entries[0].start, topDicts.entries[0].end);
99
+ if (top === null)
100
+ return null;
101
+ const charstringsOffset = top.get(CFF_OPERATOR_CHARSTRINGS)?.[0];
102
+ if (charstringsOffset === undefined)
103
+ return null;
104
+ const charstringsAt = table.offset + charstringsOffset;
105
+ if (charstringsAt < table.offset || charstringsAt >= tableEnd)
106
+ return null;
107
+ const charstrings = readCffIndex(bytes, charstringsAt);
108
+ if (charstrings === null)
109
+ return null;
110
+ // A CID-keyed font is several fonts in one table: an FDArray of font DICTs, each with its own private
111
+ // DICT and therefore ITS OWN local subroutine pool, plus an FDSelect saying which glyph uses which.
112
+ // Detected by the operators rather than by `ROS` alone, since the pools are what actually matter here.
113
+ const isCid = top.has(CFF_OPERATOR_FD_ARRAY) && top.has(CFF_OPERATOR_FD_SELECT);
114
+ if (isCid) {
115
+ const perGlyph = readCffCidSubrs(bytes, top, table.offset, tableEnd, charstrings.entries.length);
116
+ // Refused rather than fallen back to the single-pool read. A fallback here is the precise failure
117
+ // this branch exists to prevent: it would bind every glyph to one pool and draw plausible geometry.
118
+ if (perGlyph === null)
119
+ return null;
120
+ return {
121
+ charstrings: charstrings.entries,
122
+ globalSubrs: globals.entries,
123
+ localSubrs: [],
124
+ localSubrsByGlyph: perGlyph,
125
+ };
126
+ }
127
+ return {
128
+ charstrings: charstrings.entries,
129
+ globalSubrs: globals.entries,
130
+ localSubrs: readCffLocalSubrs(bytes, top, table.offset, tableEnd),
131
+ localSubrsByGlyph: null,
132
+ };
133
+ }
134
+ //# sourceMappingURL=cffTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cffTable.js","sourceRoot":"","sources":["../src/cffTable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export * from './index';
2
+ export { cffSubroutineBias, runCffCharstring } from './cffCharstring';
3
+ export { CFF_OPERATOR_CHARSTRINGS, CFF_OPERATOR_FD_ARRAY, CFF_OPERATOR_FD_SELECT, CFF_OPERATOR_PRIVATE, CFF_OPERATOR_ROS, CFF_OPERATOR_SUBRS, readCffDict, } from './cffDict';
4
+ export { readCffFdSelect } from './cffFdSelect';
5
+ export { readCffIndex } from './cffIndex';
6
+ export { readCffTable } from './cffTable';
7
+ export { findOpenTypeUnicodeSubtable, rankOpenTypeUnicodeEncoding, readOpenTypeCodepointMap } from './openTypeCmap';
8
+ export { readOpenTypeGlyphOutline, readOpenTypeGlyphRanges } from './openTypeGlyf';
9
+ export { readOpenTypeAdvances, readOpenTypeGlyphCount, readOpenTypeLocaFormat, readOpenTypeMetrics, } from './openTypeMetrics';
10
+ export { readSfntTableDirectory, readSfntTag } from './sfntTableDirectory';
11
+ export { readWoffChecksumMismatches, readWoffFont, WOFF_COMPRESSION } from './woffFont';
12
+ export { assembleSfntFont, computeSfntTableChecksum, packSfntTag } from './sfntAssembly';
13
+ export { readWoff2Font, readWoff2TableDirectory, WOFF2_COMPRESSION } from './woff2Font';
14
+ export { readWoff2GlyfStreams, readWoff2Short } from './woff2GlyfTransform';
15
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AACpH,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,15 @@
1
+ export * from './index';
2
+ export { cffSubroutineBias, runCffCharstring } from './cffCharstring';
3
+ export { CFF_OPERATOR_CHARSTRINGS, CFF_OPERATOR_FD_ARRAY, CFF_OPERATOR_FD_SELECT, CFF_OPERATOR_PRIVATE, CFF_OPERATOR_ROS, CFF_OPERATOR_SUBRS, readCffDict, } from './cffDict';
4
+ export { readCffFdSelect } from './cffFdSelect';
5
+ export { readCffIndex } from './cffIndex';
6
+ export { readCffTable } from './cffTable';
7
+ export { findOpenTypeUnicodeSubtable, rankOpenTypeUnicodeEncoding, readOpenTypeCodepointMap } from './openTypeCmap';
8
+ export { readOpenTypeGlyphOutline, readOpenTypeGlyphRanges } from './openTypeGlyf';
9
+ export { readOpenTypeAdvances, readOpenTypeGlyphCount, readOpenTypeLocaFormat, readOpenTypeMetrics, } from './openTypeMetrics';
10
+ export { readSfntTableDirectory, readSfntTag } from './sfntTableDirectory';
11
+ export { readWoffChecksumMismatches, readWoffFont, WOFF_COMPRESSION } from './woffFont';
12
+ export { assembleSfntFont, computeSfntTableChecksum, packSfntTag } from './sfntAssembly';
13
+ export { readWoff2Font, readWoff2TableDirectory, WOFF2_COMPRESSION } from './woff2Font';
14
+ export { readWoff2GlyfStreams, readWoff2Short } from './woff2GlyfTransform';
15
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EACL,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,2BAA2B,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AACpH,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createGlyphOutlineSourceFromOpenTypeFont, explainOpenTypeFont } from './openTypeGlyphOutlineSource';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createGlyphOutlineSourceFromOpenTypeFont, explainOpenTypeFont } from './openTypeGlyphOutlineSource';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wCAAwC,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { SfntTableDirectory } from '@flighthq/types/contract';
2
+ export declare function findOpenTypeUnicodeSubtable(view: Readonly<DataView>, cmapOffset: number, cmapLength: number, byteLength: number): number;
3
+ export declare function rankOpenTypeUnicodeEncoding(platform: number, encoding: number): number;
4
+ export declare function readOpenTypeCodepointMap(bytes: Readonly<Uint8Array>, directory: Readonly<SfntTableDirectory>): Map<number, number> | null;
5
+ //# sourceMappingURL=openTypeCmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openTypeCmap.d.ts","sourceRoot":"","sources":["../src/openTypeCmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAyBnE,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,EACxB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,MAAM,CAqBR;AAoBD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtF;AAKD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,SAAS,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GACtC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAY5B"}
@@ -0,0 +1,161 @@
1
+ // The codepoint → glyph-index map. `cmap` is a table of sub-tables, each tagged with a platform and
2
+ // encoding, because a font may carry several mappings for different systems. Only the Unicode ones are
3
+ // read here: the format's job is to say which glyph draws a codepoint, and the legacy platform-specific
4
+ // encodings answer a different question that nothing in this SDK asks.
5
+ //
6
+ // Two sub-table formats are read, and between them they cover every modern font:
7
+ // format 4 — segmented ranges over the Basic Multilingual Plane. Effectively universal.
8
+ // format 12 — flat 32-bit groups, which is how anything above U+FFFF is reached at all.
9
+ // A font carrying neither maps nothing, and every codepoint lookup returns -1 rather than guessing.
10
+ // Picks the best Unicode sub-table the font offers, preferring one that can express codepoints above
11
+ // the BMP. Returns -1 when the font declares no Unicode mapping this reader can read.
12
+ //
13
+ // Platform 3 encoding 10 and platform 0 encoding 4/6 are the full-repertoire mappings; platform 3
14
+ // encoding 1 and platform 0 encodings 0-3 are BMP-only. Preferring the former matters for emoji and for
15
+ // CJK extensions, which is exactly the material a BMP-only map silently drops.
16
+ //
17
+ // ★ READABILITY IS PART OF THE CHOICE, NOT A TEST APPLIED AFTERWARDS. Ranking on encoding alone picks
18
+ // the widest-repertoire sub-table even when it is stored in a format this reader does not implement,
19
+ // and the font is then refused whole while a readable sub-table sits beside it. That is not
20
+ // hypothetical: a real font in this shape carries a readable format 4 at rank 1 and a format 0 at
21
+ // rank 2, and ranking alone rejected the entire font. A narrower map that works beats a wider one that
22
+ // cannot be read.
23
+ export function findOpenTypeUnicodeSubtable(view, cmapOffset, cmapLength, byteLength) {
24
+ const recordCount = view.getUint16(cmapOffset + 2);
25
+ let best = -1;
26
+ let bestRank = -1;
27
+ for (let index = 0; index < recordCount; index += 1) {
28
+ const record = cmapOffset + 4 + index * 8;
29
+ if (record + 8 > cmapOffset + cmapLength || record + 8 > byteLength)
30
+ break;
31
+ const platform = view.getUint16(record);
32
+ const encoding = view.getUint16(record + 2);
33
+ const offset = cmapOffset + view.getUint32(record + 4);
34
+ if (offset + 4 > byteLength)
35
+ continue;
36
+ const rank = rankOpenTypeUnicodeEncoding(platform, encoding);
37
+ if (rank <= bestRank)
38
+ continue;
39
+ if (!isOpenTypeCmapFormatReadable(view.getUint16(offset)))
40
+ continue;
41
+ best = offset;
42
+ bestRank = rank;
43
+ }
44
+ return best;
45
+ }
46
+ // Whether `readOpenTypeCodepointMap` can turn this sub-table format into a map. Kept beside the chooser
47
+ // because the two must agree: a format the chooser accepts and the reader then declines produces the
48
+ // refusal this function exists to prevent.
49
+ //
50
+ // ★ FORMAT 6 IS ABSENT DELIBERATELY, AND ADDING IT WOULD BE UNREACHABLE CODE. A format 6 sub-table is
51
+ // a trimmed 16-bit range, and in practice it is written at platform 1 encoding 0 — the legacy Macintosh
52
+ // encoding, which `rankOpenTypeUnicodeEncoding` scores -1 as *not a Unicode mapping*. So the chooser
53
+ // never offers one to this predicate, whatever it answers: the exclusion happens a layer earlier, for a
54
+ // reason that has nothing to do with the format. Measured across a corpus of real system fonts rather
55
+ // than assumed — every format 6 found sat at platform 1 encoding 0, and none would have been selected
56
+ // over a readable rival. Implementing it would close nothing and add a branch no font reaches.
57
+ // Format 14 is likewise absent on purpose: it carries variation-selector sequences, not a codepoint
58
+ // map, so it answers a different question and is correctly scored out of the ranking too.
59
+ function isOpenTypeCmapFormatReadable(format) {
60
+ return format === 4 || format === 12;
61
+ }
62
+ // 2 = full Unicode repertoire, 1 = BMP only, -1 = not a Unicode mapping.
63
+ export function rankOpenTypeUnicodeEncoding(platform, encoding) {
64
+ if (platform === 3 && encoding === 10)
65
+ return 2;
66
+ if (platform === 0 && (encoding === 4 || encoding === 6))
67
+ return 2;
68
+ if (platform === 3 && encoding === 1)
69
+ return 1;
70
+ if (platform === 0 && encoding <= 3)
71
+ return 1;
72
+ return -1;
73
+ }
74
+ // Builds the map eagerly into a plain Map. A font's cmap is thousands of entries at most, and the
75
+ // alternative — binary searching the encoded segments per lookup — trades a one-off parse for a cost on
76
+ // every glyph, in a lookup that sits inside text layout.
77
+ export function readOpenTypeCodepointMap(bytes, directory) {
78
+ const cmap = directory.tables.get('cmap');
79
+ if (cmap === undefined || cmap.length < 4)
80
+ return null;
81
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
82
+ const subtableOffset = findOpenTypeUnicodeSubtable(view, cmap.offset, cmap.length, bytes.byteLength);
83
+ if (subtableOffset === -1)
84
+ return null;
85
+ const format = view.getUint16(subtableOffset);
86
+ if (format === 4)
87
+ return readOpenTypeCmapFormat4(view, subtableOffset, bytes.byteLength);
88
+ if (format === 12)
89
+ return readOpenTypeCmapFormat12(view, subtableOffset, bytes.byteLength);
90
+ return null;
91
+ }
92
+ // Format 4: parallel arrays of segment ends, starts, deltas, and range offsets. A segment either adds a
93
+ // constant delta to the codepoint or indexes into a glyph-id array that follows — the second form is
94
+ // what lets a font map a scattered range without a segment per character.
95
+ function readOpenTypeCmapFormat4(view, offset, byteLength) {
96
+ const map = new Map();
97
+ const segmentCount = view.getUint16(offset + 6) / 2;
98
+ const endsAt = offset + 14;
99
+ const startsAt = endsAt + segmentCount * 2 + 2;
100
+ const deltasAt = startsAt + segmentCount * 2;
101
+ const rangesAt = deltasAt + segmentCount * 2;
102
+ if (rangesAt + segmentCount * 2 > byteLength)
103
+ return map;
104
+ for (let segment = 0; segment < segmentCount; segment += 1) {
105
+ const end = view.getUint16(endsAt + segment * 2);
106
+ const start = view.getUint16(startsAt + segment * 2);
107
+ // The final segment is a required 0xFFFF terminator rather than real coverage.
108
+ if (start > end || start === 0xffff)
109
+ continue;
110
+ const delta = view.getInt16(deltasAt + segment * 2);
111
+ const rangeOffsetAt = rangesAt + segment * 2;
112
+ const rangeOffset = view.getUint16(rangeOffsetAt);
113
+ for (let codePoint = start; codePoint <= end; codePoint += 1) {
114
+ let glyph;
115
+ if (rangeOffset === 0) {
116
+ glyph = (codePoint + delta) & 0xffff;
117
+ }
118
+ else {
119
+ // The range offset is a byte distance from its OWN slot, which is why this is computed from
120
+ // `rangeOffsetAt` and not from the start of the table.
121
+ const glyphAt = rangeOffsetAt + rangeOffset + (codePoint - start) * 2;
122
+ if (glyphAt + 2 > byteLength)
123
+ continue;
124
+ const raw = view.getUint16(glyphAt);
125
+ // A zero here means "no glyph" and must NOT have the delta applied, which would turn an absent
126
+ // glyph into a plausible wrong one.
127
+ if (raw === 0)
128
+ continue;
129
+ glyph = (raw + delta) & 0xffff;
130
+ }
131
+ if (glyph !== 0)
132
+ map.set(codePoint, glyph);
133
+ }
134
+ }
135
+ return map;
136
+ }
137
+ // Format 12: flat groups of contiguous codepoints, each mapping to a contiguous run of glyph ids. The
138
+ // only sub-table format that reaches past U+FFFF.
139
+ function readOpenTypeCmapFormat12(view, offset, byteLength) {
140
+ const map = new Map();
141
+ if (offset + 16 > byteLength)
142
+ return map;
143
+ const groupCount = view.getUint32(offset + 12);
144
+ for (let group = 0; group < groupCount; group += 1) {
145
+ const record = offset + 16 + group * 12;
146
+ if (record + 12 > byteLength)
147
+ break;
148
+ const start = view.getUint32(record);
149
+ const end = view.getUint32(record + 4);
150
+ const startGlyph = view.getUint32(record + 8);
151
+ if (start > end)
152
+ continue;
153
+ for (let codePoint = start; codePoint <= end; codePoint += 1) {
154
+ const glyph = startGlyph + (codePoint - start);
155
+ if (glyph !== 0)
156
+ map.set(codePoint, glyph);
157
+ }
158
+ }
159
+ return map;
160
+ }
161
+ //# sourceMappingURL=openTypeCmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openTypeCmap.js","sourceRoot":"","sources":["../src/openTypeCmap.ts"],"names":[],"mappings":"AAEA,oGAAoG;AACpG,uGAAuG;AACvG,wGAAwG;AACxG,uEAAuE;AACvE,EAAE;AACF,iFAAiF;AACjF,2FAA2F;AAC3F,0FAA0F;AAC1F,oGAAoG;AAEpG,qGAAqG;AACrG,sFAAsF;AACtF,EAAE;AACF,kGAAkG;AAClG,wGAAwG;AACxG,+EAA+E;AAC/E,EAAE;AACF,sGAAsG;AACtG,qGAAqG;AACrG,4FAA4F;AAC5F,kGAAkG;AAClG,uGAAuG;AACvG,kBAAkB;AAClB,MAAM,UAAU,2BAA2B,CACzC,IAAwB,EACxB,UAAkB,EAClB,UAAkB,EAClB,UAAkB;IAElB,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IACnD,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;IAElB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,WAAW,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,UAAU,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAC1C,IAAI,MAAM,GAAG,CAAC,GAAG,UAAU,GAAG,UAAU,IAAI,MAAM,GAAG,CAAC,GAAG,UAAU;YAAE,MAAM;QAE3E,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvD,IAAI,MAAM,GAAG,CAAC,GAAG,UAAU;YAAE,SAAS;QAEtC,MAAM,IAAI,GAAG,2BAA2B,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC7D,IAAI,IAAI,IAAI,QAAQ;YAAE,SAAS;QAC/B,IAAI,CAAC,4BAA4B,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAAE,SAAS;QACpE,IAAI,GAAG,MAAM,CAAC;QACd,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wGAAwG;AACxG,qGAAqG;AACrG,2CAA2C;AAC3C,EAAE;AACF,sGAAsG;AACtG,wGAAwG;AACxG,qGAAqG;AACrG,wGAAwG;AACxG,sGAAsG;AACtG,sGAAsG;AACtG,+FAA+F;AAC/F,oGAAoG;AACpG,0FAA0F;AAC1F,SAAS,4BAA4B,CAAC,MAAc;IAClD,OAAO,MAAM,KAAK,CAAC,IAAI,MAAM,KAAK,EAAE,CAAC;AACvC,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,2BAA2B,CAAC,QAAgB,EAAE,QAAgB;IAC5E,IAAI,QAAQ,KAAK,CAAC,IAAI,QAAQ,KAAK,EAAE;QAAE,OAAO,CAAC,CAAC;IAChD,IAAI,QAAQ,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACnE,IAAI,QAAQ,KAAK,CAAC,IAAI,QAAQ,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,QAAQ,KAAK,CAAC,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC9C,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,kGAAkG;AAClG,wGAAwG;AACxG,yDAAyD;AACzD,MAAM,UAAU,wBAAwB,CACtC,KAA2B,EAC3B,SAAuC;IAEvC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC5E,MAAM,cAAc,GAAG,2BAA2B,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACrG,IAAI,cAAc,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC9C,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,uBAAuB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACzF,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,wBAAwB,CAAC,IAAI,EAAE,cAAc,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,wGAAwG;AACxG,qGAAqG;AACrG,0EAA0E;AAC1E,SAAS,uBAAuB,CAAC,IAAwB,EAAE,MAAc,EAAE,UAAkB;IAC3F,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,CAAC,CAAC;IAC7C,IAAI,QAAQ,GAAG,YAAY,GAAG,CAAC,GAAG,UAAU;QAAE,OAAO,GAAG,CAAC;IAEzD,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,YAAY,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC;QACrD,+EAA+E;QAC/E,IAAI,KAAK,GAAG,GAAG,IAAI,KAAK,KAAK,MAAM;YAAE,SAAS;QAE9C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC;QACpD,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC;QAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QAElD,KAAK,IAAI,SAAS,GAAG,KAAK,EAAE,SAAS,IAAI,GAAG,EAAE,SAAS,IAAI,CAAC,EAAE,CAAC;YAC7D,IAAI,KAAa,CAAC;YAClB,IAAI,WAAW,KAAK,CAAC,EAAE,CAAC;gBACtB,KAAK,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,4FAA4F;gBAC5F,uDAAuD;gBACvD,MAAM,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;gBACtE,IAAI,OAAO,GAAG,CAAC,GAAG,UAAU;oBAAE,SAAS;gBACvC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACpC,+FAA+F;gBAC/F,oCAAoC;gBACpC,IAAI,GAAG,KAAK,CAAC;oBAAE,SAAS;gBACxB,KAAK,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,MAAM,CAAC;YACjC,CAAC;YACD,IAAI,KAAK,KAAK,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sGAAsG;AACtG,kDAAkD;AAClD,SAAS,wBAAwB,CAAC,IAAwB,EAAE,MAAc,EAAE,UAAkB;IAC5F,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,IAAI,MAAM,GAAG,EAAE,GAAG,UAAU;QAAE,OAAO,GAAG,CAAC;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAE/C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;QACxC,IAAI,MAAM,GAAG,EAAE,GAAG,UAAU;YAAE,MAAM;QAEpC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC9C,IAAI,KAAK,GAAG,GAAG;YAAE,SAAS;QAE1B,KAAK,IAAI,SAAS,GAAG,KAAK,EAAE,SAAS,IAAI,GAAG,EAAE,SAAS,IAAI,CAAC,EAAE,CAAC;YAC7D,MAAM,KAAK,GAAG,UAAU,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC;YAC/C,IAAI,KAAK,KAAK,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Path, SfntTableDirectory } from '@flighthq/types/contract';
2
+ export declare function readOpenTypeGlyphOutline(out: Path, bytes: Readonly<Uint8Array>, directory: Readonly<SfntTableDirectory>, ranges: Readonly<Uint32Array>, glyphIndex: number): boolean;
3
+ export declare function readOpenTypeGlyphRanges(bytes: Readonly<Uint8Array>, directory: Readonly<SfntTableDirectory>, glyphCount: number, locaFormat: number): Uint32Array | null;
4
+ //# sourceMappingURL=openTypeGlyf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openTypeGlyf.d.ts","sourceRoot":"","sources":["../src/openTypeGlyf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA6BzE,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,IAAI,EACT,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,SAAS,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EACvC,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB,OAAO,CAmDT;AAKD,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,SAAS,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EACvC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,GACjB,WAAW,GAAG,IAAI,CAgBpB"}
@@ -0,0 +1,229 @@
1
+ import { PathCommand } from '@flighthq/types/contract';
2
+ // TrueType outlines: `loca` gives each glyph's byte range inside `glyf`, and a glyph is a set of closed
3
+ // contours of points, each point flagged on-curve or off-curve.
4
+ //
5
+ // THE ONE THING THAT MAKES THIS FORMAT DIFFERENT FROM EVERY OTHER PATH FORMAT: consecutive off-curve
6
+ // points imply an on-curve point exactly halfway between them. The format omits those midpoints because
7
+ // they are recoverable, so a reader that treats the point list literally produces contours that visibly
8
+ // cut corners. They are reconstructed below.
9
+ //
10
+ // Coordinates are design units, y-up in the font's own convention. `Path` is y-down, so y is negated at
11
+ // this seam — once, here — which is what makes the produced outlines match `GlyphOutlineMetrics`'
12
+ // documented "ink above the baseline has negative y".
13
+ const ON_CURVE = 0x01;
14
+ const X_SHORT = 0x02;
15
+ const Y_SHORT = 0x04;
16
+ const REPEAT = 0x08;
17
+ const X_SAME_OR_POSITIVE = 0x10;
18
+ const Y_SAME_OR_POSITIVE = 0x20;
19
+ // Replaces `out` with one glyph's contours. Returns false for a glyph whose data is unreadable; returns
20
+ // true with an empty path for a glyph that legitimately has no outline.
21
+ //
22
+ // Composite glyphs — an accented letter assembled from a base and a mark — are NOT expanded. They are
23
+ // reported as an empty outline rather than as a failure, because the glyph exists and its advance is
24
+ // still correct; only its ink is missing. Expanding them needs component transforms and is a deliberate
25
+ // follow-up rather than something to half-do inside the simple-glyph reader.
26
+ export function readOpenTypeGlyphOutline(out, bytes, directory, ranges, glyphIndex) {
27
+ const glyf = directory.tables.get('glyf');
28
+ if (glyf === undefined || glyphIndex < 0 || glyphIndex + 1 >= ranges.length)
29
+ return false;
30
+ out.commands.length = 0;
31
+ out.data.length = 0;
32
+ // `out` is REPLACED, so every field it owns is written — including this one. Both outline
33
+ // flavors fill by the nonzero rule, and a caller reusing a scratch path would otherwise keep
34
+ // whatever winding the previous glyph left, which turns a counter into a solid blob.
35
+ out.winding = 'nonZero';
36
+ const start = glyf.offset + ranges[glyphIndex];
37
+ const end = glyf.offset + ranges[glyphIndex + 1];
38
+ // An empty range is a glyph with no ink. True, not false: the caller still needs its advance.
39
+ if (end <= start)
40
+ return true;
41
+ if (end > bytes.byteLength || start + 10 > bytes.byteLength)
42
+ return false;
43
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
44
+ const contourCount = view.getInt16(start);
45
+ // Negative means composite. Empty outline, advance preserved — see above.
46
+ if (contourCount <= 0)
47
+ return true;
48
+ const endPoints = new Uint16Array(contourCount);
49
+ let cursor = start + 10;
50
+ if (cursor + contourCount * 2 + 2 > bytes.byteLength)
51
+ return false;
52
+ for (let contour = 0; contour < contourCount; contour += 1) {
53
+ endPoints[contour] = view.getUint16(cursor);
54
+ cursor += 2;
55
+ }
56
+ const pointCount = endPoints[contourCount - 1] + 1;
57
+ // Skip the hinting program: this package produces unhinted design-unit outlines by charter.
58
+ cursor += 2 + view.getUint16(cursor);
59
+ const flags = readGlyfFlags(view, cursor, pointCount, bytes.byteLength);
60
+ if (flags === null)
61
+ return false;
62
+ cursor = flags.cursor;
63
+ const xs = readGlyfCoordinates(view, cursor, flags.flags, X_SHORT, X_SAME_OR_POSITIVE, bytes.byteLength);
64
+ if (xs === null)
65
+ return false;
66
+ const ys = readGlyfCoordinates(view, xs.cursor, flags.flags, Y_SHORT, Y_SAME_OR_POSITIVE, bytes.byteLength);
67
+ if (ys === null)
68
+ return false;
69
+ let first = 0;
70
+ for (let contour = 0; contour < contourCount; contour += 1) {
71
+ const last = endPoints[contour];
72
+ if (last >= pointCount)
73
+ return false;
74
+ appendGlyfContour(out, flags.flags, xs.values, ys.values, first, last);
75
+ first = last + 1;
76
+ }
77
+ return true;
78
+ }
79
+ // Byte ranges of every glyph, indexed by glyph id, with one extra trailing entry so glyph `n` spans
80
+ // `[offsets[n], offsets[n + 1])`. An empty span is a real and common answer — a space has no outline —
81
+ // and is preserved rather than dropped, because the glyph still exists and still advances.
82
+ export function readOpenTypeGlyphRanges(bytes, directory, glyphCount, locaFormat) {
83
+ const loca = directory.tables.get('loca');
84
+ if (loca === undefined)
85
+ return null;
86
+ const entryCount = glyphCount + 1;
87
+ const entryBytes = locaFormat === 0 ? 2 : 4;
88
+ if (entryCount * entryBytes > loca.length)
89
+ return null;
90
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
91
+ const offsets = new Uint32Array(entryCount);
92
+ for (let index = 0; index < entryCount; index += 1) {
93
+ // The short form stores HALVED offsets, which is the whole reason the format flag exists.
94
+ offsets[index] =
95
+ locaFormat === 0 ? view.getUint16(loca.offset + index * 2) * 2 : view.getUint32(loca.offset + index * 4);
96
+ }
97
+ return offsets;
98
+ }
99
+ // One closed contour, with the implied on-curve midpoints reconstructed.
100
+ //
101
+ // The contour may begin on an off-curve point, in which case the true start is either the last point
102
+ // (if that one is on-curve) or the midpoint between the two. Getting this wrong rotates the whole
103
+ // contour by one point and is invisible on a circle while obvious on a letter.
104
+ function appendGlyfContour(out, flags, xs, ys, first, last) {
105
+ const count = last - first + 1;
106
+ if (count <= 0)
107
+ return;
108
+ const onCurve = (index) => (flags[first + (((index % count) + count) % count)] & ON_CURVE) !== 0;
109
+ const pointX = (index) => xs[first + (((index % count) + count) % count)];
110
+ // y is negated here — the single place the font's y-up convention becomes `Path`'s y-down.
111
+ const pointY = (index) => -ys[first + (((index % count) + count) % count)];
112
+ let startX;
113
+ let startY;
114
+ let startIndex;
115
+ // How many points remain to be traversed after the start. When the start IS one of the contour's
116
+ // points, that point must not be walked again — traversing all `count` would emit a zero-length
117
+ // segment back onto the start that `CLOSE` already implies. Only the synthesized-midpoint start,
118
+ // which is not a point of the contour, leaves all `count` still to visit.
119
+ let stepCount;
120
+ if (onCurve(0)) {
121
+ startX = pointX(0);
122
+ startY = pointY(0);
123
+ startIndex = 1;
124
+ stepCount = count - 1;
125
+ }
126
+ else if (onCurve(count - 1)) {
127
+ startX = pointX(count - 1);
128
+ startY = pointY(count - 1);
129
+ startIndex = 0;
130
+ stepCount = count - 1;
131
+ }
132
+ else {
133
+ startX = (pointX(0) + pointX(count - 1)) / 2;
134
+ startY = (pointY(0) + pointY(count - 1)) / 2;
135
+ startIndex = 0;
136
+ stepCount = count;
137
+ }
138
+ out.commands.push(PathCommand.MOVE_TO);
139
+ out.data.push(startX, startY);
140
+ let controlX = 0;
141
+ let controlY = 0;
142
+ let hasControl = false;
143
+ for (let step = 0; step < stepCount; step += 1) {
144
+ const index = startIndex + step;
145
+ const x = pointX(index);
146
+ const y = pointY(index);
147
+ if (onCurve(index)) {
148
+ if (hasControl) {
149
+ out.commands.push(PathCommand.CURVE_TO);
150
+ out.data.push(controlX, controlY, x, y);
151
+ hasControl = false;
152
+ }
153
+ else {
154
+ out.commands.push(PathCommand.LINE_TO);
155
+ out.data.push(x, y);
156
+ }
157
+ continue;
158
+ }
159
+ // Two off-curve points in a row: the on-curve point between them was omitted because it is exactly
160
+ // their midpoint. Emit it, then carry this point as the next control.
161
+ if (hasControl) {
162
+ out.commands.push(PathCommand.CURVE_TO);
163
+ out.data.push(controlX, controlY, (controlX + x) / 2, (controlY + y) / 2);
164
+ }
165
+ controlX = x;
166
+ controlY = y;
167
+ hasControl = true;
168
+ }
169
+ // Close back onto the start, through a trailing control point when the contour ended off-curve.
170
+ if (hasControl) {
171
+ out.commands.push(PathCommand.CURVE_TO);
172
+ out.data.push(controlX, controlY, startX, startY);
173
+ }
174
+ out.commands.push(PathCommand.CLOSE);
175
+ }
176
+ // Flags are run-length encoded: a flag with REPEAT set is followed by a count of additional points
177
+ // carrying the same flag. Reading them as one byte per point desynchronizes every coordinate after the
178
+ // first repeat, which is why this is expanded before any coordinate is touched.
179
+ function readGlyfFlags(view, start, pointCount, byteLength) {
180
+ const flags = new Uint8Array(pointCount);
181
+ let cursor = start;
182
+ for (let point = 0; point < pointCount;) {
183
+ if (cursor >= byteLength)
184
+ return null;
185
+ const flag = view.getUint8(cursor);
186
+ cursor += 1;
187
+ flags[point] = flag;
188
+ point += 1;
189
+ if ((flag & REPEAT) === 0)
190
+ continue;
191
+ if (cursor >= byteLength)
192
+ return null;
193
+ let repeats = view.getUint8(cursor);
194
+ cursor += 1;
195
+ while (repeats > 0 && point < pointCount) {
196
+ flags[point] = flag;
197
+ point += 1;
198
+ repeats -= 1;
199
+ }
200
+ }
201
+ return { cursor, flags };
202
+ }
203
+ // Coordinates are stored as DELTAS, in one of three widths chosen per point by two flag bits: one byte
204
+ // with the sign carried by the second bit, two bytes signed, or omitted entirely to mean "unchanged
205
+ // from the previous point". Accumulated into absolute values here.
206
+ function readGlyfCoordinates(view, start, flags, shortBit, sameOrPositiveBit, byteLength) {
207
+ const values = new Int32Array(flags.length);
208
+ let cursor = start;
209
+ let value = 0;
210
+ for (let point = 0; point < flags.length; point += 1) {
211
+ const flag = flags[point];
212
+ if ((flag & shortBit) !== 0) {
213
+ if (cursor >= byteLength)
214
+ return null;
215
+ const magnitude = view.getUint8(cursor);
216
+ cursor += 1;
217
+ value += (flag & sameOrPositiveBit) !== 0 ? magnitude : -magnitude;
218
+ }
219
+ else if ((flag & sameOrPositiveBit) === 0) {
220
+ if (cursor + 2 > byteLength)
221
+ return null;
222
+ value += view.getInt16(cursor);
223
+ cursor += 2;
224
+ }
225
+ values[point] = value;
226
+ }
227
+ return { cursor, values };
228
+ }
229
+ //# sourceMappingURL=openTypeGlyf.js.map