@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.
Files changed (140) hide show
  1. package/dist/browser-module.mjs +4423 -1117
  2. package/dist/browser-module.mjs.map +1 -1
  3. package/dist/browser.cjs +4424 -1117
  4. package/dist/browser.cjs.map +1 -1
  5. package/dist/main.cjs +4424 -1117
  6. package/dist/main.cjs.map +1 -1
  7. package/dist/module.mjs +4423 -1117
  8. package/dist/module.mjs.map +1 -1
  9. package/package.json +3 -1
  10. package/src/CmapProcessor.js +59 -20
  11. package/src/DFont.js +114 -14
  12. package/src/TTFFont.js +259 -57
  13. package/src/TrueTypeCollection.js +54 -10
  14. package/src/WOFF2Font.js +128 -16
  15. package/src/WOFFFont.js +45 -8
  16. package/src/aat/AATFeatureMap.js +62 -18
  17. package/src/aat/AATLayoutEngine.js +33 -1
  18. package/src/aat/AATLookupTable.js +22 -4
  19. package/src/aat/AATMorxProcessor.js +189 -52
  20. package/src/aat/AATStateMachine.js +32 -0
  21. package/src/base.js +19 -0
  22. package/src/cff/CFFCharsets.js +3 -0
  23. package/src/cff/CFFDict.js +79 -9
  24. package/src/cff/CFFEncodings.js +2 -0
  25. package/src/cff/CFFFont.js +119 -23
  26. package/src/cff/CFFIndex.js +62 -5
  27. package/src/cff/CFFOperand.js +52 -17
  28. package/src/cff/CFFPointer.js +41 -2
  29. package/src/cff/CFFPrivateDict.js +14 -4
  30. package/src/cff/CFFStandardStrings.js +1 -0
  31. package/src/cff/CFFTop.js +103 -10
  32. package/src/decorators.js +32 -13
  33. package/src/encodings.js +22 -5
  34. package/src/fs.js +10 -0
  35. package/src/glyph/BBox.js +14 -0
  36. package/src/glyph/CFFGlyph.js +290 -148
  37. package/src/glyph/COLRGlyph.js +38 -3
  38. package/src/glyph/Glyph.js +68 -9
  39. package/src/glyph/GlyphVariationProcessor.js +135 -34
  40. package/src/glyph/Path.js +107 -20
  41. package/src/glyph/SBIXGlyph.js +57 -8
  42. package/src/glyph/StandardNames.js +1 -0
  43. package/src/glyph/TTFGlyph.js +176 -29
  44. package/src/glyph/TTFGlyphEncoder.js +32 -0
  45. package/src/glyph/WOFF2Glyph.js +23 -4
  46. package/src/layout/GlyphPosition.js +6 -0
  47. package/src/layout/GlyphRun.js +25 -7
  48. package/src/layout/KernProcessor.js +62 -3
  49. package/src/layout/LayoutEngine.js +86 -12
  50. package/src/layout/Script.js +27 -1
  51. package/src/layout/UnicodeLayoutEngine.js +29 -4
  52. package/src/opentype/GPOSProcessor.js +156 -45
  53. package/src/opentype/GSUBProcessor.js +92 -33
  54. package/src/opentype/GlyphInfo.js +52 -4
  55. package/src/opentype/GlyphIterator.js +51 -2
  56. package/src/opentype/OTLayoutEngine.js +66 -8
  57. package/src/opentype/OTProcessor.js +283 -70
  58. package/src/opentype/ShapingPlan.js +51 -3
  59. package/src/opentype/shapers/ArabicShaper.js +19 -0
  60. package/src/opentype/shapers/DefaultShaper.js +51 -7
  61. package/src/opentype/shapers/HangulShaper.js +85 -7
  62. package/src/opentype/shapers/HebrewShaper.js +45 -11
  63. package/src/opentype/shapers/IndicShaper.js +141 -26
  64. package/src/opentype/shapers/ThaiShaper.js +35 -4
  65. package/src/opentype/shapers/UniversalShaper.js +83 -17
  66. package/src/opentype/shapers/index.js +15 -2
  67. package/src/packages/unicode-properties/data-trie.js +1 -0
  68. package/src/packages/unicode-properties/data.js +12 -0
  69. package/src/packages/unicode-properties/dist/index.cjs +22 -9
  70. package/src/packages/unicode-properties/dist/index.cjs.map +2 -2
  71. package/src/packages/unicode-properties/dist/index.mjs +21 -9
  72. package/src/packages/unicode-properties/dist/index.mjs.map +2 -2
  73. package/src/packages/unicode-properties/index.js +65 -0
  74. package/src/packages/unicode-properties/package.json +1 -1
  75. package/src/packages/unicode-trie/builder.js +128 -7
  76. package/src/packages/unicode-trie/dist/builder.cjs +129 -16
  77. package/src/packages/unicode-trie/dist/builder.cjs.map +2 -2
  78. package/src/packages/unicode-trie/dist/builder.mjs +128 -16
  79. package/src/packages/unicode-trie/dist/builder.mjs.map +2 -2
  80. package/src/packages/unicode-trie/dist/index.cjs +22 -9
  81. package/src/packages/unicode-trie/dist/index.cjs.map +2 -2
  82. package/src/packages/unicode-trie/dist/index.mjs +21 -9
  83. package/src/packages/unicode-trie/dist/index.mjs.map +2 -2
  84. package/src/packages/unicode-trie/index.js +62 -10
  85. package/src/packages/unicode-trie/package.json +1 -1
  86. package/src/packages/unicode-trie/swap.js +13 -0
  87. package/src/subset/CFFSubset.js +112 -22
  88. package/src/subset/Subset.js +21 -1
  89. package/src/subset/TTFSubset.js +79 -36
  90. package/src/tables/BASE.js +1 -0
  91. package/src/tables/COLR.js +1 -0
  92. package/src/tables/CPAL.js +1 -0
  93. package/src/tables/DSIG.js +1 -0
  94. package/src/tables/EBDT.js +10 -3
  95. package/src/tables/EBLC.js +67 -7
  96. package/src/tables/GDEF.js +1 -0
  97. package/src/tables/GPOS.js +79 -16
  98. package/src/tables/GSUB.js +14 -3
  99. package/src/tables/HVAR.js +51 -5
  100. package/src/tables/JSTF.js +3 -2
  101. package/src/tables/LTSH.js +1 -0
  102. package/src/tables/OS2.js +1 -0
  103. package/src/tables/PCLT.js +1 -0
  104. package/src/tables/STAT.js +46 -6
  105. package/src/tables/VDMX.js +1 -0
  106. package/src/tables/VORG.js +1 -0
  107. package/src/tables/WOFF2Directory.js +56 -8
  108. package/src/tables/WOFFDirectory.js +14 -2
  109. package/src/tables/aat.js +160 -35
  110. package/src/tables/avar.js +1 -0
  111. package/src/tables/bsln.js +3 -2
  112. package/src/tables/cmap.js +26 -6
  113. package/src/tables/cvt.js +1 -0
  114. package/src/tables/directory.js +44 -16
  115. package/src/tables/feat.js +24 -2
  116. package/src/tables/fpgm.js +1 -0
  117. package/src/tables/fvar.js +32 -4
  118. package/src/tables/gasp.js +1 -0
  119. package/src/tables/glyf.js +1 -0
  120. package/src/tables/gvar.js +29 -2
  121. package/src/tables/hdmx.js +12 -1
  122. package/src/tables/head.js +1 -0
  123. package/src/tables/hhea.js +1 -0
  124. package/src/tables/hmtx.js +18 -2
  125. package/src/tables/index.js +1 -0
  126. package/src/tables/just.js +15 -4
  127. package/src/tables/kern.js +43 -6
  128. package/src/tables/loca.js +21 -8
  129. package/src/tables/maxp.js +1 -0
  130. package/src/tables/morx.js +14 -7
  131. package/src/tables/name.js +104 -23
  132. package/src/tables/opbd.js +2 -1
  133. package/src/tables/opentype.js +39 -4
  134. package/src/tables/post.js +8 -1
  135. package/src/tables/prep.js +1 -0
  136. package/src/tables/sbix.js +12 -1
  137. package/src/tables/variations.js +23 -3
  138. package/src/tables/vhea.js +1 -0
  139. package/src/tables/vmtx.js +18 -2
  140. package/src/utils.js +15 -0
@@ -1,9 +1,18 @@
1
+ /** @typedef {import('restructure').DecodeStream} DecodeStream */
2
+ /** @typedef {import('restructure').EncodeStream} EncodeStream */
3
+
4
+ /**
5
+ * Operand value that may force a 32-bit encoding (e.g. CFF pointer placeholders).
6
+ * @typedef {number | { forceLarge?: boolean, valueOf(): number }} CFFOperandValue
7
+ */
8
+
1
9
  const FLOAT_EOF = 0xf;
2
10
  const FLOAT_LOOKUP = [
3
11
  '0', '1', '2', '3', '4', '5', '6', '7',
4
12
  '8', '9', '.', 'E', 'E-', null, '-'
5
13
  ];
6
14
 
15
+ /** @type {Record<string, number>} */
7
16
  const FLOAT_ENCODE_LOOKUP = {
8
17
  '.': 10,
9
18
  E: 11,
@@ -12,6 +21,11 @@ const FLOAT_ENCODE_LOOKUP = {
12
21
  };
13
22
 
14
23
  export default class CFFOperand {
24
+ /**
25
+ * @param {DecodeStream} stream
26
+ * @param {number} value
27
+ * @returns {number | null}
28
+ */
15
29
  static decode(stream, value) {
16
30
  if (32 <= value && value <= 246) {
17
31
  return value - 139;
@@ -53,73 +67,94 @@ export default class CFFOperand {
53
67
  return null;
54
68
  }
55
69
 
70
+ /**
71
+ * @param {CFFOperandValue} value
72
+ * @returns {number}
73
+ */
56
74
  static size(value) {
57
75
  // if the value needs to be forced to the largest size (32 bit)
58
76
  // e.g. for unknown pointers, set to 32768
59
- if (value.forceLarge) {
60
- value = 32768;
77
+ /** @type {number} */
78
+ let n;
79
+ if (value && typeof value === 'object' && value.forceLarge) {
80
+ n = 32768;
81
+ } else {
82
+ n = Number(value);
61
83
  }
62
84
 
63
- if ((value | 0) !== value) { // floating point
64
- let str = '' + value;
85
+ if ((n | 0) !== n) { // floating point
86
+ let str = '' + n;
65
87
  return 1 + Math.ceil((str.length + 1) / 2);
66
- } else if (-107 <= value && value <= 107) {
88
+ } else if (-107 <= n && n <= 107) {
67
89
  return 1;
68
- } else if (108 <= value && value <= 1131 || -1131 <= value && value <= -108) {
90
+ } else if (108 <= n && n <= 1131 || -1131 <= n && n <= -108) {
69
91
  return 2;
70
- } else if (-32768 <= value && value <= 32767) {
92
+ } else if (-32768 <= n && n <= 32767) {
71
93
  return 3;
72
94
  } else {
73
95
  return 5;
74
96
  }
75
97
  }
76
98
 
99
+ /**
100
+ * @param {EncodeStream} stream
101
+ * @param {CFFOperandValue} value
102
+ * @returns {void}
103
+ */
77
104
  static encode(stream, value) {
78
105
  // if the value needs to be forced to the largest size (32 bit)
79
106
  // e.g. for unknown pointers, save the old value and set to 32768
80
107
  let val = Number(value);
81
108
 
82
- if (value.forceLarge) {
109
+ if (value && typeof value === 'object' && value.forceLarge) {
83
110
  stream.writeUInt8(29);
84
- return stream.writeInt32BE(val);
111
+ stream.writeInt32BE(val);
112
+ return;
85
113
  } else if ((val | 0) !== val) { // floating point
86
114
  stream.writeUInt8(30);
87
115
 
88
116
  let str = '' + val;
117
+ /** @type {number | undefined} */
89
118
  let n2;
90
119
  for (let i = 0; i < str.length; i += 2) {
91
120
  let c1 = str[i];
92
- let n1 = FLOAT_ENCODE_LOOKUP[c1] || +c1;
121
+ let n1 = FLOAT_ENCODE_LOOKUP[c1] ?? (+c1);
93
122
 
94
123
  if (i === str.length - 1) {
95
124
  n2 = FLOAT_EOF;
96
125
  } else {
97
126
  let c2 = str[i + 1];
98
- n2 = FLOAT_ENCODE_LOOKUP[c2] || +c2;
127
+ n2 = FLOAT_ENCODE_LOOKUP[c2] ?? (+c2);
99
128
  }
100
129
 
101
130
  stream.writeUInt8((n1 << 4) | (n2 & 15));
102
131
  }
103
132
 
104
133
  if (n2 !== FLOAT_EOF) {
105
- return stream.writeUInt8((FLOAT_EOF << 4));
134
+ stream.writeUInt8((FLOAT_EOF << 4));
106
135
  }
136
+ return;
107
137
  } else if (-107 <= val && val <= 107) {
108
- return stream.writeUInt8(val + 139);
138
+ stream.writeUInt8(val + 139);
139
+ return;
109
140
  } else if (108 <= val && val <= 1131) {
110
141
  val -= 108;
111
142
  stream.writeUInt8((val >> 8) + 247);
112
- return stream.writeUInt8(val & 0xff);
143
+ stream.writeUInt8(val & 0xff);
144
+ return;
113
145
  } else if (-1131 <= val && val <= -108) {
114
146
  val = -val - 108;
115
147
  stream.writeUInt8((val >> 8) + 251);
116
- return stream.writeUInt8(val & 0xff);
148
+ stream.writeUInt8(val & 0xff);
149
+ return;
117
150
  } else if (-32768 <= val && val <= 32767) {
118
151
  stream.writeUInt8(28);
119
- return stream.writeInt16BE(val);
152
+ stream.writeInt16BE(val);
153
+ return;
120
154
  } else {
121
155
  stream.writeUInt8(29);
122
- return stream.writeInt32BE(val);
156
+ stream.writeInt32BE(val);
157
+ return;
123
158
  }
124
159
  }
125
160
  }
@@ -1,6 +1,20 @@
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').PointerOptions} PointerOptions */
7
+ /** @typedef {import('restructure').StructValue} StructValue */
8
+
9
+ /**
10
+ * CFF dict pointer: offset comes from a prior operand rather than the stream.
11
+ * Temporary offsetType stubs only implement the method needed for that phase.
12
+ */
3
13
  export default class CFFPointer extends r.Pointer {
14
+ /**
15
+ * @param {BaseType | null} type
16
+ * @param {PointerOptions} [options]
17
+ */
4
18
  constructor(type, options = {}) {
5
19
  if (options.type == null) {
6
20
  options.type = 'global';
@@ -9,6 +23,12 @@ export default class CFFPointer extends r.Pointer {
9
23
  super(null, type, options);
10
24
  }
11
25
 
26
+ /**
27
+ * @param {DecodeStream} stream
28
+ * @param {StructValue | null | undefined} parent
29
+ * @param {number[]} operands
30
+ * @returns {unknown}
31
+ */
12
32
  decode(stream, parent, operands) {
13
33
  this.offsetType = {
14
34
  decode: () => operands[0]
@@ -17,6 +37,12 @@ export default class CFFPointer extends r.Pointer {
17
37
  return super.decode(stream, parent, operands);
18
38
  }
19
39
 
40
+ /**
41
+ * @param {EncodeStream | null} stream
42
+ * @param {unknown} value
43
+ * @param {StructValue | null | undefined} ctx
44
+ * @returns {Ptr[]}
45
+ */
20
46
  encode(stream, value, ctx) {
21
47
  if (!stream) {
22
48
  // compute the size (so ctx.pointerSize is correct)
@@ -28,22 +54,35 @@ export default class CFFPointer extends r.Pointer {
28
54
  return [new Ptr(0)];
29
55
  }
30
56
 
57
+ /** @type {number | null} */
31
58
  let ptr = null;
32
59
  this.offsetType = {
33
- encode: (stream, val) => ptr = val
60
+ /**
61
+ * @param {EncodeStream} _stream
62
+ * @param {number} val
63
+ */
64
+ encode: (_stream, val) => { ptr = val; }
34
65
  };
35
66
 
36
67
  super.encode(stream, value, ctx);
37
- return [new Ptr(ptr)];
68
+ return [new Ptr(ptr ?? 0)];
38
69
  }
39
70
  }
40
71
 
41
72
  class Ptr {
73
+ /**
74
+ * @param {number} val
75
+ */
42
76
  constructor(val) {
77
+ /** @type {number} */
43
78
  this.val = val;
79
+ /** @type {boolean} */
44
80
  this.forceLarge = true;
45
81
  }
46
82
 
83
+ /**
84
+ * @returns {number}
85
+ */
47
86
  valueOf() {
48
87
  return this.val;
49
88
  }
@@ -2,17 +2,27 @@ import CFFDict from './CFFDict';
2
2
  import CFFIndex from './CFFIndex';
3
3
  import CFFPointer from './CFFPointer';
4
4
 
5
- class CFFBlendOp {
6
- static decode(stream, parent, operands) {
5
+ /** @typedef {import('restructure').DecodeStream} DecodeStream */
6
+ /** @typedef {import('restructure').StructValue} StructValue */
7
+
8
+ /** @type {import('../../types/fontkit').CFFOperandType} */
9
+ const CFFBlendOp = {
10
+ /**
11
+ * @param {DecodeStream} _stream
12
+ * @param {StructValue} _parent
13
+ * @param {number[]} operands
14
+ * @returns {void}
15
+ */
16
+ decode(_stream, _parent, operands) {
7
17
  let numBlends = operands.pop();
8
18
 
9
19
  // TODO: actually blend. For now just consume the deltas
10
20
  // since we don't use any of the values anyway.
11
- while (operands.length > numBlends) {
21
+ while (operands.length > /** @type {number} */ (numBlends)) {
12
22
  operands.pop();
13
23
  }
14
24
  }
15
- }
25
+ };
16
26
 
17
27
  export default new CFFDict([
18
28
  // key name type default
@@ -1,5 +1,6 @@
1
1
  // Automatically generated from Appendix A of the CFF specification; do
2
2
  // not edit. Length should be 391.
3
+ /** @type {string[]} */
3
4
  export default [
4
5
  '.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar',
5
6
  'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
package/src/cff/CFFTop.js CHANGED
@@ -8,33 +8,89 @@ import { StandardEncoding, ExpertEncoding } from './CFFEncodings';
8
8
  import { ISOAdobeCharset, ExpertCharset, ExpertSubsetCharset } from './CFFCharsets';
9
9
  import { ItemVariationStore } from '../tables/variations';
10
10
 
11
+ /** @typedef {import('restructure').BaseType} BaseType */
12
+ /** @typedef {import('restructure').DecodeStream} DecodeStream */
13
+ /** @typedef {import('restructure').EncodeStream} EncodeStream */
14
+ /** @typedef {import('restructure').StructValue} StructValue */
15
+ /** @typedef {import('../../types/fontkit').CFFEncodeContext} CFFEncodeContext */
16
+
17
+ /**
18
+ * @param {StructValue} t
19
+ * @returns {number}
20
+ */
21
+ function charStringsCount(t) {
22
+ let parent = t.parent;
23
+ if (!parent) {
24
+ return 0;
25
+ }
26
+ let cs = parent.CharStrings;
27
+ if (cs && typeof cs === 'object' && 'length' in cs && typeof /** @type {{ length: unknown }} */ (cs).length === 'number') {
28
+ return /** @type {{ length: number }} */ (cs).length;
29
+ }
30
+ return 0;
31
+ }
32
+
11
33
  // Checks if an operand is an index of a predefined value,
12
34
  // otherwise delegates to the provided type.
13
35
  class PredefinedOp {
36
+ /**
37
+ * @param {unknown[]} predefinedOps
38
+ * @param {BaseType} type
39
+ */
14
40
  constructor(predefinedOps, type) {
41
+ /** @type {unknown[]} */
15
42
  this.predefinedOps = predefinedOps;
43
+ /** @type {BaseType} */
16
44
  this.type = type;
17
45
  }
18
46
 
47
+ /**
48
+ * @param {DecodeStream} stream
49
+ * @param {StructValue} parent
50
+ * @param {number[]} operands
51
+ * @returns {unknown}
52
+ */
19
53
  decode(stream, parent, operands) {
20
- if (this.predefinedOps[operands[0]]) {
54
+ if (this.predefinedOps[operands[0]] != null) {
21
55
  return this.predefinedOps[operands[0]];
22
56
  }
23
57
 
58
+ if (!this.type.decode) {
59
+ throw new Error('PredefinedOp type must implement decode()');
60
+ }
24
61
  return this.type.decode(stream, parent, operands);
25
62
  }
26
63
 
64
+ /**
65
+ * @param {unknown} value
66
+ * @param {StructValue | null | undefined} ctx
67
+ * @returns {unknown}
68
+ */
27
69
  size(value, ctx) {
70
+ if (!this.type.size) {
71
+ throw new Error('PredefinedOp type must implement size()');
72
+ }
28
73
  return this.type.size(value, ctx);
29
74
  }
30
75
 
76
+ /**
77
+ * @param {EncodeStream | null} stream
78
+ * @param {unknown} value
79
+ * @param {StructValue | null | undefined} ctx
80
+ * @returns {unknown[]}
81
+ */
31
82
  encode(stream, value, ctx) {
32
83
  let index = this.predefinedOps.indexOf(value);
33
84
  if (index !== -1) {
34
- return index;
85
+ // Must be an operand list — CFFDict iterates with for-of.
86
+ return [index];
35
87
  }
36
88
 
37
- return this.type.encode(stream, value, ctx);
89
+ if (!this.type.encode) {
90
+ throw new Error('PredefinedOp type must implement encode()');
91
+ }
92
+ let encoded = this.type.encode(stream, value, ctx);
93
+ return Array.isArray(encoded) ? encoded : [encoded];
38
94
  }
39
95
  }
40
96
 
@@ -43,6 +99,10 @@ class CFFEncodingVersion extends r.Number {
43
99
  super('UInt8');
44
100
  }
45
101
 
102
+ /**
103
+ * @param {DecodeStream} stream
104
+ * @returns {number}
105
+ */
46
106
  decode(stream) {
47
107
  return r.uint8.decode(stream) & 0x7f;
48
108
  }
@@ -77,15 +137,29 @@ let CFFEncoding = new PredefinedOp([StandardEncoding, ExpertEncoding], new CFFPo
77
137
  // Decodes an array of ranges until the total
78
138
  // length is equal to the provided length.
79
139
  class RangeArray extends r.Array {
140
+ /**
141
+ * @param {DecodeStream} stream
142
+ * @param {StructValue} parent
143
+ * @returns {Array<StructValue & { nLeft: number, offset: number }>}
144
+ */
80
145
  decode(stream, parent) {
146
+ if (this.length == null) {
147
+ throw new Error('RangeArray requires a length');
148
+ }
81
149
  let length = resolveLength(this.length, stream, parent);
82
150
  let count = 0;
151
+ /** @type {Array<StructValue & { nLeft: number, offset: number }>} */
83
152
  let res = [];
84
153
  while (count < length) {
85
- let range = this.type.decode(stream, parent);
154
+ if (!this.type.decode) {
155
+ throw new Error('RangeArray element type must implement decode()');
156
+ }
157
+ let range = /** @type {StructValue & { nLeft: number, offset?: number }} */ (
158
+ this.type.decode(stream, parent)
159
+ );
86
160
  range.offset = count;
87
161
  count += range.nLeft + 1;
88
- res.push(range);
162
+ res.push(/** @type {StructValue & { nLeft: number, offset: number }} */ (range));
89
163
  }
90
164
 
91
165
  return res;
@@ -94,15 +168,15 @@ class RangeArray extends r.Array {
94
168
 
95
169
  let CFFCustomCharset = new r.VersionedStruct(r.uint8, {
96
170
  0: {
97
- glyphs: new r.Array(r.uint16, t => t.parent.CharStrings.length - 1)
171
+ glyphs: new r.Array(r.uint16, t => charStringsCount(t) - 1)
98
172
  },
99
173
 
100
174
  1: {
101
- ranges: new RangeArray(Range1, t => t.parent.CharStrings.length - 1)
175
+ ranges: new RangeArray(Range1, t => charStringsCount(t) - 1)
102
176
  },
103
177
 
104
178
  2: {
105
- ranges: new RangeArray(Range2, t => t.parent.CharStrings.length - 1)
179
+ ranges: new RangeArray(Range2, t => charStringsCount(t) - 1)
106
180
  }
107
181
  });
108
182
 
@@ -120,7 +194,7 @@ let FDRange4 = new r.Struct({
120
194
 
121
195
  let FDSelect = new r.VersionedStruct(r.uint8, {
122
196
  0: {
123
- fds: new r.Array(r.uint8, t => t.parent.CharStrings.length)
197
+ fds: new r.Array(r.uint8, t => charStringsCount(t))
124
198
  },
125
199
 
126
200
  3: {
@@ -138,15 +212,34 @@ let FDSelect = new r.VersionedStruct(r.uint8, {
138
212
 
139
213
  let ptr = new CFFPointer(CFFPrivateDict);
140
214
  class CFFPrivateOp {
215
+ /**
216
+ * @param {DecodeStream} stream
217
+ * @param {StructValue} parent
218
+ * @param {number[]} operands
219
+ * @returns {unknown}
220
+ */
141
221
  decode(stream, parent, operands) {
142
222
  parent.length = operands[0];
143
223
  return ptr.decode(stream, parent, [operands[1]]);
144
224
  }
145
225
 
226
+ /**
227
+ * Size operands match encode(null, …): [privateDictByteLength, pointerOperand].
228
+ * @param {StructValue} dict
229
+ * @param {CFFEncodeContext | StructValue} ctx
230
+ * @returns {unknown[]}
231
+ */
146
232
  size(dict, ctx) {
147
- return [CFFPrivateDict.size(dict, ctx, false), ptr.size(dict, ctx)[0]];
233
+ // Delegate to encode(null) so pointerSize is updated and operands match.
234
+ return this.encode(null, dict, ctx);
148
235
  }
149
236
 
237
+ /**
238
+ * @param {EncodeStream | null} stream
239
+ * @param {StructValue} dict
240
+ * @param {CFFEncodeContext | StructValue} ctx
241
+ * @returns {unknown[]}
242
+ */
150
243
  encode(stream, dict, ctx) {
151
244
  return [CFFPrivateDict.size(dict, ctx, false), ptr.encode(stream, dict, ctx)[0]];
152
245
  }
package/src/decorators.js CHANGED
@@ -1,7 +1,12 @@
1
1
  /**
2
- * This decorator caches the results of a getter or method such that
3
- * the results are lazily computed once, and then cached.
4
- * @private
2
+ * Cache decorator for getters/methods.
3
+ * Results are lazily computed once, then cached on the instance.
4
+ *
5
+ * @template T
6
+ * @param {object} target
7
+ * @param {string} key
8
+ * @param {TypedPropertyDescriptor<T>} descriptor
9
+ * @returns {TypedPropertyDescriptor<T> | void}
5
10
  */
6
11
  export function cache(target, key, descriptor) {
7
12
  if (descriptor.get) {
@@ -11,26 +16,40 @@ export function cache(target, key, descriptor) {
11
16
  Object.defineProperty(this, key, { value });
12
17
  return value;
13
18
  };
14
- } else if (typeof descriptor.value === 'function') {
15
- let fn = descriptor.value;
19
+ return;
20
+ }
21
+
22
+ if (typeof descriptor.value === 'function') {
23
+ let fn = /** @type {(...args: unknown[]) => T} */ (descriptor.value);
16
24
 
17
- return {
25
+ /** @type {TypedPropertyDescriptor<T>} */
26
+ let replacement = {
27
+ configurable: true,
28
+ enumerable: false,
18
29
  get() {
19
- let cache = new Map();
20
- function memoized(...args) {
21
- let key = args.length > 0 ? args[0] : 'value';
22
- if (cache.has(key)) {
23
- return cache.get(key);
30
+ /** @type {Map<unknown, T>} */
31
+ let cacheMap = new Map();
32
+
33
+ /**
34
+ * @param {...unknown} args
35
+ * @returns {T}
36
+ */
37
+ let memoized = (...args) => {
38
+ let cacheKey = args.length > 0 ? args[0] : 'value';
39
+ if (cacheMap.has(cacheKey)) {
40
+ return /** @type {T} */ (cacheMap.get(cacheKey));
24
41
  }
25
42
 
26
43
  let result = fn.apply(this, args);
27
- cache.set(key, result);
44
+ cacheMap.set(cacheKey, result);
28
45
  return result;
29
46
  };
30
47
 
31
48
  Object.defineProperty(this, key, { value: memoized });
32
- return memoized;
49
+ return /** @type {T} */ (/** @type {unknown} */ (memoized));
33
50
  }
34
51
  };
52
+
53
+ return replacement;
35
54
  }
36
55
  }
package/src/encodings.js CHANGED
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * Gets an encoding name from platform, encoding, and language ids.
3
3
  * Returned encoding names can be used in iconv-lite to decode text.
4
+ * @param {number} platformID
5
+ * @param {number} encodingID
6
+ * @param {number} [languageID]
7
+ * @returns {string | null | undefined}
4
8
  */
5
9
  export function getEncoding(platformID, encodingID, languageID = 0) {
6
10
  if (platformID === 1 && MAC_LANGUAGE_ENCODINGS[languageID]) {
@@ -10,7 +14,10 @@ export function getEncoding(platformID, encodingID, languageID = 0) {
10
14
  return ENCODINGS[platformID][encodingID];
11
15
  }
12
16
 
17
+ /** @type {Set<string>} */
13
18
  const SINGLE_BYTE_ENCODINGS = new Set(['x-mac-roman', 'x-mac-cyrillic', 'iso-8859-6', 'iso-8859-8']);
19
+
20
+ /** @type {Record<string, string>} */
14
21
  const MAC_ENCODINGS = {
15
22
  'x-mac-croatian': 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈ƫȅ ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ',
16
23
  'x-mac-gaelic': 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæøṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ',
@@ -22,8 +29,13 @@ const MAC_ENCODINGS = {
22
29
  'x-mac-turkish': 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ'
23
30
  };
24
31
 
32
+ /** @type {Map<string, Map<number, number>>} */
25
33
  const encodingCache = new Map();
26
34
 
35
+ /**
36
+ * @param {string} encoding
37
+ * @returns {Map<number, number> | undefined}
38
+ */
27
39
  export function getEncodingMapping(encoding) {
28
40
  let cached = encodingCache.get(encoding);
29
41
  if (cached) {
@@ -47,13 +59,13 @@ export function getEncodingMapping(encoding) {
47
59
  // TextEncoder only supports utf8, whereas TextDecoder supports legacy encodings.
48
60
  // Use this to create a mapping of code points.
49
61
  let decoder = new TextDecoder(encoding);
50
- let mapping = new Uint8Array(0x80);
62
+ let bytes = new Uint8Array(0x80);
51
63
  for (let i = 0; i < 0x80; i++) {
52
- mapping[i] = 0x80 + i;
64
+ bytes[i] = 0x80 + i;
53
65
  }
54
66
 
55
67
  let res = new Map();
56
- let s = decoder.decode(mapping);
68
+ let s = decoder.decode(bytes);
57
69
  for (let i = 0; i < 0x80; i++) {
58
70
  res.set(s.charCodeAt(i), 0x80 + i);
59
71
  }
@@ -61,9 +73,12 @@ export function getEncodingMapping(encoding) {
61
73
  encodingCache.set(encoding, res);
62
74
  return res;
63
75
  }
76
+
77
+ return undefined;
64
78
  }
65
79
 
66
80
  // Map of platform ids to encoding ids.
81
+ /** @type {(string | null)[][]} */
67
82
  export const ENCODINGS = [
68
83
  // unicode
69
84
  ['utf-16be', 'utf-16be', 'utf-16be', 'utf-16be', 'utf-16be', 'utf-16be', 'utf-16be'],
@@ -103,6 +118,7 @@ export const ENCODINGS = [
103
118
 
104
119
  // Overrides for Mac scripts by language id.
105
120
  // See http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/Readme.txt
121
+ /** @type {Record<number, string>} */
106
122
  export const MAC_LANGUAGE_ENCODINGS = {
107
123
  15: 'x-mac-icelandic',
108
124
  17: 'x-mac-turkish',
@@ -122,9 +138,10 @@ export const MAC_LANGUAGE_ENCODINGS = {
122
138
  };
123
139
 
124
140
  // Map of platform ids to BCP-47 language codes.
141
+ /** @type {Array<Record<number, string>>} */
125
142
  export const LANGUAGES = [
126
143
  // unicode
127
- [],
144
+ {},
128
145
 
129
146
  { // macintosh
130
147
  0: 'en', 30: 'fo', 60: 'ks', 90: 'rw',
@@ -160,7 +177,7 @@ export const LANGUAGES = [
160
177
  },
161
178
 
162
179
  // ISO (deprecated)
163
- [],
180
+ {},
164
181
 
165
182
  { // windows
166
183
  0x0436: 'af', 0x4009: 'en-IN', 0x0487: 'rw', 0x0432: 'tn',
package/src/fs.js CHANGED
@@ -1,11 +1,21 @@
1
1
  import { create } from './base';
2
2
  import fs from 'fs';
3
3
 
4
+ /**
5
+ * @param {string | import('fs').PathLike} filename
6
+ * @param {string | Uint8Array} [postscriptName]
7
+ * @returns {import('../types/fontkit').OpenedFont | null | undefined}
8
+ */
4
9
  export function openSync(filename, postscriptName) {
5
10
  let buffer = fs.readFileSync(filename);
6
11
  return create(buffer, postscriptName);
7
12
  }
8
13
 
14
+ /**
15
+ * @param {string | import('fs').PathLike} filename
16
+ * @param {string | Uint8Array} [postscriptName]
17
+ * @returns {Promise<import('../types/fontkit').OpenedFont | null | undefined>}
18
+ */
9
19
  export async function open(filename, postscriptName) {
10
20
  let buffer = await fs.promises.readFile(filename);
11
21
  return create(buffer, postscriptName);
package/src/glyph/BBox.js CHANGED
@@ -2,6 +2,12 @@
2
2
  * Represents a glyph bounding box
3
3
  */
4
4
  export default class BBox {
5
+ /**
6
+ * @param {number} [minX]
7
+ * @param {number} [minY]
8
+ * @param {number} [maxX]
9
+ * @param {number} [maxY]
10
+ */
5
11
  constructor(minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity) {
6
12
  /**
7
13
  * The minimum X position in the bounding box
@@ -44,6 +50,11 @@ export default class BBox {
44
50
  return this.maxY - this.minY;
45
51
  }
46
52
 
53
+ /**
54
+ * @param {number} x
55
+ * @param {number} y
56
+ * @returns {void}
57
+ */
47
58
  addPoint(x, y) {
48
59
  if (Math.abs(x) !== Infinity) {
49
60
  if (x < this.minX) {
@@ -66,6 +77,9 @@ export default class BBox {
66
77
  }
67
78
  }
68
79
 
80
+ /**
81
+ * @returns {BBox}
82
+ */
69
83
  copy() {
70
84
  return new BBox(this.minX, this.minY, this.maxX, this.maxY);
71
85
  }