@cantoo/fontkit 2.0.5 → 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 +4423 -1117
- package/dist/browser-module.mjs.map +1 -1
- package/dist/browser.cjs +4424 -1117
- package/dist/browser.cjs.map +1 -1
- package/dist/main.cjs +4424 -1117
- package/dist/main.cjs.map +1 -1
- package/dist/module.mjs +4423 -1117
- package/dist/module.mjs.map +1 -1
- package/package.json +3 -1
- package/src/CmapProcessor.js +59 -20
- package/src/DFont.js +114 -14
- package/src/TTFFont.js +259 -57
- package/src/TrueTypeCollection.js +54 -10
- package/src/WOFF2Font.js +128 -16
- package/src/WOFFFont.js +45 -8
- package/src/aat/AATFeatureMap.js +62 -18
- package/src/aat/AATLayoutEngine.js +33 -1
- package/src/aat/AATLookupTable.js +22 -4
- package/src/aat/AATMorxProcessor.js +189 -52
- package/src/aat/AATStateMachine.js +32 -0
- package/src/base.js +19 -0
- package/src/cff/CFFCharsets.js +3 -0
- package/src/cff/CFFDict.js +79 -9
- package/src/cff/CFFEncodings.js +2 -0
- package/src/cff/CFFFont.js +119 -23
- package/src/cff/CFFIndex.js +62 -5
- package/src/cff/CFFOperand.js +52 -17
- package/src/cff/CFFPointer.js +41 -2
- package/src/cff/CFFPrivateDict.js +14 -4
- package/src/cff/CFFStandardStrings.js +1 -0
- package/src/cff/CFFTop.js +103 -10
- package/src/decorators.js +32 -13
- package/src/encodings.js +22 -5
- package/src/fs.js +10 -0
- package/src/glyph/BBox.js +14 -0
- package/src/glyph/CFFGlyph.js +290 -148
- package/src/glyph/COLRGlyph.js +38 -3
- package/src/glyph/Glyph.js +68 -9
- package/src/glyph/GlyphVariationProcessor.js +135 -34
- package/src/glyph/Path.js +107 -20
- package/src/glyph/SBIXGlyph.js +57 -8
- package/src/glyph/StandardNames.js +1 -0
- package/src/glyph/TTFGlyph.js +176 -29
- package/src/glyph/TTFGlyphEncoder.js +32 -0
- package/src/glyph/WOFF2Glyph.js +23 -4
- package/src/layout/GlyphPosition.js +6 -0
- package/src/layout/GlyphRun.js +25 -7
- package/src/layout/KernProcessor.js +62 -3
- package/src/layout/LayoutEngine.js +86 -12
- package/src/layout/Script.js +27 -1
- package/src/layout/UnicodeLayoutEngine.js +29 -4
- package/src/opentype/GPOSProcessor.js +156 -45
- package/src/opentype/GSUBProcessor.js +92 -33
- package/src/opentype/GlyphInfo.js +52 -4
- package/src/opentype/GlyphIterator.js +51 -2
- package/src/opentype/OTLayoutEngine.js +66 -8
- package/src/opentype/OTProcessor.js +283 -70
- package/src/opentype/ShapingPlan.js +51 -3
- package/src/opentype/shapers/ArabicShaper.js +19 -0
- package/src/opentype/shapers/DefaultShaper.js +51 -7
- package/src/opentype/shapers/HangulShaper.js +85 -7
- package/src/opentype/shapers/HebrewShaper.js +45 -11
- package/src/opentype/shapers/IndicShaper.js +141 -26
- package/src/opentype/shapers/ThaiShaper.js +35 -4
- package/src/opentype/shapers/UniversalShaper.js +83 -17
- package/src/opentype/shapers/index.js +15 -2
- package/src/packages/unicode-properties/data-trie.js +1 -0
- package/src/packages/unicode-properties/data.js +12 -0
- package/src/packages/unicode-properties/dist/index.cjs +22 -9
- package/src/packages/unicode-properties/dist/index.cjs.map +2 -2
- package/src/packages/unicode-properties/dist/index.mjs +21 -9
- package/src/packages/unicode-properties/dist/index.mjs.map +2 -2
- package/src/packages/unicode-properties/index.js +65 -0
- package/src/packages/unicode-properties/package.json +1 -1
- package/src/packages/unicode-trie/builder.js +128 -7
- package/src/packages/unicode-trie/dist/builder.cjs +129 -16
- package/src/packages/unicode-trie/dist/builder.cjs.map +2 -2
- package/src/packages/unicode-trie/dist/builder.mjs +128 -16
- 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 +62 -10
- package/src/packages/unicode-trie/package.json +1 -1
- package/src/packages/unicode-trie/swap.js +13 -0
- package/src/subset/CFFSubset.js +112 -22
- package/src/subset/Subset.js +21 -1
- package/src/subset/TTFSubset.js +79 -36
- package/src/tables/BASE.js +1 -0
- package/src/tables/COLR.js +1 -0
- package/src/tables/CPAL.js +1 -0
- package/src/tables/DSIG.js +1 -0
- package/src/tables/EBDT.js +10 -3
- package/src/tables/EBLC.js +67 -7
- package/src/tables/GDEF.js +1 -0
- package/src/tables/GPOS.js +79 -16
- package/src/tables/GSUB.js +14 -3
- package/src/tables/HVAR.js +51 -5
- package/src/tables/JSTF.js +3 -2
- package/src/tables/LTSH.js +1 -0
- package/src/tables/OS2.js +1 -0
- package/src/tables/PCLT.js +1 -0
- package/src/tables/STAT.js +46 -6
- package/src/tables/VDMX.js +1 -0
- package/src/tables/VORG.js +1 -0
- package/src/tables/WOFF2Directory.js +56 -8
- package/src/tables/WOFFDirectory.js +14 -2
- 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 +26 -6
- package/src/tables/cvt.js +1 -0
- package/src/tables/directory.js +44 -16
- 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 +1 -0
- package/src/tables/glyf.js +1 -0
- package/src/tables/gvar.js +29 -2
- package/src/tables/hdmx.js +12 -1
- package/src/tables/head.js +1 -0
- package/src/tables/hhea.js +1 -0
- package/src/tables/hmtx.js +18 -2
- package/src/tables/index.js +1 -0
- package/src/tables/just.js +15 -4
- package/src/tables/kern.js +43 -6
- package/src/tables/loca.js +21 -8
- package/src/tables/maxp.js +1 -0
- package/src/tables/morx.js +14 -7
- package/src/tables/name.js +104 -23
- package/src/tables/opbd.js +2 -1
- package/src/tables/opentype.js +39 -4
- package/src/tables/post.js +8 -1
- package/src/tables/prep.js +1 -0
- package/src/tables/sbix.js +12 -1
- package/src/tables/variations.js +23 -3
- package/src/tables/vhea.js +1 -0
- package/src/tables/vmtx.js +18 -2
- package/src/utils.js +15 -0
package/src/cff/CFFDict.js
CHANGED
|
@@ -2,9 +2,32 @@ import isEqual from 'fast-deep-equal';
|
|
|
2
2
|
import CFFOperand from './CFFOperand';
|
|
3
3
|
import { PropertyDescriptor } from 'restructure';
|
|
4
4
|
|
|
5
|
+
/** @typedef {import('restructure').BaseType} BaseType */
|
|
6
|
+
/** @typedef {import('restructure').DecodeStream} DecodeStream */
|
|
7
|
+
/** @typedef {import('restructure').EncodeStream} EncodeStream */
|
|
8
|
+
/** @typedef {import('restructure').StructValue} StructValue */
|
|
9
|
+
/** @typedef {import('../../types/fontkit').CFFDictField} CFFDictField */
|
|
10
|
+
/** @typedef {import('../../types/fontkit').CFFOperandType} CFFOperandType */
|
|
11
|
+
/** @typedef {import('../../types/fontkit').CFFEncodeContext} CFFEncodeContext */
|
|
12
|
+
|
|
13
|
+
/** @typedef {number | { forceLarge?: boolean, valueOf(): number }} CFFOperandValue */
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {CFFOperandType} type
|
|
17
|
+
* @returns {type is BaseType}
|
|
18
|
+
*/
|
|
19
|
+
function isCodec(type) {
|
|
20
|
+
return typeof type === 'object' && type != null && !Array.isArray(type);
|
|
21
|
+
}
|
|
22
|
+
|
|
5
23
|
export default class CFFDict {
|
|
24
|
+
/**
|
|
25
|
+
* @param {CFFDictField[]} [ops]
|
|
26
|
+
*/
|
|
6
27
|
constructor(ops = []) {
|
|
28
|
+
/** @type {CFFDictField[]} */
|
|
7
29
|
this.ops = ops;
|
|
30
|
+
/** @type {Record<number, CFFDictField>} */
|
|
8
31
|
this.fields = {};
|
|
9
32
|
for (let field of ops) {
|
|
10
33
|
let key = Array.isArray(field[0]) ? field[0][0] << 8 | field[0][1] : field[0];
|
|
@@ -12,10 +35,17 @@ export default class CFFDict {
|
|
|
12
35
|
}
|
|
13
36
|
}
|
|
14
37
|
|
|
38
|
+
/**
|
|
39
|
+
* @param {CFFOperandType} type
|
|
40
|
+
* @param {DecodeStream} stream
|
|
41
|
+
* @param {StructValue} ret
|
|
42
|
+
* @param {unknown[]} operands
|
|
43
|
+
* @returns {unknown}
|
|
44
|
+
*/
|
|
15
45
|
decodeOperands(type, stream, ret, operands) {
|
|
16
46
|
if (Array.isArray(type)) {
|
|
17
47
|
return operands.map((op, i) => this.decodeOperands(type[i], stream, ret, [op]));
|
|
18
|
-
} else if (type.decode != null) {
|
|
48
|
+
} else if (isCodec(type) && type.decode != null) {
|
|
19
49
|
return type.decode(stream, ret, operands);
|
|
20
50
|
} else {
|
|
21
51
|
switch (type) {
|
|
@@ -31,11 +61,26 @@ export default class CFFDict {
|
|
|
31
61
|
}
|
|
32
62
|
}
|
|
33
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @param {CFFOperandType} type
|
|
66
|
+
* @param {EncodeStream | null} stream
|
|
67
|
+
* @param {CFFEncodeContext | StructValue} ctx
|
|
68
|
+
* @param {unknown} operands
|
|
69
|
+
* @returns {unknown[]}
|
|
70
|
+
*/
|
|
34
71
|
encodeOperands(type, stream, ctx, operands) {
|
|
35
72
|
if (Array.isArray(type)) {
|
|
73
|
+
if (!Array.isArray(operands)) {
|
|
74
|
+
return [operands];
|
|
75
|
+
}
|
|
36
76
|
return operands.map((op, i) => this.encodeOperands(type[i], stream, ctx, op)[0]);
|
|
37
|
-
} else if (type.encode != null) {
|
|
38
|
-
|
|
77
|
+
} else if (isCodec(type) && type.encode != null) {
|
|
78
|
+
let encoded = type.encode(stream, operands, ctx);
|
|
79
|
+
if (Array.isArray(encoded)) {
|
|
80
|
+
return encoded;
|
|
81
|
+
}
|
|
82
|
+
// Custom ops must return an operand list; coerce scalars (e.g. sid index).
|
|
83
|
+
return [encoded];
|
|
39
84
|
} else if (typeof operands === 'number') {
|
|
40
85
|
return [operands];
|
|
41
86
|
} else if (typeof operands === 'boolean') {
|
|
@@ -47,9 +92,17 @@ export default class CFFDict {
|
|
|
47
92
|
}
|
|
48
93
|
}
|
|
49
94
|
|
|
95
|
+
/**
|
|
96
|
+
* @param {DecodeStream} stream
|
|
97
|
+
* @param {StructValue} parent
|
|
98
|
+
* @returns {StructValue}
|
|
99
|
+
*/
|
|
50
100
|
decode(stream, parent) {
|
|
51
|
-
let
|
|
101
|
+
let dictLength = typeof parent.length === 'number' ? parent.length : 0;
|
|
102
|
+
let end = stream.pos + dictLength;
|
|
103
|
+
/** @type {StructValue} */
|
|
52
104
|
let ret = {};
|
|
105
|
+
/** @type {unknown[]} */
|
|
53
106
|
let operands = [];
|
|
54
107
|
|
|
55
108
|
// define hidden properties
|
|
@@ -94,12 +147,20 @@ export default class CFFDict {
|
|
|
94
147
|
return ret;
|
|
95
148
|
}
|
|
96
149
|
|
|
150
|
+
/**
|
|
151
|
+
* @param {StructValue} dict
|
|
152
|
+
* @param {StructValue | CFFEncodeContext} parent
|
|
153
|
+
* @param {boolean} [includePointers]
|
|
154
|
+
* @returns {number}
|
|
155
|
+
*/
|
|
97
156
|
size(dict, parent, includePointers = true) {
|
|
157
|
+
/** @type {CFFEncodeContext} */
|
|
98
158
|
let ctx = {
|
|
99
159
|
parent,
|
|
100
160
|
val: dict,
|
|
101
161
|
pointerSize: 0,
|
|
102
|
-
startOffset: parent.startOffset
|
|
162
|
+
startOffset: (typeof parent.startOffset === 'number' ? parent.startOffset : 0),
|
|
163
|
+
pointers: []
|
|
103
164
|
};
|
|
104
165
|
|
|
105
166
|
let len = 0;
|
|
@@ -113,7 +174,7 @@ export default class CFFDict {
|
|
|
113
174
|
|
|
114
175
|
let operands = this.encodeOperands(field[2], null, ctx, val);
|
|
115
176
|
for (let op of operands) {
|
|
116
|
-
len += CFFOperand.size(op);
|
|
177
|
+
len += CFFOperand.size(/** @type {CFFOperandValue} */ (op));
|
|
117
178
|
}
|
|
118
179
|
|
|
119
180
|
let key = Array.isArray(field[0]) ? field[0] : [field[0]];
|
|
@@ -127,11 +188,18 @@ export default class CFFDict {
|
|
|
127
188
|
return len;
|
|
128
189
|
}
|
|
129
190
|
|
|
191
|
+
/**
|
|
192
|
+
* @param {EncodeStream} stream
|
|
193
|
+
* @param {StructValue} dict
|
|
194
|
+
* @param {StructValue | null | undefined} parent
|
|
195
|
+
* @returns {void}
|
|
196
|
+
*/
|
|
130
197
|
encode(stream, dict, parent) {
|
|
198
|
+
/** @type {CFFEncodeContext} */
|
|
131
199
|
let ctx = {
|
|
132
200
|
pointers: [],
|
|
133
201
|
startOffset: stream.pos,
|
|
134
|
-
parent,
|
|
202
|
+
parent: parent ?? undefined,
|
|
135
203
|
val: dict,
|
|
136
204
|
pointerSize: 0
|
|
137
205
|
};
|
|
@@ -146,7 +214,7 @@ export default class CFFDict {
|
|
|
146
214
|
|
|
147
215
|
let operands = this.encodeOperands(field[2], stream, ctx, val);
|
|
148
216
|
for (let op of operands) {
|
|
149
|
-
CFFOperand.encode(stream, op);
|
|
217
|
+
CFFOperand.encode(stream, /** @type {CFFOperandValue} */ (op));
|
|
150
218
|
}
|
|
151
219
|
|
|
152
220
|
let key = Array.isArray(field[0]) ? field[0] : [field[0]];
|
|
@@ -158,7 +226,9 @@ export default class CFFDict {
|
|
|
158
226
|
let i = 0;
|
|
159
227
|
while (i < ctx.pointers.length) {
|
|
160
228
|
let ptr = ctx.pointers[i++];
|
|
161
|
-
ptr.type.encode
|
|
229
|
+
if (ptr.type.encode) {
|
|
230
|
+
ptr.type.encode(stream, ptr.val, ptr.parent);
|
|
231
|
+
}
|
|
162
232
|
}
|
|
163
233
|
|
|
164
234
|
return;
|
package/src/cff/CFFEncodings.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @type {string[]} */
|
|
1
2
|
export let StandardEncoding = [
|
|
2
3
|
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
|
3
4
|
'', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright',
|
|
@@ -18,6 +19,7 @@ export let StandardEncoding = [
|
|
|
18
19
|
'lslash', 'oslash', 'oe', 'germandbls'
|
|
19
20
|
];
|
|
20
21
|
|
|
22
|
+
/** @type {string[]} */
|
|
21
23
|
export let ExpertEncoding = [
|
|
22
24
|
'', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
|
|
23
25
|
'', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior',
|
package/src/cff/CFFFont.js
CHANGED
|
@@ -1,68 +1,131 @@
|
|
|
1
1
|
import CFFTop from './CFFTop';
|
|
2
2
|
import standardStrings from './CFFStandardStrings';
|
|
3
3
|
|
|
4
|
+
/** @typedef {import('restructure').DecodeStream} DecodeStream */
|
|
5
|
+
/** @typedef {import('restructure').BinaryBuffer} BinaryBuffer */
|
|
6
|
+
/** @typedef {import('restructure').StructValue} StructValue */
|
|
7
|
+
/** @typedef {import('../../types/fontkit').CFFTopDict} CFFTopDict */
|
|
8
|
+
/** @typedef {import('../../types/fontkit').CFFPrivateDict} CFFPrivateDict */
|
|
9
|
+
/** @typedef {import('../../types/fontkit').CFFCharString} CFFCharString */
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Decoded CFF / CFF2 font table.
|
|
13
|
+
* Properties from CFFTop are copied onto the instance in decode().
|
|
14
|
+
*/
|
|
4
15
|
class CFFFont {
|
|
16
|
+
/**
|
|
17
|
+
* @param {DecodeStream} stream
|
|
18
|
+
*/
|
|
5
19
|
constructor(stream) {
|
|
20
|
+
/** @type {DecodeStream} */
|
|
6
21
|
this.stream = stream;
|
|
22
|
+
/** @type {number} */
|
|
23
|
+
this.version = 0;
|
|
24
|
+
/** @type {number | undefined} */
|
|
25
|
+
this.hdrSize = undefined;
|
|
26
|
+
/** @type {CFFTopDict} */
|
|
27
|
+
this.topDict = /** @type {CFFTopDict} */ ({ CharStrings: [] });
|
|
28
|
+
/** @type {StructValue[] | undefined} */
|
|
29
|
+
this.topDictIndex = undefined;
|
|
30
|
+
/** @type {string[] | undefined} */
|
|
31
|
+
this.nameIndex = undefined;
|
|
32
|
+
/** @type {string[] | undefined} */
|
|
33
|
+
this.stringIndex = undefined;
|
|
34
|
+
/** @type {CFFCharString[] | undefined} */
|
|
35
|
+
this.globalSubrIndex = undefined;
|
|
36
|
+
/** @type {boolean} */
|
|
37
|
+
this.isCIDFont = false;
|
|
7
38
|
this.decode();
|
|
8
39
|
}
|
|
9
40
|
|
|
41
|
+
/**
|
|
42
|
+
* @param {DecodeStream} stream
|
|
43
|
+
* @returns {CFFFont}
|
|
44
|
+
*/
|
|
10
45
|
static decode(stream) {
|
|
11
46
|
return new CFFFont(stream);
|
|
12
47
|
}
|
|
13
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @returns {this}
|
|
51
|
+
*/
|
|
14
52
|
decode() {
|
|
15
53
|
let top = CFFTop.decode(this.stream);
|
|
16
54
|
for (let key in top) {
|
|
17
|
-
|
|
18
|
-
this[key] = val;
|
|
55
|
+
/** @type {Record<string, unknown>} */ (/** @type {unknown} */ (this))[key] = top[key];
|
|
19
56
|
}
|
|
20
57
|
|
|
21
58
|
if (this.version < 2) {
|
|
22
|
-
if (this.topDictIndex.length !== 1) {
|
|
59
|
+
if (!this.topDictIndex || this.topDictIndex.length !== 1) {
|
|
23
60
|
throw new Error('Only a single font is allowed in CFF');
|
|
24
61
|
}
|
|
25
62
|
|
|
26
|
-
this.topDict = this.topDictIndex[0];
|
|
63
|
+
this.topDict = /** @type {CFFTopDict} */ (this.topDictIndex[0]);
|
|
27
64
|
}
|
|
28
65
|
|
|
29
66
|
this.isCIDFont = this.topDict.ROS != null;
|
|
30
67
|
return this;
|
|
31
68
|
}
|
|
32
69
|
|
|
70
|
+
/**
|
|
71
|
+
* @param {number | null | undefined} sid
|
|
72
|
+
* @returns {string | null}
|
|
73
|
+
*/
|
|
33
74
|
string(sid) {
|
|
34
75
|
if (this.version >= 2) {
|
|
35
76
|
return null;
|
|
36
77
|
}
|
|
37
78
|
|
|
79
|
+
if (sid == null) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
38
83
|
if (sid < standardStrings.length) {
|
|
39
84
|
return standardStrings[sid];
|
|
40
85
|
}
|
|
41
86
|
|
|
42
|
-
return this.stringIndex[sid - standardStrings.length];
|
|
87
|
+
return this.stringIndex ? this.stringIndex[sid - standardStrings.length] : null;
|
|
43
88
|
}
|
|
44
89
|
|
|
90
|
+
/**
|
|
91
|
+
* @returns {string | null}
|
|
92
|
+
*/
|
|
45
93
|
get postscriptName() {
|
|
46
94
|
if (this.version < 2) {
|
|
47
|
-
return this.nameIndex[0];
|
|
95
|
+
return this.nameIndex ? this.nameIndex[0] : null;
|
|
48
96
|
}
|
|
49
97
|
|
|
50
98
|
return null;
|
|
51
99
|
}
|
|
52
100
|
|
|
101
|
+
/**
|
|
102
|
+
* @returns {string | null}
|
|
103
|
+
*/
|
|
53
104
|
get fullName() {
|
|
54
105
|
return this.string(this.topDict.FullName);
|
|
55
106
|
}
|
|
56
107
|
|
|
108
|
+
/**
|
|
109
|
+
* @returns {string | null}
|
|
110
|
+
*/
|
|
57
111
|
get familyName() {
|
|
58
112
|
return this.string(this.topDict.FamilyName);
|
|
59
113
|
}
|
|
60
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @param {number} glyph
|
|
117
|
+
* @returns {BinaryBuffer}
|
|
118
|
+
*/
|
|
61
119
|
getCharString(glyph) {
|
|
62
|
-
|
|
63
|
-
|
|
120
|
+
let cs = /** @type {CFFCharString} */ (this.topDict.CharStrings[glyph]);
|
|
121
|
+
this.stream.pos = cs.offset;
|
|
122
|
+
return this.stream.readBuffer(cs.length);
|
|
64
123
|
}
|
|
65
124
|
|
|
125
|
+
/**
|
|
126
|
+
* @param {number} gid
|
|
127
|
+
* @returns {string | null}
|
|
128
|
+
*/
|
|
66
129
|
getGlyphName(gid) {
|
|
67
130
|
// CFF2 glyph names are in the post table.
|
|
68
131
|
if (this.version >= 2) {
|
|
@@ -76,7 +139,7 @@ class CFFFont {
|
|
|
76
139
|
|
|
77
140
|
let { charset } = this.topDict;
|
|
78
141
|
if (Array.isArray(charset)) {
|
|
79
|
-
return charset[gid];
|
|
142
|
+
return /** @type {string} */ (charset[gid]);
|
|
80
143
|
}
|
|
81
144
|
|
|
82
145
|
if (gid === 0) {
|
|
@@ -85,14 +148,30 @@ class CFFFont {
|
|
|
85
148
|
|
|
86
149
|
gid -= 1;
|
|
87
150
|
|
|
88
|
-
|
|
151
|
+
if (!charset || typeof charset !== 'object') {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @typedef {{
|
|
157
|
+
* version?: number,
|
|
158
|
+
* glyphs?: number[],
|
|
159
|
+
* ranges?: Array<{ offset: number, nLeft: number, first: number }>
|
|
160
|
+
* }} CharsetTable
|
|
161
|
+
*/
|
|
162
|
+
let cs = /** @type {StructValue & CharsetTable} */ (charset);
|
|
163
|
+
|
|
164
|
+
switch (cs.version) {
|
|
89
165
|
case 0:
|
|
90
|
-
return this.string(
|
|
166
|
+
return this.string(cs.glyphs ? cs.glyphs[gid] : undefined);
|
|
91
167
|
|
|
92
168
|
case 1:
|
|
93
169
|
case 2:
|
|
94
|
-
|
|
95
|
-
|
|
170
|
+
if (!cs.ranges) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
for (let i = 0; i < cs.ranges.length; i++) {
|
|
174
|
+
let range = cs.ranges[i];
|
|
96
175
|
if (range.offset <= gid && gid <= range.offset + range.nLeft) {
|
|
97
176
|
return this.string(range.first + (gid - range.offset));
|
|
98
177
|
}
|
|
@@ -103,44 +182,59 @@ class CFFFont {
|
|
|
103
182
|
return null;
|
|
104
183
|
}
|
|
105
184
|
|
|
185
|
+
/**
|
|
186
|
+
* @param {number} gid
|
|
187
|
+
* @returns {number | null}
|
|
188
|
+
*/
|
|
106
189
|
fdForGlyph(gid) {
|
|
107
190
|
if (!this.topDict.FDSelect) {
|
|
108
191
|
return null;
|
|
109
192
|
}
|
|
110
193
|
|
|
111
|
-
|
|
194
|
+
let fdSelect = this.topDict.FDSelect;
|
|
195
|
+
|
|
196
|
+
switch (fdSelect.version) {
|
|
112
197
|
case 0:
|
|
113
|
-
return
|
|
198
|
+
return fdSelect.fds ? fdSelect.fds[gid] : null;
|
|
114
199
|
|
|
115
200
|
case 3:
|
|
116
201
|
case 4: {
|
|
117
|
-
let { ranges } =
|
|
202
|
+
let { ranges } = fdSelect;
|
|
203
|
+
if (!ranges) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
118
206
|
let low = 0;
|
|
119
207
|
let high = ranges.length - 1;
|
|
120
208
|
|
|
121
209
|
while (low <= high) {
|
|
122
210
|
let mid = (low + high) >> 1;
|
|
211
|
+
let midRange = ranges[mid];
|
|
212
|
+
let nextRange = ranges[mid + 1];
|
|
123
213
|
|
|
124
|
-
if (gid <
|
|
214
|
+
if (gid < midRange.first) {
|
|
125
215
|
high = mid - 1;
|
|
126
|
-
} else if (mid < high && gid >=
|
|
216
|
+
} else if (mid < high && nextRange && gid >= nextRange.first) {
|
|
127
217
|
low = mid + 1;
|
|
128
218
|
} else {
|
|
129
|
-
return
|
|
219
|
+
return midRange.fd;
|
|
130
220
|
}
|
|
131
221
|
}
|
|
132
222
|
|
|
133
|
-
throw new Error(`Unknown FDSelect version: ${
|
|
223
|
+
throw new Error(`Unknown FDSelect version: ${fdSelect.version}`);
|
|
134
224
|
}
|
|
135
225
|
default:
|
|
136
|
-
throw new Error(`Unknown FDSelect version: ${
|
|
226
|
+
throw new Error(`Unknown FDSelect version: ${fdSelect.version}`);
|
|
137
227
|
}
|
|
138
228
|
}
|
|
139
229
|
|
|
230
|
+
/**
|
|
231
|
+
* @param {number} gid
|
|
232
|
+
* @returns {CFFPrivateDict | null | undefined}
|
|
233
|
+
*/
|
|
140
234
|
privateDictForGlyph(gid) {
|
|
141
235
|
if (this.topDict.FDSelect) {
|
|
142
236
|
let fd = this.fdForGlyph(gid);
|
|
143
|
-
if (this.topDict.FDArray[fd]) {
|
|
237
|
+
if (fd != null && this.topDict.FDArray && this.topDict.FDArray[fd]) {
|
|
144
238
|
return this.topDict.FDArray[fd].Private;
|
|
145
239
|
}
|
|
146
240
|
|
|
@@ -151,7 +245,9 @@ class CFFFont {
|
|
|
151
245
|
return this.topDict.Private;
|
|
152
246
|
}
|
|
153
247
|
|
|
154
|
-
return this.topDict.FDArray[0]
|
|
248
|
+
return this.topDict.FDArray && this.topDict.FDArray[0]
|
|
249
|
+
? this.topDict.FDArray[0].Private
|
|
250
|
+
: null;
|
|
155
251
|
}
|
|
156
252
|
}
|
|
157
253
|
|
package/src/cff/CFFIndex.js
CHANGED
|
@@ -1,18 +1,38 @@
|
|
|
1
1
|
import * as r from 'restructure';
|
|
2
2
|
|
|
3
|
+
/** @typedef {import('restructure').BaseType} BaseType */
|
|
4
|
+
/** @typedef {import('restructure').DecodeStream} DecodeStream */
|
|
5
|
+
/** @typedef {import('restructure').EncodeStream} EncodeStream */
|
|
6
|
+
/** @typedef {import('restructure').NumberT} NumberT */
|
|
7
|
+
/** @typedef {import('restructure').StructValue} StructValue */
|
|
8
|
+
/** @typedef {import('../../types/fontkit').CFFCharString} CFFCharString */
|
|
9
|
+
|
|
3
10
|
export default class CFFIndex {
|
|
11
|
+
/**
|
|
12
|
+
* @param {BaseType} [type]
|
|
13
|
+
*/
|
|
4
14
|
constructor(type) {
|
|
15
|
+
/** @type {BaseType | undefined} */
|
|
5
16
|
this.type = type;
|
|
6
17
|
}
|
|
7
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @param {StructValue | null | undefined} ctx
|
|
21
|
+
* @returns {number}
|
|
22
|
+
*/
|
|
8
23
|
getCFFVersion(ctx) {
|
|
9
24
|
while (ctx && !ctx.hdrSize) {
|
|
10
25
|
ctx = ctx.parent;
|
|
11
26
|
}
|
|
12
27
|
|
|
13
|
-
return ctx ? ctx.version : -1;
|
|
28
|
+
return ctx && typeof ctx.version === 'number' ? ctx.version : -1;
|
|
14
29
|
}
|
|
15
30
|
|
|
31
|
+
/**
|
|
32
|
+
* @param {DecodeStream} stream
|
|
33
|
+
* @param {StructValue} parent
|
|
34
|
+
* @returns {unknown[]}
|
|
35
|
+
*/
|
|
16
36
|
decode(stream, parent) {
|
|
17
37
|
let version = this.getCFFVersion(parent);
|
|
18
38
|
let count = version >= 2
|
|
@@ -24,6 +44,7 @@ export default class CFFIndex {
|
|
|
24
44
|
}
|
|
25
45
|
|
|
26
46
|
let offSize = stream.readUInt8();
|
|
47
|
+
/** @type {NumberT} */
|
|
27
48
|
let offsetType;
|
|
28
49
|
if (offSize === 1) {
|
|
29
50
|
offsetType = r.uint8;
|
|
@@ -37,6 +58,7 @@ export default class CFFIndex {
|
|
|
37
58
|
throw new Error(`Bad offset size in CFFIndex: ${offSize} ${stream.pos}`);
|
|
38
59
|
}
|
|
39
60
|
|
|
61
|
+
/** @type {unknown[]} */
|
|
40
62
|
let ret = [];
|
|
41
63
|
let startPos = stream.pos + ((count + 1) * offSize) - 1;
|
|
42
64
|
|
|
@@ -44,7 +66,7 @@ export default class CFFIndex {
|
|
|
44
66
|
for (let i = 0; i < count; i++) {
|
|
45
67
|
let end = offsetType.decode(stream);
|
|
46
68
|
|
|
47
|
-
if (this.type != null) {
|
|
69
|
+
if (this.type != null && this.type.decode) {
|
|
48
70
|
let pos = stream.pos;
|
|
49
71
|
stream.pos = startPos + start;
|
|
50
72
|
|
|
@@ -52,10 +74,12 @@ export default class CFFIndex {
|
|
|
52
74
|
ret.push(this.type.decode(stream, parent));
|
|
53
75
|
stream.pos = pos;
|
|
54
76
|
} else {
|
|
55
|
-
|
|
77
|
+
/** @type {CFFCharString} */
|
|
78
|
+
let range = {
|
|
56
79
|
offset: startPos + start,
|
|
57
80
|
length: end - start
|
|
58
|
-
}
|
|
81
|
+
};
|
|
82
|
+
ret.push(range);
|
|
59
83
|
}
|
|
60
84
|
|
|
61
85
|
start = end;
|
|
@@ -65,21 +89,35 @@ export default class CFFIndex {
|
|
|
65
89
|
return ret;
|
|
66
90
|
}
|
|
67
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @param {unknown[]} arr
|
|
94
|
+
* @param {StructValue | null | undefined} parent
|
|
95
|
+
* @returns {number}
|
|
96
|
+
*/
|
|
68
97
|
size(arr, parent) {
|
|
69
98
|
let size = 2;
|
|
70
99
|
if (arr.length === 0) {
|
|
71
100
|
return size;
|
|
72
101
|
}
|
|
73
102
|
|
|
103
|
+
/** @type {BaseType} */
|
|
74
104
|
let type = this.type || new r.Buffer();
|
|
75
105
|
|
|
76
106
|
// find maximum offset to detminine offset type
|
|
77
107
|
let offset = 1;
|
|
78
108
|
for (let i = 0; i < arr.length; i++) {
|
|
79
109
|
let item = arr[i];
|
|
80
|
-
|
|
110
|
+
if (!type.size) {
|
|
111
|
+
throw new Error('CFFIndex element type must implement size()');
|
|
112
|
+
}
|
|
113
|
+
let itemSize = type.size(item, parent);
|
|
114
|
+
if (typeof itemSize !== 'number') {
|
|
115
|
+
throw new Error('CFFIndex element size() must return a number');
|
|
116
|
+
}
|
|
117
|
+
offset += itemSize;
|
|
81
118
|
}
|
|
82
119
|
|
|
120
|
+
/** @type {NumberT} */
|
|
83
121
|
let offsetType;
|
|
84
122
|
if (offset <= 0xff) {
|
|
85
123
|
offsetType = r.uint8;
|
|
@@ -99,23 +137,38 @@ export default class CFFIndex {
|
|
|
99
137
|
return size;
|
|
100
138
|
}
|
|
101
139
|
|
|
140
|
+
/**
|
|
141
|
+
* @param {EncodeStream} stream
|
|
142
|
+
* @param {unknown[]} arr
|
|
143
|
+
* @param {StructValue | null | undefined} parent
|
|
144
|
+
* @returns {void}
|
|
145
|
+
*/
|
|
102
146
|
encode(stream, arr, parent) {
|
|
103
147
|
stream.writeUInt16BE(arr.length);
|
|
104
148
|
if (arr.length === 0) {
|
|
105
149
|
return;
|
|
106
150
|
}
|
|
107
151
|
|
|
152
|
+
/** @type {BaseType} */
|
|
108
153
|
let type = this.type || new r.Buffer();
|
|
109
154
|
|
|
110
155
|
// find maximum offset to detminine offset type
|
|
156
|
+
/** @type {number[]} */
|
|
111
157
|
let sizes = [];
|
|
112
158
|
let offset = 1;
|
|
113
159
|
for (let item of arr) {
|
|
160
|
+
if (!type.size) {
|
|
161
|
+
throw new Error('CFFIndex element type must implement size()');
|
|
162
|
+
}
|
|
114
163
|
let s = type.size(item, parent);
|
|
164
|
+
if (typeof s !== 'number') {
|
|
165
|
+
throw new Error('CFFIndex element size() must return a number');
|
|
166
|
+
}
|
|
115
167
|
sizes.push(s);
|
|
116
168
|
offset += s;
|
|
117
169
|
}
|
|
118
170
|
|
|
171
|
+
/** @type {NumberT} */
|
|
119
172
|
let offsetType;
|
|
120
173
|
if (offset <= 0xff) {
|
|
121
174
|
offsetType = r.uint8;
|
|
@@ -142,6 +195,10 @@ export default class CFFIndex {
|
|
|
142
195
|
}
|
|
143
196
|
|
|
144
197
|
for (let item of arr) {
|
|
198
|
+
if (!type.encode) {
|
|
199
|
+
throw new Error('CFFIndex element type must implement encode()');
|
|
200
|
+
}
|
|
201
|
+
// Element type varies (String, Buffer, CFFDict, …); BaseType.encode accepts unknown.
|
|
145
202
|
type.encode(stream, item, parent);
|
|
146
203
|
}
|
|
147
204
|
|