@cantoo/fontkit 2.0.5 → 2.0.7

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 (153) hide show
  1. package/dist/browser-module.d.ts +239 -0
  2. package/dist/browser-module.mjs +4423 -1117
  3. package/dist/browser-module.mjs.map +1 -1
  4. package/dist/browser.cjs +4424 -1117
  5. package/dist/browser.cjs.map +1 -1
  6. package/dist/browser.d.ts +239 -0
  7. package/dist/fontkit.umd.d.ts +239 -0
  8. package/dist/fontkit.umd.js +22076 -0
  9. package/dist/fontkit.umd.js.map +7 -0
  10. package/dist/index.d.ts +239 -0
  11. package/dist/main.cjs +4424 -1117
  12. package/dist/main.cjs.map +1 -1
  13. package/dist/main.d.ts +239 -0
  14. package/dist/module.d.ts +239 -0
  15. package/dist/module.mjs +4423 -1117
  16. package/dist/module.mjs.map +1 -1
  17. package/package.json +22 -5
  18. package/src/CmapProcessor.js +59 -20
  19. package/src/DFont.js +114 -14
  20. package/src/TTFFont.js +259 -57
  21. package/src/TrueTypeCollection.js +54 -10
  22. package/src/WOFF2Font.js +128 -16
  23. package/src/WOFFFont.js +45 -8
  24. package/src/aat/AATFeatureMap.js +62 -18
  25. package/src/aat/AATLayoutEngine.js +33 -1
  26. package/src/aat/AATLookupTable.js +22 -4
  27. package/src/aat/AATMorxProcessor.js +189 -52
  28. package/src/aat/AATStateMachine.js +32 -0
  29. package/src/base.js +19 -0
  30. package/src/cff/CFFCharsets.js +3 -0
  31. package/src/cff/CFFDict.js +79 -9
  32. package/src/cff/CFFEncodings.js +2 -0
  33. package/src/cff/CFFFont.js +119 -23
  34. package/src/cff/CFFIndex.js +62 -5
  35. package/src/cff/CFFOperand.js +52 -17
  36. package/src/cff/CFFPointer.js +41 -2
  37. package/src/cff/CFFPrivateDict.js +14 -4
  38. package/src/cff/CFFStandardStrings.js +1 -0
  39. package/src/cff/CFFTop.js +103 -10
  40. package/src/decorators.js +32 -13
  41. package/src/encodings.js +22 -5
  42. package/src/fs.js +10 -0
  43. package/src/glyph/BBox.js +14 -0
  44. package/src/glyph/CFFGlyph.js +290 -148
  45. package/src/glyph/COLRGlyph.js +38 -3
  46. package/src/glyph/Glyph.js +68 -9
  47. package/src/glyph/GlyphVariationProcessor.js +135 -34
  48. package/src/glyph/Path.js +107 -20
  49. package/src/glyph/SBIXGlyph.js +57 -8
  50. package/src/glyph/StandardNames.js +1 -0
  51. package/src/glyph/TTFGlyph.js +176 -29
  52. package/src/glyph/TTFGlyphEncoder.js +32 -0
  53. package/src/glyph/WOFF2Glyph.js +23 -4
  54. package/src/layout/GlyphPosition.js +6 -0
  55. package/src/layout/GlyphRun.js +25 -7
  56. package/src/layout/KernProcessor.js +62 -3
  57. package/src/layout/LayoutEngine.js +86 -12
  58. package/src/layout/Script.js +27 -1
  59. package/src/layout/UnicodeLayoutEngine.js +29 -4
  60. package/src/opentype/GPOSProcessor.js +156 -45
  61. package/src/opentype/GSUBProcessor.js +92 -33
  62. package/src/opentype/GlyphInfo.js +52 -4
  63. package/src/opentype/GlyphIterator.js +51 -2
  64. package/src/opentype/OTLayoutEngine.js +66 -8
  65. package/src/opentype/OTProcessor.js +283 -70
  66. package/src/opentype/ShapingPlan.js +51 -3
  67. package/src/opentype/shapers/ArabicShaper.js +19 -0
  68. package/src/opentype/shapers/DefaultShaper.js +51 -7
  69. package/src/opentype/shapers/HangulShaper.js +85 -7
  70. package/src/opentype/shapers/HebrewShaper.js +45 -11
  71. package/src/opentype/shapers/IndicShaper.js +141 -26
  72. package/src/opentype/shapers/ThaiShaper.js +35 -4
  73. package/src/opentype/shapers/UniversalShaper.js +83 -17
  74. package/src/opentype/shapers/index.js +15 -2
  75. package/src/packages/unicode-properties/data-trie.js +1 -0
  76. package/src/packages/unicode-properties/data.js +12 -0
  77. package/src/packages/unicode-properties/dist/index.cjs +22 -9
  78. package/src/packages/unicode-properties/dist/index.cjs.map +2 -2
  79. package/src/packages/unicode-properties/dist/index.mjs +21 -9
  80. package/src/packages/unicode-properties/dist/index.mjs.map +2 -2
  81. package/src/packages/unicode-properties/index.js +65 -0
  82. package/src/packages/unicode-properties/package.json +1 -1
  83. package/src/packages/unicode-trie/builder.js +128 -7
  84. package/src/packages/unicode-trie/dist/builder.cjs +129 -16
  85. package/src/packages/unicode-trie/dist/builder.cjs.map +2 -2
  86. package/src/packages/unicode-trie/dist/builder.mjs +128 -16
  87. package/src/packages/unicode-trie/dist/builder.mjs.map +2 -2
  88. package/src/packages/unicode-trie/dist/index.cjs +22 -9
  89. package/src/packages/unicode-trie/dist/index.cjs.map +2 -2
  90. package/src/packages/unicode-trie/dist/index.mjs +21 -9
  91. package/src/packages/unicode-trie/dist/index.mjs.map +2 -2
  92. package/src/packages/unicode-trie/index.js +62 -10
  93. package/src/packages/unicode-trie/package.json +1 -1
  94. package/src/packages/unicode-trie/swap.js +13 -0
  95. package/src/subset/CFFSubset.js +112 -22
  96. package/src/subset/Subset.js +21 -1
  97. package/src/subset/TTFSubset.js +79 -36
  98. package/src/tables/BASE.js +1 -0
  99. package/src/tables/COLR.js +1 -0
  100. package/src/tables/CPAL.js +1 -0
  101. package/src/tables/DSIG.js +1 -0
  102. package/src/tables/EBDT.js +10 -3
  103. package/src/tables/EBLC.js +67 -7
  104. package/src/tables/GDEF.js +1 -0
  105. package/src/tables/GPOS.js +79 -16
  106. package/src/tables/GSUB.js +14 -3
  107. package/src/tables/HVAR.js +51 -5
  108. package/src/tables/JSTF.js +3 -2
  109. package/src/tables/LTSH.js +1 -0
  110. package/src/tables/OS2.js +1 -0
  111. package/src/tables/PCLT.js +1 -0
  112. package/src/tables/STAT.js +46 -6
  113. package/src/tables/VDMX.js +1 -0
  114. package/src/tables/VORG.js +1 -0
  115. package/src/tables/WOFF2Directory.js +56 -8
  116. package/src/tables/WOFFDirectory.js +14 -2
  117. package/src/tables/aat.js +160 -35
  118. package/src/tables/avar.js +1 -0
  119. package/src/tables/bsln.js +3 -2
  120. package/src/tables/cmap.js +26 -6
  121. package/src/tables/cvt.js +1 -0
  122. package/src/tables/directory.js +44 -16
  123. package/src/tables/feat.js +24 -2
  124. package/src/tables/fpgm.js +1 -0
  125. package/src/tables/fvar.js +32 -4
  126. package/src/tables/gasp.js +1 -0
  127. package/src/tables/glyf.js +1 -0
  128. package/src/tables/gvar.js +29 -2
  129. package/src/tables/hdmx.js +12 -1
  130. package/src/tables/head.js +1 -0
  131. package/src/tables/hhea.js +1 -0
  132. package/src/tables/hmtx.js +18 -2
  133. package/src/tables/index.js +1 -0
  134. package/src/tables/just.js +15 -4
  135. package/src/tables/kern.js +43 -6
  136. package/src/tables/loca.js +21 -8
  137. package/src/tables/maxp.js +1 -0
  138. package/src/tables/morx.js +14 -7
  139. package/src/tables/name.js +104 -23
  140. package/src/tables/opbd.js +2 -1
  141. package/src/tables/opentype.js +39 -4
  142. package/src/tables/post.js +8 -1
  143. package/src/tables/prep.js +1 -0
  144. package/src/tables/sbix.js +12 -1
  145. package/src/tables/variations.js +23 -3
  146. package/src/tables/vhea.js +1 -0
  147. package/src/tables/vmtx.js +18 -2
  148. package/src/utils.js +15 -0
  149. package/types/assets.d.ts +13 -0
  150. package/types/deps.d.ts +83 -0
  151. package/types/fontkit.d.ts +1324 -0
  152. package/types/index.d.ts +239 -0
  153. package/types/restructure.d.ts +354 -0
@@ -1,15 +1,27 @@
1
1
  import { cache } from '../decorators';
2
2
  import { range } from '../utils';
3
3
 
4
+ /** @typedef {import('../../types/fontkit').AATLookupTableData} AATLookupTableData */
5
+ /** @typedef {import('../../types/fontkit').AATUnboundedArray<number>} AATNumberArray */
6
+ /** @typedef {import('../../types/fontkit').AATLookupSegmentSingle} AATLookupSegmentSingle */
7
+
4
8
  export default class AATLookupTable {
9
+ /**
10
+ * @param {AATLookupTableData} table
11
+ */
5
12
  constructor(table) {
13
+ /** @type {AATLookupTableData} */
6
14
  this.table = table;
7
15
  }
8
16
 
17
+ /**
18
+ * @param {number} glyph
19
+ * @returns {number | null | undefined}
20
+ */
9
21
  lookup(glyph) {
10
22
  switch (this.table.version) {
11
23
  case 0: // simple array format
12
- return this.table.values.getItem(glyph);
24
+ return /** @type {AATNumberArray} */ (this.table.values).getItem(glyph);
13
25
 
14
26
  case 2: // segment format
15
27
  case 4: {
@@ -67,15 +79,20 @@ export default class AATLookupTable {
67
79
  }
68
80
 
69
81
  case 8: // lookup trimmed
70
- return this.table.values[glyph - this.table.firstGlyph];
82
+ return /** @type {number[]} */ (this.table.values)[glyph - this.table.firstGlyph];
71
83
 
72
84
  default:
73
85
  throw new Error(`Unknown lookup table format: ${this.table.version}`);
74
86
  }
75
87
  }
76
88
 
89
+ /**
90
+ * @param {number} classValue
91
+ * @returns {number[]}
92
+ */
77
93
  @cache
78
94
  glyphsForValue(classValue) {
95
+ /** @type {number[]} */
79
96
  let res = [];
80
97
 
81
98
  switch (this.table.version) {
@@ -107,8 +124,9 @@ export default class AATLookupTable {
107
124
  }
108
125
 
109
126
  case 8: { // lookup trimmed
110
- for (let i = 0; i < this.table.values.length; i++) {
111
- if (this.table.values[i] === classValue) {
127
+ let values = /** @type {number[]} */ (this.table.values);
128
+ for (let i = 0; i < values.length; i++) {
129
+ if (values[i] === classValue) {
112
130
  res.push(this.table.firstGlyph + i);
113
131
  }
114
132
  }
@@ -2,6 +2,14 @@ import AATStateMachine from './AATStateMachine';
2
2
  import AATLookupTable from './AATLookupTable';
3
3
  import { cache } from '../decorators';
4
4
 
5
+ /** @typedef {import('../../types/fontkit').LayoutFont} LayoutFont */
6
+ /** @typedef {import('../../types/fontkit').LayoutGlyph} LayoutGlyph */
7
+ /** @typedef {import('../../types/fontkit').MorxTable} MorxTable */
8
+ /** @typedef {import('../../types/fontkit').MorxSubtable} MorxSubtable */
9
+ /** @typedef {import('../../types/fontkit').AATStateEntry} AATStateEntry */
10
+ /** @typedef {import('../../types/fontkit').AATFeatureSettings} AATFeatureSettings */
11
+ /** @typedef {import('../../types/fontkit').FeatureValue} FeatureValue */
12
+
5
13
  // indic replacement flags
6
14
  const MARK_FIRST = 0x8000;
7
15
  const MARK_LAST = 0x2000;
@@ -31,20 +39,49 @@ const MARKED_INSERT_BEFORE = 0x0400;
31
39
  const CURRENT_INSERT_COUNT = 0x03E0;
32
40
  const MARKED_INSERT_COUNT = 0x001F;
33
41
 
42
+ /**
43
+ * @typedef {[number, number]} GlyphRange
44
+ */
45
+
34
46
  export default class AATMorxProcessor {
47
+ /**
48
+ * @param {LayoutFont} font
49
+ */
35
50
  constructor(font) {
36
51
  this.processIndicRearragement = this.processIndicRearragement.bind(this);
37
52
  this.processContextualSubstitution = this.processContextualSubstitution.bind(this);
38
53
  this.processLigature = this.processLigature.bind(this);
39
54
  this.processNoncontextualSubstitutions = this.processNoncontextualSubstitutions.bind(this);
40
55
  this.processGlyphInsertion = this.processGlyphInsertion.bind(this);
56
+ /** @type {LayoutFont} */
41
57
  this.font = font;
42
- this.morx = font.morx;
58
+ /** @type {MorxTable} */
59
+ this.morx = /** @type {MorxTable} */ (font.morx);
60
+ /** @type {Record<number, number[][]> | null} */
43
61
  this.inputCache = null;
62
+ /** @type {MorxSubtable | undefined} */
63
+ this.subtable = undefined;
64
+ /** @type {LayoutGlyph[]} */
65
+ this.glyphs = [];
66
+ /** @type {number[]} */
67
+ this.ligatureStack = [];
68
+ /** @type {number | null} */
69
+ this.markedGlyph = null;
70
+ /** @type {number | null} */
71
+ this.firstGlyph = null;
72
+ /** @type {number | null} */
73
+ this.lastGlyph = null;
74
+ /** @type {number | null} */
75
+ this.markedIndex = null;
44
76
  }
45
77
 
46
- // Processes an array of glyphs and applies the specified features
47
- // Features should be in the form of {featureType:{featureSetting:boolean}}
78
+ /**
79
+ * Processes an array of glyphs and applies the specified features.
80
+ * Features should be in the form of {featureType:{featureSetting:boolean}}
81
+ * @param {LayoutGlyph[]} glyphs
82
+ * @param {AATFeatureSettings | Record<number, Record<number, FeatureValue>>} [features]
83
+ * @returns {LayoutGlyph[]}
84
+ */
48
85
  process(glyphs, features = {}) {
49
86
  for (let chain of this.morx.chains) {
50
87
  let flags = chain.defaultFlags;
@@ -83,6 +120,11 @@ export default class AATMorxProcessor {
83
120
  return glyphs;
84
121
  }
85
122
 
123
+ /**
124
+ * @param {MorxSubtable} subtable
125
+ * @param {LayoutGlyph[]} glyphs
126
+ * @returns {LayoutGlyph[] | void}
127
+ */
86
128
  processSubtable(subtable, glyphs) {
87
129
  this.subtable = subtable;
88
130
  this.glyphs = glyphs;
@@ -104,28 +146,38 @@ export default class AATMorxProcessor {
104
146
  return stateMachine.process(this.glyphs, reverse, process);
105
147
  }
106
148
 
149
+ /**
150
+ * @param {MorxSubtable} subtable
151
+ * @returns {AATStateMachine}
152
+ */
107
153
  @cache
108
154
  getStateMachine(subtable) {
109
- return new AATStateMachine(subtable.table.stateTable);
155
+ return new AATStateMachine(/** @type {import('../../types/fontkit').AATStateTable} */ (subtable.table.stateTable));
110
156
  }
111
157
 
158
+ /**
159
+ * @returns {(glyph: LayoutGlyph | null, entry: AATStateEntry, index: number) => void}
160
+ */
112
161
  getProcessor() {
113
- switch (this.subtable.type) {
162
+ switch (/** @type {MorxSubtable} */ (this.subtable).type) {
114
163
  case 0:
115
164
  return this.processIndicRearragement;
116
165
  case 1:
117
166
  return this.processContextualSubstitution;
118
167
  case 2:
119
168
  return this.processLigature;
120
- case 4:
121
- return this.processNoncontextualSubstitutions;
122
169
  case 5:
123
170
  return this.processGlyphInsertion;
124
171
  default:
125
- throw new Error(`Invalid morx subtable type: ${this.subtable.type}`);
172
+ throw new Error(`Invalid morx subtable type: ${/** @type {MorxSubtable} */ (this.subtable).type}`);
126
173
  }
127
174
  }
128
175
 
176
+ /**
177
+ * @param {LayoutGlyph | null} glyph
178
+ * @param {AATStateEntry} entry
179
+ * @param {number} index
180
+ */
129
181
  processIndicRearragement(glyph, entry, index) {
130
182
  if (entry.flags & MARK_FIRST) {
131
183
  this.firstGlyph = index;
@@ -138,25 +190,37 @@ export default class AATMorxProcessor {
138
190
  reorderGlyphs(this.glyphs, entry.flags & VERB, this.firstGlyph, this.lastGlyph);
139
191
  }
140
192
 
193
+ /**
194
+ * @param {LayoutGlyph | null} glyph
195
+ * @param {AATStateEntry} entry
196
+ * @param {number} index
197
+ */
141
198
  processContextualSubstitution(glyph, entry, index) {
142
- let subsitutions = this.subtable.table.substitutionTable.items;
199
+ let subtable = /** @type {MorxSubtable} */ (this.subtable);
200
+ let subsitutions = subtable.table.substitutionTable.items;
143
201
  if (entry.markIndex !== 0xffff) {
144
- let lookup = subsitutions.getItem(entry.markIndex);
202
+ let lookup = subsitutions.getItem(/** @type {number} */ (entry.markIndex));
145
203
  let lookupTable = new AATLookupTable(lookup);
146
- glyph = this.glyphs[this.markedGlyph];
204
+ glyph = this.glyphs[/** @type {number} */ (this.markedGlyph)];
147
205
  let gid = lookupTable.lookup(glyph.id);
148
206
  if (gid) {
149
- this.glyphs[this.markedGlyph] = this.font.getGlyph(gid, glyph.codePoints);
207
+ let substituted = this.font.getGlyph(gid, glyph.codePoints);
208
+ if (substituted) {
209
+ this.glyphs[/** @type {number} */ (this.markedGlyph)] = substituted;
210
+ }
150
211
  }
151
212
  }
152
213
 
153
214
  if (entry.currentIndex !== 0xffff) {
154
- let lookup = subsitutions.getItem(entry.currentIndex);
215
+ let lookup = subsitutions.getItem(/** @type {number} */ (entry.currentIndex));
155
216
  let lookupTable = new AATLookupTable(lookup);
156
217
  glyph = this.glyphs[index];
157
218
  let gid = lookupTable.lookup(glyph.id);
158
219
  if (gid) {
159
- this.glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);
220
+ let substituted = this.font.getGlyph(gid, glyph.codePoints);
221
+ if (substituted) {
222
+ this.glyphs[index] = substituted;
223
+ }
160
224
  }
161
225
  }
162
226
 
@@ -165,43 +229,57 @@ export default class AATMorxProcessor {
165
229
  }
166
230
  }
167
231
 
232
+ /**
233
+ * @param {LayoutGlyph | null} glyph
234
+ * @param {AATStateEntry} entry
235
+ * @param {number} index
236
+ */
168
237
  processLigature(glyph, entry, index) {
169
238
  if (entry.flags & SET_COMPONENT) {
170
239
  this.ligatureStack.push(index);
171
240
  }
172
241
 
173
242
  if (entry.flags & PERFORM_ACTION) {
174
- let actions = this.subtable.table.ligatureActions;
175
- let components = this.subtable.table.components;
176
- let ligatureList = this.subtable.table.ligatureList;
243
+ let subtable = /** @type {MorxSubtable} */ (this.subtable);
244
+ let actions = subtable.table.ligatureActions;
245
+ let components = subtable.table.components;
246
+ let ligatureList = subtable.table.ligatureList;
177
247
 
178
- let actionIndex = entry.action;
248
+ let actionIndex = /** @type {number} */ (entry.action);
179
249
  let last = false;
180
250
  let ligatureIndex = 0;
251
+ /** @type {number[]} */
181
252
  let codePoints = [];
253
+ /** @type {number[]} */
182
254
  let ligatureGlyphs = [];
183
255
 
184
256
  while (!last) {
185
257
  let componentGlyph = this.ligatureStack.pop();
186
- codePoints.unshift(...this.glyphs[componentGlyph].codePoints);
258
+ codePoints.unshift(...this.glyphs[/** @type {number} */ (componentGlyph)].codePoints);
187
259
 
188
260
  let action = actions.getItem(actionIndex++);
189
261
  last = !!(action & LAST_MASK);
190
262
  let store = !!(action & STORE_MASK);
191
263
  let offset = (action & OFFSET_MASK) << 2 >> 2; // sign extend 30 to 32 bits
192
- offset += this.glyphs[componentGlyph].id;
264
+ offset += this.glyphs[/** @type {number} */ (componentGlyph)].id;
193
265
 
194
266
  let component = components.getItem(offset);
195
267
  ligatureIndex += component;
196
268
 
197
269
  if (last || store) {
198
270
  let ligatureEntry = ligatureList.getItem(ligatureIndex);
199
- this.glyphs[componentGlyph] = this.font.getGlyph(ligatureEntry, codePoints);
200
- ligatureGlyphs.push(componentGlyph);
271
+ let ligature = this.font.getGlyph(ligatureEntry, codePoints);
272
+ if (ligature) {
273
+ this.glyphs[/** @type {number} */ (componentGlyph)] = ligature;
274
+ }
275
+ ligatureGlyphs.push(/** @type {number} */ (componentGlyph));
201
276
  ligatureIndex = 0;
202
277
  codePoints = [];
203
278
  } else {
204
- this.glyphs[componentGlyph] = this.font.getGlyph(0xffff);
279
+ let deleted = this.font.getGlyph(0xffff);
280
+ if (deleted) {
281
+ this.glyphs[/** @type {number} */ (componentGlyph)] = deleted;
282
+ }
205
283
  }
206
284
  }
207
285
 
@@ -210,25 +288,44 @@ export default class AATMorxProcessor {
210
288
  }
211
289
  }
212
290
 
291
+ /**
292
+ * @param {MorxSubtable} subtable
293
+ * @param {LayoutGlyph[]} glyphs
294
+ * @param {number} [index]
295
+ */
213
296
  processNoncontextualSubstitutions(subtable, glyphs, index) {
214
- let lookupTable = new AATLookupTable(subtable.table.lookupTable);
297
+ let lookupTable = new AATLookupTable(/** @type {import('../../types/fontkit').AATLookupTableData} */ (subtable.table.lookupTable));
215
298
 
216
299
  for (index = 0; index < glyphs.length; index++) {
217
300
  let glyph = glyphs[index];
218
301
  if (glyph.id !== 0xffff) {
219
302
  let gid = lookupTable.lookup(glyph.id);
220
303
  if (gid) { // 0 means do nothing
221
- glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);
304
+ let substituted = this.font.getGlyph(gid, glyph.codePoints);
305
+ if (substituted) {
306
+ glyphs[index] = substituted;
307
+ }
222
308
  }
223
309
  }
224
310
  }
225
311
  }
226
312
 
313
+ /**
314
+ * @param {number} glyphIndex
315
+ * @param {number} insertionActionIndex
316
+ * @param {number} count
317
+ * @param {boolean} isBefore
318
+ */
227
319
  _insertGlyphs(glyphIndex, insertionActionIndex, count, isBefore) {
320
+ /** @type {LayoutGlyph[]} */
228
321
  let insertions = [];
322
+ let subtable = /** @type {MorxSubtable} */ (this.subtable);
229
323
  while (count--) {
230
- let gid = this.subtable.table.insertionActions.getItem(insertionActionIndex++);
231
- insertions.push(this.font.getGlyph(gid));
324
+ let gid = subtable.table.insertionActions.getItem(insertionActionIndex++);
325
+ let inserted = this.font.getGlyph(gid);
326
+ if (inserted) {
327
+ insertions.push(inserted);
328
+ }
232
329
  }
233
330
 
234
331
  if (!isBefore) {
@@ -238,6 +335,11 @@ export default class AATMorxProcessor {
238
335
  this.glyphs.splice(glyphIndex, 0, ...insertions);
239
336
  }
240
337
 
338
+ /**
339
+ * @param {LayoutGlyph | null} glyph
340
+ * @param {AATStateEntry} entry
341
+ * @param {number} index
342
+ */
241
343
  processGlyphInsertion(glyph, entry, index) {
242
344
  if (entry.flags & SET_MARK) {
243
345
  this.markedIndex = index;
@@ -246,17 +348,21 @@ export default class AATMorxProcessor {
246
348
  if (entry.markedInsertIndex !== 0xffff) {
247
349
  let count = (entry.flags & MARKED_INSERT_COUNT) >>> 5;
248
350
  let isBefore = !!(entry.flags & MARKED_INSERT_BEFORE);
249
- this._insertGlyphs(this.markedIndex, entry.markedInsertIndex, count, isBefore);
351
+ this._insertGlyphs(/** @type {number} */ (this.markedIndex), /** @type {number} */ (entry.markedInsertIndex), count, isBefore);
250
352
  }
251
353
 
252
354
  if (entry.currentInsertIndex !== 0xffff) {
253
355
  let count = (entry.flags & CURRENT_INSERT_COUNT) >>> 5;
254
356
  let isBefore = !!(entry.flags & CURRENT_INSERT_BEFORE);
255
- this._insertGlyphs(index, entry.currentInsertIndex, count, isBefore);
357
+ this._insertGlyphs(index, /** @type {number} */ (entry.currentInsertIndex), count, isBefore);
256
358
  }
257
359
  }
258
360
 
361
+ /**
362
+ * @returns {Array<[number, number]>}
363
+ */
259
364
  getSupportedFeatures() {
365
+ /** @type {Array<[number, number]>} */
260
366
  let features = [];
261
367
  for (let chain of this.morx.chains) {
262
368
  for (let feature of chain.features) {
@@ -267,12 +373,16 @@ export default class AATMorxProcessor {
267
373
  return features;
268
374
  }
269
375
 
376
+ /**
377
+ * @param {number} gid
378
+ * @returns {number[][]}
379
+ */
270
380
  generateInputs(gid) {
271
381
  if (!this.inputCache) {
272
382
  this.generateInputCache();
273
383
  }
274
384
 
275
- return this.inputCache[gid] || [];
385
+ return /** @type {Record<number, number[][]>} */ (this.inputCache)[gid] || [];
276
386
  }
277
387
 
278
388
  generateInputCache() {
@@ -289,6 +399,9 @@ export default class AATMorxProcessor {
289
399
  }
290
400
  }
291
401
 
402
+ /**
403
+ * @param {MorxSubtable} subtable
404
+ */
292
405
  generateInputsForSubtable(subtable) {
293
406
  // Currently, only supporting ligature subtables.
294
407
  if (subtable.type !== 2) {
@@ -306,7 +419,9 @@ export default class AATMorxProcessor {
306
419
  let stateMachine = this.getStateMachine(subtable);
307
420
  let process = this.getProcessor();
308
421
 
422
+ /** @type {LayoutGlyph[]} */
309
423
  let input = [];
424
+ /** @type {Array<{ glyphs: LayoutGlyph[], ligatureStack: number[] }>} */
310
425
  let stack = [];
311
426
  this.glyphs = [];
312
427
 
@@ -320,8 +435,11 @@ export default class AATMorxProcessor {
320
435
 
321
436
  // Add glyph to input and glyphs to process.
322
437
  let g = this.font.getGlyph(glyph);
438
+ if (!g) {
439
+ return;
440
+ }
323
441
  input.push(g);
324
- glyphs.push(input[input.length - 1]);
442
+ glyphs.push(g);
325
443
 
326
444
  // Process ligature substitution
327
445
  process(glyphs[glyphs.length - 1], entry, glyphs.length - 1);
@@ -338,26 +456,35 @@ export default class AATMorxProcessor {
338
456
 
339
457
  if (count === 1) {
340
458
  let result = input.map(g => g.id);
341
- let cache = this.inputCache[found];
459
+ let cacheMap = /** @type {Record<number, number[][]>} */ (this.inputCache);
460
+ let cache = cacheMap[found];
342
461
  if (cache) {
343
462
  cache.push(result);
344
463
  } else {
345
- this.inputCache[found] = [result];
464
+ cacheMap[found] = [result];
346
465
  }
347
466
  }
348
467
  },
349
468
 
350
469
  exit: () => {
351
- ({ glyphs: this.glyphs, ligatureStack: this.ligatureStack } = stack.pop());
470
+ ({ glyphs: this.glyphs, ligatureStack: this.ligatureStack } = /** @type {{ glyphs: LayoutGlyph[], ligatureStack: number[] }} */ (stack.pop()));
352
471
  input.pop();
353
472
  }
354
473
  });
355
474
  }
356
475
  }
357
476
 
358
- // swaps the glyphs in rangeA with those in rangeB
359
- // reverse the glyphs inside those ranges if specified
360
- // ranges are in [offset, length] format
477
+ /**
478
+ * swaps the glyphs in rangeA with those in rangeB
479
+ * reverse the glyphs inside those ranges if specified
480
+ * ranges are in [offset, length] format
481
+ * @param {LayoutGlyph[]} glyphs
482
+ * @param {GlyphRange} rangeA
483
+ * @param {GlyphRange} rangeB
484
+ * @param {boolean} [reverseA]
485
+ * @param {boolean} [reverseB]
486
+ * @returns {LayoutGlyph[]}
487
+ */
361
488
  function swap(glyphs, rangeA, rangeB, reverseA = false, reverseB = false) {
362
489
  let end = glyphs.splice(rangeB[0] - (rangeB[1] - 1), rangeB[1]);
363
490
  if (reverseB) {
@@ -373,55 +500,65 @@ function swap(glyphs, rangeA, rangeB, reverseA = false, reverseB = false) {
373
500
  return glyphs;
374
501
  }
375
502
 
503
+ /**
504
+ * @param {LayoutGlyph[]} glyphs
505
+ * @param {number} verb
506
+ * @param {number | null} firstGlyph
507
+ * @param {number | null} lastGlyph
508
+ * @returns {LayoutGlyph[]}
509
+ */
376
510
  function reorderGlyphs(glyphs, verb, firstGlyph, lastGlyph) {
511
+ let first = /** @type {number} */ (firstGlyph);
512
+ let last = /** @type {number} */ (lastGlyph);
513
+
377
514
  switch (verb) {
378
515
  case 0: // no change
379
516
  return glyphs;
380
517
 
381
518
  case 1: // Ax => xA
382
- return swap(glyphs, [firstGlyph, 1], [lastGlyph, 0]);
519
+ return swap(glyphs, [first, 1], [last, 0]);
383
520
 
384
521
  case 2: // xD => Dx
385
- return swap(glyphs, [firstGlyph, 0], [lastGlyph, 1]);
522
+ return swap(glyphs, [first, 0], [last, 1]);
386
523
 
387
524
  case 3: // AxD => DxA
388
- return swap(glyphs, [firstGlyph, 1], [lastGlyph, 1]);
525
+ return swap(glyphs, [first, 1], [last, 1]);
389
526
 
390
527
  case 4: // ABx => xAB
391
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0]);
528
+ return swap(glyphs, [first, 2], [last, 0]);
392
529
 
393
530
  case 5: // ABx => xBA
394
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0], true, false);
531
+ return swap(glyphs, [first, 2], [last, 0], true, false);
395
532
 
396
533
  case 6: // xCD => CDx
397
- return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2]);
534
+ return swap(glyphs, [first, 0], [last, 2]);
398
535
 
399
536
  case 7: // xCD => DCx
400
- return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2], false, true);
537
+ return swap(glyphs, [first, 0], [last, 2], false, true);
401
538
 
402
539
  case 8: // AxCD => CDxA
403
- return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2]);
540
+ return swap(glyphs, [first, 1], [last, 2]);
404
541
 
405
542
  case 9: // AxCD => DCxA
406
- return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2], false, true);
543
+ return swap(glyphs, [first, 1], [last, 2], false, true);
407
544
 
408
545
  case 10: // ABxD => DxAB
409
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1]);
546
+ return swap(glyphs, [first, 2], [last, 1]);
410
547
 
411
548
  case 11: // ABxD => DxBA
412
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1], true, false);
549
+ return swap(glyphs, [first, 2], [last, 1], true, false);
413
550
 
414
551
  case 12: // ABxCD => CDxAB
415
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2]);
552
+ return swap(glyphs, [first, 2], [last, 2]);
416
553
 
417
554
  case 13: // ABxCD => CDxBA
418
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, false);
555
+ return swap(glyphs, [first, 2], [last, 2], true, false);
419
556
 
420
557
  case 14: // ABxCD => DCxAB
421
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], false, true);
558
+ return swap(glyphs, [first, 2], [last, 2], false, true);
422
559
 
423
560
  case 15: // ABxCD => DCxBA
424
- return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, true);
561
+ return swap(glyphs, [first, 2], [last, 2], true, true);
425
562
 
426
563
  default:
427
564
  throw new Error(`Unknown verb: ${verb}`);
@@ -1,5 +1,9 @@
1
1
  import AATLookupTable from './AATLookupTable';
2
2
 
3
+ /** @typedef {import('../../types/fontkit').AATStateTable} AATStateTable */
4
+ /** @typedef {import('../../types/fontkit').AATStateEntry} AATStateEntry */
5
+ /** @typedef {import('../../types/fontkit').LayoutGlyph} LayoutGlyph */
6
+
3
7
  const START_OF_TEXT_STATE = 0;
4
8
  const _START_OF_LINE_STATE = 1;
5
9
 
@@ -10,18 +14,43 @@ const _END_OF_LINE_CLASS = 3;
10
14
 
11
15
  const DONT_ADVANCE = 0x4000;
12
16
 
17
+ /**
18
+ * @callback AATProcessEntry
19
+ * @param {LayoutGlyph | null} glyph
20
+ * @param {AATStateEntry} entry
21
+ * @param {number} index
22
+ */
23
+
24
+ /**
25
+ * @typedef {object} AATTraverseOpts
26
+ * @property {(glyph: number, entry: AATStateEntry) => void} [enter]
27
+ * @property {(glyph: number, entry: AATStateEntry) => void} [exit]
28
+ */
29
+
13
30
  export default class AATStateMachine {
31
+ /**
32
+ * @param {AATStateTable} stateTable
33
+ */
14
34
  constructor(stateTable) {
35
+ /** @type {AATStateTable} */
15
36
  this.stateTable = stateTable;
37
+ /** @type {AATLookupTable} */
16
38
  this.lookupTable = new AATLookupTable(stateTable.classTable);
17
39
  }
18
40
 
41
+ /**
42
+ * @param {LayoutGlyph[]} glyphs
43
+ * @param {boolean} reverse
44
+ * @param {AATProcessEntry} processEntry
45
+ * @returns {LayoutGlyph[]}
46
+ */
19
47
  process(glyphs, reverse, processEntry) {
20
48
  let currentState = START_OF_TEXT_STATE; // START_OF_LINE_STATE is used for kashida glyph insertions sometimes I think?
21
49
  let index = reverse ? glyphs.length - 1 : 0;
22
50
  let dir = reverse ? -1 : 1;
23
51
 
24
52
  while ((dir === 1 && index <= glyphs.length) || (dir === -1 && index >= -1)) {
53
+ /** @type {LayoutGlyph | null} */
25
54
  let glyph = null;
26
55
  let classCode;
27
56
  let shouldAdvance = true;
@@ -61,6 +90,9 @@ export default class AATStateMachine {
61
90
  /**
62
91
  * Performs a depth-first traversal of the glyph strings
63
92
  * represented by the state machine.
93
+ * @param {AATTraverseOpts} opts
94
+ * @param {number} [state]
95
+ * @param {Set<number>} [visited]
64
96
  */
65
97
  traverse(opts, state = 0, visited = new Set()) {
66
98
  if (visited.has(state)) {
package/src/base.js CHANGED
@@ -1,12 +1,26 @@
1
1
  import { DecodeStream } from 'restructure';
2
2
 
3
+ /** @typedef {import('../types/fontkit').FontFormat} FontFormat */
4
+ /** @typedef {import('../types/fontkit').OpenedFont} OpenedFont */
5
+
3
6
  export let logErrors = false;
4
7
 
8
+ /** @type {FontFormat[]} */
5
9
  let formats = [];
10
+
11
+ /**
12
+ * @param {FontFormat} format
13
+ * @returns {void}
14
+ */
6
15
  export function registerFormat(format) {
7
16
  formats.push(format);
8
17
  };
9
18
 
19
+ /**
20
+ * @param {ArrayBufferView} buffer
21
+ * @param {string | Uint8Array} [postscriptName]
22
+ * @returns {OpenedFont | null | undefined}
23
+ */
10
24
  export function create(buffer, postscriptName) {
11
25
  for (let i = 0; i < formats.length; i++) {
12
26
  let format = formats[i];
@@ -24,6 +38,11 @@ export function create(buffer, postscriptName) {
24
38
  };
25
39
 
26
40
  export let defaultLanguage = 'en';
41
+
42
+ /**
43
+ * @param {string} [lang]
44
+ * @returns {void}
45
+ */
27
46
  export function setDefaultLanguage(lang = 'en') {
28
47
  defaultLanguage = lang;
29
48
  };
@@ -1,3 +1,4 @@
1
+ /** @type {string[]} */
1
2
  export let ISOAdobeCharset = [
2
3
  '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
3
4
  'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
@@ -35,6 +36,7 @@ export let ISOAdobeCharset = [
35
36
  'ugrave', 'yacute', 'ydieresis', 'zcaron'
36
37
  ];
37
38
 
39
+ /** @type {string[]} */
38
40
  export let ExpertCharset = [
39
41
  '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
40
42
  'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
@@ -75,6 +77,7 @@ export let ExpertCharset = [
75
77
  'Ydieresissmall'
76
78
  ];
77
79
 
80
+ /** @type {string[]} */
78
81
  export let ExpertSubsetCharset = [
79
82
  '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
80
83
  'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',