@cantoo/fontkit 2.0.4

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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/dist/browser-module.mjs +13660 -0
  4. package/dist/browser-module.mjs.map +1 -0
  5. package/dist/browser.cjs +13689 -0
  6. package/dist/browser.cjs.map +1 -0
  7. package/dist/main.cjs +13712 -0
  8. package/dist/main.cjs.map +1 -0
  9. package/dist/module.mjs +13673 -0
  10. package/dist/module.mjs.map +1 -0
  11. package/package.json +99 -0
  12. package/src/CmapProcessor.js +285 -0
  13. package/src/DFont.js +113 -0
  14. package/src/TTFFont.js +621 -0
  15. package/src/TrueTypeCollection.js +65 -0
  16. package/src/WOFF2Font.js +222 -0
  17. package/src/WOFFFont.js +56 -0
  18. package/src/aat/AATFeatureMap.js +545 -0
  19. package/src/aat/AATLayoutEngine.js +48 -0
  20. package/src/aat/AATLookupTable.js +125 -0
  21. package/src/aat/AATMorxProcessor.js +429 -0
  22. package/src/aat/AATStateMachine.js +96 -0
  23. package/src/base.js +29 -0
  24. package/src/cff/CFFCharsets.js +99 -0
  25. package/src/cff/CFFDict.js +166 -0
  26. package/src/cff/CFFEncodings.js +48 -0
  27. package/src/cff/CFFFont.js +158 -0
  28. package/src/cff/CFFIndex.js +150 -0
  29. package/src/cff/CFFOperand.js +135 -0
  30. package/src/cff/CFFPointer.js +50 -0
  31. package/src/cff/CFFPrivateDict.js +39 -0
  32. package/src/cff/CFFStandardStrings.js +71 -0
  33. package/src/cff/CFFTop.js +236 -0
  34. package/src/decorators.js +36 -0
  35. package/src/encodings.js +219 -0
  36. package/src/fs.js +12 -0
  37. package/src/glyph/BBox.js +72 -0
  38. package/src/glyph/CBDTGlyph.js +9 -0
  39. package/src/glyph/CFFGlyph.js +635 -0
  40. package/src/glyph/COLRGlyph.js +108 -0
  41. package/src/glyph/Glyph.js +270 -0
  42. package/src/glyph/GlyphVariationProcessor.js +487 -0
  43. package/src/glyph/Path.js +257 -0
  44. package/src/glyph/SBIXGlyph.js +54 -0
  45. package/src/glyph/StandardNames.js +27 -0
  46. package/src/glyph/TTFGlyph.js +408 -0
  47. package/src/glyph/TTFGlyphEncoder.js +158 -0
  48. package/src/glyph/WOFF2Glyph.js +70 -0
  49. package/src/index.js +15 -0
  50. package/src/layout/GlyphPosition.js +30 -0
  51. package/src/layout/GlyphRun.js +108 -0
  52. package/src/layout/KernProcessor.js +97 -0
  53. package/src/layout/LayoutEngine.js +190 -0
  54. package/src/layout/Script.js +231 -0
  55. package/src/layout/UnicodeLayoutEngine.js +250 -0
  56. package/src/node.js +16 -0
  57. package/src/opentype/GPOSProcessor.js +311 -0
  58. package/src/opentype/GSUBProcessor.js +208 -0
  59. package/src/opentype/GlyphInfo.js +57 -0
  60. package/src/opentype/GlyphIterator.js +82 -0
  61. package/src/opentype/OTLayoutEngine.js +117 -0
  62. package/src/opentype/OTProcessor.js +472 -0
  63. package/src/opentype/ShapingPlan.js +121 -0
  64. package/src/opentype/shapers/ArabicShaper.js +124 -0
  65. package/src/opentype/shapers/DefaultShaper.js +116 -0
  66. package/src/opentype/shapers/HangulShaper.js +285 -0
  67. package/src/opentype/shapers/HebrewShaper.js +105 -0
  68. package/src/opentype/shapers/IndicShaper.js +914 -0
  69. package/src/opentype/shapers/ThaiShaper.js +238 -0
  70. package/src/opentype/shapers/UniversalShaper.js +186 -0
  71. package/src/opentype/shapers/data.trie +0 -0
  72. package/src/opentype/shapers/gen-indic.js +208 -0
  73. package/src/opentype/shapers/gen-use.js +287 -0
  74. package/src/opentype/shapers/generate-data.js +33 -0
  75. package/src/opentype/shapers/index.js +109 -0
  76. package/src/opentype/shapers/indic-data.js +175 -0
  77. package/src/opentype/shapers/indic.json +1 -0
  78. package/src/opentype/shapers/indic.machine +31 -0
  79. package/src/opentype/shapers/indic.trie +0 -0
  80. package/src/opentype/shapers/use.json +1 -0
  81. package/src/opentype/shapers/use.machine +44 -0
  82. package/src/opentype/shapers/use.trie +0 -0
  83. package/src/packages/unicode-properties/LICENSE +8 -0
  84. package/src/packages/unicode-properties/README.md +12 -0
  85. package/src/packages/unicode-properties/data-trie.js +1 -0
  86. package/src/packages/unicode-properties/data.js +1 -0
  87. package/src/packages/unicode-properties/data.json +1 -0
  88. package/src/packages/unicode-properties/data.trie +0 -0
  89. package/src/packages/unicode-properties/dist/index.cjs +257 -0
  90. package/src/packages/unicode-properties/dist/index.cjs.map +7 -0
  91. package/src/packages/unicode-properties/dist/index.mjs +234 -0
  92. package/src/packages/unicode-properties/dist/index.mjs.map +7 -0
  93. package/src/packages/unicode-properties/generate.js +107 -0
  94. package/src/packages/unicode-properties/index.js +184 -0
  95. package/src/packages/unicode-properties/package.json +50 -0
  96. package/src/packages/unicode-trie/LICENSE +8 -0
  97. package/src/packages/unicode-trie/README.md +13 -0
  98. package/src/packages/unicode-trie/builder.js +965 -0
  99. package/src/packages/unicode-trie/dist/builder.cjs +711 -0
  100. package/src/packages/unicode-trie/dist/builder.cjs.map +7 -0
  101. package/src/packages/unicode-trie/dist/builder.mjs +690 -0
  102. package/src/packages/unicode-trie/dist/builder.mjs.map +7 -0
  103. package/src/packages/unicode-trie/dist/index.cjs +112 -0
  104. package/src/packages/unicode-trie/dist/index.cjs.map +7 -0
  105. package/src/packages/unicode-trie/dist/index.mjs +91 -0
  106. package/src/packages/unicode-trie/dist/index.mjs.map +7 -0
  107. package/src/packages/unicode-trie/index.js +135 -0
  108. package/src/packages/unicode-trie/package.json +49 -0
  109. package/src/packages/unicode-trie/swap.js +21 -0
  110. package/src/subset/CFFSubset.js +176 -0
  111. package/src/subset/Subset.js +63 -0
  112. package/src/subset/TTFSubset.js +130 -0
  113. package/src/tables/BASE.js +78 -0
  114. package/src/tables/COLR.js +25 -0
  115. package/src/tables/CPAL.js +24 -0
  116. package/src/tables/DSIG.js +21 -0
  117. package/src/tables/EBDT.js +91 -0
  118. package/src/tables/EBLC.js +80 -0
  119. package/src/tables/GDEF.js +57 -0
  120. package/src/tables/GPOS.js +209 -0
  121. package/src/tables/GSUB.js +85 -0
  122. package/src/tables/HVAR.js +44 -0
  123. package/src/tables/JSTF.js +43 -0
  124. package/src/tables/LTSH.js +10 -0
  125. package/src/tables/OS2.js +84 -0
  126. package/src/tables/PCLT.js +21 -0
  127. package/src/tables/STAT.js +99 -0
  128. package/src/tables/VDMX.js +33 -0
  129. package/src/tables/VORG.js +14 -0
  130. package/src/tables/WOFF2Directory.js +73 -0
  131. package/src/tables/WOFFDirectory.js +37 -0
  132. package/src/tables/aat.js +157 -0
  133. package/src/tables/avar.js +19 -0
  134. package/src/tables/bsln.js +31 -0
  135. package/src/tables/cmap.js +127 -0
  136. package/src/tables/cvt.js +6 -0
  137. package/src/tables/directory.js +58 -0
  138. package/src/tables/feat.js +28 -0
  139. package/src/tables/fpgm.js +8 -0
  140. package/src/tables/fvar.js +31 -0
  141. package/src/tables/gasp.js +15 -0
  142. package/src/tables/glyf.js +4 -0
  143. package/src/tables/gvar.js +27 -0
  144. package/src/tables/hdmx.js +15 -0
  145. package/src/tables/head.js +25 -0
  146. package/src/tables/hhea.js +19 -0
  147. package/src/tables/hmtx.js +11 -0
  148. package/src/tables/index.js +119 -0
  149. package/src/tables/just.js +81 -0
  150. package/src/tables/kern.js +91 -0
  151. package/src/tables/loca.js +30 -0
  152. package/src/tables/maxp.js +20 -0
  153. package/src/tables/morx.js +79 -0
  154. package/src/tables/name.js +157 -0
  155. package/src/tables/opbd.js +15 -0
  156. package/src/tables/opentype.js +217 -0
  157. package/src/tables/post.js +34 -0
  158. package/src/tables/prep.js +6 -0
  159. package/src/tables/sbix.js +17 -0
  160. package/src/tables/variations.js +80 -0
  161. package/src/tables/vhea.js +19 -0
  162. package/src/tables/vmtx.js +12 -0
  163. package/src/utils.js +62 -0
@@ -0,0 +1,166 @@
1
+ import isEqual from 'fast-deep-equal';
2
+ import CFFOperand from './CFFOperand';
3
+ import { PropertyDescriptor } from 'restructure';
4
+
5
+ export default class CFFDict {
6
+ constructor(ops = []) {
7
+ this.ops = ops;
8
+ this.fields = {};
9
+ for (let field of ops) {
10
+ let key = Array.isArray(field[0]) ? field[0][0] << 8 | field[0][1] : field[0];
11
+ this.fields[key] = field;
12
+ }
13
+ }
14
+
15
+ decodeOperands(type, stream, ret, operands) {
16
+ if (Array.isArray(type)) {
17
+ return operands.map((op, i) => this.decodeOperands(type[i], stream, ret, [op]));
18
+ } else if (type.decode != null) {
19
+ return type.decode(stream, ret, operands);
20
+ } else {
21
+ switch (type) {
22
+ case 'number':
23
+ case 'offset':
24
+ case 'sid':
25
+ return operands[0];
26
+ case 'boolean':
27
+ return !!operands[0];
28
+ default:
29
+ return operands;
30
+ }
31
+ }
32
+ }
33
+
34
+ encodeOperands(type, stream, ctx, operands) {
35
+ if (Array.isArray(type)) {
36
+ return operands.map((op, i) => this.encodeOperands(type[i], stream, ctx, op)[0]);
37
+ } else if (type.encode != null) {
38
+ return type.encode(stream, operands, ctx);
39
+ } else if (typeof operands === 'number') {
40
+ return [operands];
41
+ } else if (typeof operands === 'boolean') {
42
+ return [+operands];
43
+ } else if (Array.isArray(operands)) {
44
+ return operands;
45
+ } else {
46
+ return [operands];
47
+ }
48
+ }
49
+
50
+ decode(stream, parent) {
51
+ let end = stream.pos + parent.length;
52
+ let ret = {};
53
+ let operands = [];
54
+
55
+ // define hidden properties
56
+ Object.defineProperties(ret, {
57
+ parent: { value: parent },
58
+ _startOffset: { value: stream.pos }
59
+ });
60
+
61
+ // fill in defaults
62
+ for (let key in this.fields) {
63
+ let field = this.fields[key];
64
+ ret[field[1]] = field[3];
65
+ }
66
+
67
+ while (stream.pos < end) {
68
+ let b = stream.readUInt8();
69
+ if (b < 28) {
70
+ if (b === 12) {
71
+ b = (b << 8) | stream.readUInt8();
72
+ }
73
+
74
+ let field = this.fields[b];
75
+ if (!field) {
76
+ throw new Error(`Unknown operator ${b}`);
77
+ }
78
+
79
+ let val = this.decodeOperands(field[2], stream, ret, operands);
80
+ if (val != null) {
81
+ if (val instanceof PropertyDescriptor) {
82
+ Object.defineProperty(ret, field[1], val);
83
+ } else {
84
+ ret[field[1]] = val;
85
+ }
86
+ }
87
+
88
+ operands = [];
89
+ } else {
90
+ operands.push(CFFOperand.decode(stream, b));
91
+ }
92
+ }
93
+
94
+ return ret;
95
+ }
96
+
97
+ size(dict, parent, includePointers = true) {
98
+ let ctx = {
99
+ parent,
100
+ val: dict,
101
+ pointerSize: 0,
102
+ startOffset: parent.startOffset || 0
103
+ };
104
+
105
+ let len = 0;
106
+
107
+ for (let k in this.fields) {
108
+ let field = this.fields[k];
109
+ let val = dict[field[1]];
110
+ if (val == null || isEqual(val, field[3])) {
111
+ continue;
112
+ }
113
+
114
+ let operands = this.encodeOperands(field[2], null, ctx, val);
115
+ for (let op of operands) {
116
+ len += CFFOperand.size(op);
117
+ }
118
+
119
+ let key = Array.isArray(field[0]) ? field[0] : [field[0]];
120
+ len += key.length;
121
+ }
122
+
123
+ if (includePointers) {
124
+ len += ctx.pointerSize;
125
+ }
126
+
127
+ return len;
128
+ }
129
+
130
+ encode(stream, dict, parent) {
131
+ let ctx = {
132
+ pointers: [],
133
+ startOffset: stream.pos,
134
+ parent,
135
+ val: dict,
136
+ pointerSize: 0
137
+ };
138
+
139
+ ctx.pointerOffset = stream.pos + this.size(dict, ctx, false);
140
+
141
+ for (let field of this.ops) {
142
+ let val = dict[field[1]];
143
+ if (val == null || isEqual(val, field[3])) {
144
+ continue;
145
+ }
146
+
147
+ let operands = this.encodeOperands(field[2], stream, ctx, val);
148
+ for (let op of operands) {
149
+ CFFOperand.encode(stream, op);
150
+ }
151
+
152
+ let key = Array.isArray(field[0]) ? field[0] : [field[0]];
153
+ for (let op of key) {
154
+ stream.writeUInt8(op);
155
+ }
156
+ }
157
+
158
+ let i = 0;
159
+ while (i < ctx.pointers.length) {
160
+ let ptr = ctx.pointers[i++];
161
+ ptr.type.encode(stream, ptr.val, ptr.parent);
162
+ }
163
+
164
+ return;
165
+ }
166
+ }
@@ -0,0 +1,48 @@
1
+ export let StandardEncoding = [
2
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
3
+ '', '', '', '', 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', 'quoteright',
4
+ 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', 'two',
5
+ 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', 'greater',
6
+ 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
7
+ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
8
+ 'quoteleft', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
9
+ 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', 'asciitilde', '', '', '', '', '', '', '', '',
10
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
11
+ 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', 'section', 'currency', 'quotesingle',
12
+ 'quotedblleft', 'guillemotleft', 'guilsinglleft', 'guilsinglright', 'fi', 'fl', '', 'endash', 'dagger',
13
+ 'daggerdbl', 'periodcentered', '', 'paragraph', 'bullet', 'quotesinglbase', 'quotedblbase', 'quotedblright',
14
+ 'guillemotright', 'ellipsis', 'perthousand', '', 'questiondown', '', 'grave', 'acute', 'circumflex', 'tilde',
15
+ 'macron', 'breve', 'dotaccent', 'dieresis', '', 'ring', 'cedilla', '', 'hungarumlaut', 'ogonek', 'caron',
16
+ 'emdash', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 'AE', '', 'ordfeminine', '', '', '',
17
+ '', 'Lslash', 'Oslash', 'OE', 'ordmasculine', '', '', '', '', '', 'ae', '', '', '', 'dotlessi', '', '',
18
+ 'lslash', 'oslash', 'oe', 'germandbls'
19
+ ];
20
+
21
+ export let ExpertEncoding = [
22
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
23
+ '', '', '', '', 'space', 'exclamsmall', 'Hungarumlautsmall', '', 'dollaroldstyle', 'dollarsuperior',
24
+ 'ampersandsmall', 'Acutesmall', 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
25
+ 'comma', 'hyphen', 'period', 'fraction', 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle',
26
+ 'fouroldstyle', 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', 'nineoldstyle', 'colon',
27
+ 'semicolon', 'commasuperior', 'threequartersemdash', 'periodsuperior', 'questionsmall', '', 'asuperior',
28
+ 'bsuperior', 'centsuperior', 'dsuperior', 'esuperior', '', '', 'isuperior', '', '', 'lsuperior', 'msuperior',
29
+ 'nsuperior', 'osuperior', '', '', 'rsuperior', 'ssuperior', 'tsuperior', '', 'ff', 'fi', 'fl', 'ffi', 'ffl',
30
+ 'parenleftinferior', '', 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', 'Asmall',
31
+ 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall',
32
+ 'Msmall', 'Nsmall', 'Osmall', 'Psmall', 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall',
33
+ 'Xsmall', 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', '', '', '', '', '', '', '',
34
+ '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '',
35
+ 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', '', '', 'Scaronsmall', 'Zcaronsmall', 'Dieresissmall',
36
+ 'Brevesmall', 'Caronsmall', '', 'Dotaccentsmall', '', '', 'Macronsmall', '', '', 'figuredash', 'hypheninferior',
37
+ '', '', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', '', '', '', 'onequarter', 'onehalf', 'threequarters',
38
+ 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', 'onethird', 'twothirds', '',
39
+ '', 'zerosuperior', 'onesuperior', 'twosuperior', 'threesuperior', 'foursuperior', 'fivesuperior',
40
+ 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', 'oneinferior', 'twoinferior',
41
+ 'threeinferior', 'fourinferior', 'fiveinferior', 'sixinferior', 'seveninferior', 'eightinferior',
42
+ 'nineinferior', 'centinferior', 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
43
+ 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', 'AEsmall', 'Ccedillasmall',
44
+ 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', 'Edieresissmall', 'Igravesmall', 'Iacutesmall',
45
+ 'Icircumflexsmall', 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
46
+ 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', 'Ugravesmall', 'Uacutesmall',
47
+ 'Ucircumflexsmall', 'Udieresissmall', 'Yacutesmall', 'Thornsmall', 'Ydieresissmall'
48
+ ];
@@ -0,0 +1,158 @@
1
+ import CFFTop from './CFFTop';
2
+ import standardStrings from './CFFStandardStrings';
3
+
4
+ class CFFFont {
5
+ constructor(stream) {
6
+ this.stream = stream;
7
+ this.decode();
8
+ }
9
+
10
+ static decode(stream) {
11
+ return new CFFFont(stream);
12
+ }
13
+
14
+ decode() {
15
+ let top = CFFTop.decode(this.stream);
16
+ for (let key in top) {
17
+ let val = top[key];
18
+ this[key] = val;
19
+ }
20
+
21
+ if (this.version < 2) {
22
+ if (this.topDictIndex.length !== 1) {
23
+ throw new Error("Only a single font is allowed in CFF");
24
+ }
25
+
26
+ this.topDict = this.topDictIndex[0];
27
+ }
28
+
29
+ this.isCIDFont = this.topDict.ROS != null;
30
+ return this;
31
+ }
32
+
33
+ string(sid) {
34
+ if (this.version >= 2) {
35
+ return null;
36
+ }
37
+
38
+ if (sid < standardStrings.length) {
39
+ return standardStrings[sid];
40
+ }
41
+
42
+ return this.stringIndex[sid - standardStrings.length];
43
+ }
44
+
45
+ get postscriptName() {
46
+ if (this.version < 2) {
47
+ return this.nameIndex[0];
48
+ }
49
+
50
+ return null;
51
+ }
52
+
53
+ get fullName() {
54
+ return this.string(this.topDict.FullName);
55
+ }
56
+
57
+ get familyName() {
58
+ return this.string(this.topDict.FamilyName);
59
+ }
60
+
61
+ getCharString(glyph) {
62
+ this.stream.pos = this.topDict.CharStrings[glyph].offset;
63
+ return this.stream.readBuffer(this.topDict.CharStrings[glyph].length);
64
+ }
65
+
66
+ getGlyphName(gid) {
67
+ // CFF2 glyph names are in the post table.
68
+ if (this.version >= 2) {
69
+ return null;
70
+ }
71
+
72
+ // CID-keyed fonts don't have glyph names
73
+ if (this.isCIDFont) {
74
+ return null;
75
+ }
76
+
77
+ let { charset } = this.topDict;
78
+ if (Array.isArray(charset)) {
79
+ return charset[gid];
80
+ }
81
+
82
+ if (gid === 0) {
83
+ return '.notdef';
84
+ }
85
+
86
+ gid -= 1;
87
+
88
+ switch (charset.version) {
89
+ case 0:
90
+ return this.string(charset.glyphs[gid]);
91
+
92
+ case 1:
93
+ case 2:
94
+ for (let i = 0; i < charset.ranges.length; i++) {
95
+ let range = charset.ranges[i];
96
+ if (range.offset <= gid && gid <= range.offset + range.nLeft) {
97
+ return this.string(range.first + (gid - range.offset));
98
+ }
99
+ }
100
+ break;
101
+ }
102
+
103
+ return null;
104
+ }
105
+
106
+ fdForGlyph(gid) {
107
+ if (!this.topDict.FDSelect) {
108
+ return null;
109
+ }
110
+
111
+ switch (this.topDict.FDSelect.version) {
112
+ case 0:
113
+ return this.topDict.FDSelect.fds[gid];
114
+
115
+ case 3:
116
+ case 4: {
117
+ let { ranges } = this.topDict.FDSelect;
118
+ let low = 0;
119
+ let high = ranges.length - 1;
120
+
121
+ while (low <= high) {
122
+ let mid = (low + high) >> 1;
123
+
124
+ if (gid < ranges[mid].first) {
125
+ high = mid - 1;
126
+ } else if (mid < high && gid >= ranges[mid + 1].first) {
127
+ low = mid + 1;
128
+ } else {
129
+ return ranges[mid].fd;
130
+ }
131
+ }
132
+
133
+ throw new Error(`Unknown FDSelect version: ${this.topDict.FDSelect.version}`);
134
+ }
135
+ default:
136
+ throw new Error(`Unknown FDSelect version: ${this.topDict.FDSelect.version}`);
137
+ }
138
+ }
139
+
140
+ privateDictForGlyph(gid) {
141
+ if (this.topDict.FDSelect) {
142
+ let fd = this.fdForGlyph(gid);
143
+ if (this.topDict.FDArray[fd]) {
144
+ return this.topDict.FDArray[fd].Private;
145
+ }
146
+
147
+ return null;
148
+ }
149
+
150
+ if (this.version < 2) {
151
+ return this.topDict.Private;
152
+ }
153
+
154
+ return this.topDict.FDArray[0].Private;
155
+ }
156
+ }
157
+
158
+ export default CFFFont;
@@ -0,0 +1,150 @@
1
+ import * as r from 'restructure';
2
+
3
+ export default class CFFIndex {
4
+ constructor(type) {
5
+ this.type = type;
6
+ }
7
+
8
+ getCFFVersion(ctx) {
9
+ while (ctx && !ctx.hdrSize) {
10
+ ctx = ctx.parent;
11
+ }
12
+
13
+ return ctx ? ctx.version : -1;
14
+ }
15
+
16
+ decode(stream, parent) {
17
+ let version = this.getCFFVersion(parent);
18
+ let count = version >= 2
19
+ ? stream.readUInt32BE()
20
+ : stream.readUInt16BE();
21
+
22
+ if (count === 0) {
23
+ return [];
24
+ }
25
+
26
+ let offSize = stream.readUInt8();
27
+ let offsetType;
28
+ if (offSize === 1) {
29
+ offsetType = r.uint8;
30
+ } else if (offSize === 2) {
31
+ offsetType = r.uint16;
32
+ } else if (offSize === 3) {
33
+ offsetType = r.uint24;
34
+ } else if (offSize === 4) {
35
+ offsetType = r.uint32;
36
+ } else {
37
+ throw new Error(`Bad offset size in CFFIndex: ${offSize} ${stream.pos}`);
38
+ }
39
+
40
+ let ret = [];
41
+ let startPos = stream.pos + ((count + 1) * offSize) - 1;
42
+
43
+ let start = offsetType.decode(stream);
44
+ for (let i = 0; i < count; i++) {
45
+ let end = offsetType.decode(stream);
46
+
47
+ if (this.type != null) {
48
+ let pos = stream.pos;
49
+ stream.pos = startPos + start;
50
+
51
+ parent.length = end - start;
52
+ ret.push(this.type.decode(stream, parent));
53
+ stream.pos = pos;
54
+ } else {
55
+ ret.push({
56
+ offset: startPos + start,
57
+ length: end - start
58
+ });
59
+ }
60
+
61
+ start = end;
62
+ }
63
+
64
+ stream.pos = startPos + start;
65
+ return ret;
66
+ }
67
+
68
+ size(arr, parent) {
69
+ let size = 2;
70
+ if (arr.length === 0) {
71
+ return size;
72
+ }
73
+
74
+ let type = this.type || new r.Buffer;
75
+
76
+ // find maximum offset to detminine offset type
77
+ let offset = 1;
78
+ for (let i = 0; i < arr.length; i++) {
79
+ let item = arr[i];
80
+ offset += type.size(item, parent);
81
+ }
82
+
83
+ let offsetType;
84
+ if (offset <= 0xff) {
85
+ offsetType = r.uint8;
86
+ } else if (offset <= 0xffff) {
87
+ offsetType = r.uint16;
88
+ } else if (offset <= 0xffffff) {
89
+ offsetType = r.uint24;
90
+ } else if (offset <= 0xffffffff) {
91
+ offsetType = r.uint32;
92
+ } else {
93
+ throw new Error("Bad offset in CFFIndex");
94
+ }
95
+
96
+ size += 1 + offsetType.size() * (arr.length + 1);
97
+ size += offset - 1;
98
+
99
+ return size;
100
+ }
101
+
102
+ encode(stream, arr, parent) {
103
+ stream.writeUInt16BE(arr.length);
104
+ if (arr.length === 0) {
105
+ return;
106
+ }
107
+
108
+ let type = this.type || new r.Buffer;
109
+
110
+ // find maximum offset to detminine offset type
111
+ let sizes = [];
112
+ let offset = 1;
113
+ for (let item of arr) {
114
+ let s = type.size(item, parent);
115
+ sizes.push(s);
116
+ offset += s;
117
+ }
118
+
119
+ let offsetType;
120
+ if (offset <= 0xff) {
121
+ offsetType = r.uint8;
122
+ } else if (offset <= 0xffff) {
123
+ offsetType = r.uint16;
124
+ } else if (offset <= 0xffffff) {
125
+ offsetType = r.uint24;
126
+ } else if (offset <= 0xffffffff) {
127
+ offsetType = r.uint32;
128
+ } else {
129
+ throw new Error("Bad offset in CFFIndex");
130
+ }
131
+
132
+ // write offset size
133
+ stream.writeUInt8(offsetType.size());
134
+
135
+ // write elements
136
+ offset = 1;
137
+ offsetType.encode(stream, offset);
138
+
139
+ for (let size of sizes) {
140
+ offset += size;
141
+ offsetType.encode(stream, offset);
142
+ }
143
+
144
+ for (let item of arr) {
145
+ type.encode(stream, item, parent);
146
+ }
147
+
148
+ return;
149
+ }
150
+ }
@@ -0,0 +1,135 @@
1
+ const FLOAT_EOF = 0xf;
2
+ const FLOAT_LOOKUP = [
3
+ '0', '1', '2', '3', '4', '5', '6', '7',
4
+ '8', '9', '.', 'E', 'E-', null, '-'
5
+ ];
6
+
7
+ const FLOAT_ENCODE_LOOKUP = {
8
+ '.': 10,
9
+ 'E': 11,
10
+ 'E-': 12,
11
+ '-': 14
12
+ };
13
+
14
+ export default class CFFOperand {
15
+ static decode(stream, value) {
16
+ if (32 <= value && value <= 246) {
17
+ return value - 139;
18
+ }
19
+
20
+ if (247 <= value && value <= 250) {
21
+ return (value - 247) * 256 + stream.readUInt8() + 108;
22
+ }
23
+
24
+ if (251 <= value && value <= 254) {
25
+ return -(value - 251) * 256 - stream.readUInt8() - 108;
26
+ }
27
+
28
+ if (value === 28) {
29
+ return stream.readInt16BE();
30
+ }
31
+
32
+ if (value === 29) {
33
+ return stream.readInt32BE();
34
+ }
35
+
36
+ if (value === 30) {
37
+ let str = '';
38
+ while (true) {
39
+ let b = stream.readUInt8();
40
+
41
+ let n1 = b >> 4;
42
+ if (n1 === FLOAT_EOF) { break; }
43
+ str += FLOAT_LOOKUP[n1];
44
+
45
+ let n2 = b & 15;
46
+ if (n2 === FLOAT_EOF) { break; }
47
+ str += FLOAT_LOOKUP[n2];
48
+ }
49
+
50
+ return parseFloat(str);
51
+ }
52
+
53
+ return null;
54
+ }
55
+
56
+ static size(value) {
57
+ // if the value needs to be forced to the largest size (32 bit)
58
+ // e.g. for unknown pointers, set to 32768
59
+ if (value.forceLarge) {
60
+ value = 32768;
61
+ }
62
+
63
+ if ((value | 0) !== value) { // floating point
64
+ let str = '' + value;
65
+ return 1 + Math.ceil((str.length + 1) / 2);
66
+
67
+ } else if (-107 <= value && value <= 107) {
68
+ return 1;
69
+
70
+ } else if (108 <= value && value <= 1131 || -1131 <= value && value <= -108) {
71
+ return 2;
72
+
73
+ } else if (-32768 <= value && value <= 32767) {
74
+ return 3;
75
+
76
+ } else {
77
+ return 5;
78
+ }
79
+ }
80
+
81
+ static encode(stream, value) {
82
+ // if the value needs to be forced to the largest size (32 bit)
83
+ // e.g. for unknown pointers, save the old value and set to 32768
84
+ let val = Number(value);
85
+
86
+ if (value.forceLarge) {
87
+ stream.writeUInt8(29);
88
+ return stream.writeInt32BE(val);
89
+
90
+ } else if ((val | 0) !== val) { // floating point
91
+ stream.writeUInt8(30);
92
+
93
+ let str = '' + val;
94
+ let n2;
95
+ for (let i = 0; i < str.length; i += 2) {
96
+ let c1 = str[i];
97
+ let n1 = FLOAT_ENCODE_LOOKUP[c1] || +c1;
98
+
99
+ if (i === str.length - 1) {
100
+ n2 = FLOAT_EOF;
101
+ } else {
102
+ let c2 = str[i + 1];
103
+ n2 = FLOAT_ENCODE_LOOKUP[c2] || +c2;
104
+ }
105
+
106
+ stream.writeUInt8((n1 << 4) | (n2 & 15));
107
+ }
108
+
109
+ if (n2 !== FLOAT_EOF) {
110
+ return stream.writeUInt8((FLOAT_EOF << 4));
111
+ }
112
+
113
+ } else if (-107 <= val && val <= 107) {
114
+ return stream.writeUInt8(val + 139);
115
+
116
+ } else if (108 <= val && val <= 1131) {
117
+ val -= 108;
118
+ stream.writeUInt8((val >> 8) + 247);
119
+ return stream.writeUInt8(val & 0xff);
120
+
121
+ } else if (-1131 <= val && val <= -108) {
122
+ val = -val - 108;
123
+ stream.writeUInt8((val >> 8) + 251);
124
+ return stream.writeUInt8(val & 0xff);
125
+
126
+ } else if (-32768 <= val && val <= 32767) {
127
+ stream.writeUInt8(28);
128
+ return stream.writeInt16BE(val);
129
+
130
+ } else {
131
+ stream.writeUInt8(29);
132
+ return stream.writeInt32BE(val);
133
+ }
134
+ }
135
+ }