@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.
Files changed (142) hide show
  1. package/dist/browser-module.mjs +4448 -1142
  2. package/dist/browser-module.mjs.map +1 -1
  3. package/dist/browser.cjs +4449 -1142
  4. package/dist/browser.cjs.map +1 -1
  5. package/dist/main.cjs +4449 -1142
  6. package/dist/main.cjs.map +1 -1
  7. package/dist/module.mjs +4448 -1142
  8. package/dist/module.mjs.map +1 -1
  9. package/package.json +4 -1
  10. package/src/CmapProcessor.js +60 -21
  11. package/src/DFont.js +114 -14
  12. package/src/TTFFont.js +260 -62
  13. package/src/TrueTypeCollection.js +59 -15
  14. package/src/WOFF2Font.js +128 -22
  15. package/src/WOFFFont.js +45 -8
  16. package/src/aat/AATFeatureMap.js +83 -40
  17. package/src/aat/AATLayoutEngine.js +34 -2
  18. package/src/aat/AATLookupTable.js +24 -6
  19. package/src/aat/AATMorxProcessor.js +202 -65
  20. package/src/aat/AATStateMachine.js +35 -3
  21. package/src/base.js +20 -1
  22. package/src/cff/CFFCharsets.js +3 -0
  23. package/src/cff/CFFDict.js +81 -11
  24. package/src/cff/CFFEncodings.js +2 -0
  25. package/src/cff/CFFFont.js +120 -24
  26. package/src/cff/CFFIndex.js +66 -9
  27. package/src/cff/CFFOperand.js +53 -28
  28. package/src/cff/CFFPointer.js +41 -2
  29. package/src/cff/CFFPrivateDict.js +34 -24
  30. package/src/cff/CFFStandardStrings.js +68 -67
  31. package/src/cff/CFFTop.js +161 -68
  32. package/src/decorators.js +34 -15
  33. package/src/encodings.js +133 -116
  34. package/src/fs.js +10 -0
  35. package/src/glyph/BBox.js +14 -0
  36. package/src/glyph/CFFGlyph.js +293 -152
  37. package/src/glyph/COLRGlyph.js +40 -5
  38. package/src/glyph/Glyph.js +72 -13
  39. package/src/glyph/GlyphVariationProcessor.js +158 -62
  40. package/src/glyph/Path.js +119 -32
  41. package/src/glyph/SBIXGlyph.js +57 -8
  42. package/src/glyph/StandardNames.js +1 -0
  43. package/src/glyph/TTFGlyph.js +203 -63
  44. package/src/glyph/TTFGlyphEncoder.js +58 -26
  45. package/src/glyph/WOFF2Glyph.js +25 -6
  46. package/src/layout/GlyphPosition.js +6 -0
  47. package/src/layout/GlyphRun.js +28 -10
  48. package/src/layout/KernProcessor.js +63 -4
  49. package/src/layout/LayoutEngine.js +99 -26
  50. package/src/layout/Script.js +52 -26
  51. package/src/layout/UnicodeLayoutEngine.js +34 -10
  52. package/src/opentype/GPOSProcessor.js +156 -45
  53. package/src/opentype/GSUBProcessor.js +92 -33
  54. package/src/opentype/GlyphInfo.js +53 -5
  55. package/src/opentype/GlyphIterator.js +51 -2
  56. package/src/opentype/OTLayoutEngine.js +66 -8
  57. package/src/opentype/OTProcessor.js +284 -71
  58. package/src/opentype/ShapingPlan.js +52 -5
  59. package/src/opentype/shapers/ArabicShaper.js +27 -8
  60. package/src/opentype/shapers/DefaultShaper.js +54 -10
  61. package/src/opentype/shapers/HangulShaper.js +120 -42
  62. package/src/opentype/shapers/HebrewShaper.js +50 -16
  63. package/src/opentype/shapers/IndicShaper.js +159 -44
  64. package/src/opentype/shapers/ThaiShaper.js +50 -19
  65. package/src/opentype/shapers/UniversalShaper.js +83 -17
  66. package/src/opentype/shapers/index.js +48 -35
  67. package/src/opentype/shapers/indic-data.js +2 -2
  68. package/src/packages/unicode-properties/data-trie.js +2 -1
  69. package/src/packages/unicode-properties/data.js +13 -1
  70. package/src/packages/unicode-properties/dist/index.cjs +23 -10
  71. package/src/packages/unicode-properties/dist/index.cjs.map +2 -2
  72. package/src/packages/unicode-properties/dist/index.mjs +22 -10
  73. package/src/packages/unicode-properties/dist/index.mjs.map +2 -2
  74. package/src/packages/unicode-properties/generate.js +3 -4
  75. package/src/packages/unicode-properties/index.js +95 -30
  76. package/src/packages/unicode-properties/package.json +1 -1
  77. package/src/packages/unicode-trie/builder.js +146 -29
  78. package/src/packages/unicode-trie/dist/builder.cjs +135 -25
  79. package/src/packages/unicode-trie/dist/builder.cjs.map +2 -2
  80. package/src/packages/unicode-trie/dist/builder.mjs +134 -25
  81. package/src/packages/unicode-trie/dist/builder.mjs.map +2 -2
  82. package/src/packages/unicode-trie/dist/index.cjs +22 -9
  83. package/src/packages/unicode-trie/dist/index.cjs.map +2 -2
  84. package/src/packages/unicode-trie/dist/index.mjs +21 -9
  85. package/src/packages/unicode-trie/dist/index.mjs.map +2 -2
  86. package/src/packages/unicode-trie/index.js +63 -12
  87. package/src/packages/unicode-trie/package.json +1 -1
  88. package/src/packages/unicode-trie/swap.js +15 -2
  89. package/src/subset/CFFSubset.js +112 -22
  90. package/src/subset/Subset.js +23 -3
  91. package/src/subset/TTFSubset.js +84 -41
  92. package/src/tables/BASE.js +28 -27
  93. package/src/tables/COLR.js +10 -9
  94. package/src/tables/CPAL.js +2 -1
  95. package/src/tables/DSIG.js +8 -7
  96. package/src/tables/EBDT.js +10 -4
  97. package/src/tables/EBLC.js +70 -10
  98. package/src/tables/GDEF.js +18 -17
  99. package/src/tables/GPOS.js +153 -90
  100. package/src/tables/GSUB.js +50 -39
  101. package/src/tables/HVAR.js +51 -5
  102. package/src/tables/JSTF.js +17 -16
  103. package/src/tables/LTSH.js +4 -3
  104. package/src/tables/OS2.js +50 -49
  105. package/src/tables/PCLT.js +16 -15
  106. package/src/tables/STAT.js +46 -6
  107. package/src/tables/VDMX.js +18 -17
  108. package/src/tables/VORG.js +8 -7
  109. package/src/tables/WOFF2Directory.js +57 -9
  110. package/src/tables/WOFFDirectory.js +32 -20
  111. package/src/tables/aat.js +160 -35
  112. package/src/tables/avar.js +1 -0
  113. package/src/tables/bsln.js +3 -2
  114. package/src/tables/cmap.js +83 -63
  115. package/src/tables/cvt.js +1 -0
  116. package/src/tables/directory.js +56 -28
  117. package/src/tables/feat.js +24 -2
  118. package/src/tables/fpgm.js +1 -0
  119. package/src/tables/fvar.js +32 -4
  120. package/src/tables/gasp.js +6 -5
  121. package/src/tables/glyf.js +2 -1
  122. package/src/tables/gvar.js +29 -2
  123. package/src/tables/hdmx.js +18 -7
  124. package/src/tables/head.js +17 -16
  125. package/src/tables/hhea.js +15 -14
  126. package/src/tables/hmtx.js +18 -2
  127. package/src/tables/index.js +1 -5
  128. package/src/tables/just.js +15 -4
  129. package/src/tables/kern.js +84 -47
  130. package/src/tables/loca.js +23 -10
  131. package/src/tables/maxp.js +16 -15
  132. package/src/tables/morx.js +27 -20
  133. package/src/tables/name.js +120 -39
  134. package/src/tables/opbd.js +2 -1
  135. package/src/tables/opentype.js +126 -91
  136. package/src/tables/post.js +18 -11
  137. package/src/tables/prep.js +1 -0
  138. package/src/tables/sbix.js +12 -1
  139. package/src/tables/variations.js +29 -9
  140. package/src/tables/vhea.js +15 -14
  141. package/src/tables/vmtx.js +20 -4
  142. package/src/utils.js +15 -0
@@ -1,22 +1,37 @@
1
1
  import Tables from '../tables';
2
2
 
3
+ /** @typedef {import('../../types/fontkit').SubsetFont} SubsetFont */
4
+ /** @typedef {import('../../types/fontkit').SubsetGlyph} SubsetGlyph */
5
+ /** @typedef {import('../../types/fontkit').TableCodec} TableCodec */
6
+
3
7
  // Tables written by TTFSubset.encode; must not be overwritten via includeTable.
4
8
  const MANAGED_TTF_TABLES = [
5
9
  'head', 'hhea', 'loca', 'maxp', 'cvt ', 'prep', 'glyf', 'hmtx', 'fpgm'
6
10
  ];
7
11
 
8
12
  export default class Subset {
13
+ /**
14
+ * @param {SubsetFont} font
15
+ */
9
16
  constructor(font) {
17
+ /** @type {SubsetFont} */
10
18
  this.font = font;
19
+ /** @type {number[]} */
11
20
  this.glyphs = [];
21
+ /** @type {Record<number, number>} */
12
22
  this.mapping = {};
13
23
  // Extra OT table tags to copy into a TTF subset (e.g. 'OS/2', 'name', 'post').
24
+ /** @type {string[]} */
14
25
  this.includedTables = [];
15
26
 
16
27
  // always include the missing glyph
17
28
  this.includeGlyph(0);
18
29
  }
19
30
 
31
+ /**
32
+ * @param {number | SubsetGlyph} glyph
33
+ * @returns {number}
34
+ */
20
35
  includeGlyph(glyph) {
21
36
  if (typeof glyph === 'object') {
22
37
  glyph = glyph.id;
@@ -32,11 +47,15 @@ export default class Subset {
32
47
 
33
48
  // Copy an OT table into the TTF subset (tag is a 4-byte string, e.g. 'OS/2').
34
49
  // Only honored by TTFSubset.encode; CFFSubset overrides this to throw.
50
+ /**
51
+ * @param {string} [tag]
52
+ * @returns {this}
53
+ */
35
54
  includeTable(tag) {
36
55
  if (typeof tag !== 'string' || tag.length !== 4) {
37
56
  throw new Error(
38
- `Invalid OpenType table tag ${JSON.stringify(tag)}: tags must be 4 characters ` +
39
- `(pad with spaces if needed, e.g. "cvt ").`
57
+ `Invalid OpenType table tag ${JSON.stringify(tag)}: tags must be 4 characters `
58
+ + `(pad with spaces if needed, e.g. "cvt ").`
40
59
  );
41
60
  }
42
61
 
@@ -50,7 +69,8 @@ export default class Subset {
50
69
  throw new Error(`Table "${tag}" is not present in this font.`);
51
70
  }
52
71
 
53
- if (!Tables[tag]) {
72
+ let encoders = /** @type {Record<string, TableCodec | undefined>} */ (/** @type {unknown} */ (Tables));
73
+ if (!encoders[tag]) {
54
74
  throw new Error(`Table "${tag}" cannot be encoded (no encoder registered in fontkit).`);
55
75
  }
56
76
 
@@ -3,36 +3,88 @@ import Subset from './Subset';
3
3
  import Directory from '../tables/directory';
4
4
  import TTFGlyphEncoder from '../glyph/TTFGlyphEncoder';
5
5
 
6
+ /** @typedef {import('../../types/fontkit').SubsetFont} SubsetFont */
7
+ /** @typedef {import('../../types/fontkit').DecodedGlyf} DecodedGlyf */
8
+ /** @typedef {import('restructure').BinaryBuffer} BinaryBuffer */
9
+ /** @typedef {import('restructure').StructValue} StructValue */
10
+
11
+ /**
12
+ * @typedef {{ advance: number, bearing: number }} HmtxMetric
13
+ */
14
+
6
15
  export default class TTFSubset extends Subset {
16
+ /** @type {TTFGlyphEncoder} */
17
+ glyphEncoder;
18
+ /** @type {Uint8Array[] | null} */
19
+ glyf = null;
20
+ /** @type {number} */
21
+ offset = 0;
22
+ /** @type {{ offsets: number[], version: number } | null} */
23
+ loca = null;
24
+ /** @type {{ metrics: HmtxMetric[], bearings: number[] } | null} */
25
+ hmtx = null;
26
+
27
+ /**
28
+ * @param {SubsetFont} font
29
+ */
7
30
  constructor(font) {
8
31
  super(font);
9
- this.glyphEncoder = new TTFGlyphEncoder;
32
+ this.glyphEncoder = new TTFGlyphEncoder();
10
33
  }
11
34
 
35
+ /**
36
+ * @param {number} gid
37
+ * @returns {number}
38
+ */
12
39
  _addGlyph(gid) {
13
40
  let glyph = this.font.getGlyph(gid);
41
+ if (!glyph || !glyph._decode) {
42
+ throw new Error(`Cannot decode glyph ${gid}`);
43
+ }
14
44
  let glyf = glyph._decode();
15
45
 
46
+ if (!this.font.loca) {
47
+ throw new Error('Font missing loca table');
48
+ }
49
+
16
50
  // get the offset to the glyph from the loca table
17
51
  let curOffset = this.font.loca.offsets[gid];
18
52
  let nextOffset = this.font.loca.offsets[gid + 1];
19
53
 
20
54
  let stream = this.font._getTableStream('glyf');
55
+ if (!stream) {
56
+ throw new Error('Font missing glyf table');
57
+ }
21
58
  stream.pos += curOffset;
22
59
 
23
- let buffer = stream.readBuffer(nextOffset - curOffset);
60
+ let raw = stream.readBuffer(nextOffset - curOffset);
61
+ /** @type {Uint8Array} */
62
+ let buffer = raw instanceof Uint8Array
63
+ ? raw
64
+ : Uint8Array.from(/** @type {Iterable<number>} */ (/** @type {unknown} */ (raw)));
24
65
 
25
66
  // if it is a compound glyph, include its components
26
67
  if (glyf && glyf.numberOfContours < 0) {
27
68
  buffer = new Uint8Array(buffer);
28
- let view = new DataView(buffer.buffer);
29
- for (let component of glyf.components) {
69
+ let ab = buffer.buffer instanceof ArrayBuffer ? buffer.buffer : new Uint8Array(buffer).buffer;
70
+ let view = new DataView(ab, buffer.byteOffset, buffer.byteLength);
71
+ for (let component of glyf.components || []) {
30
72
  gid = this.includeGlyph(component.glyphID);
31
73
  view.setUint16(component.pos, gid);
32
74
  }
33
75
  } else if (glyf && this.font._variationProcessor) {
34
76
  // If this is a TrueType variation glyph, re-encode the path
35
- buffer = this.glyphEncoder.encodeSimple(glyph.path, glyf.instructions);
77
+ let encoded = this.glyphEncoder.encodeSimple(
78
+ /** @type {import('../glyph/Path').default} */ (/** @type {unknown} */ (glyph.path)),
79
+ glyf.instructions
80
+ );
81
+ buffer = encoded instanceof Uint8Array
82
+ ? encoded
83
+ : Uint8Array.from(/** @type {Iterable<number>} */ (/** @type {unknown} */ (encoded)));
84
+ }
85
+
86
+ if (!this.glyf || !this.loca || !this.hmtx) {
87
+ throw new Error('TTFSubset.encode must initialize glyf/loca/hmtx before _addGlyph');
36
88
  }
37
89
 
38
90
  this.glyf.push(buffer);
@@ -43,10 +95,13 @@ export default class TTFSubset extends Subset {
43
95
  bearing: glyph._getMetrics().leftBearing
44
96
  });
45
97
 
46
- this.offset += buffer.length;
98
+ this.offset += buffer.byteLength;
47
99
  return this.glyf.length - 1;
48
100
  }
49
101
 
102
+ /**
103
+ * @returns {BinaryBuffer}
104
+ */
50
105
  encode() {
51
106
  // tables required by PDF spec:
52
107
  // head, hhea, loca, maxp, cvt , prep, glyf, hmtx, fpgm
@@ -54,16 +109,17 @@ export default class TTFSubset extends Subset {
54
109
  // additional tables required for standalone fonts:
55
110
  // name, cmap, OS/2, post
56
111
 
112
+ /** @type {Uint8Array[]} */
57
113
  this.glyf = [];
58
114
  this.offset = 0;
59
115
  this.loca = {
60
- offsets: [],
61
- version: this.font.loca.version
116
+ offsets: /** @type {number[]} */ ([]),
117
+ version: this.font.loca ? (this.font.loca.version ?? 0) : 0
62
118
  };
63
119
 
64
120
  this.hmtx = {
65
- metrics: [],
66
- bearings: []
121
+ metrics: /** @type {HmtxMetric[]} */ ([]),
122
+ bearings: /** @type {number[]} */ ([])
67
123
  };
68
124
 
69
125
  // include all the glyphs
@@ -75,41 +131,27 @@ export default class TTFSubset extends Subset {
75
131
  }
76
132
 
77
133
  let maxp = cloneDeep(this.font.maxp);
78
- maxp.numGlyphs = this.glyf.length;
134
+ if (maxp && typeof maxp === 'object') {
135
+ /** @type {StructValue} */ (maxp).numGlyphs = this.glyf.length;
136
+ }
79
137
 
80
- this.loca.offsets.push(this.offset);
138
+ let loca = this.loca;
139
+ loca.offsets.push(this.offset);
81
140
 
82
141
  let head = cloneDeep(this.font.head);
83
- head.indexToLocFormat = this.loca.version;
142
+ if (head && typeof head === 'object') {
143
+ /** @type {StructValue} */ (head).indexToLocFormat = loca.version;
144
+ }
84
145
 
85
146
  let hhea = cloneDeep(this.font.hhea);
86
- hhea.numberOfMetrics = this.hmtx.metrics.length;
87
-
88
- // map = []
89
- // for index in [0...256]
90
- // if index < @numGlyphs
91
- // map[index] = index
92
- // else
93
- // map[index] = 0
94
- //
95
- // cmapTable =
96
- // version: 0
97
- // length: 262
98
- // language: 0
99
- // codeMap: map
100
- //
101
- // cmap =
102
- // version: 0
103
- // numSubtables: 1
104
- // tables: [
105
- // platformID: 1
106
- // encodingID: 0
107
- // table: cmapTable
108
- // ]
147
+ if (hhea && typeof hhea === 'object') {
148
+ /** @type {StructValue} */ (hhea).numberOfMetrics = this.hmtx.metrics.length;
149
+ }
109
150
 
110
151
  // TODO: subset prep, cvt, fpgm?
111
152
  // The following is the minimum set of tables.
112
- let t = {
153
+ /** @type {Record<string, unknown>} */
154
+ let t = {
113
155
  head,
114
156
  hhea,
115
157
  loca: this.loca,
@@ -118,13 +160,14 @@ export default class TTFSubset extends Subset {
118
160
  prep: this.font.prep,
119
161
  glyf: this.glyf,
120
162
  hmtx: this.hmtx,
121
- fpgm: this.font.fpgm,
122
- }
163
+ fpgm: this.font.fpgm
164
+ };
123
165
 
166
+ let fontTables = /** @type {Record<string, unknown>} */ (/** @type {unknown} */ (this.font));
124
167
  for (const tag of this.includedTables) {
125
- t[tag] = cloneDeep(this.font[tag]);
168
+ t[tag] = cloneDeep(fontTables[tag]);
126
169
  }
127
170
 
128
- return Directory.toBuffer({tables: t});
171
+ return Directory.toBuffer({ tables: t });
129
172
  }
130
173
  }
@@ -1,58 +1,58 @@
1
1
  import * as r from 'restructure';
2
- import {Device} from './opentype';
3
- import {ItemVariationStore} from './variations';
2
+ import { Device } from './opentype';
3
+ import { ItemVariationStore } from './variations';
4
4
 
5
5
  let BaseCoord = new r.VersionedStruct(r.uint16, {
6
6
  1: { // Design units only
7
- coordinate: r.int16 // X or Y value, in design units
7
+ coordinate: r.int16 // X or Y value, in design units
8
8
  },
9
9
 
10
10
  2: { // Design units plus contour point
11
- coordinate: r.int16, // X or Y value, in design units
12
- referenceGlyph: r.uint16, // GlyphID of control glyph
13
- baseCoordPoint: r.uint16 // Index of contour point on the referenceGlyph
11
+ coordinate: r.int16, // X or Y value, in design units
12
+ referenceGlyph: r.uint16, // GlyphID of control glyph
13
+ baseCoordPoint: r.uint16 // Index of contour point on the referenceGlyph
14
14
  },
15
15
 
16
16
  3: { // Design units plus Device table
17
- coordinate: r.int16, // X or Y value, in design units
18
- deviceTable: new r.Pointer(r.uint16, Device) // Device table for X or Y value
17
+ coordinate: r.int16, // X or Y value, in design units
18
+ deviceTable: new r.Pointer(r.uint16, Device) // Device table for X or Y value
19
19
  }
20
20
  });
21
21
 
22
22
  let BaseValues = new r.Struct({
23
- defaultIndex: r.uint16, // Index of default baseline for this script-same index in the BaseTagList
23
+ defaultIndex: r.uint16, // Index of default baseline for this script-same index in the BaseTagList
24
24
  baseCoordCount: r.uint16,
25
- baseCoords: new r.Array(new r.Pointer(r.uint16, BaseCoord), 'baseCoordCount')
25
+ baseCoords: new r.Array(new r.Pointer(r.uint16, BaseCoord), 'baseCoordCount')
26
26
  });
27
27
 
28
28
  let FeatMinMaxRecord = new r.Struct({
29
- tag: new r.String(4), // 4-byte feature identification tag-must match FeatureTag in FeatureList
30
- minCoord: new r.Pointer(r.uint16, BaseCoord, {type: 'parent'}), // May be NULL
31
- maxCoord: new r.Pointer(r.uint16, BaseCoord, {type: 'parent'}) // May be NULL
29
+ tag: new r.String(4), // 4-byte feature identification tag-must match FeatureTag in FeatureList
30
+ minCoord: new r.Pointer(r.uint16, BaseCoord, { type: 'parent' }), // May be NULL
31
+ maxCoord: new r.Pointer(r.uint16, BaseCoord, { type: 'parent' }) // May be NULL
32
32
  });
33
33
 
34
34
  let MinMax = new r.Struct({
35
- minCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL
36
- maxCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL
37
- featMinMaxCount: r.uint16, // May be 0
38
- featMinMaxRecords: new r.Array(FeatMinMaxRecord, 'featMinMaxCount') // In alphabetical order
35
+ minCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL
36
+ maxCoord: new r.Pointer(r.uint16, BaseCoord), // May be NULL
37
+ featMinMaxCount: r.uint16, // May be 0
38
+ featMinMaxRecords: new r.Array(FeatMinMaxRecord, 'featMinMaxCount') // In alphabetical order
39
39
  });
40
40
 
41
41
  let BaseLangSysRecord = new r.Struct({
42
- tag: new r.String(4), // 4-byte language system identification tag
43
- minMax: new r.Pointer(r.uint16, MinMax, {type: 'parent'})
42
+ tag: new r.String(4), // 4-byte language system identification tag
43
+ minMax: new r.Pointer(r.uint16, MinMax, { type: 'parent' })
44
44
  });
45
45
 
46
46
  let BaseScript = new r.Struct({
47
- baseValues: new r.Pointer(r.uint16, BaseValues), // May be NULL
48
- defaultMinMax: new r.Pointer(r.uint16, MinMax), // May be NULL
49
- baseLangSysCount: r.uint16, // May be 0
47
+ baseValues: new r.Pointer(r.uint16, BaseValues), // May be NULL
48
+ defaultMinMax: new r.Pointer(r.uint16, MinMax), // May be NULL
49
+ baseLangSysCount: r.uint16, // May be 0
50
50
  baseLangSysRecords: new r.Array(BaseLangSysRecord, 'baseLangSysCount') // in alphabetical order by BaseLangSysTag
51
51
  });
52
52
 
53
53
  let BaseScriptRecord = new r.Struct({
54
- tag: new r.String(4), // 4-byte script identification tag
55
- script: new r.Pointer(r.uint16, BaseScript, {type: 'parent'})
54
+ tag: new r.String(4), // 4-byte script identification tag
55
+ script: new r.Pointer(r.uint16, BaseScript, { type: 'parent' })
56
56
  });
57
57
 
58
58
  let BaseScriptList = new r.Array(BaseScriptRecord, r.uint16);
@@ -61,14 +61,15 @@ let BaseScriptList = new r.Array(BaseScriptRecord, r.uint16);
61
61
  let BaseTagList = new r.Array(new r.String(4), r.uint16);
62
62
 
63
63
  let Axis = new r.Struct({
64
- baseTagList: new r.Pointer(r.uint16, BaseTagList), // May be NULL
64
+ baseTagList: new r.Pointer(r.uint16, BaseTagList), // May be NULL
65
65
  baseScriptList: new r.Pointer(r.uint16, BaseScriptList)
66
66
  });
67
67
 
68
+ /** @type {import('restructure').VersionedStruct} */
68
69
  export default new r.VersionedStruct(r.uint32, {
69
70
  header: {
70
- horizAxis: new r.Pointer(r.uint16, Axis), // May be NULL
71
- vertAxis: new r.Pointer(r.uint16, Axis) // May be NULL
71
+ horizAxis: new r.Pointer(r.uint16, Axis), // May be NULL
72
+ vertAxis: new r.Pointer(r.uint16, Axis) // May be NULL
72
73
  },
73
74
 
74
75
  0x00010000: {},
@@ -1,21 +1,22 @@
1
1
  import * as r from 'restructure';
2
2
 
3
3
  let LayerRecord = new r.Struct({
4
- gid: r.uint16, // Glyph ID of layer glyph (must be in z-order from bottom to top).
5
- paletteIndex: r.uint16 // Index value to use in the appropriate palette. This value must
6
- }); // be less than numPaletteEntries in the CPAL table, except for
7
- // the special case noted below. Each palette entry is 16 bits.
8
- // A palette index of 0xFFFF is a special case indicating that
9
- // the text foreground color should be used.
4
+ gid: r.uint16, // Glyph ID of layer glyph (must be in z-order from bottom to top).
5
+ paletteIndex: r.uint16 // Index value to use in the appropriate palette. This value must
6
+ }); // be less than numPaletteEntries in the CPAL table, except for
7
+ // the special case noted below. Each palette entry is 16 bits.
8
+ // A palette index of 0xFFFF is a special case indicating that
9
+ // the text foreground color should be used.
10
10
 
11
11
  let BaseGlyphRecord = new r.Struct({
12
- gid: r.uint16, // Glyph ID of reference glyph. This glyph is for reference only
13
- // and is not rendered for color.
12
+ gid: r.uint16, // Glyph ID of reference glyph. This glyph is for reference only
13
+ // and is not rendered for color.
14
14
  firstLayerIndex: r.uint16, // Index (from beginning of the Layer Records) to the layer record.
15
- // There will be numLayers consecutive entries for this base glyph.
15
+ // There will be numLayers consecutive entries for this base glyph.
16
16
  numLayers: r.uint16
17
17
  });
18
18
 
19
+ /** @type {import('restructure').Struct} */
19
20
  export default new r.Struct({
20
21
  version: r.uint16,
21
22
  numBaseGlyphRecords: r.uint16,
@@ -7,13 +7,14 @@ let ColorRecord = new r.Struct({
7
7
  alpha: r.uint8
8
8
  });
9
9
 
10
+ /** @type {import('restructure').VersionedStruct} */
10
11
  export default new r.VersionedStruct(r.uint16, {
11
12
  header: {
12
13
  numPaletteEntries: r.uint16,
13
14
  numPalettes: r.uint16,
14
15
  numColorRecords: r.uint16,
15
16
  colorRecords: new r.Pointer(r.uint32, new r.Array(ColorRecord, 'numColorRecords')),
16
- colorRecordIndices: new r.Array(r.uint16, 'numPalettes'),
17
+ colorRecordIndices: new r.Array(r.uint16, 'numPalettes')
17
18
  },
18
19
  0: {},
19
20
  1: {
@@ -7,15 +7,16 @@ let Signature = new r.Struct({
7
7
  });
8
8
 
9
9
  let SignatureBlock = new r.Struct({
10
- reserved: new r.Reserved(r.uint16, 2),
11
- cbSignature: r.uint32, // Length (in bytes) of the PKCS#7 packet in pbSignature
12
- signature: new r.Buffer('cbSignature')
10
+ reserved: new r.Reserved(r.uint16, 2),
11
+ cbSignature: r.uint32, // Length (in bytes) of the PKCS#7 packet in pbSignature
12
+ signature: new r.Buffer('cbSignature')
13
13
  });
14
14
 
15
+ /** @type {import('restructure').Struct} */
15
16
  export default new r.Struct({
16
- ulVersion: r.uint32, // Version number of the DSIG table (0x00000001)
17
- usNumSigs: r.uint16, // Number of signatures in the table
18
- usFlag: r.uint16, // Permission flags
19
- signatures: new r.Array(Signature, 'usNumSigs'),
17
+ ulVersion: r.uint32, // Version number of the DSIG table (0x00000001)
18
+ usNumSigs: r.uint16, // Number of signatures in the table
19
+ usFlag: r.uint16, // Permission flags
20
+ signatures: new r.Array(Signature, 'usNumSigs'),
20
21
  signatureBlocks: new r.Array(SignatureBlock, 'usNumSigs')
21
22
  });
@@ -1,5 +1,8 @@
1
1
  import * as r from 'restructure';
2
2
 
3
+ /** @typedef {import('restructure').BaseType} BaseType */
4
+
5
+ /** @type {import('restructure').Struct} */
3
6
  export let BigMetrics = new r.Struct({
4
7
  height: r.uint8,
5
8
  width: r.uint8,
@@ -11,6 +14,7 @@ export let BigMetrics = new r.Struct({
11
14
  vertAdvance: r.uint8
12
15
  });
13
16
 
17
+ /** @type {import('restructure').Struct} */
14
18
  export let SmallMetrics = new r.Struct({
15
19
  height: r.uint8,
16
20
  width: r.uint8,
@@ -25,10 +29,13 @@ let EBDTComponent = new r.Struct({
25
29
  yOffset: r.int8
26
30
  });
27
31
 
28
- class ByteAligned {}
29
-
30
- class BitAligned {}
32
+ /** Marker codecs for bitmap payload layout (decoded by glyph consumers). */
33
+ /** @type {BaseType} */
34
+ const ByteAligned = {};
35
+ /** @type {BaseType} */
36
+ const BitAligned = {};
31
37
 
38
+ /** @type {import('restructure').VersionedStruct} */
32
39
  export let glyph = new r.VersionedStruct('version', {
33
40
  1: {
34
41
  metrics: SmallMetrics,
@@ -88,4 +95,3 @@ export let glyph = new r.VersionedStruct('version', {
88
95
  data: new r.Buffer('dataLen')
89
96
  }
90
97
  });
91
-
@@ -1,5 +1,7 @@
1
1
  import * as r from 'restructure';
2
- import {BigMetrics} from './EBDT';
2
+ import { BigMetrics } from './EBDT';
3
+
4
+ /** @typedef {import('restructure').StructValue} StructValue */
3
5
 
4
6
  let SBitLineMetrics = new r.Struct({
5
7
  ascender: r.int8,
@@ -20,6 +22,17 @@ let CodeOffsetPair = new r.Struct({
20
22
  offset: r.uint16
21
23
  });
22
24
 
25
+ /**
26
+ * Spec: numOffsets = lastGlyphIndex - firstGlyphIndex + 2 (extra sentinel for last glyph size).
27
+ * @param {StructValue} t
28
+ * @returns {number}
29
+ */
30
+ function glyphRangeOffsetCount(t) {
31
+ let parent = /** @type {StructValue} */ (t.parent);
32
+ return /** @type {number} */ (parent.lastGlyphIndex)
33
+ - /** @type {number} */ (parent.firstGlyphIndex) + 2;
34
+ }
35
+
23
36
  let IndexSubtable = new r.VersionedStruct(r.uint16, {
24
37
  header: {
25
38
  imageFormat: r.uint16,
@@ -27,7 +40,7 @@ let IndexSubtable = new r.VersionedStruct(r.uint16, {
27
40
  },
28
41
 
29
42
  1: {
30
- offsetArray: new r.Array(r.uint32, t => t.parent.lastGlyphIndex - t.parent.firstGlyphIndex + 1)
43
+ offsetArray: new r.Array(r.uint32, glyphRangeOffsetCount)
31
44
  },
32
45
 
33
46
  2: {
@@ -36,30 +49,67 @@ let IndexSubtable = new r.VersionedStruct(r.uint16, {
36
49
  },
37
50
 
38
51
  3: {
39
- offsetArray: new r.Array(r.uint16, t => t.parent.lastGlyphIndex - t.parent.firstGlyphIndex + 1)
52
+ offsetArray: new r.Array(r.uint16, glyphRangeOffsetCount),
53
+ // Format 3 pads to 32-bit alignment when the offset count is odd.
54
+ pad: new r.Reserved(
55
+ r.uint16,
56
+ /** @param {StructValue} t @returns {number} */
57
+ t => glyphRangeOffsetCount(t) % 2
58
+ )
40
59
  },
41
60
 
42
61
  4: {
43
62
  numGlyphs: r.uint32,
44
- glyphArray: new r.Array(CodeOffsetPair, t => t.numGlyphs + 1)
63
+ glyphArray: new r.Array(
64
+ CodeOffsetPair,
65
+ /** @param {StructValue} t @returns {number} */
66
+ t => /** @type {number} */ (t.numGlyphs) + 1
67
+ )
45
68
  },
46
69
 
47
70
  5: {
48
71
  imageSize: r.uint32,
49
72
  bigMetrics: BigMetrics,
50
73
  numGlyphs: r.uint32,
51
- glyphCodeArray: new r.Array(r.uint16, 'numGlyphs')
74
+ glyphCodeArray: new r.Array(r.uint16, 'numGlyphs'),
75
+ // Format 5 pads to 32-bit alignment when glyphCodeArray length is odd.
76
+ pad: new r.Reserved(
77
+ r.uint16,
78
+ /** @param {StructValue} t @returns {number} */
79
+ t => /** @type {number} */ (t.numGlyphs) % 2
80
+ )
52
81
  }
53
82
  });
54
83
 
55
- let IndexSubtableArray = new r.Struct({
84
+ let IndexSubtableRecord = new r.Struct({
56
85
  firstGlyphIndex: r.uint16,
57
86
  lastGlyphIndex: r.uint16,
58
- subtable: new r.Pointer(r.uint32, IndexSubtable)
87
+ // Offset from the start of IndexSubTableList (OpenType IndexSubTableArray).
88
+ subtable: new r.Pointer(r.uint32, IndexSubtable, { type: 'parent' })
89
+ });
90
+
91
+ /**
92
+ * Wrapper so record pointers resolve relative to the list start.
93
+ * process() on BitmapSizeTable unwraps `.tables` so the public shape stays an array.
94
+ */
95
+ let IndexSubTableList = new r.Struct({
96
+ tables: new r.Array(
97
+ IndexSubtableRecord,
98
+ /** @param {StructValue} t @returns {number} */
99
+ t => /** @type {number} */ (/** @type {StructValue} */ (t.parent).numberOfIndexSubTables)
100
+ )
59
101
  });
60
102
 
103
+ /**
104
+ * @typedef {StructValue & {
105
+ * indexSubTableArray: { tables: StructValue[] } | StructValue[],
106
+ * numberOfIndexSubTables: number
107
+ * }} BitmapSizeTableValue
108
+ */
109
+
61
110
  let BitmapSizeTable = new r.Struct({
62
- indexSubTableArray: new r.Pointer(r.uint32, new r.Array(IndexSubtableArray, 1), { type: 'parent' }),
111
+ // Lazy: numberOfIndexSubTables is stored after this pointer in the binary layout.
112
+ indexSubTableArray: new r.Pointer(r.uint32, IndexSubTableList, { type: 'parent', lazy: true }),
63
113
  indexTablesSize: r.uint32,
64
114
  numberOfIndexSubTables: r.uint32,
65
115
  colorRef: r.uint32,
@@ -73,8 +123,18 @@ let BitmapSizeTable = new r.Struct({
73
123
  flags: new r.Bitfield(r.uint8, ['horizontal', 'vertical'])
74
124
  });
75
125
 
126
+ BitmapSizeTable.process = function () {
127
+ let self = /** @type {BitmapSizeTableValue} */ (this);
128
+ // Access forces lazy decode now that numberOfIndexSubTables is available.
129
+ let list = self.indexSubTableArray;
130
+ if (list && !Array.isArray(list) && Array.isArray(list.tables)) {
131
+ self.indexSubTableArray = list.tables;
132
+ }
133
+ };
134
+
135
+ /** @type {import('restructure').Struct} */
76
136
  export default new r.Struct({
77
- version: r.uint32, // 0x00020000
137
+ version: r.uint32, // 0x00020000
78
138
  numSizes: r.uint32,
79
- sizes: new r.Array(BitmapSizeTable, 'numSizes')
139
+ sizes: new r.Array(BitmapSizeTable, 'numSizes')
80
140
  });