@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,3 +1,4 @@
1
+ "use strict";
1
2
  var __defProp = Object.defineProperty;
2
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -45,6 +46,9 @@ var swap32LE = (array) => {
45
46
  };
46
47
 
47
48
  // index.js
49
+ function isNodeBuffer(value) {
50
+ return typeof value === "object" && value !== null && "readUInt32BE" in value && "readUInt32LE" in value && "slice" in value && typeof value.readUInt32BE === "function" && typeof value.readUInt32LE === "function" && typeof value.slice === "function";
51
+ }
48
52
  var SHIFT_1 = 6 + 5;
49
53
  var SHIFT_2 = 5;
50
54
  var SHIFT_1_2 = SHIFT_1 - SHIFT_2;
@@ -62,29 +66,38 @@ var UTF8_2B_INDEX_2_LENGTH = 2048 >> 6;
62
66
  var INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;
63
67
  var DATA_GRANULARITY = 1 << INDEX_SHIFT;
64
68
  var UnicodeTrie = class {
69
+ /**
70
+ * @param {Uint8Array | Buffer | UnicodeTrieInit} data
71
+ */
65
72
  constructor(data) {
66
- const isBuffer = typeof data.readUInt32BE === "function" && typeof data.slice === "function";
67
- if (isBuffer || data instanceof Uint8Array) {
73
+ if (isNodeBuffer(data) || data instanceof Uint8Array) {
74
+ let bytes;
68
75
  let uncompressedLength;
69
- if (isBuffer) {
76
+ if (isNodeBuffer(data)) {
70
77
  this.highStart = data.readUInt32LE(0);
71
78
  this.errorValue = data.readUInt32LE(4);
72
79
  uncompressedLength = data.readUInt32LE(8);
73
- data = data.slice(12);
80
+ bytes = new Uint8Array(data.buffer, data.byteOffset + 12, data.byteLength - 12);
74
81
  } else {
75
82
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
76
83
  this.highStart = view.getUint32(0, true);
77
84
  this.errorValue = view.getUint32(4, true);
78
85
  uncompressedLength = view.getUint32(8, true);
79
- data = data.subarray(12);
86
+ bytes = data.subarray(12);
80
87
  }
81
- data = (0, import_fflate.inflateSync)(data, { out: new Uint8Array(uncompressedLength) });
82
- swap32LE(data);
83
- this.data = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);
88
+ bytes = (0, import_fflate.inflateSync)(bytes, { out: new Uint8Array(uncompressedLength) });
89
+ swap32LE(bytes);
90
+ this.data = new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength >> 2);
84
91
  } else {
85
- ({ data: this.data, highStart: this.highStart, errorValue: this.errorValue } = data);
92
+ this.data = data.data;
93
+ this.highStart = data.highStart;
94
+ this.errorValue = data.errorValue;
86
95
  }
87
96
  }
97
+ /**
98
+ * @param {number} codePoint
99
+ * @returns {number}
100
+ */
88
101
  get(codePoint) {
89
102
  let index;
90
103
  if (codePoint < 0 || codePoint > 1114111) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../index.js", "../swap.js"],
4
- "sourcesContent": ["import { inflateSync } from 'fflate';\nimport { swap32LE } from './swap.js';\n\n// Shift size for getting the index-1 table offset.\nconst SHIFT_1 = 6 + 5;\n\n// Shift size for getting the index-2 table offset.\nconst SHIFT_2 = 5;\n\n// Difference between the two shift sizes,\n// for getting an index-1 offset from an index-2 offset. 6=11-5\nconst SHIFT_1_2 = SHIFT_1 - SHIFT_2;\n\n// Number of index-1 entries for the BMP. 32=0x20\n// This part of the index-1 table is omitted from the serialized form.\nconst OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;\n\n// Number of entries in an index-2 block. 64=0x40\nconst INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;\n\n// Mask for getting the lower bits for the in-index-2-block offset. */\nconst INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;\n\n// Shift size for shifting left the index array values.\n// Increases possible data size with 16-bit index values at the cost\n// of compactability.\n// This requires data blocks to be aligned by DATA_GRANULARITY.\nconst INDEX_SHIFT = 2;\n\n// Number of entries in a data block. 32=0x20\nconst DATA_BLOCK_LENGTH = 1 << SHIFT_2;\n\n// Mask for getting the lower bits for the in-data-block offset.\nconst DATA_MASK = DATA_BLOCK_LENGTH - 1;\n\n// The part of the index-2 table for U+D800..U+DBFF stores values for\n// lead surrogate code _units_ not code _points_.\n// Values for lead surrogate code _points_ are indexed with this portion of the table.\n// Length=32=0x20=0x400>>SHIFT_2. (There are 1024=0x400 lead surrogates.)\nconst LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2;\nconst LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2;\n\n// Count the lengths of both BMP pieces. 2080=0x820\nconst INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;\n\n// The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820.\n// Length 32=0x20 for lead bytes C0..DF, regardless of SHIFT_2.\nconst UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;\nconst UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; // U+0800 is the first code point after 2-byte UTF-8\n\n// The index-1 table, only used for supplementary code points, at offset 2112=0x840.\n// Variable length, for code points up to highStart, where the last single-value range starts.\n// Maximum length 512=0x200=0x100000>>SHIFT_1.\n// (For 0x100000 supplementary code points U+10000..U+10ffff.)\n//\n// The part of the index-2 table for supplementary code points starts\n// after this index-1 table.\n//\n// Both the index-1 table and the following part of the index-2 table\n// are omitted completely if there is only BMP data.\nconst INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;\n\n// The alignment size of a data block. Also the granularity for compaction.\nconst DATA_GRANULARITY = 1 << INDEX_SHIFT;\n\nclass UnicodeTrie {\n constructor(data) {\n const isBuffer = (typeof data.readUInt32BE === 'function') && (typeof data.slice === 'function');\n\n if (isBuffer || data instanceof Uint8Array) {\n // read binary format\n let uncompressedLength;\n if (isBuffer) {\n this.highStart = data.readUInt32LE(0);\n this.errorValue = data.readUInt32LE(4);\n uncompressedLength = data.readUInt32LE(8);\n data = data.slice(12);\n } else {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n this.highStart = view.getUint32(0, true);\n this.errorValue = view.getUint32(4, true);\n uncompressedLength = view.getUint32(8, true);\n data = data.subarray(12);\n }\n\n // inflate the actual trie data (raw deflate, matching builder)\n data = inflateSync(data, { out: new Uint8Array(uncompressedLength) });\n\n // swap bytes from little-endian\n swap32LE(data);\n\n this.data = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);\n\n } else {\n // pre-parsed data\n ({ data: this.data, highStart: this.highStart, errorValue: this.errorValue } = data);\n }\n }\n\n get(codePoint) {\n let index;\n if ((codePoint < 0) || (codePoint > 0x10ffff)) {\n return this.errorValue;\n }\n\n if ((codePoint < 0xd800) || ((codePoint > 0xdbff) && (codePoint <= 0xffff))) {\n // Ordinary BMP code point, excluding leading surrogates.\n // BMP uses a single level lookup. BMP index starts at offset 0 in the index.\n // data is stored in the index array itself.\n index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint <= 0xffff) {\n // Lead Surrogate Code Point. A Separate index section is stored for\n // lead surrogate code units and code points.\n // The main index has the code unit data.\n // For this function, we need the code point data.\n index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint < this.highStart) {\n // Supplemental code point, use two-level lookup.\n index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];\n index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];\n index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n return this.data[this.data.length - DATA_GRANULARITY];\n }\n}\n\nexport default UnicodeTrie;\n", "const isBigEndian = (new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12);\n\nconst swap = (b, n, m) => {\n let i = b[n];\n b[n] = b[m];\n b[m] = i;\n};\n\nconst swap32 = array => {\n const len = array.length;\n for (let i = 0; i < len; i += 4) {\n swap(array, i, i + 3);\n swap(array, i + 1, i + 2);\n }\n};\n\nexport const swap32LE = array => {\n if (isBigEndian) {\n swap32(array);\n }\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { inflateSync } from 'fflate';\nimport { swap32LE } from './swap.js';\n\n/**\n * Pre-parsed trie payload (e.g. from UnicodeTrieBuilder.freeze).\n * @typedef {object} UnicodeTrieInit\n * @property {Int32Array | Uint32Array} data\n * @property {number} highStart\n * @property {number} errorValue\n */\n\n/**\n * Duck-type Node Buffer (has LE/BE readers + slice), matching prior runtime checks.\n * @param {unknown} value\n * @returns {value is Buffer}\n */\nfunction isNodeBuffer(value) {\n return (\n typeof value === 'object'\n && value !== null\n && 'readUInt32BE' in value\n && 'readUInt32LE' in value\n && 'slice' in value\n && typeof value.readUInt32BE === 'function'\n && typeof value.readUInt32LE === 'function'\n && typeof value.slice === 'function'\n );\n}\n\n// Shift size for getting the index-1 table offset.\nconst SHIFT_1 = 6 + 5;\n\n// Shift size for getting the index-2 table offset.\nconst SHIFT_2 = 5;\n\n// Difference between the two shift sizes,\n// for getting an index-1 offset from an index-2 offset. 6=11-5\nconst SHIFT_1_2 = SHIFT_1 - SHIFT_2;\n\n// Number of index-1 entries for the BMP. 32=0x20\n// This part of the index-1 table is omitted from the serialized form.\nconst OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;\n\n// Number of entries in an index-2 block. 64=0x40\nconst INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;\n\n// Mask for getting the lower bits for the in-index-2-block offset. */\nconst INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;\n\n// Shift size for shifting left the index array values.\n// Increases possible data size with 16-bit index values at the cost\n// of compactability.\n// This requires data blocks to be aligned by DATA_GRANULARITY.\nconst INDEX_SHIFT = 2;\n\n// Number of entries in a data block. 32=0x20\nconst DATA_BLOCK_LENGTH = 1 << SHIFT_2;\n\n// Mask for getting the lower bits for the in-data-block offset.\nconst DATA_MASK = DATA_BLOCK_LENGTH - 1;\n\n// The part of the index-2 table for U+D800..U+DBFF stores values for\n// lead surrogate code _units_ not code _points_.\n// Values for lead surrogate code _points_ are indexed with this portion of the table.\n// Length=32=0x20=0x400>>SHIFT_2. (There are 1024=0x400 lead surrogates.)\nconst LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2;\nconst LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2;\n\n// Count the lengths of both BMP pieces. 2080=0x820\nconst INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;\n\n// The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820.\n// Length 32=0x20 for lead bytes C0..DF, regardless of SHIFT_2.\nconst UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;\nconst UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; // U+0800 is the first code point after 2-byte UTF-8\n\n// The index-1 table, only used for supplementary code points, at offset 2112=0x840.\n// Variable length, for code points up to highStart, where the last single-value range starts.\n// Maximum length 512=0x200=0x100000>>SHIFT_1.\n// (For 0x100000 supplementary code points U+10000..U+10ffff.)\n//\n// The part of the index-2 table for supplementary code points starts\n// after this index-1 table.\n//\n// Both the index-1 table and the following part of the index-2 table\n// are omitted completely if there is only BMP data.\nconst INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;\n\n// The alignment size of a data block. Also the granularity for compaction.\nconst DATA_GRANULARITY = 1 << INDEX_SHIFT;\n\nclass UnicodeTrie {\n /**\n * @param {Uint8Array | Buffer | UnicodeTrieInit} data\n */\n constructor(data) {\n if (isNodeBuffer(data) || data instanceof Uint8Array) {\n // read binary format\n /** @type {Uint8Array} */\n let bytes;\n let uncompressedLength;\n if (isNodeBuffer(data)) {\n this.highStart = data.readUInt32LE(0);\n this.errorValue = data.readUInt32LE(4);\n uncompressedLength = data.readUInt32LE(8);\n // View past the 12-byte header (avoids Buffer.slice \u2192 Uint8Array assignability issues).\n bytes = new Uint8Array(data.buffer, data.byteOffset + 12, data.byteLength - 12);\n } else {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n this.highStart = view.getUint32(0, true);\n this.errorValue = view.getUint32(4, true);\n uncompressedLength = view.getUint32(8, true);\n bytes = data.subarray(12);\n }\n\n // inflate the actual trie data (raw deflate, matching builder)\n bytes = inflateSync(bytes, { out: new Uint8Array(uncompressedLength) });\n\n // swap bytes from little-endian\n swap32LE(bytes);\n\n /**\n * Compacted index + data table.\n * @type {Uint32Array | Int32Array}\n */\n this.data = new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength >> 2);\n } else {\n // pre-parsed data\n /**\n * Compacted index + data table.\n * @type {Uint32Array | Int32Array}\n */\n this.data = data.data;\n /**\n * First code point of the final single-value range.\n * @type {number}\n */\n this.highStart = data.highStart;\n /**\n * Value returned for out-of-range code points.\n * @type {number}\n */\n this.errorValue = data.errorValue;\n }\n }\n\n /**\n * @param {number} codePoint\n * @returns {number}\n */\n get(codePoint) {\n let index;\n if ((codePoint < 0) || (codePoint > 0x10ffff)) {\n return this.errorValue;\n }\n\n if ((codePoint < 0xd800) || ((codePoint > 0xdbff) && (codePoint <= 0xffff))) {\n // Ordinary BMP code point, excluding leading surrogates.\n // BMP uses a single level lookup. BMP index starts at offset 0 in the index.\n // data is stored in the index array itself.\n index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint <= 0xffff) {\n // Lead Surrogate Code Point. A Separate index section is stored for\n // lead surrogate code units and code points.\n // The main index has the code unit data.\n // For this function, we need the code point data.\n index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint < this.highStart) {\n // Supplemental code point, use two-level lookup.\n index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];\n index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];\n index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n return this.data[this.data.length - DATA_GRANULARITY];\n }\n}\n\nexport default UnicodeTrie;\n", "const isBigEndian = (new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12);\n\n/**\n * @param {Uint8Array} b\n * @param {number} n\n * @param {number} m\n */\nconst swap = (b, n, m) => {\n let i = b[n];\n b[n] = b[m];\n b[m] = i;\n};\n\n/**\n * @param {Uint8Array} array\n */\nconst swap32 = (array) => {\n const len = array.length;\n for (let i = 0; i < len; i += 4) {\n swap(array, i, i + 3);\n swap(array, i + 1, i + 2);\n }\n};\n\n/**\n * Swap byte order of each 32-bit word in-place when running on a big-endian host,\n * so the trie data is little-endian as expected by the runtime.\n * @param {Uint8Array} array\n */\nexport const swap32LE = (array) => {\n if (isBigEndian) {\n swap32(array);\n }\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -22,6 +22,9 @@ var swap32LE = (array) => {
22
22
  };
23
23
 
24
24
  // index.js
25
+ function isNodeBuffer(value) {
26
+ return typeof value === "object" && value !== null && "readUInt32BE" in value && "readUInt32LE" in value && "slice" in value && typeof value.readUInt32BE === "function" && typeof value.readUInt32LE === "function" && typeof value.slice === "function";
27
+ }
25
28
  var SHIFT_1 = 6 + 5;
26
29
  var SHIFT_2 = 5;
27
30
  var SHIFT_1_2 = SHIFT_1 - SHIFT_2;
@@ -39,29 +42,38 @@ var UTF8_2B_INDEX_2_LENGTH = 2048 >> 6;
39
42
  var INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;
40
43
  var DATA_GRANULARITY = 1 << INDEX_SHIFT;
41
44
  var UnicodeTrie = class {
45
+ /**
46
+ * @param {Uint8Array | Buffer | UnicodeTrieInit} data
47
+ */
42
48
  constructor(data) {
43
- const isBuffer = typeof data.readUInt32BE === "function" && typeof data.slice === "function";
44
- if (isBuffer || data instanceof Uint8Array) {
49
+ if (isNodeBuffer(data) || data instanceof Uint8Array) {
50
+ let bytes;
45
51
  let uncompressedLength;
46
- if (isBuffer) {
52
+ if (isNodeBuffer(data)) {
47
53
  this.highStart = data.readUInt32LE(0);
48
54
  this.errorValue = data.readUInt32LE(4);
49
55
  uncompressedLength = data.readUInt32LE(8);
50
- data = data.slice(12);
56
+ bytes = new Uint8Array(data.buffer, data.byteOffset + 12, data.byteLength - 12);
51
57
  } else {
52
58
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
53
59
  this.highStart = view.getUint32(0, true);
54
60
  this.errorValue = view.getUint32(4, true);
55
61
  uncompressedLength = view.getUint32(8, true);
56
- data = data.subarray(12);
62
+ bytes = data.subarray(12);
57
63
  }
58
- data = inflateSync(data, { out: new Uint8Array(uncompressedLength) });
59
- swap32LE(data);
60
- this.data = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);
64
+ bytes = inflateSync(bytes, { out: new Uint8Array(uncompressedLength) });
65
+ swap32LE(bytes);
66
+ this.data = new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength >> 2);
61
67
  } else {
62
- ({ data: this.data, highStart: this.highStart, errorValue: this.errorValue } = data);
68
+ this.data = data.data;
69
+ this.highStart = data.highStart;
70
+ this.errorValue = data.errorValue;
63
71
  }
64
72
  }
73
+ /**
74
+ * @param {number} codePoint
75
+ * @returns {number}
76
+ */
65
77
  get(codePoint) {
66
78
  let index;
67
79
  if (codePoint < 0 || codePoint > 1114111) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../index.js", "../swap.js"],
4
- "sourcesContent": ["import { inflateSync } from 'fflate';\nimport { swap32LE } from './swap.js';\n\n// Shift size for getting the index-1 table offset.\nconst SHIFT_1 = 6 + 5;\n\n// Shift size for getting the index-2 table offset.\nconst SHIFT_2 = 5;\n\n// Difference between the two shift sizes,\n// for getting an index-1 offset from an index-2 offset. 6=11-5\nconst SHIFT_1_2 = SHIFT_1 - SHIFT_2;\n\n// Number of index-1 entries for the BMP. 32=0x20\n// This part of the index-1 table is omitted from the serialized form.\nconst OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;\n\n// Number of entries in an index-2 block. 64=0x40\nconst INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;\n\n// Mask for getting the lower bits for the in-index-2-block offset. */\nconst INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;\n\n// Shift size for shifting left the index array values.\n// Increases possible data size with 16-bit index values at the cost\n// of compactability.\n// This requires data blocks to be aligned by DATA_GRANULARITY.\nconst INDEX_SHIFT = 2;\n\n// Number of entries in a data block. 32=0x20\nconst DATA_BLOCK_LENGTH = 1 << SHIFT_2;\n\n// Mask for getting the lower bits for the in-data-block offset.\nconst DATA_MASK = DATA_BLOCK_LENGTH - 1;\n\n// The part of the index-2 table for U+D800..U+DBFF stores values for\n// lead surrogate code _units_ not code _points_.\n// Values for lead surrogate code _points_ are indexed with this portion of the table.\n// Length=32=0x20=0x400>>SHIFT_2. (There are 1024=0x400 lead surrogates.)\nconst LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2;\nconst LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2;\n\n// Count the lengths of both BMP pieces. 2080=0x820\nconst INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;\n\n// The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820.\n// Length 32=0x20 for lead bytes C0..DF, regardless of SHIFT_2.\nconst UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;\nconst UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; // U+0800 is the first code point after 2-byte UTF-8\n\n// The index-1 table, only used for supplementary code points, at offset 2112=0x840.\n// Variable length, for code points up to highStart, where the last single-value range starts.\n// Maximum length 512=0x200=0x100000>>SHIFT_1.\n// (For 0x100000 supplementary code points U+10000..U+10ffff.)\n//\n// The part of the index-2 table for supplementary code points starts\n// after this index-1 table.\n//\n// Both the index-1 table and the following part of the index-2 table\n// are omitted completely if there is only BMP data.\nconst INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;\n\n// The alignment size of a data block. Also the granularity for compaction.\nconst DATA_GRANULARITY = 1 << INDEX_SHIFT;\n\nclass UnicodeTrie {\n constructor(data) {\n const isBuffer = (typeof data.readUInt32BE === 'function') && (typeof data.slice === 'function');\n\n if (isBuffer || data instanceof Uint8Array) {\n // read binary format\n let uncompressedLength;\n if (isBuffer) {\n this.highStart = data.readUInt32LE(0);\n this.errorValue = data.readUInt32LE(4);\n uncompressedLength = data.readUInt32LE(8);\n data = data.slice(12);\n } else {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n this.highStart = view.getUint32(0, true);\n this.errorValue = view.getUint32(4, true);\n uncompressedLength = view.getUint32(8, true);\n data = data.subarray(12);\n }\n\n // inflate the actual trie data (raw deflate, matching builder)\n data = inflateSync(data, { out: new Uint8Array(uncompressedLength) });\n\n // swap bytes from little-endian\n swap32LE(data);\n\n this.data = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);\n\n } else {\n // pre-parsed data\n ({ data: this.data, highStart: this.highStart, errorValue: this.errorValue } = data);\n }\n }\n\n get(codePoint) {\n let index;\n if ((codePoint < 0) || (codePoint > 0x10ffff)) {\n return this.errorValue;\n }\n\n if ((codePoint < 0xd800) || ((codePoint > 0xdbff) && (codePoint <= 0xffff))) {\n // Ordinary BMP code point, excluding leading surrogates.\n // BMP uses a single level lookup. BMP index starts at offset 0 in the index.\n // data is stored in the index array itself.\n index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint <= 0xffff) {\n // Lead Surrogate Code Point. A Separate index section is stored for\n // lead surrogate code units and code points.\n // The main index has the code unit data.\n // For this function, we need the code point data.\n index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint < this.highStart) {\n // Supplemental code point, use two-level lookup.\n index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];\n index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];\n index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n return this.data[this.data.length - DATA_GRANULARITY];\n }\n}\n\nexport default UnicodeTrie;\n", "const isBigEndian = (new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12);\n\nconst swap = (b, n, m) => {\n let i = b[n];\n b[n] = b[m];\n b[m] = i;\n};\n\nconst swap32 = array => {\n const len = array.length;\n for (let i = 0; i < len; i += 4) {\n swap(array, i, i + 3);\n swap(array, i + 1, i + 2);\n }\n};\n\nexport const swap32LE = array => {\n if (isBigEndian) {\n swap32(array);\n }\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { inflateSync } from 'fflate';\nimport { swap32LE } from './swap.js';\n\n/**\n * Pre-parsed trie payload (e.g. from UnicodeTrieBuilder.freeze).\n * @typedef {object} UnicodeTrieInit\n * @property {Int32Array | Uint32Array} data\n * @property {number} highStart\n * @property {number} errorValue\n */\n\n/**\n * Duck-type Node Buffer (has LE/BE readers + slice), matching prior runtime checks.\n * @param {unknown} value\n * @returns {value is Buffer}\n */\nfunction isNodeBuffer(value) {\n return (\n typeof value === 'object'\n && value !== null\n && 'readUInt32BE' in value\n && 'readUInt32LE' in value\n && 'slice' in value\n && typeof value.readUInt32BE === 'function'\n && typeof value.readUInt32LE === 'function'\n && typeof value.slice === 'function'\n );\n}\n\n// Shift size for getting the index-1 table offset.\nconst SHIFT_1 = 6 + 5;\n\n// Shift size for getting the index-2 table offset.\nconst SHIFT_2 = 5;\n\n// Difference between the two shift sizes,\n// for getting an index-1 offset from an index-2 offset. 6=11-5\nconst SHIFT_1_2 = SHIFT_1 - SHIFT_2;\n\n// Number of index-1 entries for the BMP. 32=0x20\n// This part of the index-1 table is omitted from the serialized form.\nconst OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;\n\n// Number of entries in an index-2 block. 64=0x40\nconst INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;\n\n// Mask for getting the lower bits for the in-index-2-block offset. */\nconst INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;\n\n// Shift size for shifting left the index array values.\n// Increases possible data size with 16-bit index values at the cost\n// of compactability.\n// This requires data blocks to be aligned by DATA_GRANULARITY.\nconst INDEX_SHIFT = 2;\n\n// Number of entries in a data block. 32=0x20\nconst DATA_BLOCK_LENGTH = 1 << SHIFT_2;\n\n// Mask for getting the lower bits for the in-data-block offset.\nconst DATA_MASK = DATA_BLOCK_LENGTH - 1;\n\n// The part of the index-2 table for U+D800..U+DBFF stores values for\n// lead surrogate code _units_ not code _points_.\n// Values for lead surrogate code _points_ are indexed with this portion of the table.\n// Length=32=0x20=0x400>>SHIFT_2. (There are 1024=0x400 lead surrogates.)\nconst LSCP_INDEX_2_OFFSET = 0x10000 >> SHIFT_2;\nconst LSCP_INDEX_2_LENGTH = 0x400 >> SHIFT_2;\n\n// Count the lengths of both BMP pieces. 2080=0x820\nconst INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;\n\n// The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820.\n// Length 32=0x20 for lead bytes C0..DF, regardless of SHIFT_2.\nconst UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;\nconst UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; // U+0800 is the first code point after 2-byte UTF-8\n\n// The index-1 table, only used for supplementary code points, at offset 2112=0x840.\n// Variable length, for code points up to highStart, where the last single-value range starts.\n// Maximum length 512=0x200=0x100000>>SHIFT_1.\n// (For 0x100000 supplementary code points U+10000..U+10ffff.)\n//\n// The part of the index-2 table for supplementary code points starts\n// after this index-1 table.\n//\n// Both the index-1 table and the following part of the index-2 table\n// are omitted completely if there is only BMP data.\nconst INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;\n\n// The alignment size of a data block. Also the granularity for compaction.\nconst DATA_GRANULARITY = 1 << INDEX_SHIFT;\n\nclass UnicodeTrie {\n /**\n * @param {Uint8Array | Buffer | UnicodeTrieInit} data\n */\n constructor(data) {\n if (isNodeBuffer(data) || data instanceof Uint8Array) {\n // read binary format\n /** @type {Uint8Array} */\n let bytes;\n let uncompressedLength;\n if (isNodeBuffer(data)) {\n this.highStart = data.readUInt32LE(0);\n this.errorValue = data.readUInt32LE(4);\n uncompressedLength = data.readUInt32LE(8);\n // View past the 12-byte header (avoids Buffer.slice \u2192 Uint8Array assignability issues).\n bytes = new Uint8Array(data.buffer, data.byteOffset + 12, data.byteLength - 12);\n } else {\n const view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n this.highStart = view.getUint32(0, true);\n this.errorValue = view.getUint32(4, true);\n uncompressedLength = view.getUint32(8, true);\n bytes = data.subarray(12);\n }\n\n // inflate the actual trie data (raw deflate, matching builder)\n bytes = inflateSync(bytes, { out: new Uint8Array(uncompressedLength) });\n\n // swap bytes from little-endian\n swap32LE(bytes);\n\n /**\n * Compacted index + data table.\n * @type {Uint32Array | Int32Array}\n */\n this.data = new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength >> 2);\n } else {\n // pre-parsed data\n /**\n * Compacted index + data table.\n * @type {Uint32Array | Int32Array}\n */\n this.data = data.data;\n /**\n * First code point of the final single-value range.\n * @type {number}\n */\n this.highStart = data.highStart;\n /**\n * Value returned for out-of-range code points.\n * @type {number}\n */\n this.errorValue = data.errorValue;\n }\n }\n\n /**\n * @param {number} codePoint\n * @returns {number}\n */\n get(codePoint) {\n let index;\n if ((codePoint < 0) || (codePoint > 0x10ffff)) {\n return this.errorValue;\n }\n\n if ((codePoint < 0xd800) || ((codePoint > 0xdbff) && (codePoint <= 0xffff))) {\n // Ordinary BMP code point, excluding leading surrogates.\n // BMP uses a single level lookup. BMP index starts at offset 0 in the index.\n // data is stored in the index array itself.\n index = (this.data[codePoint >> SHIFT_2] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint <= 0xffff) {\n // Lead Surrogate Code Point. A Separate index section is stored for\n // lead surrogate code units and code points.\n // The main index has the code unit data.\n // For this function, we need the code point data.\n index = (this.data[LSCP_INDEX_2_OFFSET + ((codePoint - 0xd800) >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n if (codePoint < this.highStart) {\n // Supplemental code point, use two-level lookup.\n index = this.data[(INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];\n index = this.data[index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];\n index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);\n return this.data[index];\n }\n\n return this.data[this.data.length - DATA_GRANULARITY];\n }\n}\n\nexport default UnicodeTrie;\n", "const isBigEndian = (new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12);\n\n/**\n * @param {Uint8Array} b\n * @param {number} n\n * @param {number} m\n */\nconst swap = (b, n, m) => {\n let i = b[n];\n b[n] = b[m];\n b[m] = i;\n};\n\n/**\n * @param {Uint8Array} array\n */\nconst swap32 = (array) => {\n const len = array.length;\n for (let i = 0; i < len; i += 4) {\n swap(array, i, i + 3);\n swap(array, i + 1, i + 2);\n }\n};\n\n/**\n * Swap byte order of each 32-bit word in-place when running on a big-endian host,\n * so the trie data is little-endian as expected by the runtime.\n * @param {Uint8Array} array\n */\nexport const swap32LE = (array) => {\n if (isBigEndian) {\n swap32(array);\n }\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,32 @@
1
1
  import { inflateSync } from 'fflate';
2
2
  import { swap32LE } from './swap.js';
3
3
 
4
+ /**
5
+ * Pre-parsed trie payload (e.g. from UnicodeTrieBuilder.freeze).
6
+ * @typedef {object} UnicodeTrieInit
7
+ * @property {Int32Array | Uint32Array} data
8
+ * @property {number} highStart
9
+ * @property {number} errorValue
10
+ */
11
+
12
+ /**
13
+ * Duck-type Node Buffer (has LE/BE readers + slice), matching prior runtime checks.
14
+ * @param {unknown} value
15
+ * @returns {value is Buffer}
16
+ */
17
+ function isNodeBuffer(value) {
18
+ return (
19
+ typeof value === 'object'
20
+ && value !== null
21
+ && 'readUInt32BE' in value
22
+ && 'readUInt32LE' in value
23
+ && 'slice' in value
24
+ && typeof value.readUInt32BE === 'function'
25
+ && typeof value.readUInt32LE === 'function'
26
+ && typeof value.slice === 'function'
27
+ );
28
+ }
29
+
4
30
  // Shift size for getting the index-1 table offset.
5
31
  const SHIFT_1 = 6 + 5;
6
32
 
@@ -46,7 +72,7 @@ const INDEX_2_BMP_LENGTH = LSCP_INDEX_2_OFFSET + LSCP_INDEX_2_LENGTH;
46
72
  // The 2-byte UTF-8 version of the index-2 table follows at offset 2080=0x820.
47
73
  // Length 32=0x20 for lead bytes C0..DF, regardless of SHIFT_2.
48
74
  const UTF8_2B_INDEX_2_OFFSET = INDEX_2_BMP_LENGTH;
49
- const UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; // U+0800 is the first code point after 2-byte UTF-8
75
+ const UTF8_2B_INDEX_2_LENGTH = 0x800 >> 6; // U+0800 is the first code point after 2-byte UTF-8
50
76
 
51
77
  // The index-1 table, only used for supplementary code points, at offset 2112=0x840.
52
78
  // Variable length, for code points up to highStart, where the last single-value range starts.
@@ -64,39 +90,64 @@ const INDEX_1_OFFSET = UTF8_2B_INDEX_2_OFFSET + UTF8_2B_INDEX_2_LENGTH;
64
90
  const DATA_GRANULARITY = 1 << INDEX_SHIFT;
65
91
 
66
92
  class UnicodeTrie {
93
+ /**
94
+ * @param {Uint8Array | Buffer | UnicodeTrieInit} data
95
+ */
67
96
  constructor(data) {
68
- const isBuffer = (typeof data.readUInt32BE === 'function') && (typeof data.slice === 'function');
69
-
70
- if (isBuffer || data instanceof Uint8Array) {
97
+ if (isNodeBuffer(data) || data instanceof Uint8Array) {
71
98
  // read binary format
99
+ /** @type {Uint8Array} */
100
+ let bytes;
72
101
  let uncompressedLength;
73
- if (isBuffer) {
102
+ if (isNodeBuffer(data)) {
74
103
  this.highStart = data.readUInt32LE(0);
75
104
  this.errorValue = data.readUInt32LE(4);
76
105
  uncompressedLength = data.readUInt32LE(8);
77
- data = data.slice(12);
106
+ // View past the 12-byte header (avoids Buffer.slice → Uint8Array assignability issues).
107
+ bytes = new Uint8Array(data.buffer, data.byteOffset + 12, data.byteLength - 12);
78
108
  } else {
79
109
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
80
110
  this.highStart = view.getUint32(0, true);
81
111
  this.errorValue = view.getUint32(4, true);
82
112
  uncompressedLength = view.getUint32(8, true);
83
- data = data.subarray(12);
113
+ bytes = data.subarray(12);
84
114
  }
85
115
 
86
116
  // inflate the actual trie data (raw deflate, matching builder)
87
- data = inflateSync(data, { out: new Uint8Array(uncompressedLength) });
117
+ bytes = inflateSync(bytes, { out: new Uint8Array(uncompressedLength) });
88
118
 
89
119
  // swap bytes from little-endian
90
- swap32LE(data);
91
-
92
- this.data = new Uint32Array(data.buffer, data.byteOffset, data.byteLength >> 2);
120
+ swap32LE(bytes);
93
121
 
122
+ /**
123
+ * Compacted index + data table.
124
+ * @type {Uint32Array | Int32Array}
125
+ */
126
+ this.data = new Uint32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength >> 2);
94
127
  } else {
95
128
  // pre-parsed data
96
- ({ data: this.data, highStart: this.highStart, errorValue: this.errorValue } = data);
129
+ /**
130
+ * Compacted index + data table.
131
+ * @type {Uint32Array | Int32Array}
132
+ */
133
+ this.data = data.data;
134
+ /**
135
+ * First code point of the final single-value range.
136
+ * @type {number}
137
+ */
138
+ this.highStart = data.highStart;
139
+ /**
140
+ * Value returned for out-of-range code points.
141
+ * @type {number}
142
+ */
143
+ this.errorValue = data.errorValue;
97
144
  }
98
145
  }
99
146
 
147
+ /**
148
+ * @param {number} codePoint
149
+ * @returns {number}
150
+ */
100
151
  get(codePoint) {
101
152
  let index;
102
153
  if ((codePoint < 0) || (codePoint > 0x10ffff)) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cantoo/unicode-trie",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Unicode Trie data structure for fast character metadata lookup, ported from ICU (fflate, no tiny-inflate/pako)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -1,12 +1,20 @@
1
1
  const isBigEndian = (new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12);
2
2
 
3
+ /**
4
+ * @param {Uint8Array} b
5
+ * @param {number} n
6
+ * @param {number} m
7
+ */
3
8
  const swap = (b, n, m) => {
4
9
  let i = b[n];
5
10
  b[n] = b[m];
6
11
  b[m] = i;
7
12
  };
8
13
 
9
- const swap32 = array => {
14
+ /**
15
+ * @param {Uint8Array} array
16
+ */
17
+ const swap32 = (array) => {
10
18
  const len = array.length;
11
19
  for (let i = 0; i < len; i += 4) {
12
20
  swap(array, i, i + 3);
@@ -14,7 +22,12 @@ const swap32 = array => {
14
22
  }
15
23
  };
16
24
 
17
- export const swap32LE = array => {
25
+ /**
26
+ * Swap byte order of each 32-bit word in-place when running on a big-endian host,
27
+ * so the trie data is little-endian as expected by the runtime.
28
+ * @param {Uint8Array} array
29
+ */
30
+ export const swap32LE = (array) => {
18
31
  if (isBigEndian) {
19
32
  swap32(array);
20
33
  }
@@ -2,39 +2,84 @@ import Subset from './Subset';
2
2
  import CFFTop from '../cff/CFFTop';
3
3
  import standardStrings from '../cff/CFFStandardStrings';
4
4
 
5
+ /** @typedef {import('../../types/fontkit').SubsetFont} SubsetFont */
6
+ /** @typedef {import('../../types/fontkit').CFFFontLike} CFFFontLike */
7
+ /** @typedef {import('../../types/fontkit').CFFTopDict} CFFTopDict */
8
+ /** @typedef {import('../../types/fontkit').CFFCharString} CFFCharString */
9
+ /** @typedef {import('restructure').BinaryBuffer} BinaryBuffer */
10
+ /** @typedef {import('restructure').StructValue} StructValue */
11
+
5
12
  export default class CFFSubset extends Subset {
13
+ /** @type {CFFFontLike} */
14
+ cff;
15
+ /** @type {BinaryBuffer[] | null} */
16
+ charstrings = null;
17
+ /** @type {BinaryBuffer[] | null} */
18
+ gsubrs = null;
19
+ /** @type {string[] | null} */
20
+ strings = null;
21
+
22
+ /**
23
+ * @param {SubsetFont} font
24
+ */
6
25
  constructor(font) {
7
26
  super(font);
8
27
 
9
- this.cff = this.font['CFF '];
10
- if (!this.cff) {
28
+ let cff = this.font['CFF '];
29
+ if (!cff) {
11
30
  throw new Error('Not a CFF Font');
12
31
  }
32
+ this.cff = cff;
13
33
  }
14
34
 
15
- includeTable() {
35
+ /**
36
+ * @param {string} [_tag]
37
+ * @returns {never}
38
+ */
39
+ includeTable(_tag) {
16
40
  throw new Error('includeTable is only supported for TrueType (glyf) subsets, not CFF.');
17
41
  }
18
42
 
43
+ /**
44
+ * @returns {void}
45
+ */
19
46
  subsetCharstrings() {
20
47
  this.charstrings = [];
48
+ /** @type {Record<string, boolean>} */
21
49
  let gsubrs = {};
22
50
 
23
51
  for (let gid of this.glyphs) {
52
+ if (!this.cff.getCharString) {
53
+ throw new Error('CFF font missing getCharString()');
54
+ }
24
55
  this.charstrings.push(this.cff.getCharString(gid));
25
56
 
26
57
  let glyph = this.font.getGlyph(gid);
58
+ if (!glyph) {
59
+ continue;
60
+ }
27
61
  void glyph.path; // this causes the glyph to be parsed
28
62
 
29
- for (let subr in glyph._usedGsubrs) {
30
- gsubrs[subr] = true;
63
+ if (glyph._usedGsubrs) {
64
+ for (let subr in glyph._usedGsubrs) {
65
+ gsubrs[subr] = true;
66
+ }
31
67
  }
32
68
  }
33
69
 
34
- this.gsubrs = this.subsetSubrs(this.cff.globalSubrIndex, gsubrs);
70
+ this.gsubrs = this.subsetSubrs(
71
+ /** @type {Array<{ offset: number, length: number }>} */ (this.cff.globalSubrIndex || []),
72
+ gsubrs
73
+ );
35
74
  }
36
75
 
76
+ /**
77
+ * @param {Array<{ offset: number, length: number }>} subrs
78
+ * @param {Record<string | number, boolean>} used
79
+ * @returns {BinaryBuffer[]}
80
+ */
37
81
  subsetSubrs(subrs, used) {
82
+ /** @type {BinaryBuffer[]} */
38
83
  let res = [];
39
84
  for (let i = 0; i < subrs.length; i++) {
40
85
  let subr = subrs[i];
@@ -49,6 +94,10 @@ export default class CFFSubset extends Subset {
49
94
  return res;
50
95
  }
51
96
 
97
+ /**
98
+ * @param {CFFTopDict} topDict
99
+ * @returns {void}
100
+ */
52
101
  subsetFontdict(topDict) {
53
102
  topDict.FDArray = [];
54
103
  topDict.FDSelect = {
@@ -56,28 +105,42 @@ export default class CFFSubset extends Subset {
56
105
  fds: []
57
106
  };
58
107
 
108
+ /** @type {Record<number, boolean>} */
59
109
  let used_fds = {};
110
+ /** @type {Array<Record<string, boolean>>} */
60
111
  let used_subrs = [];
112
+ /** @type {Record<number, number>} */
61
113
  let fd_select = {};
62
114
  for (let gid of this.glyphs) {
115
+ if (!this.cff.fdForGlyph) {
116
+ continue;
117
+ }
63
118
  let fd = this.cff.fdForGlyph(gid);
64
119
  if (fd == null) {
65
120
  continue;
66
121
  }
67
122
 
68
123
  if (!used_fds[fd]) {
69
- topDict.FDArray.push(Object.assign({}, this.cff.topDict.FDArray[fd]));
124
+ let src = this.cff.topDict.FDArray && this.cff.topDict.FDArray[fd];
125
+ topDict.FDArray.push(Object.assign({}, src));
70
126
  used_subrs.push({});
71
127
  fd_select[fd] = topDict.FDArray.length - 1;
72
128
  }
73
129
 
74
130
  used_fds[fd] = true;
75
- topDict.FDSelect.fds.push(fd_select[fd]);
131
+ if (topDict.FDSelect.fds) {
132
+ topDict.FDSelect.fds.push(fd_select[fd]);
133
+ }
76
134
 
77
135
  let glyph = this.font.getGlyph(gid);
136
+ if (!glyph) {
137
+ continue;
138
+ }
78
139
  void glyph.path; // this causes the glyph to be parsed
79
- for (let subr in glyph._usedSubrs) {
80
- used_subrs[fd_select[fd]][subr] = true;
140
+ if (glyph._usedSubrs) {
141
+ for (let subr in glyph._usedSubrs) {
142
+ used_subrs[fd_select[fd]][subr] = true;
143
+ }
81
144
  }
82
145
  }
83
146
 
@@ -86,38 +149,59 @@ export default class CFFSubset extends Subset {
86
149
  delete dict.FontName;
87
150
  if (dict.Private && dict.Private.Subrs) {
88
151
  dict.Private = Object.assign({}, dict.Private);
89
- dict.Private.Subrs = this.subsetSubrs(dict.Private.Subrs, used_subrs[i]);
152
+ dict.Private.Subrs = this.subsetSubrs(
153
+ /** @type {Array<{ offset: number, length: number }>} */ (dict.Private.Subrs),
154
+ used_subrs[i]
155
+ );
90
156
  }
91
157
  }
92
158
 
93
159
  return;
94
160
  }
95
161
 
162
+ /**
163
+ * @param {CFFTopDict} topDict
164
+ * @returns {StructValue}
165
+ */
96
166
  createCIDFontdict(topDict) {
167
+ /** @type {Record<string, boolean>} */
97
168
  let used_subrs = {};
98
169
  for (let gid of this.glyphs) {
99
170
  let glyph = this.font.getGlyph(gid);
171
+ if (!glyph) {
172
+ continue;
173
+ }
100
174
  void glyph.path; // this causes the glyph to be parsed
101
175
 
102
- for (let subr in glyph._usedSubrs) {
103
- used_subrs[subr] = true;
176
+ if (glyph._usedSubrs) {
177
+ for (let subr in glyph._usedSubrs) {
178
+ used_subrs[subr] = true;
179
+ }
104
180
  }
105
181
  }
106
182
 
107
183
  let privateDict = Object.assign({}, this.cff.topDict.Private);
108
184
  if (this.cff.topDict.Private && this.cff.topDict.Private.Subrs) {
109
- privateDict.Subrs = this.subsetSubrs(this.cff.topDict.Private.Subrs, used_subrs);
185
+ privateDict.Subrs = this.subsetSubrs(
186
+ /** @type {Array<{ offset: number, length: number }>} */ (this.cff.topDict.Private.Subrs),
187
+ used_subrs
188
+ );
110
189
  }
111
190
 
112
191
  topDict.FDArray = [{ Private: privateDict }];
192
+ let charstrings = this.charstrings || [];
113
193
  return topDict.FDSelect = {
114
194
  version: 3,
115
195
  nRanges: 1,
116
196
  ranges: [{ first: 0, fd: 0 }],
117
- sentinel: this.charstrings.length
197
+ sentinel: charstrings.length
118
198
  };
119
199
  }
120
200
 
201
+ /**
202
+ * @param {string | null | undefined} string
203
+ * @returns {number | null}
204
+ */
121
205
  addString(string) {
122
206
  if (!string) {
123
207
  return null;
@@ -131,28 +215,34 @@ export default class CFFSubset extends Subset {
131
215
  return standardStrings.length + this.strings.length - 1;
132
216
  }
133
217
 
218
+ /**
219
+ * @returns {import('restructure').BinaryBuffer}
220
+ */
134
221
  encode() {
135
222
  this.subsetCharstrings();
136
223
 
224
+ let charstrings = this.charstrings || [];
225
+
137
226
  let charset = {
138
- version: this.charstrings.length > 255 ? 2 : 1,
139
- ranges: this.charstrings.length > 1
140
- ? [{ first: 1, nLeft: this.charstrings.length - 2 }]
227
+ version: charstrings.length > 255 ? 2 : 1,
228
+ ranges: charstrings.length > 1
229
+ ? [{ first: 1, nLeft: charstrings.length - 2 }]
141
230
  : []
142
231
  };
143
232
 
144
- let topDict = Object.assign({}, this.cff.topDict);
233
+ let topDict = /** @type {CFFTopDict} */ (Object.assign({}, this.cff.topDict));
145
234
  topDict.Private = null;
146
235
  topDict.charset = charset;
147
236
  topDict.Encoding = null;
148
- topDict.CharStrings = this.charstrings;
237
+ topDict.CharStrings = charstrings;
149
238
 
150
239
  for (let key of ['version', 'Notice', 'Copyright', 'FullName', 'FamilyName', 'Weight', 'PostScript', 'BaseFontName', 'FontName']) {
151
- topDict[key] = this.addString(this.cff.string(topDict[key]));
240
+ let sid = /** @type {number | null | undefined} */ (topDict[key]);
241
+ topDict[key] = this.cff.string ? this.addString(this.cff.string(sid)) : null;
152
242
  }
153
243
 
154
244
  topDict.ROS = [this.addString('Adobe'), this.addString('Identity'), 0];
155
- topDict.CIDCount = this.charstrings.length;
245
+ topDict.CIDCount = charstrings.length;
156
246
 
157
247
  if (this.cff.isCIDFont) {
158
248
  this.subsetFontdict(topDict);