@cantoo/fontkit 2.0.4 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-module.mjs +4448 -1142
- package/dist/browser-module.mjs.map +1 -1
- package/dist/browser.cjs +4449 -1142
- package/dist/browser.cjs.map +1 -1
- package/dist/main.cjs +4449 -1142
- package/dist/main.cjs.map +1 -1
- package/dist/module.mjs +4448 -1142
- package/dist/module.mjs.map +1 -1
- package/package.json +4 -1
- package/src/CmapProcessor.js +60 -21
- package/src/DFont.js +114 -14
- package/src/TTFFont.js +260 -62
- package/src/TrueTypeCollection.js +59 -15
- package/src/WOFF2Font.js +128 -22
- package/src/WOFFFont.js +45 -8
- package/src/aat/AATFeatureMap.js +83 -40
- package/src/aat/AATLayoutEngine.js +34 -2
- package/src/aat/AATLookupTable.js +24 -6
- package/src/aat/AATMorxProcessor.js +202 -65
- package/src/aat/AATStateMachine.js +35 -3
- package/src/base.js +20 -1
- package/src/cff/CFFCharsets.js +3 -0
- package/src/cff/CFFDict.js +81 -11
- package/src/cff/CFFEncodings.js +2 -0
- package/src/cff/CFFFont.js +120 -24
- package/src/cff/CFFIndex.js +66 -9
- package/src/cff/CFFOperand.js +53 -28
- package/src/cff/CFFPointer.js +41 -2
- package/src/cff/CFFPrivateDict.js +34 -24
- package/src/cff/CFFStandardStrings.js +68 -67
- package/src/cff/CFFTop.js +161 -68
- package/src/decorators.js +34 -15
- package/src/encodings.js +133 -116
- package/src/fs.js +10 -0
- package/src/glyph/BBox.js +14 -0
- package/src/glyph/CFFGlyph.js +293 -152
- package/src/glyph/COLRGlyph.js +40 -5
- package/src/glyph/Glyph.js +72 -13
- package/src/glyph/GlyphVariationProcessor.js +158 -62
- package/src/glyph/Path.js +119 -32
- package/src/glyph/SBIXGlyph.js +57 -8
- package/src/glyph/StandardNames.js +1 -0
- package/src/glyph/TTFGlyph.js +203 -63
- package/src/glyph/TTFGlyphEncoder.js +58 -26
- package/src/glyph/WOFF2Glyph.js +25 -6
- package/src/layout/GlyphPosition.js +6 -0
- package/src/layout/GlyphRun.js +28 -10
- package/src/layout/KernProcessor.js +63 -4
- package/src/layout/LayoutEngine.js +99 -26
- package/src/layout/Script.js +52 -26
- package/src/layout/UnicodeLayoutEngine.js +34 -10
- package/src/opentype/GPOSProcessor.js +156 -45
- package/src/opentype/GSUBProcessor.js +92 -33
- package/src/opentype/GlyphInfo.js +53 -5
- package/src/opentype/GlyphIterator.js +51 -2
- package/src/opentype/OTLayoutEngine.js +66 -8
- package/src/opentype/OTProcessor.js +284 -71
- package/src/opentype/ShapingPlan.js +52 -5
- package/src/opentype/shapers/ArabicShaper.js +27 -8
- package/src/opentype/shapers/DefaultShaper.js +54 -10
- package/src/opentype/shapers/HangulShaper.js +120 -42
- package/src/opentype/shapers/HebrewShaper.js +50 -16
- package/src/opentype/shapers/IndicShaper.js +159 -44
- package/src/opentype/shapers/ThaiShaper.js +50 -19
- package/src/opentype/shapers/UniversalShaper.js +83 -17
- package/src/opentype/shapers/index.js +48 -35
- package/src/opentype/shapers/indic-data.js +2 -2
- package/src/packages/unicode-properties/data-trie.js +2 -1
- package/src/packages/unicode-properties/data.js +13 -1
- package/src/packages/unicode-properties/dist/index.cjs +23 -10
- package/src/packages/unicode-properties/dist/index.cjs.map +2 -2
- package/src/packages/unicode-properties/dist/index.mjs +22 -10
- package/src/packages/unicode-properties/dist/index.mjs.map +2 -2
- package/src/packages/unicode-properties/generate.js +3 -4
- package/src/packages/unicode-properties/index.js +95 -30
- package/src/packages/unicode-properties/package.json +1 -1
- package/src/packages/unicode-trie/builder.js +146 -29
- package/src/packages/unicode-trie/dist/builder.cjs +135 -25
- package/src/packages/unicode-trie/dist/builder.cjs.map +2 -2
- package/src/packages/unicode-trie/dist/builder.mjs +134 -25
- package/src/packages/unicode-trie/dist/builder.mjs.map +2 -2
- package/src/packages/unicode-trie/dist/index.cjs +22 -9
- package/src/packages/unicode-trie/dist/index.cjs.map +2 -2
- package/src/packages/unicode-trie/dist/index.mjs +21 -9
- package/src/packages/unicode-trie/dist/index.mjs.map +2 -2
- package/src/packages/unicode-trie/index.js +63 -12
- package/src/packages/unicode-trie/package.json +1 -1
- package/src/packages/unicode-trie/swap.js +15 -2
- package/src/subset/CFFSubset.js +112 -22
- package/src/subset/Subset.js +23 -3
- package/src/subset/TTFSubset.js +84 -41
- package/src/tables/BASE.js +28 -27
- package/src/tables/COLR.js +10 -9
- package/src/tables/CPAL.js +2 -1
- package/src/tables/DSIG.js +8 -7
- package/src/tables/EBDT.js +10 -4
- package/src/tables/EBLC.js +70 -10
- package/src/tables/GDEF.js +18 -17
- package/src/tables/GPOS.js +153 -90
- package/src/tables/GSUB.js +50 -39
- package/src/tables/HVAR.js +51 -5
- package/src/tables/JSTF.js +17 -16
- package/src/tables/LTSH.js +4 -3
- package/src/tables/OS2.js +50 -49
- package/src/tables/PCLT.js +16 -15
- package/src/tables/STAT.js +46 -6
- package/src/tables/VDMX.js +18 -17
- package/src/tables/VORG.js +8 -7
- package/src/tables/WOFF2Directory.js +57 -9
- package/src/tables/WOFFDirectory.js +32 -20
- package/src/tables/aat.js +160 -35
- package/src/tables/avar.js +1 -0
- package/src/tables/bsln.js +3 -2
- package/src/tables/cmap.js +83 -63
- package/src/tables/cvt.js +1 -0
- package/src/tables/directory.js +56 -28
- package/src/tables/feat.js +24 -2
- package/src/tables/fpgm.js +1 -0
- package/src/tables/fvar.js +32 -4
- package/src/tables/gasp.js +6 -5
- package/src/tables/glyf.js +2 -1
- package/src/tables/gvar.js +29 -2
- package/src/tables/hdmx.js +18 -7
- package/src/tables/head.js +17 -16
- package/src/tables/hhea.js +15 -14
- package/src/tables/hmtx.js +18 -2
- package/src/tables/index.js +1 -5
- package/src/tables/just.js +15 -4
- package/src/tables/kern.js +84 -47
- package/src/tables/loca.js +23 -10
- package/src/tables/maxp.js +16 -15
- package/src/tables/morx.js +27 -20
- package/src/tables/name.js +120 -39
- package/src/tables/opbd.js +2 -1
- package/src/tables/opentype.js +126 -91
- package/src/tables/post.js +18 -11
- package/src/tables/prep.js +1 -0
- package/src/tables/sbix.js +12 -1
- package/src/tables/variations.js +29 -9
- package/src/tables/vhea.js +15 -14
- package/src/tables/vmtx.js +20 -4
- package/src/utils.js +15 -0
|
@@ -1,50 +1,87 @@
|
|
|
1
1
|
import AATStateMachine from './AATStateMachine';
|
|
2
2
|
import AATLookupTable from './AATLookupTable';
|
|
3
|
-
import {cache} from '../decorators';
|
|
3
|
+
import { cache } from '../decorators';
|
|
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 */
|
|
4
12
|
|
|
5
13
|
// indic replacement flags
|
|
6
14
|
const MARK_FIRST = 0x8000;
|
|
7
|
-
const MARK_LAST
|
|
8
|
-
const VERB
|
|
15
|
+
const MARK_LAST = 0x2000;
|
|
16
|
+
const VERB = 0x000F;
|
|
9
17
|
|
|
10
18
|
// contextual substitution and glyph insertion flag
|
|
11
19
|
const SET_MARK = 0x8000;
|
|
12
20
|
|
|
13
21
|
// ligature entry flags
|
|
14
|
-
const SET_COMPONENT
|
|
22
|
+
const SET_COMPONENT = 0x8000;
|
|
15
23
|
const PERFORM_ACTION = 0x2000;
|
|
16
24
|
|
|
17
25
|
// ligature action masks
|
|
18
|
-
const LAST_MASK
|
|
19
|
-
const STORE_MASK
|
|
26
|
+
const LAST_MASK = 0x80000000;
|
|
27
|
+
const STORE_MASK = 0x40000000;
|
|
20
28
|
const OFFSET_MASK = 0x3FFFFFFF;
|
|
21
29
|
|
|
22
|
-
const _VERTICAL_ONLY
|
|
23
|
-
const REVERSE_DIRECTION
|
|
30
|
+
const _VERTICAL_ONLY = 0x800000;
|
|
31
|
+
const REVERSE_DIRECTION = 0x400000;
|
|
24
32
|
const _HORIZONTAL_AND_VERTICAL = 0x200000;
|
|
25
33
|
|
|
26
34
|
// glyph insertion flags
|
|
27
35
|
const _CURRENT_IS_KASHIDA_LIKE = 0x2000;
|
|
28
|
-
const _MARKED_IS_KASHIDA_LIKE
|
|
29
|
-
const CURRENT_INSERT_BEFORE
|
|
30
|
-
const MARKED_INSERT_BEFORE
|
|
31
|
-
const CURRENT_INSERT_COUNT
|
|
32
|
-
const MARKED_INSERT_COUNT
|
|
36
|
+
const _MARKED_IS_KASHIDA_LIKE = 0x1000;
|
|
37
|
+
const CURRENT_INSERT_BEFORE = 0x0800;
|
|
38
|
+
const MARKED_INSERT_BEFORE = 0x0400;
|
|
39
|
+
const CURRENT_INSERT_COUNT = 0x03E0;
|
|
40
|
+
const MARKED_INSERT_COUNT = 0x001F;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {[number, number]} GlyphRange
|
|
44
|
+
*/
|
|
33
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
|
-
|
|
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
|
-
|
|
47
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
175
|
-
let
|
|
176
|
-
let
|
|
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
|
-
|
|
200
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
231
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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, [
|
|
519
|
+
return swap(glyphs, [first, 1], [last, 0]);
|
|
383
520
|
|
|
384
521
|
case 2: // xD => Dx
|
|
385
|
-
return swap(glyphs, [
|
|
522
|
+
return swap(glyphs, [first, 0], [last, 1]);
|
|
386
523
|
|
|
387
524
|
case 3: // AxD => DxA
|
|
388
|
-
return swap(glyphs, [
|
|
525
|
+
return swap(glyphs, [first, 1], [last, 1]);
|
|
389
526
|
|
|
390
527
|
case 4: // ABx => xAB
|
|
391
|
-
return swap(glyphs, [
|
|
528
|
+
return swap(glyphs, [first, 2], [last, 0]);
|
|
392
529
|
|
|
393
530
|
case 5: // ABx => xBA
|
|
394
|
-
return swap(glyphs, [
|
|
531
|
+
return swap(glyphs, [first, 2], [last, 0], true, false);
|
|
395
532
|
|
|
396
533
|
case 6: // xCD => CDx
|
|
397
|
-
return swap(glyphs, [
|
|
534
|
+
return swap(glyphs, [first, 0], [last, 2]);
|
|
398
535
|
|
|
399
536
|
case 7: // xCD => DCx
|
|
400
|
-
return swap(glyphs, [
|
|
537
|
+
return swap(glyphs, [first, 0], [last, 2], false, true);
|
|
401
538
|
|
|
402
539
|
case 8: // AxCD => CDxA
|
|
403
|
-
return swap(glyphs, [
|
|
540
|
+
return swap(glyphs, [first, 1], [last, 2]);
|
|
404
541
|
|
|
405
542
|
case 9: // AxCD => DCxA
|
|
406
|
-
return swap(glyphs, [
|
|
543
|
+
return swap(glyphs, [first, 1], [last, 2], false, true);
|
|
407
544
|
|
|
408
545
|
case 10: // ABxD => DxAB
|
|
409
|
-
return swap(glyphs, [
|
|
546
|
+
return swap(glyphs, [first, 2], [last, 1]);
|
|
410
547
|
|
|
411
548
|
case 11: // ABxD => DxBA
|
|
412
|
-
return swap(glyphs, [
|
|
549
|
+
return swap(glyphs, [first, 2], [last, 1], true, false);
|
|
413
550
|
|
|
414
551
|
case 12: // ABxCD => CDxAB
|
|
415
|
-
return swap(glyphs, [
|
|
552
|
+
return swap(glyphs, [first, 2], [last, 2]);
|
|
416
553
|
|
|
417
554
|
case 13: // ABxCD => CDxBA
|
|
418
|
-
return swap(glyphs, [
|
|
555
|
+
return swap(glyphs, [first, 2], [last, 2], true, false);
|
|
419
556
|
|
|
420
557
|
case 14: // ABxCD => DCxAB
|
|
421
|
-
return swap(glyphs, [
|
|
558
|
+
return swap(glyphs, [first, 2], [last, 2], false, true);
|
|
422
559
|
|
|
423
560
|
case 15: // ABxCD => DCxBA
|
|
424
|
-
return swap(glyphs, [
|
|
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;
|
|
@@ -44,7 +73,7 @@ export default class AATStateMachine {
|
|
|
44
73
|
let entryIndex = row[classCode];
|
|
45
74
|
let entry = this.stateTable.entryTable.getItem(entryIndex);
|
|
46
75
|
|
|
47
|
-
if (classCode !== END_OF_TEXT_CLASS && classCode !==
|
|
76
|
+
if (classCode !== END_OF_TEXT_CLASS && classCode !== DELETED_GLYPH_CLASS) {
|
|
48
77
|
processEntry(glyph, entry, index);
|
|
49
78
|
shouldAdvance = !(entry.flags & DONT_ADVANCE);
|
|
50
79
|
}
|
|
@@ -61,15 +90,18 @@ 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
|
-
traverse(opts, state = 0, visited = new Set) {
|
|
97
|
+
traverse(opts, state = 0, visited = new Set()) {
|
|
66
98
|
if (visited.has(state)) {
|
|
67
99
|
return;
|
|
68
100
|
}
|
|
69
101
|
|
|
70
102
|
visited.add(state);
|
|
71
103
|
|
|
72
|
-
let {nClasses, stateArray, entryTable} = this.stateTable;
|
|
104
|
+
let { nClasses, stateArray, entryTable } = this.stateTable;
|
|
73
105
|
let row = stateArray.getItem(state);
|
|
74
106
|
|
|
75
107
|
// Skip predefined classes
|
package/src/base.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
|
-
import {DecodeStream} from 'restructure';
|
|
1
|
+
import { DecodeStream } from 'restructure';
|
|
2
|
+
|
|
3
|
+
/** @typedef {import('../types/fontkit').FontFormat} FontFormat */
|
|
4
|
+
/** @typedef {import('../types/fontkit').OpenedFont} OpenedFont */
|
|
2
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
|
};
|
package/src/cff/CFFCharsets.js
CHANGED
|
@@ -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',
|