@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
package/src/TTFFont.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as r from 'restructure';
|
|
2
1
|
import { cache } from './decorators';
|
|
3
2
|
import * as fontkit from './base';
|
|
3
|
+
import * as r from 'restructure';
|
|
4
4
|
import Directory from './tables/directory';
|
|
5
5
|
import tables from './tables';
|
|
6
6
|
import CmapProcessor from './CmapProcessor';
|
|
@@ -16,18 +16,114 @@ import CFFSubset from './subset/CFFSubset';
|
|
|
16
16
|
import BBox from './glyph/BBox';
|
|
17
17
|
import { asciiDecoder } from './utils';
|
|
18
18
|
|
|
19
|
+
/** @typedef {import('restructure').DecodeStream} DecodeStream */
|
|
20
|
+
/** @typedef {import('restructure').BinaryBuffer} BinaryBuffer */
|
|
21
|
+
/** @typedef {import('../types/fontkit').FontDirectory} FontDirectory */
|
|
22
|
+
/** @typedef {import('../types/fontkit').FontLike} FontLike */
|
|
23
|
+
/** @typedef {import('../types/fontkit').FontMetrics} FontMetrics */
|
|
24
|
+
/** @typedef {import('../types/fontkit').TableEntry} TableEntry */
|
|
25
|
+
/** @typedef {import('../types/fontkit').TableCodec} TableCodec */
|
|
26
|
+
/** @typedef {import('../types/fontkit').VariationCoords} VariationCoords */
|
|
27
|
+
/** @typedef {import('../types/fontkit').NameString} NameString */
|
|
28
|
+
/** @typedef {import('../types/fontkit').HeadTable} HeadTable */
|
|
29
|
+
/** @typedef {import('../types/fontkit').HheaTable} HheaTable */
|
|
30
|
+
/** @typedef {import('../types/fontkit').MaxpTable} MaxpTable */
|
|
31
|
+
/** @typedef {import('../types/fontkit').OS2Table} OS2Table */
|
|
32
|
+
/** @typedef {import('../types/fontkit').NameTable} NameTable */
|
|
33
|
+
/** @typedef {import('../types/fontkit').PostTable} PostTable */
|
|
34
|
+
/** @typedef {import('../types/fontkit').CmapTable} CmapTable */
|
|
35
|
+
/** @typedef {import('../types/fontkit').MetricsTable} MetricsTable */
|
|
36
|
+
/** @typedef {import('../types/fontkit').FvarTable} FvarTable */
|
|
37
|
+
/** @typedef {import('../types/fontkit').FvarAxis} FvarAxis */
|
|
38
|
+
/** @typedef {import('../types/fontkit').CFFFontLike} CFFFontLike */
|
|
39
|
+
/** @typedef {import('../types/fontkit').FeatureInput} FeatureInput */
|
|
40
|
+
/** @typedef {import('../types/fontkit').ScriptTag} ScriptTag */
|
|
41
|
+
/** @typedef {import('../types/fontkit').LanguageTag} LanguageTag */
|
|
42
|
+
/** @typedef {import('../types/fontkit').TextDirection} TextDirection */
|
|
43
|
+
/** @typedef {import('./glyph/Glyph').default} Glyph */
|
|
44
|
+
/** @typedef {import('./layout/GlyphRun').default} GlyphRun */
|
|
45
|
+
/** @typedef {import('./subset/Subset').default} Subset */
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Axis description from {@link TTFFont#variationAxes}.
|
|
49
|
+
* @typedef {{ name: NameString | undefined, min: number, default: number, max: number }} VariationAxisInfo
|
|
50
|
+
*/
|
|
51
|
+
|
|
19
52
|
/**
|
|
20
53
|
* This is the base class for all SFNT-based font formats in fontkit.
|
|
21
54
|
* It supports TrueType, and PostScript glyphs, and several color glyph formats.
|
|
55
|
+
*
|
|
56
|
+
* Dynamic SFNT table accessors (`cmap`, `head`, `hhea`, …) are installed by
|
|
57
|
+
* `_installTableGetters` and typed here so call sites see real table shapes.
|
|
58
|
+
*
|
|
59
|
+
* @implements {FontLike}
|
|
22
60
|
*/
|
|
23
61
|
export default class TTFFont {
|
|
62
|
+
/** @type {string} */
|
|
24
63
|
type = 'TTF';
|
|
25
64
|
|
|
65
|
+
/** @type {DecodeStream} */
|
|
66
|
+
stream = new r.DecodeStream(new Uint8Array(0));
|
|
67
|
+
/** @type {FontDirectory} */
|
|
68
|
+
directory = /** @type {FontDirectory} */ ({ tables: {} });
|
|
69
|
+
/** @type {string | null} */
|
|
70
|
+
defaultLanguage = null;
|
|
71
|
+
/** @type {number[] | null} */
|
|
72
|
+
variationCoords = null;
|
|
73
|
+
/** @type {number} */
|
|
74
|
+
_directoryPos = 0;
|
|
75
|
+
/** @type {Record<string, unknown>} */
|
|
76
|
+
_tables = {};
|
|
77
|
+
/** @type {Record<number, Glyph | undefined>} */
|
|
78
|
+
_glyphs = {};
|
|
79
|
+
/** @type {FontMetrics | undefined} */
|
|
80
|
+
_metrics;
|
|
81
|
+
|
|
82
|
+
// SFNT tables installed as configurable getters by `_installTableGetters`.
|
|
83
|
+
/** @type {CmapTable | undefined} */
|
|
84
|
+
cmap;
|
|
85
|
+
/** @type {HeadTable} */
|
|
86
|
+
head = /** @type {HeadTable} */ ({ unitsPerEm: 0, xMin: 0, yMin: 0, xMax: 0, yMax: 0 });
|
|
87
|
+
/** @type {HheaTable | undefined} */
|
|
88
|
+
hhea;
|
|
89
|
+
/** @type {MetricsTable} */
|
|
90
|
+
hmtx = /** @type {MetricsTable} */ ({
|
|
91
|
+
metrics: { length: 0, get() { return undefined; } },
|
|
92
|
+
bearings: { length: 0, get() { return undefined; } }
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/** @type {MaxpTable} */
|
|
96
|
+
maxp = { numGlyphs: 0 };
|
|
97
|
+
/** @type {NameTable | undefined} */
|
|
98
|
+
name;
|
|
99
|
+
/** @type {OS2Table | undefined} */
|
|
100
|
+
'OS/2';
|
|
101
|
+
/** @type {PostTable} */
|
|
102
|
+
post = { version: 0, italicAngle: 0, underlinePosition: 0, underlineThickness: 0 };
|
|
103
|
+
/** @type {FvarTable | undefined} */
|
|
104
|
+
fvar;
|
|
105
|
+
/** @type {CFFFontLike | undefined} */
|
|
106
|
+
CFF2;
|
|
107
|
+
/** @type {CFFFontLike | undefined} */
|
|
108
|
+
'CFF ';
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {ArrayBufferView} buffer
|
|
112
|
+
* @returns {boolean}
|
|
113
|
+
*/
|
|
26
114
|
static probe(buffer) {
|
|
27
|
-
let
|
|
115
|
+
let bytes
|
|
116
|
+
= buffer instanceof Uint8Array
|
|
117
|
+
? buffer
|
|
118
|
+
: new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
119
|
+
let format = asciiDecoder.decode(bytes.subarray(0, 4));
|
|
28
120
|
return format === 'true' || format === 'OTTO' || format === String.fromCharCode(0, 1, 0, 0);
|
|
29
121
|
}
|
|
30
122
|
|
|
123
|
+
/**
|
|
124
|
+
* @param {DecodeStream} stream
|
|
125
|
+
* @param {number[] | null} [variationCoords]
|
|
126
|
+
*/
|
|
31
127
|
constructor(stream, variationCoords = null) {
|
|
32
128
|
this.defaultLanguage = null;
|
|
33
129
|
this.stream = stream;
|
|
@@ -36,14 +132,28 @@ export default class TTFFont {
|
|
|
36
132
|
this._directoryPos = this.stream.pos;
|
|
37
133
|
this._tables = {};
|
|
38
134
|
this._glyphs = {};
|
|
135
|
+
this._metrics = undefined;
|
|
136
|
+
this.directory = /** @type {FontDirectory} */ ({ tables: {} });
|
|
137
|
+
|
|
39
138
|
this._decodeDirectory();
|
|
40
139
|
this._installTableGetters();
|
|
41
140
|
}
|
|
42
141
|
|
|
142
|
+
/**
|
|
143
|
+
* @param {DecodeStream} stream
|
|
144
|
+
* @returns {void}
|
|
145
|
+
*/
|
|
146
|
+
_setStream(stream) {
|
|
147
|
+
this.stream = stream;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** @returns {void} */
|
|
43
151
|
_installTableGetters() {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
152
|
+
let tableMap = this.directory.tables;
|
|
153
|
+
for (let tag in tableMap) {
|
|
154
|
+
let table = tableMap[tag];
|
|
155
|
+
let codec = tables[tag];
|
|
156
|
+
if (codec && table && table.length > 0) {
|
|
47
157
|
Object.defineProperty(this, tag, {
|
|
48
158
|
get: this._getTable.bind(this, table),
|
|
49
159
|
configurable: true
|
|
@@ -52,10 +162,18 @@ export default class TTFFont {
|
|
|
52
162
|
}
|
|
53
163
|
}
|
|
54
164
|
|
|
165
|
+
/**
|
|
166
|
+
* @param {string | null} [lang]
|
|
167
|
+
* @returns {void}
|
|
168
|
+
*/
|
|
55
169
|
setDefaultLanguage(lang = null) {
|
|
56
170
|
this.defaultLanguage = lang;
|
|
57
171
|
}
|
|
58
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @param {TableEntry} table
|
|
175
|
+
* @returns {unknown}
|
|
176
|
+
*/
|
|
59
177
|
_getTable(table) {
|
|
60
178
|
if (!(table.tag in this._tables)) {
|
|
61
179
|
try {
|
|
@@ -63,7 +181,8 @@ export default class TTFFont {
|
|
|
63
181
|
} catch (e) {
|
|
64
182
|
if (fontkit.logErrors) {
|
|
65
183
|
console.error(`Error decoding table ${table.tag}`);
|
|
66
|
-
|
|
184
|
+
let err = /** @type {{ stack?: string }} */ (e);
|
|
185
|
+
console.error(err.stack);
|
|
67
186
|
}
|
|
68
187
|
}
|
|
69
188
|
}
|
|
@@ -71,6 +190,10 @@ export default class TTFFont {
|
|
|
71
190
|
return this._tables[table.tag];
|
|
72
191
|
}
|
|
73
192
|
|
|
193
|
+
/**
|
|
194
|
+
* @param {string} tag
|
|
195
|
+
* @returns {DecodeStream | null}
|
|
196
|
+
*/
|
|
74
197
|
_getTableStream(tag) {
|
|
75
198
|
let table = this.directory.tables[tag];
|
|
76
199
|
if (table) {
|
|
@@ -81,20 +204,36 @@ export default class TTFFont {
|
|
|
81
204
|
return null;
|
|
82
205
|
}
|
|
83
206
|
|
|
207
|
+
/** @returns {void} */
|
|
84
208
|
_decodeDirectory() {
|
|
85
|
-
|
|
209
|
+
this.directory = /** @type {FontDirectory} */ (
|
|
210
|
+
/** @type {unknown} */ (Directory.decode(this.stream, { _startOffset: 0 }))
|
|
211
|
+
);
|
|
86
212
|
}
|
|
87
213
|
|
|
214
|
+
/**
|
|
215
|
+
* @param {TableEntry} table
|
|
216
|
+
* @returns {unknown}
|
|
217
|
+
*/
|
|
88
218
|
_decodeTable(table) {
|
|
89
219
|
let pos = this.stream.pos;
|
|
90
220
|
|
|
91
221
|
let stream = this._getTableStream(table.tag);
|
|
92
|
-
let
|
|
222
|
+
let codec = /** @type {TableCodec | undefined} */ (tables[table.tag]);
|
|
223
|
+
if (!stream || !codec || !codec.decode) {
|
|
224
|
+
this.stream.pos = pos;
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
let result = codec.decode(stream, this, table.length);
|
|
93
229
|
|
|
94
230
|
this.stream.pos = pos;
|
|
95
231
|
return result;
|
|
96
232
|
}
|
|
97
233
|
|
|
234
|
+
/**
|
|
235
|
+
* @returns {FontMetrics}
|
|
236
|
+
*/
|
|
98
237
|
_getMetrics() {
|
|
99
238
|
if (this._metrics) {
|
|
100
239
|
return this._metrics;
|
|
@@ -104,21 +243,34 @@ export default class TTFFont {
|
|
|
104
243
|
// https://gitlab.freedesktop.org/freetype/freetype/-/blob/master/src/sfnt/sfobjs.c
|
|
105
244
|
// typo*/win* fields exist only in OS/2 version >= 1
|
|
106
245
|
let os2 = this['OS/2'];
|
|
107
|
-
let hasTypo = os2 && os2.version > 0;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
246
|
+
let hasTypo = !!(os2 && os2.version > 0);
|
|
247
|
+
/** @type {number} */
|
|
248
|
+
let ascent;
|
|
249
|
+
/** @type {number} */
|
|
250
|
+
let descent;
|
|
251
|
+
/** @type {number} */
|
|
252
|
+
let lineGap;
|
|
253
|
+
|
|
254
|
+
if (hasTypo && os2 && os2.fsSelection.useTypoMetrics) {
|
|
255
|
+
ascent = /** @type {number} */ (os2.typoAscender);
|
|
256
|
+
descent = /** @type {number} */ (os2.typoDescender);
|
|
257
|
+
lineGap = /** @type {number} */ (os2.typoLineGap);
|
|
112
258
|
} else {
|
|
113
|
-
|
|
259
|
+
let hhea = this.hhea;
|
|
260
|
+
if (!hhea) {
|
|
261
|
+
throw new Error('Missing hhea table');
|
|
262
|
+
}
|
|
263
|
+
({ ascent, descent, lineGap } = hhea);
|
|
114
264
|
|
|
115
265
|
// Only when both hhea values are zero — FreeType uses !(ascender || descender)
|
|
116
|
-
if (!(ascent || descent) && hasTypo) {
|
|
266
|
+
if (!(ascent || descent) && hasTypo && os2) {
|
|
117
267
|
if (os2.typoAscender || os2.typoDescender) {
|
|
118
|
-
|
|
268
|
+
ascent = /** @type {number} */ (os2.typoAscender);
|
|
269
|
+
descent = /** @type {number} */ (os2.typoDescender);
|
|
270
|
+
lineGap = /** @type {number} */ (os2.typoLineGap);
|
|
119
271
|
} else {
|
|
120
|
-
ascent = os2.winAscent;
|
|
121
|
-
descent = -os2.winDescent;
|
|
272
|
+
ascent = /** @type {number} */ (os2.winAscent);
|
|
273
|
+
descent = -(/** @type {number} */ (os2.winDescent));
|
|
122
274
|
lineGap = 0;
|
|
123
275
|
}
|
|
124
276
|
}
|
|
@@ -135,19 +287,23 @@ export default class TTFFont {
|
|
|
135
287
|
/**
|
|
136
288
|
* Gets a string from the font's `name` table
|
|
137
289
|
* `lang` is a BCP-47 language code.
|
|
138
|
-
* @
|
|
290
|
+
* @param {string} key
|
|
291
|
+
* @param {string | null} [lang]
|
|
292
|
+
* @returns {NameString | null}
|
|
139
293
|
*/
|
|
140
294
|
getName(key, lang = this.defaultLanguage || fontkit.defaultLanguage) {
|
|
141
295
|
let record = this.name && this.name.records[key];
|
|
142
|
-
if (record) {
|
|
296
|
+
if (record && typeof record === 'object') {
|
|
143
297
|
// Attempt to retrieve the entry, depending on which translation is available:
|
|
298
|
+
/** @type {import('../types/fontkit').NameLocaleMap} */
|
|
299
|
+
let locales = /** @type {import('../types/fontkit').NameLocaleMap} */ (record);
|
|
144
300
|
return (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
301
|
+
(lang ? locales[lang] : undefined)
|
|
302
|
+
|| (this.defaultLanguage ? locales[this.defaultLanguage] : undefined)
|
|
303
|
+
|| locales[fontkit.defaultLanguage]
|
|
304
|
+
|| locales['en']
|
|
305
|
+
|| locales[Object.keys(locales)[0]] // Seriously, ANY language would be fine
|
|
306
|
+
|| null
|
|
151
307
|
);
|
|
152
308
|
}
|
|
153
309
|
|
|
@@ -156,7 +312,7 @@ export default class TTFFont {
|
|
|
156
312
|
|
|
157
313
|
/**
|
|
158
314
|
* The unique PostScript name for this font, e.g. "Helvetica-Bold"
|
|
159
|
-
* @type {
|
|
315
|
+
* @type {NameString | null}
|
|
160
316
|
*/
|
|
161
317
|
get postscriptName() {
|
|
162
318
|
return this.getName('postscriptName');
|
|
@@ -164,7 +320,7 @@ export default class TTFFont {
|
|
|
164
320
|
|
|
165
321
|
/**
|
|
166
322
|
* The font's full name, e.g. "Helvetica Bold"
|
|
167
|
-
* @type {
|
|
323
|
+
* @type {NameString | null}
|
|
168
324
|
*/
|
|
169
325
|
get fullName() {
|
|
170
326
|
return this.getName('fullName');
|
|
@@ -172,7 +328,7 @@ export default class TTFFont {
|
|
|
172
328
|
|
|
173
329
|
/**
|
|
174
330
|
* The font's family name, e.g. "Helvetica"
|
|
175
|
-
* @type {
|
|
331
|
+
* @type {NameString | null}
|
|
176
332
|
*/
|
|
177
333
|
get familyName() {
|
|
178
334
|
return this.getName('fontFamily');
|
|
@@ -180,7 +336,7 @@ export default class TTFFont {
|
|
|
180
336
|
|
|
181
337
|
/**
|
|
182
338
|
* The font's sub-family, e.g. "Bold".
|
|
183
|
-
* @type {
|
|
339
|
+
* @type {NameString | null}
|
|
184
340
|
*/
|
|
185
341
|
get subfamilyName() {
|
|
186
342
|
return this.getName('fontSubfamily');
|
|
@@ -188,7 +344,7 @@ export default class TTFFont {
|
|
|
188
344
|
|
|
189
345
|
/**
|
|
190
346
|
* The font's copyright information
|
|
191
|
-
* @type {
|
|
347
|
+
* @type {NameString | null}
|
|
192
348
|
*/
|
|
193
349
|
get copyright() {
|
|
194
350
|
return this.getName('copyright');
|
|
@@ -196,7 +352,7 @@ export default class TTFFont {
|
|
|
196
352
|
|
|
197
353
|
/**
|
|
198
354
|
* The font's version number
|
|
199
|
-
* @type {
|
|
355
|
+
* @type {NameString | null}
|
|
200
356
|
*/
|
|
201
357
|
get version() {
|
|
202
358
|
return this.getName('version');
|
|
@@ -266,7 +422,7 @@ export default class TTFFont {
|
|
|
266
422
|
*/
|
|
267
423
|
get capHeight() {
|
|
268
424
|
let os2 = this['OS/2'];
|
|
269
|
-
return os2 ? os2.capHeight : this.ascent;
|
|
425
|
+
return os2 && os2.capHeight != null ? os2.capHeight : this.ascent;
|
|
270
426
|
}
|
|
271
427
|
|
|
272
428
|
/**
|
|
@@ -276,7 +432,7 @@ export default class TTFFont {
|
|
|
276
432
|
*/
|
|
277
433
|
get xHeight() {
|
|
278
434
|
let os2 = this['OS/2'];
|
|
279
|
-
return os2 ? os2.xHeight : 0;
|
|
435
|
+
return os2 && os2.xHeight != null ? os2.xHeight : 0;
|
|
280
436
|
}
|
|
281
437
|
|
|
282
438
|
/**
|
|
@@ -304,9 +460,12 @@ export default class TTFFont {
|
|
|
304
460
|
return Object.freeze(new BBox(this.head.xMin, this.head.yMin, this.head.xMax, this.head.yMax));
|
|
305
461
|
}
|
|
306
462
|
|
|
463
|
+
/**
|
|
464
|
+
* @type {CmapProcessor}
|
|
465
|
+
*/
|
|
307
466
|
@cache
|
|
308
467
|
get _cmapProcessor() {
|
|
309
|
-
return new CmapProcessor(this.cmap);
|
|
468
|
+
return new CmapProcessor(/** @type {CmapTable} */ (this.cmap));
|
|
310
469
|
}
|
|
311
470
|
|
|
312
471
|
/**
|
|
@@ -333,7 +492,7 @@ export default class TTFFont {
|
|
|
333
492
|
* Does not perform any advanced substitutions (there is no context to do so).
|
|
334
493
|
*
|
|
335
494
|
* @param {number} codePoint
|
|
336
|
-
* @return {Glyph}
|
|
495
|
+
* @return {Glyph | null}
|
|
337
496
|
*/
|
|
338
497
|
glyphForCodePoint(codePoint) {
|
|
339
498
|
return this.getGlyph(this._cmapProcessor.lookup(codePoint), [codePoint]);
|
|
@@ -349,6 +508,7 @@ export default class TTFFont {
|
|
|
349
508
|
* @return {Glyph[]}
|
|
350
509
|
*/
|
|
351
510
|
glyphsForString(string) {
|
|
511
|
+
/** @type {Glyph[]} */
|
|
352
512
|
let glyphs = [];
|
|
353
513
|
let len = string.length;
|
|
354
514
|
let idx = 0;
|
|
@@ -378,10 +538,16 @@ export default class TTFFont {
|
|
|
378
538
|
|
|
379
539
|
if (state === 0 && nextState === 1) {
|
|
380
540
|
// Variation selector following normal codepoint.
|
|
381
|
-
|
|
541
|
+
let g = this.getGlyph(this._cmapProcessor.lookup(last, code), [last, code]);
|
|
542
|
+
if (g) {
|
|
543
|
+
glyphs.push(g);
|
|
544
|
+
}
|
|
382
545
|
} else if (state === 0 && nextState === 0) {
|
|
383
546
|
// Normal codepoint following normal codepoint.
|
|
384
|
-
|
|
547
|
+
let g = this.glyphForCodePoint(last);
|
|
548
|
+
if (g) {
|
|
549
|
+
glyphs.push(g);
|
|
550
|
+
}
|
|
385
551
|
}
|
|
386
552
|
|
|
387
553
|
last = code;
|
|
@@ -391,6 +557,9 @@ export default class TTFFont {
|
|
|
391
557
|
return glyphs;
|
|
392
558
|
}
|
|
393
559
|
|
|
560
|
+
/**
|
|
561
|
+
* @type {LayoutEngine}
|
|
562
|
+
*/
|
|
394
563
|
@cache
|
|
395
564
|
get _layoutEngine() {
|
|
396
565
|
return new LayoutEngine(this);
|
|
@@ -400,10 +569,10 @@ export default class TTFFont {
|
|
|
400
569
|
* Returns a GlyphRun object, which includes an array of Glyphs and GlyphPositions for the given string.
|
|
401
570
|
*
|
|
402
571
|
* @param {string} string
|
|
403
|
-
* @param {
|
|
404
|
-
* @param {
|
|
405
|
-
* @param {
|
|
406
|
-
* @param {
|
|
572
|
+
* @param {FeatureInput} [userFeatures]
|
|
573
|
+
* @param {ScriptTag} [script]
|
|
574
|
+
* @param {LanguageTag} [language]
|
|
575
|
+
* @param {TextDirection} [direction]
|
|
407
576
|
* @return {GlyphRun}
|
|
408
577
|
*/
|
|
409
578
|
layout(string, userFeatures, script, language, direction) {
|
|
@@ -413,6 +582,7 @@ export default class TTFFont {
|
|
|
413
582
|
/**
|
|
414
583
|
* Returns an array of strings that map to the given glyph id.
|
|
415
584
|
* @param {number} gid - glyph id
|
|
585
|
+
* @returns {string[]}
|
|
416
586
|
*/
|
|
417
587
|
stringsForGlyph(gid) {
|
|
418
588
|
return this._layoutEngine.stringsForGlyph(gid);
|
|
@@ -430,16 +600,27 @@ export default class TTFFont {
|
|
|
430
600
|
return this._layoutEngine.getAvailableFeatures();
|
|
431
601
|
}
|
|
432
602
|
|
|
603
|
+
/**
|
|
604
|
+
* @param {ScriptTag} [script]
|
|
605
|
+
* @param {LanguageTag} [language]
|
|
606
|
+
* @returns {string[]}
|
|
607
|
+
*/
|
|
433
608
|
getAvailableFeatures(script, language) {
|
|
434
609
|
return this._layoutEngine.getAvailableFeatures(script, language);
|
|
435
610
|
}
|
|
436
611
|
|
|
612
|
+
/**
|
|
613
|
+
* @param {number} glyph
|
|
614
|
+
* @param {number[]} [characters]
|
|
615
|
+
* @returns {Glyph | null | undefined}
|
|
616
|
+
*/
|
|
437
617
|
_getBaseGlyph(glyph, characters = []) {
|
|
438
618
|
let cached = this._glyphs[glyph];
|
|
439
|
-
if (cached
|
|
619
|
+
if (cached && typeof (/** @type {{ _getContours?: unknown }} */ (cached))._getContours === 'function') {
|
|
440
620
|
return cached;
|
|
441
621
|
}
|
|
442
622
|
|
|
623
|
+
/** @type {Glyph | null} */
|
|
443
624
|
let outline = null;
|
|
444
625
|
if (this.directory.tables.glyf) {
|
|
445
626
|
outline = new TTFGlyph(glyph, characters, this);
|
|
@@ -460,20 +641,17 @@ export default class TTFFont {
|
|
|
460
641
|
* your use later, and it will be stored in the glyph object.
|
|
461
642
|
*
|
|
462
643
|
* @param {number} glyph
|
|
463
|
-
* @param {number[]} characters
|
|
464
|
-
* @return {Glyph}
|
|
644
|
+
* @param {number[]} [characters]
|
|
645
|
+
* @return {Glyph | null}
|
|
465
646
|
*/
|
|
466
647
|
getGlyph(glyph, characters = []) {
|
|
467
648
|
if (!this._glyphs[glyph]) {
|
|
468
649
|
if (this.directory.tables.sbix) {
|
|
469
650
|
this._glyphs[glyph] = new SBIXGlyph(glyph, characters, this);
|
|
470
|
-
|
|
471
651
|
} else if ((this.directory.tables.COLR) && (this.directory.tables.CPAL)) {
|
|
472
652
|
this._glyphs[glyph] = new COLRGlyph(glyph, characters, this);
|
|
473
|
-
|
|
474
653
|
} else if (this.directory.tables.CBLC || this.directory.tables.EBLC) {
|
|
475
654
|
this._glyphs[glyph] = new CBDTGlyph(glyph, characters, this);
|
|
476
|
-
|
|
477
655
|
} else {
|
|
478
656
|
this._getBaseGlyph(glyph, characters);
|
|
479
657
|
}
|
|
@@ -499,10 +677,11 @@ export default class TTFFont {
|
|
|
499
677
|
* that this font supports. Keys are setting tags, and values
|
|
500
678
|
* contain the axis name, range, and default value.
|
|
501
679
|
*
|
|
502
|
-
* @type {
|
|
680
|
+
* @type {Record<string, VariationAxisInfo>}
|
|
503
681
|
*/
|
|
504
682
|
@cache
|
|
505
683
|
get variationAxes() {
|
|
684
|
+
/** @type {Record<string, VariationAxisInfo>} */
|
|
506
685
|
let res = {};
|
|
507
686
|
if (!this.fvar) {
|
|
508
687
|
return res;
|
|
@@ -510,7 +689,7 @@ export default class TTFFont {
|
|
|
510
689
|
|
|
511
690
|
for (let axis of this.fvar.axis) {
|
|
512
691
|
res[axis.axisTag.trim()] = {
|
|
513
|
-
name: axis.name.en,
|
|
692
|
+
name: axis.name && axis.name.en,
|
|
514
693
|
min: axis.minValue,
|
|
515
694
|
default: axis.defaultValue,
|
|
516
695
|
max: axis.maxValue
|
|
@@ -525,23 +704,28 @@ export default class TTFFont {
|
|
|
525
704
|
* that the font designer has specified. Keys are variation names
|
|
526
705
|
* and values are the variation settings for this instance.
|
|
527
706
|
*
|
|
528
|
-
* @type {
|
|
707
|
+
* @type {Record<string, Record<string, number>>}
|
|
529
708
|
*/
|
|
530
709
|
@cache
|
|
531
710
|
get namedVariations() {
|
|
711
|
+
/** @type {Record<string, Record<string, number>>} */
|
|
532
712
|
let res = {};
|
|
533
713
|
if (!this.fvar) {
|
|
534
714
|
return res;
|
|
535
715
|
}
|
|
536
716
|
|
|
537
717
|
for (let instance of this.fvar.instance) {
|
|
718
|
+
/** @type {Record<string, number>} */
|
|
538
719
|
let settings = {};
|
|
539
720
|
for (let i = 0; i < this.fvar.axis.length; i++) {
|
|
540
721
|
let axis = this.fvar.axis[i];
|
|
541
722
|
settings[axis.axisTag.trim()] = instance.coord[i];
|
|
542
723
|
}
|
|
543
724
|
|
|
544
|
-
|
|
725
|
+
let key = instance.name && instance.name.en;
|
|
726
|
+
if (typeof key === 'string') {
|
|
727
|
+
res[key] = settings;
|
|
728
|
+
}
|
|
545
729
|
}
|
|
546
730
|
|
|
547
731
|
return res;
|
|
@@ -552,7 +736,7 @@ export default class TTFFont {
|
|
|
552
736
|
* Settings can either be an instance name, or an object containing
|
|
553
737
|
* variation tags as specified by the `variationAxes` property.
|
|
554
738
|
*
|
|
555
|
-
* @param {
|
|
739
|
+
* @param {string | Record<string, number>} settings
|
|
556
740
|
* @return {TTFFont}
|
|
557
741
|
*/
|
|
558
742
|
getVariation(settings) {
|
|
@@ -560,27 +744,34 @@ export default class TTFFont {
|
|
|
560
744
|
throw new Error('Variations require a font with the fvar, gvar and glyf, or CFF2 tables.');
|
|
561
745
|
}
|
|
562
746
|
|
|
747
|
+
/** @type {Record<string, number> | undefined} */
|
|
748
|
+
let resolved;
|
|
563
749
|
if (typeof settings === 'string') {
|
|
564
|
-
|
|
750
|
+
resolved = this.namedVariations[settings];
|
|
751
|
+
} else {
|
|
752
|
+
resolved = settings;
|
|
565
753
|
}
|
|
566
754
|
|
|
567
|
-
if (typeof
|
|
755
|
+
if (typeof resolved !== 'object' || resolved == null) {
|
|
568
756
|
throw new Error('Variation settings must be either a variation name or settings object.');
|
|
569
757
|
}
|
|
570
758
|
|
|
759
|
+
let fvar = /** @type {FvarTable} */ (this.fvar);
|
|
760
|
+
|
|
571
761
|
// normalize the coordinates
|
|
572
|
-
let coords =
|
|
762
|
+
let coords = fvar.axis.map((/** @type {FvarAxis} */ axis) => {
|
|
573
763
|
let axisTag = axis.axisTag.trim();
|
|
574
|
-
if (axisTag in
|
|
575
|
-
return Math.max(axis.minValue, Math.min(axis.maxValue,
|
|
764
|
+
if (axisTag in resolved) {
|
|
765
|
+
return Math.max(axis.minValue, Math.min(axis.maxValue, resolved[axisTag]));
|
|
576
766
|
} else {
|
|
577
767
|
return axis.defaultValue;
|
|
578
768
|
}
|
|
579
769
|
});
|
|
580
770
|
|
|
581
771
|
// Decompress WOFF/WOFF2 on the source once so the clone shares resolved tables.
|
|
582
|
-
|
|
583
|
-
|
|
772
|
+
let maybeDecompress = /** @type {{ _decompress?: () => void }} */ (this)._decompress;
|
|
773
|
+
if (typeof maybeDecompress === 'function') {
|
|
774
|
+
maybeDecompress.call(this);
|
|
584
775
|
}
|
|
585
776
|
|
|
586
777
|
// Preserve subclass (WOFF/WOFF2) and share decoded state. @cache values and
|
|
@@ -594,6 +785,9 @@ export default class TTFFont {
|
|
|
594
785
|
return font;
|
|
595
786
|
}
|
|
596
787
|
|
|
788
|
+
/**
|
|
789
|
+
* @type {GlyphVariationProcessor | null}
|
|
790
|
+
*/
|
|
597
791
|
@cache
|
|
598
792
|
get _variationProcessor() {
|
|
599
793
|
if (!this.fvar) {
|
|
@@ -608,14 +802,18 @@ export default class TTFFont {
|
|
|
608
802
|
}
|
|
609
803
|
|
|
610
804
|
if (!variationCoords) {
|
|
611
|
-
variationCoords = this.fvar.axis.map(axis => axis.defaultValue);
|
|
805
|
+
variationCoords = this.fvar.axis.map((/** @type {FvarAxis} */ axis) => axis.defaultValue);
|
|
612
806
|
}
|
|
613
807
|
|
|
614
808
|
return new GlyphVariationProcessor(this, variationCoords);
|
|
615
809
|
}
|
|
616
810
|
|
|
617
811
|
// Standardized format plugin API
|
|
812
|
+
/**
|
|
813
|
+
* @param {string | Uint8Array | Record<string, number>} name
|
|
814
|
+
* @returns {TTFFont}
|
|
815
|
+
*/
|
|
618
816
|
getFont(name) {
|
|
619
|
-
return this.getVariation(name);
|
|
817
|
+
return this.getVariation(/** @type {string | Record<string, number>} */ (name));
|
|
620
818
|
}
|
|
621
819
|
}
|