@cantoo/fontkit 2.0.4

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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/dist/browser-module.mjs +13660 -0
  4. package/dist/browser-module.mjs.map +1 -0
  5. package/dist/browser.cjs +13689 -0
  6. package/dist/browser.cjs.map +1 -0
  7. package/dist/main.cjs +13712 -0
  8. package/dist/main.cjs.map +1 -0
  9. package/dist/module.mjs +13673 -0
  10. package/dist/module.mjs.map +1 -0
  11. package/package.json +99 -0
  12. package/src/CmapProcessor.js +285 -0
  13. package/src/DFont.js +113 -0
  14. package/src/TTFFont.js +621 -0
  15. package/src/TrueTypeCollection.js +65 -0
  16. package/src/WOFF2Font.js +222 -0
  17. package/src/WOFFFont.js +56 -0
  18. package/src/aat/AATFeatureMap.js +545 -0
  19. package/src/aat/AATLayoutEngine.js +48 -0
  20. package/src/aat/AATLookupTable.js +125 -0
  21. package/src/aat/AATMorxProcessor.js +429 -0
  22. package/src/aat/AATStateMachine.js +96 -0
  23. package/src/base.js +29 -0
  24. package/src/cff/CFFCharsets.js +99 -0
  25. package/src/cff/CFFDict.js +166 -0
  26. package/src/cff/CFFEncodings.js +48 -0
  27. package/src/cff/CFFFont.js +158 -0
  28. package/src/cff/CFFIndex.js +150 -0
  29. package/src/cff/CFFOperand.js +135 -0
  30. package/src/cff/CFFPointer.js +50 -0
  31. package/src/cff/CFFPrivateDict.js +39 -0
  32. package/src/cff/CFFStandardStrings.js +71 -0
  33. package/src/cff/CFFTop.js +236 -0
  34. package/src/decorators.js +36 -0
  35. package/src/encodings.js +219 -0
  36. package/src/fs.js +12 -0
  37. package/src/glyph/BBox.js +72 -0
  38. package/src/glyph/CBDTGlyph.js +9 -0
  39. package/src/glyph/CFFGlyph.js +635 -0
  40. package/src/glyph/COLRGlyph.js +108 -0
  41. package/src/glyph/Glyph.js +270 -0
  42. package/src/glyph/GlyphVariationProcessor.js +487 -0
  43. package/src/glyph/Path.js +257 -0
  44. package/src/glyph/SBIXGlyph.js +54 -0
  45. package/src/glyph/StandardNames.js +27 -0
  46. package/src/glyph/TTFGlyph.js +408 -0
  47. package/src/glyph/TTFGlyphEncoder.js +158 -0
  48. package/src/glyph/WOFF2Glyph.js +70 -0
  49. package/src/index.js +15 -0
  50. package/src/layout/GlyphPosition.js +30 -0
  51. package/src/layout/GlyphRun.js +108 -0
  52. package/src/layout/KernProcessor.js +97 -0
  53. package/src/layout/LayoutEngine.js +190 -0
  54. package/src/layout/Script.js +231 -0
  55. package/src/layout/UnicodeLayoutEngine.js +250 -0
  56. package/src/node.js +16 -0
  57. package/src/opentype/GPOSProcessor.js +311 -0
  58. package/src/opentype/GSUBProcessor.js +208 -0
  59. package/src/opentype/GlyphInfo.js +57 -0
  60. package/src/opentype/GlyphIterator.js +82 -0
  61. package/src/opentype/OTLayoutEngine.js +117 -0
  62. package/src/opentype/OTProcessor.js +472 -0
  63. package/src/opentype/ShapingPlan.js +121 -0
  64. package/src/opentype/shapers/ArabicShaper.js +124 -0
  65. package/src/opentype/shapers/DefaultShaper.js +116 -0
  66. package/src/opentype/shapers/HangulShaper.js +285 -0
  67. package/src/opentype/shapers/HebrewShaper.js +105 -0
  68. package/src/opentype/shapers/IndicShaper.js +914 -0
  69. package/src/opentype/shapers/ThaiShaper.js +238 -0
  70. package/src/opentype/shapers/UniversalShaper.js +186 -0
  71. package/src/opentype/shapers/data.trie +0 -0
  72. package/src/opentype/shapers/gen-indic.js +208 -0
  73. package/src/opentype/shapers/gen-use.js +287 -0
  74. package/src/opentype/shapers/generate-data.js +33 -0
  75. package/src/opentype/shapers/index.js +109 -0
  76. package/src/opentype/shapers/indic-data.js +175 -0
  77. package/src/opentype/shapers/indic.json +1 -0
  78. package/src/opentype/shapers/indic.machine +31 -0
  79. package/src/opentype/shapers/indic.trie +0 -0
  80. package/src/opentype/shapers/use.json +1 -0
  81. package/src/opentype/shapers/use.machine +44 -0
  82. package/src/opentype/shapers/use.trie +0 -0
  83. package/src/packages/unicode-properties/LICENSE +8 -0
  84. package/src/packages/unicode-properties/README.md +12 -0
  85. package/src/packages/unicode-properties/data-trie.js +1 -0
  86. package/src/packages/unicode-properties/data.js +1 -0
  87. package/src/packages/unicode-properties/data.json +1 -0
  88. package/src/packages/unicode-properties/data.trie +0 -0
  89. package/src/packages/unicode-properties/dist/index.cjs +257 -0
  90. package/src/packages/unicode-properties/dist/index.cjs.map +7 -0
  91. package/src/packages/unicode-properties/dist/index.mjs +234 -0
  92. package/src/packages/unicode-properties/dist/index.mjs.map +7 -0
  93. package/src/packages/unicode-properties/generate.js +107 -0
  94. package/src/packages/unicode-properties/index.js +184 -0
  95. package/src/packages/unicode-properties/package.json +50 -0
  96. package/src/packages/unicode-trie/LICENSE +8 -0
  97. package/src/packages/unicode-trie/README.md +13 -0
  98. package/src/packages/unicode-trie/builder.js +965 -0
  99. package/src/packages/unicode-trie/dist/builder.cjs +711 -0
  100. package/src/packages/unicode-trie/dist/builder.cjs.map +7 -0
  101. package/src/packages/unicode-trie/dist/builder.mjs +690 -0
  102. package/src/packages/unicode-trie/dist/builder.mjs.map +7 -0
  103. package/src/packages/unicode-trie/dist/index.cjs +112 -0
  104. package/src/packages/unicode-trie/dist/index.cjs.map +7 -0
  105. package/src/packages/unicode-trie/dist/index.mjs +91 -0
  106. package/src/packages/unicode-trie/dist/index.mjs.map +7 -0
  107. package/src/packages/unicode-trie/index.js +135 -0
  108. package/src/packages/unicode-trie/package.json +49 -0
  109. package/src/packages/unicode-trie/swap.js +21 -0
  110. package/src/subset/CFFSubset.js +176 -0
  111. package/src/subset/Subset.js +63 -0
  112. package/src/subset/TTFSubset.js +130 -0
  113. package/src/tables/BASE.js +78 -0
  114. package/src/tables/COLR.js +25 -0
  115. package/src/tables/CPAL.js +24 -0
  116. package/src/tables/DSIG.js +21 -0
  117. package/src/tables/EBDT.js +91 -0
  118. package/src/tables/EBLC.js +80 -0
  119. package/src/tables/GDEF.js +57 -0
  120. package/src/tables/GPOS.js +209 -0
  121. package/src/tables/GSUB.js +85 -0
  122. package/src/tables/HVAR.js +44 -0
  123. package/src/tables/JSTF.js +43 -0
  124. package/src/tables/LTSH.js +10 -0
  125. package/src/tables/OS2.js +84 -0
  126. package/src/tables/PCLT.js +21 -0
  127. package/src/tables/STAT.js +99 -0
  128. package/src/tables/VDMX.js +33 -0
  129. package/src/tables/VORG.js +14 -0
  130. package/src/tables/WOFF2Directory.js +73 -0
  131. package/src/tables/WOFFDirectory.js +37 -0
  132. package/src/tables/aat.js +157 -0
  133. package/src/tables/avar.js +19 -0
  134. package/src/tables/bsln.js +31 -0
  135. package/src/tables/cmap.js +127 -0
  136. package/src/tables/cvt.js +6 -0
  137. package/src/tables/directory.js +58 -0
  138. package/src/tables/feat.js +28 -0
  139. package/src/tables/fpgm.js +8 -0
  140. package/src/tables/fvar.js +31 -0
  141. package/src/tables/gasp.js +15 -0
  142. package/src/tables/glyf.js +4 -0
  143. package/src/tables/gvar.js +27 -0
  144. package/src/tables/hdmx.js +15 -0
  145. package/src/tables/head.js +25 -0
  146. package/src/tables/hhea.js +19 -0
  147. package/src/tables/hmtx.js +11 -0
  148. package/src/tables/index.js +119 -0
  149. package/src/tables/just.js +81 -0
  150. package/src/tables/kern.js +91 -0
  151. package/src/tables/loca.js +30 -0
  152. package/src/tables/maxp.js +20 -0
  153. package/src/tables/morx.js +79 -0
  154. package/src/tables/name.js +157 -0
  155. package/src/tables/opbd.js +15 -0
  156. package/src/tables/opentype.js +217 -0
  157. package/src/tables/post.js +34 -0
  158. package/src/tables/prep.js +6 -0
  159. package/src/tables/sbix.js +17 -0
  160. package/src/tables/variations.js +80 -0
  161. package/src/tables/vhea.js +19 -0
  162. package/src/tables/vmtx.js +12 -0
  163. package/src/utils.js +62 -0
@@ -0,0 +1,429 @@
1
+ import AATStateMachine from './AATStateMachine';
2
+ import AATLookupTable from './AATLookupTable';
3
+ import {cache} from '../decorators';
4
+
5
+ // indic replacement flags
6
+ const MARK_FIRST = 0x8000;
7
+ const MARK_LAST = 0x2000;
8
+ const VERB = 0x000F;
9
+
10
+ // contextual substitution and glyph insertion flag
11
+ const SET_MARK = 0x8000;
12
+
13
+ // ligature entry flags
14
+ const SET_COMPONENT = 0x8000;
15
+ const PERFORM_ACTION = 0x2000;
16
+
17
+ // ligature action masks
18
+ const LAST_MASK = 0x80000000;
19
+ const STORE_MASK = 0x40000000;
20
+ const OFFSET_MASK = 0x3FFFFFFF;
21
+
22
+ const _VERTICAL_ONLY = 0x800000;
23
+ const REVERSE_DIRECTION = 0x400000;
24
+ const _HORIZONTAL_AND_VERTICAL = 0x200000;
25
+
26
+ // glyph insertion flags
27
+ const _CURRENT_IS_KASHIDA_LIKE = 0x2000;
28
+ const _MARKED_IS_KASHIDA_LIKE = 0x1000;
29
+ const CURRENT_INSERT_BEFORE = 0x0800;
30
+ const MARKED_INSERT_BEFORE = 0x0400;
31
+ const CURRENT_INSERT_COUNT = 0x03E0;
32
+ const MARKED_INSERT_COUNT = 0x001F;
33
+
34
+ export default class AATMorxProcessor {
35
+ constructor(font) {
36
+ this.processIndicRearragement = this.processIndicRearragement.bind(this);
37
+ this.processContextualSubstitution = this.processContextualSubstitution.bind(this);
38
+ this.processLigature = this.processLigature.bind(this);
39
+ this.processNoncontextualSubstitutions = this.processNoncontextualSubstitutions.bind(this);
40
+ this.processGlyphInsertion = this.processGlyphInsertion.bind(this);
41
+ this.font = font;
42
+ this.morx = font.morx;
43
+ this.inputCache = null;
44
+ }
45
+
46
+ // Processes an array of glyphs and applies the specified features
47
+ // Features should be in the form of {featureType:{featureSetting:boolean}}
48
+ process(glyphs, features = {}) {
49
+ for (let chain of this.morx.chains) {
50
+ let flags = chain.defaultFlags;
51
+
52
+ // enable/disable the requested features
53
+ for (let feature of chain.features) {
54
+ let f;
55
+ if ((f = features[feature.featureType])) {
56
+ if (f[feature.featureSetting]) {
57
+ flags &= feature.disableFlags;
58
+ flags |= feature.enableFlags;
59
+ } else if (f[feature.featureSetting] === false) {
60
+ flags |= ~feature.disableFlags;
61
+ flags &= ~feature.enableFlags;
62
+ }
63
+ }
64
+ }
65
+
66
+ for (let subtable of chain.subtables) {
67
+ if (subtable.subFeatureFlags & flags) {
68
+ this.processSubtable(subtable, glyphs);
69
+ }
70
+ }
71
+ }
72
+
73
+ // remove deleted glyphs
74
+ let index = glyphs.length - 1;
75
+ while (index >= 0) {
76
+ if (glyphs[index].id === 0xffff) {
77
+ glyphs.splice(index, 1);
78
+ }
79
+
80
+ index--;
81
+ }
82
+
83
+ return glyphs;
84
+ }
85
+
86
+ processSubtable(subtable, glyphs) {
87
+ this.subtable = subtable;
88
+ this.glyphs = glyphs;
89
+ if (this.subtable.type === 4) {
90
+ this.processNoncontextualSubstitutions(this.subtable, this.glyphs);
91
+ return;
92
+ }
93
+
94
+ this.ligatureStack = [];
95
+ this.markedGlyph = null;
96
+ this.firstGlyph = null;
97
+ this.lastGlyph = null;
98
+ this.markedIndex = null;
99
+
100
+ let stateMachine = this.getStateMachine(subtable);
101
+ let process = this.getProcessor();
102
+
103
+ let reverse = !!(this.subtable.coverage & REVERSE_DIRECTION);
104
+ return stateMachine.process(this.glyphs, reverse, process);
105
+ }
106
+
107
+ @cache
108
+ getStateMachine(subtable) {
109
+ return new AATStateMachine(subtable.table.stateTable);
110
+ }
111
+
112
+ getProcessor() {
113
+ switch (this.subtable.type) {
114
+ case 0:
115
+ return this.processIndicRearragement;
116
+ case 1:
117
+ return this.processContextualSubstitution;
118
+ case 2:
119
+ return this.processLigature;
120
+ case 4:
121
+ return this.processNoncontextualSubstitutions;
122
+ case 5:
123
+ return this.processGlyphInsertion;
124
+ default:
125
+ throw new Error(`Invalid morx subtable type: ${this.subtable.type}`);
126
+ }
127
+ }
128
+
129
+ processIndicRearragement(glyph, entry, index) {
130
+ if (entry.flags & MARK_FIRST) {
131
+ this.firstGlyph = index;
132
+ }
133
+
134
+ if (entry.flags & MARK_LAST) {
135
+ this.lastGlyph = index;
136
+ }
137
+
138
+ reorderGlyphs(this.glyphs, entry.flags & VERB, this.firstGlyph, this.lastGlyph);
139
+ }
140
+
141
+ processContextualSubstitution(glyph, entry, index) {
142
+ let subsitutions = this.subtable.table.substitutionTable.items;
143
+ if (entry.markIndex !== 0xffff) {
144
+ let lookup = subsitutions.getItem(entry.markIndex);
145
+ let lookupTable = new AATLookupTable(lookup);
146
+ glyph = this.glyphs[this.markedGlyph];
147
+ let gid = lookupTable.lookup(glyph.id);
148
+ if (gid) {
149
+ this.glyphs[this.markedGlyph] = this.font.getGlyph(gid, glyph.codePoints);
150
+ }
151
+ }
152
+
153
+ if (entry.currentIndex !== 0xffff) {
154
+ let lookup = subsitutions.getItem(entry.currentIndex);
155
+ let lookupTable = new AATLookupTable(lookup);
156
+ glyph = this.glyphs[index];
157
+ let gid = lookupTable.lookup(glyph.id);
158
+ if (gid) {
159
+ this.glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);
160
+ }
161
+ }
162
+
163
+ if (entry.flags & SET_MARK) {
164
+ this.markedGlyph = index;
165
+ }
166
+ }
167
+
168
+ processLigature(glyph, entry, index) {
169
+ if (entry.flags & SET_COMPONENT) {
170
+ this.ligatureStack.push(index);
171
+ }
172
+
173
+ 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;
177
+
178
+ let actionIndex = entry.action;
179
+ let last = false;
180
+ let ligatureIndex = 0;
181
+ let codePoints = [];
182
+ let ligatureGlyphs = [];
183
+
184
+ while (!last) {
185
+ let componentGlyph = this.ligatureStack.pop();
186
+ codePoints.unshift(...this.glyphs[componentGlyph].codePoints);
187
+
188
+ let action = actions.getItem(actionIndex++);
189
+ last = !!(action & LAST_MASK);
190
+ let store = !!(action & STORE_MASK);
191
+ let offset = (action & OFFSET_MASK) << 2 >> 2; // sign extend 30 to 32 bits
192
+ offset += this.glyphs[componentGlyph].id;
193
+
194
+ let component = components.getItem(offset);
195
+ ligatureIndex += component;
196
+
197
+ if (last || store) {
198
+ let ligatureEntry = ligatureList.getItem(ligatureIndex);
199
+ this.glyphs[componentGlyph] = this.font.getGlyph(ligatureEntry, codePoints);
200
+ ligatureGlyphs.push(componentGlyph);
201
+ ligatureIndex = 0;
202
+ codePoints = [];
203
+ } else {
204
+ this.glyphs[componentGlyph] = this.font.getGlyph(0xffff);
205
+ }
206
+ }
207
+
208
+ // Put ligature glyph indexes back on the stack
209
+ this.ligatureStack.push(...ligatureGlyphs);
210
+ }
211
+ }
212
+
213
+ processNoncontextualSubstitutions(subtable, glyphs, index) {
214
+ let lookupTable = new AATLookupTable(subtable.table.lookupTable);
215
+
216
+ for (index = 0; index < glyphs.length; index++) {
217
+ let glyph = glyphs[index];
218
+ if (glyph.id !== 0xffff) {
219
+ let gid = lookupTable.lookup(glyph.id);
220
+ if (gid) { // 0 means do nothing
221
+ glyphs[index] = this.font.getGlyph(gid, glyph.codePoints);
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ _insertGlyphs(glyphIndex, insertionActionIndex, count, isBefore) {
228
+ let insertions = [];
229
+ while (count--) {
230
+ let gid = this.subtable.table.insertionActions.getItem(insertionActionIndex++);
231
+ insertions.push(this.font.getGlyph(gid));
232
+ }
233
+
234
+ if (!isBefore) {
235
+ glyphIndex++;
236
+ }
237
+
238
+ this.glyphs.splice(glyphIndex, 0, ...insertions);
239
+ }
240
+
241
+ processGlyphInsertion(glyph, entry, index) {
242
+ if (entry.flags & SET_MARK) {
243
+ this.markedIndex = index;
244
+ }
245
+
246
+ if (entry.markedInsertIndex !== 0xffff) {
247
+ let count = (entry.flags & MARKED_INSERT_COUNT) >>> 5;
248
+ let isBefore = !!(entry.flags & MARKED_INSERT_BEFORE);
249
+ this._insertGlyphs(this.markedIndex, entry.markedInsertIndex, count, isBefore);
250
+ }
251
+
252
+ if (entry.currentInsertIndex !== 0xffff) {
253
+ let count = (entry.flags & CURRENT_INSERT_COUNT) >>> 5;
254
+ let isBefore = !!(entry.flags & CURRENT_INSERT_BEFORE);
255
+ this._insertGlyphs(index, entry.currentInsertIndex, count, isBefore);
256
+ }
257
+ }
258
+
259
+ getSupportedFeatures() {
260
+ let features = [];
261
+ for (let chain of this.morx.chains) {
262
+ for (let feature of chain.features) {
263
+ features.push([feature.featureType, feature.featureSetting]);
264
+ }
265
+ }
266
+
267
+ return features;
268
+ }
269
+
270
+ generateInputs(gid) {
271
+ if (!this.inputCache) {
272
+ this.generateInputCache();
273
+ }
274
+
275
+ return this.inputCache[gid] || [];
276
+ }
277
+
278
+ generateInputCache() {
279
+ this.inputCache = {};
280
+
281
+ for (let chain of this.morx.chains) {
282
+ let flags = chain.defaultFlags;
283
+
284
+ for (let subtable of chain.subtables) {
285
+ if (subtable.subFeatureFlags & flags) {
286
+ this.generateInputsForSubtable(subtable);
287
+ }
288
+ }
289
+ }
290
+ }
291
+
292
+ generateInputsForSubtable(subtable) {
293
+ // Currently, only supporting ligature subtables.
294
+ if (subtable.type !== 2) {
295
+ return;
296
+ }
297
+
298
+ let reverse = !!(subtable.coverage & REVERSE_DIRECTION);
299
+ if (reverse) {
300
+ throw new Error('Reverse subtable, not supported.');
301
+ }
302
+
303
+ this.subtable = subtable;
304
+ this.ligatureStack = [];
305
+
306
+ let stateMachine = this.getStateMachine(subtable);
307
+ let process = this.getProcessor();
308
+
309
+ let input = [];
310
+ let stack = [];
311
+ this.glyphs = [];
312
+
313
+ stateMachine.traverse({
314
+ enter: (glyph, entry) => {
315
+ let glyphs = this.glyphs;
316
+ stack.push({
317
+ glyphs: glyphs.slice(),
318
+ ligatureStack: this.ligatureStack.slice()
319
+ });
320
+
321
+ // Add glyph to input and glyphs to process.
322
+ let g = this.font.getGlyph(glyph);
323
+ input.push(g);
324
+ glyphs.push(input[input.length - 1]);
325
+
326
+ // Process ligature substitution
327
+ process(glyphs[glyphs.length - 1], entry, glyphs.length - 1);
328
+
329
+ // Add input to result if only one matching (non-deleted) glyph remains.
330
+ let count = 0;
331
+ let found = 0;
332
+ for (let i = 0; i < glyphs.length && count <= 1; i++) {
333
+ if (glyphs[i].id !== 0xffff) {
334
+ count++;
335
+ found = glyphs[i].id;
336
+ }
337
+ }
338
+
339
+ if (count === 1) {
340
+ let result = input.map(g => g.id);
341
+ let cache = this.inputCache[found];
342
+ if (cache) {
343
+ cache.push(result);
344
+ } else {
345
+ this.inputCache[found] = [result];
346
+ }
347
+ }
348
+ },
349
+
350
+ exit: () => {
351
+ ({glyphs: this.glyphs, ligatureStack: this.ligatureStack} = stack.pop());
352
+ input.pop();
353
+ }
354
+ });
355
+ }
356
+ }
357
+
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
361
+ function swap(glyphs, rangeA, rangeB, reverseA = false, reverseB = false) {
362
+ let end = glyphs.splice(rangeB[0] - (rangeB[1] - 1), rangeB[1]);
363
+ if (reverseB) {
364
+ end.reverse();
365
+ }
366
+
367
+ let start = glyphs.splice(rangeA[0], rangeA[1], ...end);
368
+ if (reverseA) {
369
+ start.reverse();
370
+ }
371
+
372
+ glyphs.splice(rangeB[0] - (rangeA[1] - 1), 0, ...start);
373
+ return glyphs;
374
+ }
375
+
376
+ function reorderGlyphs(glyphs, verb, firstGlyph, lastGlyph) {
377
+ switch (verb) {
378
+ case 0: // no change
379
+ return glyphs;
380
+
381
+ case 1: // Ax => xA
382
+ return swap(glyphs, [firstGlyph, 1], [lastGlyph, 0]);
383
+
384
+ case 2: // xD => Dx
385
+ return swap(glyphs, [firstGlyph, 0], [lastGlyph, 1]);
386
+
387
+ case 3: // AxD => DxA
388
+ return swap(glyphs, [firstGlyph, 1], [lastGlyph, 1]);
389
+
390
+ case 4: // ABx => xAB
391
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0]);
392
+
393
+ case 5: // ABx => xBA
394
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 0], true, false);
395
+
396
+ case 6: // xCD => CDx
397
+ return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2]);
398
+
399
+ case 7: // xCD => DCx
400
+ return swap(glyphs, [firstGlyph, 0], [lastGlyph, 2], false, true);
401
+
402
+ case 8: // AxCD => CDxA
403
+ return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2]);
404
+
405
+ case 9: // AxCD => DCxA
406
+ return swap(glyphs, [firstGlyph, 1], [lastGlyph, 2], false, true);
407
+
408
+ case 10: // ABxD => DxAB
409
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1]);
410
+
411
+ case 11: // ABxD => DxBA
412
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 1], true, false);
413
+
414
+ case 12: // ABxCD => CDxAB
415
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2]);
416
+
417
+ case 13: // ABxCD => CDxBA
418
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, false);
419
+
420
+ case 14: // ABxCD => DCxAB
421
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], false, true);
422
+
423
+ case 15: // ABxCD => DCxBA
424
+ return swap(glyphs, [firstGlyph, 2], [lastGlyph, 2], true, true);
425
+
426
+ default:
427
+ throw new Error(`Unknown verb: ${verb}`);
428
+ }
429
+ }
@@ -0,0 +1,96 @@
1
+ import AATLookupTable from './AATLookupTable';
2
+
3
+ const START_OF_TEXT_STATE = 0;
4
+ const _START_OF_LINE_STATE = 1;
5
+
6
+ const END_OF_TEXT_CLASS = 0;
7
+ const OUT_OF_BOUNDS_CLASS = 1;
8
+ const DELETED_GLYPH_CLASS = 2;
9
+ const _END_OF_LINE_CLASS = 3;
10
+
11
+ const DONT_ADVANCE = 0x4000;
12
+
13
+ export default class AATStateMachine {
14
+ constructor(stateTable) {
15
+ this.stateTable = stateTable;
16
+ this.lookupTable = new AATLookupTable(stateTable.classTable);
17
+ }
18
+
19
+ process(glyphs, reverse, processEntry) {
20
+ let currentState = START_OF_TEXT_STATE; // START_OF_LINE_STATE is used for kashida glyph insertions sometimes I think?
21
+ let index = reverse ? glyphs.length - 1 : 0;
22
+ let dir = reverse ? -1 : 1;
23
+
24
+ while ((dir === 1 && index <= glyphs.length) || (dir === -1 && index >= -1)) {
25
+ let glyph = null;
26
+ let classCode;
27
+ let shouldAdvance = true;
28
+
29
+ if (index === glyphs.length || index === -1) {
30
+ classCode = END_OF_TEXT_CLASS;
31
+ } else {
32
+ glyph = glyphs[index];
33
+ if (glyph.id === 0xffff) { // deleted glyph
34
+ classCode = DELETED_GLYPH_CLASS;
35
+ } else {
36
+ classCode = this.lookupTable.lookup(glyph.id);
37
+ if (classCode == null) {
38
+ classCode = OUT_OF_BOUNDS_CLASS;
39
+ }
40
+ }
41
+ }
42
+
43
+ let row = this.stateTable.stateArray.getItem(currentState);
44
+ let entryIndex = row[classCode];
45
+ let entry = this.stateTable.entryTable.getItem(entryIndex);
46
+
47
+ if (classCode !== END_OF_TEXT_CLASS && classCode !== DELETED_GLYPH_CLASS) {
48
+ processEntry(glyph, entry, index);
49
+ shouldAdvance = !(entry.flags & DONT_ADVANCE);
50
+ }
51
+
52
+ currentState = entry.newState;
53
+ if (shouldAdvance) {
54
+ index += dir;
55
+ }
56
+ }
57
+
58
+ return glyphs;
59
+ }
60
+
61
+ /**
62
+ * Performs a depth-first traversal of the glyph strings
63
+ * represented by the state machine.
64
+ */
65
+ traverse(opts, state = 0, visited = new Set) {
66
+ if (visited.has(state)) {
67
+ return;
68
+ }
69
+
70
+ visited.add(state);
71
+
72
+ let {nClasses, stateArray, entryTable} = this.stateTable;
73
+ let row = stateArray.getItem(state);
74
+
75
+ // Skip predefined classes
76
+ for (let classCode = 4; classCode < nClasses; classCode++) {
77
+ let entryIndex = row[classCode];
78
+ let entry = entryTable.getItem(entryIndex);
79
+
80
+ // Try all glyphs in the class
81
+ for (let glyph of this.lookupTable.glyphsForValue(classCode)) {
82
+ if (opts.enter) {
83
+ opts.enter(glyph, entry);
84
+ }
85
+
86
+ if (entry.newState !== 0) {
87
+ this.traverse(opts, entry.newState, visited);
88
+ }
89
+
90
+ if (opts.exit) {
91
+ opts.exit(glyph, entry);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
package/src/base.js ADDED
@@ -0,0 +1,29 @@
1
+ import {DecodeStream} from 'restructure';
2
+
3
+ export let logErrors = false;
4
+
5
+ let formats = [];
6
+ export function registerFormat(format) {
7
+ formats.push(format);
8
+ };
9
+
10
+ export function create(buffer, postscriptName) {
11
+ for (let i = 0; i < formats.length; i++) {
12
+ let format = formats[i];
13
+ if (format.probe(buffer)) {
14
+ let font = new format(new DecodeStream(buffer));
15
+ if (postscriptName) {
16
+ return font.getFont(postscriptName);
17
+ }
18
+
19
+ return font;
20
+ }
21
+ }
22
+
23
+ throw new Error('Unknown font format');
24
+ };
25
+
26
+ export let defaultLanguage = 'en';
27
+ export function setDefaultLanguage(lang = 'en') {
28
+ defaultLanguage = lang;
29
+ };
@@ -0,0 +1,99 @@
1
+ export let ISOAdobeCharset = [
2
+ '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
3
+ 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
4
+ 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero',
5
+ 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
6
+ 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater', 'question',
7
+ 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
8
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
9
+ 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
10
+ 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
11
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
12
+ 'braceleft', 'bar', 'braceright', 'asciitilde', 'exclamdown', 'cent',
13
+ 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency',
14
+ 'quotesingle', 'quotedblleft', 'guillemotleft', 'guilsinglleft',
15
+ 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', 'daggerdbl',
16
+ 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
17
+ 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis',
18
+ 'perthousand', 'questiondown', 'grave', 'acute', 'circumflex', 'tilde',
19
+ 'macron', 'breve', 'dotaccent', 'dieresis', 'ring', 'cedilla',
20
+ 'hungarumlaut', 'ogonek', 'caron', 'emdash', 'AE', 'ordfeminine',
21
+ 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', 'dotlessi', 'lslash',
22
+ 'oslash', 'oe', 'germandbls', 'onesuperior', 'logicalnot', 'mu',
23
+ 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', 'onequarter',
24
+ 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', 'twosuperior',
25
+ 'registered', 'minus', 'eth', 'multiply', 'threesuperior', 'copyright',
26
+ 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', 'Atilde',
27
+ 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', 'Iacute',
28
+ 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', 'Ocircumflex',
29
+ 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', 'Ucircumflex',
30
+ 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', 'aacute',
31
+ 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
32
+ 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
33
+ 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
34
+ 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis',
35
+ 'ugrave', 'yacute', 'ydieresis', 'zcaron'
36
+ ];
37
+
38
+ export let ExpertCharset = [
39
+ '.notdef', 'space', 'exclamsmall', 'Hungarumlautsmall', 'dollaroldstyle',
40
+ 'dollarsuperior', 'ampersandsmall', 'Acutesmall', 'parenleftsuperior',
41
+ 'parenrightsuperior', 'twodotenleader', 'onedotenleader', 'comma',
42
+ 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle',
43
+ 'twooldstyle', 'threeoldstyle', 'fouroldstyle', 'fiveoldstyle',
44
+ 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle',
45
+ 'colon', 'semicolon', 'commasuperior', 'threequartersemdash',
46
+ 'periodsuperior', 'questionsmall', 'asuperior', 'bsuperior',
47
+ 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
48
+ 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
49
+ 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
50
+ 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
51
+ 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall',
52
+ 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall',
53
+ 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall',
54
+ 'Vsmall', 'Wsmall', 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary',
55
+ 'onefitted', 'rupiah', 'Tildesmall', 'exclamdownsmall', 'centoldstyle',
56
+ 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
57
+ 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
58
+ 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall',
59
+ 'Cedillasmall', 'onequarter', 'onehalf', 'threequarters',
60
+ 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths',
61
+ 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
62
+ 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
63
+ 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
64
+ 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
65
+ 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
66
+ 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
67
+ 'periodinferior', 'commainferior', 'Agravesmall', 'Aacutesmall',
68
+ 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
69
+ 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall',
70
+ 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
71
+ 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall',
72
+ 'Ogravesmall', 'Oacutesmall', 'Ocircumflexsmall', 'Otildesmall',
73
+ 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
74
+ 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall',
75
+ 'Ydieresissmall'
76
+ ];
77
+
78
+ export let ExpertSubsetCharset = [
79
+ '.notdef', 'space', 'dollaroldstyle', 'dollarsuperior',
80
+ 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader',
81
+ 'onedotenleader', 'comma', 'hyphen', 'period', 'fraction',
82
+ 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
83
+ 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle',
84
+ 'eightoldstyle', 'nineoldstyle', 'colon', 'semicolon', 'commasuperior',
85
+ 'threequartersemdash', 'periodsuperior', 'asuperior', 'bsuperior',
86
+ 'centsuperior', 'dsuperior', 'esuperior', 'isuperior', 'lsuperior',
87
+ 'msuperior', 'nsuperior', 'osuperior', 'rsuperior', 'ssuperior',
88
+ 'tsuperior', 'ff', 'fi', 'fl', 'ffi', 'ffl', 'parenleftinferior',
89
+ 'parenrightinferior', 'hyphensuperior', 'colonmonetary', 'onefitted',
90
+ 'rupiah', 'centoldstyle', 'figuredash', 'hypheninferior', 'onequarter',
91
+ 'onehalf', 'threequarters', 'oneeighth', 'threeeighths', 'fiveeighths',
92
+ 'seveneighths', 'onethird', 'twothirds', 'zerosuperior', 'onesuperior',
93
+ 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
94
+ 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior',
95
+ 'zeroinferior', 'oneinferior', 'twoinferior', 'threeinferior',
96
+ 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior',
97
+ 'eightinferior', 'nineinferior', 'centinferior', 'dollarinferior',
98
+ 'periodinferior', 'commainferior'
99
+ ];