@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.
- package/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/browser-module.mjs +13660 -0
- package/dist/browser-module.mjs.map +1 -0
- package/dist/browser.cjs +13689 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/main.cjs +13712 -0
- package/dist/main.cjs.map +1 -0
- package/dist/module.mjs +13673 -0
- package/dist/module.mjs.map +1 -0
- package/package.json +99 -0
- package/src/CmapProcessor.js +285 -0
- package/src/DFont.js +113 -0
- package/src/TTFFont.js +621 -0
- package/src/TrueTypeCollection.js +65 -0
- package/src/WOFF2Font.js +222 -0
- package/src/WOFFFont.js +56 -0
- package/src/aat/AATFeatureMap.js +545 -0
- package/src/aat/AATLayoutEngine.js +48 -0
- package/src/aat/AATLookupTable.js +125 -0
- package/src/aat/AATMorxProcessor.js +429 -0
- package/src/aat/AATStateMachine.js +96 -0
- package/src/base.js +29 -0
- package/src/cff/CFFCharsets.js +99 -0
- package/src/cff/CFFDict.js +166 -0
- package/src/cff/CFFEncodings.js +48 -0
- package/src/cff/CFFFont.js +158 -0
- package/src/cff/CFFIndex.js +150 -0
- package/src/cff/CFFOperand.js +135 -0
- package/src/cff/CFFPointer.js +50 -0
- package/src/cff/CFFPrivateDict.js +39 -0
- package/src/cff/CFFStandardStrings.js +71 -0
- package/src/cff/CFFTop.js +236 -0
- package/src/decorators.js +36 -0
- package/src/encodings.js +219 -0
- package/src/fs.js +12 -0
- package/src/glyph/BBox.js +72 -0
- package/src/glyph/CBDTGlyph.js +9 -0
- package/src/glyph/CFFGlyph.js +635 -0
- package/src/glyph/COLRGlyph.js +108 -0
- package/src/glyph/Glyph.js +270 -0
- package/src/glyph/GlyphVariationProcessor.js +487 -0
- package/src/glyph/Path.js +257 -0
- package/src/glyph/SBIXGlyph.js +54 -0
- package/src/glyph/StandardNames.js +27 -0
- package/src/glyph/TTFGlyph.js +408 -0
- package/src/glyph/TTFGlyphEncoder.js +158 -0
- package/src/glyph/WOFF2Glyph.js +70 -0
- package/src/index.js +15 -0
- package/src/layout/GlyphPosition.js +30 -0
- package/src/layout/GlyphRun.js +108 -0
- package/src/layout/KernProcessor.js +97 -0
- package/src/layout/LayoutEngine.js +190 -0
- package/src/layout/Script.js +231 -0
- package/src/layout/UnicodeLayoutEngine.js +250 -0
- package/src/node.js +16 -0
- package/src/opentype/GPOSProcessor.js +311 -0
- package/src/opentype/GSUBProcessor.js +208 -0
- package/src/opentype/GlyphInfo.js +57 -0
- package/src/opentype/GlyphIterator.js +82 -0
- package/src/opentype/OTLayoutEngine.js +117 -0
- package/src/opentype/OTProcessor.js +472 -0
- package/src/opentype/ShapingPlan.js +121 -0
- package/src/opentype/shapers/ArabicShaper.js +124 -0
- package/src/opentype/shapers/DefaultShaper.js +116 -0
- package/src/opentype/shapers/HangulShaper.js +285 -0
- package/src/opentype/shapers/HebrewShaper.js +105 -0
- package/src/opentype/shapers/IndicShaper.js +914 -0
- package/src/opentype/shapers/ThaiShaper.js +238 -0
- package/src/opentype/shapers/UniversalShaper.js +186 -0
- package/src/opentype/shapers/data.trie +0 -0
- package/src/opentype/shapers/gen-indic.js +208 -0
- package/src/opentype/shapers/gen-use.js +287 -0
- package/src/opentype/shapers/generate-data.js +33 -0
- package/src/opentype/shapers/index.js +109 -0
- package/src/opentype/shapers/indic-data.js +175 -0
- package/src/opentype/shapers/indic.json +1 -0
- package/src/opentype/shapers/indic.machine +31 -0
- package/src/opentype/shapers/indic.trie +0 -0
- package/src/opentype/shapers/use.json +1 -0
- package/src/opentype/shapers/use.machine +44 -0
- package/src/opentype/shapers/use.trie +0 -0
- package/src/packages/unicode-properties/LICENSE +8 -0
- package/src/packages/unicode-properties/README.md +12 -0
- package/src/packages/unicode-properties/data-trie.js +1 -0
- package/src/packages/unicode-properties/data.js +1 -0
- package/src/packages/unicode-properties/data.json +1 -0
- package/src/packages/unicode-properties/data.trie +0 -0
- package/src/packages/unicode-properties/dist/index.cjs +257 -0
- package/src/packages/unicode-properties/dist/index.cjs.map +7 -0
- package/src/packages/unicode-properties/dist/index.mjs +234 -0
- package/src/packages/unicode-properties/dist/index.mjs.map +7 -0
- package/src/packages/unicode-properties/generate.js +107 -0
- package/src/packages/unicode-properties/index.js +184 -0
- package/src/packages/unicode-properties/package.json +50 -0
- package/src/packages/unicode-trie/LICENSE +8 -0
- package/src/packages/unicode-trie/README.md +13 -0
- package/src/packages/unicode-trie/builder.js +965 -0
- package/src/packages/unicode-trie/dist/builder.cjs +711 -0
- package/src/packages/unicode-trie/dist/builder.cjs.map +7 -0
- package/src/packages/unicode-trie/dist/builder.mjs +690 -0
- package/src/packages/unicode-trie/dist/builder.mjs.map +7 -0
- package/src/packages/unicode-trie/dist/index.cjs +112 -0
- package/src/packages/unicode-trie/dist/index.cjs.map +7 -0
- package/src/packages/unicode-trie/dist/index.mjs +91 -0
- package/src/packages/unicode-trie/dist/index.mjs.map +7 -0
- package/src/packages/unicode-trie/index.js +135 -0
- package/src/packages/unicode-trie/package.json +49 -0
- package/src/packages/unicode-trie/swap.js +21 -0
- package/src/subset/CFFSubset.js +176 -0
- package/src/subset/Subset.js +63 -0
- package/src/subset/TTFSubset.js +130 -0
- package/src/tables/BASE.js +78 -0
- package/src/tables/COLR.js +25 -0
- package/src/tables/CPAL.js +24 -0
- package/src/tables/DSIG.js +21 -0
- package/src/tables/EBDT.js +91 -0
- package/src/tables/EBLC.js +80 -0
- package/src/tables/GDEF.js +57 -0
- package/src/tables/GPOS.js +209 -0
- package/src/tables/GSUB.js +85 -0
- package/src/tables/HVAR.js +44 -0
- package/src/tables/JSTF.js +43 -0
- package/src/tables/LTSH.js +10 -0
- package/src/tables/OS2.js +84 -0
- package/src/tables/PCLT.js +21 -0
- package/src/tables/STAT.js +99 -0
- package/src/tables/VDMX.js +33 -0
- package/src/tables/VORG.js +14 -0
- package/src/tables/WOFF2Directory.js +73 -0
- package/src/tables/WOFFDirectory.js +37 -0
- package/src/tables/aat.js +157 -0
- package/src/tables/avar.js +19 -0
- package/src/tables/bsln.js +31 -0
- package/src/tables/cmap.js +127 -0
- package/src/tables/cvt.js +6 -0
- package/src/tables/directory.js +58 -0
- package/src/tables/feat.js +28 -0
- package/src/tables/fpgm.js +8 -0
- package/src/tables/fvar.js +31 -0
- package/src/tables/gasp.js +15 -0
- package/src/tables/glyf.js +4 -0
- package/src/tables/gvar.js +27 -0
- package/src/tables/hdmx.js +15 -0
- package/src/tables/head.js +25 -0
- package/src/tables/hhea.js +19 -0
- package/src/tables/hmtx.js +11 -0
- package/src/tables/index.js +119 -0
- package/src/tables/just.js +81 -0
- package/src/tables/kern.js +91 -0
- package/src/tables/loca.js +30 -0
- package/src/tables/maxp.js +20 -0
- package/src/tables/morx.js +79 -0
- package/src/tables/name.js +157 -0
- package/src/tables/opbd.js +15 -0
- package/src/tables/opentype.js +217 -0
- package/src/tables/post.js +34 -0
- package/src/tables/prep.js +6 -0
- package/src/tables/sbix.js +17 -0
- package/src/tables/variations.js +80 -0
- package/src/tables/vhea.js +19 -0
- package/src/tables/vmtx.js +12 -0
- 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
|
+
];
|