1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.CFFTopDict = exports.CFFStrings = exports.CFFStandardStrings = exports.CFFPrivateDict = exports.CFFParser = exports.CFFIndex = exports.CFFHeader = exports.CFFFDSelect = exports.CFFCompiler = exports.CFFCharset = exports.CFF = void 0;
|
28 |
|
29 | var _util = require("../shared/util.js");
|
30 |
|
31 | var _charsets = require("./charsets.js");
|
32 |
|
33 | var _encodings = require("./encodings.js");
|
34 |
|
35 | const MAX_SUBR_NESTING = 10;
|
36 | const CFFStandardStrings = [".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold"];
|
37 | exports.CFFStandardStrings = CFFStandardStrings;
|
38 | const NUM_STANDARD_CFF_STRINGS = 391;
|
39 |
|
40 | const CFFParser = function CFFParserClosure() {
|
41 | const CharstringValidationData = [null, {
|
42 | id: "hstem",
|
43 | min: 2,
|
44 | stackClearing: true,
|
45 | stem: true
|
46 | }, null, {
|
47 | id: "vstem",
|
48 | min: 2,
|
49 | stackClearing: true,
|
50 | stem: true
|
51 | }, {
|
52 | id: "vmoveto",
|
53 | min: 1,
|
54 | stackClearing: true
|
55 | }, {
|
56 | id: "rlineto",
|
57 | min: 2,
|
58 | resetStack: true
|
59 | }, {
|
60 | id: "hlineto",
|
61 | min: 1,
|
62 | resetStack: true
|
63 | }, {
|
64 | id: "vlineto",
|
65 | min: 1,
|
66 | resetStack: true
|
67 | }, {
|
68 | id: "rrcurveto",
|
69 | min: 6,
|
70 | resetStack: true
|
71 | }, null, {
|
72 | id: "callsubr",
|
73 | min: 1,
|
74 | undefStack: true
|
75 | }, {
|
76 | id: "return",
|
77 | min: 0,
|
78 | undefStack: true
|
79 | }, null, null, {
|
80 | id: "endchar",
|
81 | min: 0,
|
82 | stackClearing: true
|
83 | }, null, null, null, {
|
84 | id: "hstemhm",
|
85 | min: 2,
|
86 | stackClearing: true,
|
87 | stem: true
|
88 | }, {
|
89 | id: "hintmask",
|
90 | min: 0,
|
91 | stackClearing: true
|
92 | }, {
|
93 | id: "cntrmask",
|
94 | min: 0,
|
95 | stackClearing: true
|
96 | }, {
|
97 | id: "rmoveto",
|
98 | min: 2,
|
99 | stackClearing: true
|
100 | }, {
|
101 | id: "hmoveto",
|
102 | min: 1,
|
103 | stackClearing: true
|
104 | }, {
|
105 | id: "vstemhm",
|
106 | min: 2,
|
107 | stackClearing: true,
|
108 | stem: true
|
109 | }, {
|
110 | id: "rcurveline",
|
111 | min: 8,
|
112 | resetStack: true
|
113 | }, {
|
114 | id: "rlinecurve",
|
115 | min: 8,
|
116 | resetStack: true
|
117 | }, {
|
118 | id: "vvcurveto",
|
119 | min: 4,
|
120 | resetStack: true
|
121 | }, {
|
122 | id: "hhcurveto",
|
123 | min: 4,
|
124 | resetStack: true
|
125 | }, null, {
|
126 | id: "callgsubr",
|
127 | min: 1,
|
128 | undefStack: true
|
129 | }, {
|
130 | id: "vhcurveto",
|
131 | min: 4,
|
132 | resetStack: true
|
133 | }, {
|
134 | id: "hvcurveto",
|
135 | min: 4,
|
136 | resetStack: true
|
137 | }];
|
138 | const CharstringValidationData12 = [null, null, null, {
|
139 | id: "and",
|
140 | min: 2,
|
141 | stackDelta: -1
|
142 | }, {
|
143 | id: "or",
|
144 | min: 2,
|
145 | stackDelta: -1
|
146 | }, {
|
147 | id: "not",
|
148 | min: 1,
|
149 | stackDelta: 0
|
150 | }, null, null, null, {
|
151 | id: "abs",
|
152 | min: 1,
|
153 | stackDelta: 0
|
154 | }, {
|
155 | id: "add",
|
156 | min: 2,
|
157 | stackDelta: -1,
|
158 | stackFn: function stack_div(stack, index) {
|
159 | stack[index - 2] = stack[index - 2] + stack[index - 1];
|
160 | }
|
161 | }, {
|
162 | id: "sub",
|
163 | min: 2,
|
164 | stackDelta: -1,
|
165 | stackFn: function stack_div(stack, index) {
|
166 | stack[index - 2] = stack[index - 2] - stack[index - 1];
|
167 | }
|
168 | }, {
|
169 | id: "div",
|
170 | min: 2,
|
171 | stackDelta: -1,
|
172 | stackFn: function stack_div(stack, index) {
|
173 | stack[index - 2] = stack[index - 2] / stack[index - 1];
|
174 | }
|
175 | }, null, {
|
176 | id: "neg",
|
177 | min: 1,
|
178 | stackDelta: 0,
|
179 | stackFn: function stack_div(stack, index) {
|
180 | stack[index - 1] = -stack[index - 1];
|
181 | }
|
182 | }, {
|
183 | id: "eq",
|
184 | min: 2,
|
185 | stackDelta: -1
|
186 | }, null, null, {
|
187 | id: "drop",
|
188 | min: 1,
|
189 | stackDelta: -1
|
190 | }, null, {
|
191 | id: "put",
|
192 | min: 2,
|
193 | stackDelta: -2
|
194 | }, {
|
195 | id: "get",
|
196 | min: 1,
|
197 | stackDelta: 0
|
198 | }, {
|
199 | id: "ifelse",
|
200 | min: 4,
|
201 | stackDelta: -3
|
202 | }, {
|
203 | id: "random",
|
204 | min: 0,
|
205 | stackDelta: 1
|
206 | }, {
|
207 | id: "mul",
|
208 | min: 2,
|
209 | stackDelta: -1,
|
210 | stackFn: function stack_div(stack, index) {
|
211 | stack[index - 2] = stack[index - 2] * stack[index - 1];
|
212 | }
|
213 | }, null, {
|
214 | id: "sqrt",
|
215 | min: 1,
|
216 | stackDelta: 0
|
217 | }, {
|
218 | id: "dup",
|
219 | min: 1,
|
220 | stackDelta: 1
|
221 | }, {
|
222 | id: "exch",
|
223 | min: 2,
|
224 | stackDelta: 0
|
225 | }, {
|
226 | id: "index",
|
227 | min: 2,
|
228 | stackDelta: 0
|
229 | }, {
|
230 | id: "roll",
|
231 | min: 3,
|
232 | stackDelta: -2
|
233 | }, null, null, null, {
|
234 | id: "hflex",
|
235 | min: 7,
|
236 | resetStack: true
|
237 | }, {
|
238 | id: "flex",
|
239 | min: 13,
|
240 | resetStack: true
|
241 | }, {
|
242 | id: "hflex1",
|
243 | min: 9,
|
244 | resetStack: true
|
245 | }, {
|
246 | id: "flex1",
|
247 | min: 11,
|
248 | resetStack: true
|
249 | }];
|
250 |
|
251 | class CFFParser {
|
252 | constructor(file, properties, seacAnalysisEnabled) {
|
253 | this.bytes = file.getBytes();
|
254 | this.properties = properties;
|
255 | this.seacAnalysisEnabled = !!seacAnalysisEnabled;
|
256 | }
|
257 |
|
258 | parse() {
|
259 | const properties = this.properties;
|
260 | const cff = new CFF();
|
261 | this.cff = cff;
|
262 | const header = this.parseHeader();
|
263 | const nameIndex = this.parseIndex(header.endPos);
|
264 | const topDictIndex = this.parseIndex(nameIndex.endPos);
|
265 | const stringIndex = this.parseIndex(topDictIndex.endPos);
|
266 | const globalSubrIndex = this.parseIndex(stringIndex.endPos);
|
267 | const topDictParsed = this.parseDict(topDictIndex.obj.get(0));
|
268 | const topDict = this.createDict(CFFTopDict, topDictParsed, cff.strings);
|
269 | cff.header = header.obj;
|
270 | cff.names = this.parseNameIndex(nameIndex.obj);
|
271 | cff.strings = this.parseStringIndex(stringIndex.obj);
|
272 | cff.topDict = topDict;
|
273 | cff.globalSubrIndex = globalSubrIndex.obj;
|
274 | this.parsePrivateDict(cff.topDict);
|
275 | cff.isCIDFont = topDict.hasName("ROS");
|
276 | const charStringOffset = topDict.getByName("CharStrings");
|
277 | const charStringIndex = this.parseIndex(charStringOffset).obj;
|
278 | const fontMatrix = topDict.getByName("FontMatrix");
|
279 |
|
280 | if (fontMatrix) {
|
281 | properties.fontMatrix = fontMatrix;
|
282 | }
|
283 |
|
284 | const fontBBox = topDict.getByName("FontBBox");
|
285 |
|
286 | if (fontBBox) {
|
287 | properties.ascent = Math.max(fontBBox[3], fontBBox[1]);
|
288 | properties.descent = Math.min(fontBBox[1], fontBBox[3]);
|
289 | properties.ascentScaled = true;
|
290 | }
|
291 |
|
292 | let charset, encoding;
|
293 |
|
294 | if (cff.isCIDFont) {
|
295 | const fdArrayIndex = this.parseIndex(topDict.getByName("FDArray")).obj;
|
296 |
|
297 | for (let i = 0, ii = fdArrayIndex.count; i < ii; ++i) {
|
298 | const dictRaw = fdArrayIndex.get(i);
|
299 | const fontDict = this.createDict(CFFTopDict, this.parseDict(dictRaw), cff.strings);
|
300 | this.parsePrivateDict(fontDict);
|
301 | cff.fdArray.push(fontDict);
|
302 | }
|
303 |
|
304 | encoding = null;
|
305 | charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, true);
|
306 | cff.fdSelect = this.parseFDSelect(topDict.getByName("FDSelect"), charStringIndex.count);
|
307 | } else {
|
308 | charset = this.parseCharsets(topDict.getByName("charset"), charStringIndex.count, cff.strings, false);
|
309 | encoding = this.parseEncoding(topDict.getByName("Encoding"), properties, cff.strings, charset.charset);
|
310 | }
|
311 |
|
312 | cff.charset = charset;
|
313 | cff.encoding = encoding;
|
314 | const charStringsAndSeacs = this.parseCharStrings({
|
315 | charStrings: charStringIndex,
|
316 | localSubrIndex: topDict.privateDict.subrsIndex,
|
317 | globalSubrIndex: globalSubrIndex.obj,
|
318 | fdSelect: cff.fdSelect,
|
319 | fdArray: cff.fdArray,
|
320 | privateDict: topDict.privateDict
|
321 | });
|
322 | cff.charStrings = charStringsAndSeacs.charStrings;
|
323 | cff.seacs = charStringsAndSeacs.seacs;
|
324 | cff.widths = charStringsAndSeacs.widths;
|
325 | return cff;
|
326 | }
|
327 |
|
328 | parseHeader() {
|
329 | let bytes = this.bytes;
|
330 | const bytesLength = bytes.length;
|
331 | let offset = 0;
|
332 |
|
333 | while (offset < bytesLength && bytes[offset] !== 1) {
|
334 | ++offset;
|
335 | }
|
336 |
|
337 | if (offset >= bytesLength) {
|
338 | throw new _util.FormatError("Invalid CFF header");
|
339 | }
|
340 |
|
341 | if (offset !== 0) {
|
342 | (0, _util.info)("cff data is shifted");
|
343 | bytes = bytes.subarray(offset);
|
344 | this.bytes = bytes;
|
345 | }
|
346 |
|
347 | const major = bytes[0];
|
348 | const minor = bytes[1];
|
349 | const hdrSize = bytes[2];
|
350 | const offSize = bytes[3];
|
351 | const header = new CFFHeader(major, minor, hdrSize, offSize);
|
352 | return {
|
353 | obj: header,
|
354 | endPos: hdrSize
|
355 | };
|
356 | }
|
357 |
|
358 | parseDict(dict) {
|
359 | let pos = 0;
|
360 |
|
361 | function parseOperand() {
|
362 | let value = dict[pos++];
|
363 |
|
364 | if (value === 30) {
|
365 | return parseFloatOperand();
|
366 | } else if (value === 28) {
|
367 | value = dict[pos++];
|
368 | value = (value << 24 | dict[pos++] << 16) >> 16;
|
369 | return value;
|
370 | } else if (value === 29) {
|
371 | value = dict[pos++];
|
372 | value = value << 8 | dict[pos++];
|
373 | value = value << 8 | dict[pos++];
|
374 | value = value << 8 | dict[pos++];
|
375 | return value;
|
376 | } else if (value >= 32 && value <= 246) {
|
377 | return value - 139;
|
378 | } else if (value >= 247 && value <= 250) {
|
379 | return (value - 247) * 256 + dict[pos++] + 108;
|
380 | } else if (value >= 251 && value <= 254) {
|
381 | return -((value - 251) * 256) - dict[pos++] - 108;
|
382 | }
|
383 |
|
384 | (0, _util.warn)('CFFParser_parseDict: "' + value + '" is a reserved command.');
|
385 | return NaN;
|
386 | }
|
387 |
|
388 | function parseFloatOperand() {
|
389 | let str = "";
|
390 | const eof = 15;
|
391 | const lookup = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "E", "E-", null, "-"];
|
392 | const length = dict.length;
|
393 |
|
394 | while (pos < length) {
|
395 | const b = dict[pos++];
|
396 | const b1 = b >> 4;
|
397 | const b2 = b & 15;
|
398 |
|
399 | if (b1 === eof) {
|
400 | break;
|
401 | }
|
402 |
|
403 | str += lookup[b1];
|
404 |
|
405 | if (b2 === eof) {
|
406 | break;
|
407 | }
|
408 |
|
409 | str += lookup[b2];
|
410 | }
|
411 |
|
412 | return parseFloat(str);
|
413 | }
|
414 |
|
415 | let operands = [];
|
416 | const entries = [];
|
417 | pos = 0;
|
418 | const end = dict.length;
|
419 |
|
420 | while (pos < end) {
|
421 | let b = dict[pos];
|
422 |
|
423 | if (b <= 21) {
|
424 | if (b === 12) {
|
425 | b = b << 8 | dict[++pos];
|
426 | }
|
427 |
|
428 | entries.push([b, operands]);
|
429 | operands = [];
|
430 | ++pos;
|
431 | } else {
|
432 | operands.push(parseOperand());
|
433 | }
|
434 | }
|
435 |
|
436 | return entries;
|
437 | }
|
438 |
|
439 | parseIndex(pos) {
|
440 | const cffIndex = new CFFIndex();
|
441 | const bytes = this.bytes;
|
442 | const count = bytes[pos++] << 8 | bytes[pos++];
|
443 | const offsets = [];
|
444 | let end = pos;
|
445 | let i, ii;
|
446 |
|
447 | if (count !== 0) {
|
448 | const offsetSize = bytes[pos++];
|
449 | const startPos = pos + (count + 1) * offsetSize - 1;
|
450 |
|
451 | for (i = 0, ii = count + 1; i < ii; ++i) {
|
452 | let offset = 0;
|
453 |
|
454 | for (let j = 0; j < offsetSize; ++j) {
|
455 | offset <<= 8;
|
456 | offset += bytes[pos++];
|
457 | }
|
458 |
|
459 | offsets.push(startPos + offset);
|
460 | }
|
461 |
|
462 | end = offsets[count];
|
463 | }
|
464 |
|
465 | for (i = 0, ii = offsets.length - 1; i < ii; ++i) {
|
466 | const offsetStart = offsets[i];
|
467 | const offsetEnd = offsets[i + 1];
|
468 | cffIndex.add(bytes.subarray(offsetStart, offsetEnd));
|
469 | }
|
470 |
|
471 | return {
|
472 | obj: cffIndex,
|
473 | endPos: end
|
474 | };
|
475 | }
|
476 |
|
477 | parseNameIndex(index) {
|
478 | const names = [];
|
479 |
|
480 | for (let i = 0, ii = index.count; i < ii; ++i) {
|
481 | const name = index.get(i);
|
482 | names.push((0, _util.bytesToString)(name));
|
483 | }
|
484 |
|
485 | return names;
|
486 | }
|
487 |
|
488 | parseStringIndex(index) {
|
489 | const strings = new CFFStrings();
|
490 |
|
491 | for (let i = 0, ii = index.count; i < ii; ++i) {
|
492 | const data = index.get(i);
|
493 | strings.add((0, _util.bytesToString)(data));
|
494 | }
|
495 |
|
496 | return strings;
|
497 | }
|
498 |
|
499 | createDict(Type, dict, strings) {
|
500 | const cffDict = new Type(strings);
|
501 |
|
502 | for (let i = 0, ii = dict.length; i < ii; ++i) {
|
503 | const pair = dict[i];
|
504 | const key = pair[0];
|
505 | const value = pair[1];
|
506 | cffDict.setByKey(key, value);
|
507 | }
|
508 |
|
509 | return cffDict;
|
510 | }
|
511 |
|
512 | parseCharString(state, data, localSubrIndex, globalSubrIndex) {
|
513 | if (!data || state.callDepth > MAX_SUBR_NESTING) {
|
514 | return false;
|
515 | }
|
516 |
|
517 | let stackSize = state.stackSize;
|
518 | const stack = state.stack;
|
519 | const length = data.length;
|
520 |
|
521 | for (let j = 0; j < length;) {
|
522 | const value = data[j++];
|
523 | let validationCommand = null;
|
524 |
|
525 | if (value === 12) {
|
526 | const q = data[j++];
|
527 |
|
528 | if (q === 0) {
|
529 | data[j - 2] = 139;
|
530 | data[j - 1] = 22;
|
531 | stackSize = 0;
|
532 | } else {
|
533 | validationCommand = CharstringValidationData12[q];
|
534 | }
|
535 | } else if (value === 28) {
|
536 | stack[stackSize] = (data[j] << 24 | data[j + 1] << 16) >> 16;
|
537 | j += 2;
|
538 | stackSize++;
|
539 | } else if (value === 14) {
|
540 | if (stackSize >= 4) {
|
541 | stackSize -= 4;
|
542 |
|
543 | if (this.seacAnalysisEnabled) {
|
544 | state.seac = stack.slice(stackSize, stackSize + 4);
|
545 | return false;
|
546 | }
|
547 | }
|
548 |
|
549 | validationCommand = CharstringValidationData[value];
|
550 | } else if (value >= 32 && value <= 246) {
|
551 | stack[stackSize] = value - 139;
|
552 | stackSize++;
|
553 | } else if (value >= 247 && value <= 254) {
|
554 | stack[stackSize] = value < 251 ? (value - 247 << 8) + data[j] + 108 : -(value - 251 << 8) - data[j] - 108;
|
555 | j++;
|
556 | stackSize++;
|
557 | } else if (value === 255) {
|
558 | stack[stackSize] = (data[j] << 24 | data[j + 1] << 16 | data[j + 2] << 8 | data[j + 3]) / 65536;
|
559 | j += 4;
|
560 | stackSize++;
|
561 | } else if (value === 19 || value === 20) {
|
562 | state.hints += stackSize >> 1;
|
563 | j += state.hints + 7 >> 3;
|
564 | stackSize %= 2;
|
565 | validationCommand = CharstringValidationData[value];
|
566 | } else if (value === 10 || value === 29) {
|
567 | let subrsIndex;
|
568 |
|
569 | if (value === 10) {
|
570 | subrsIndex = localSubrIndex;
|
571 | } else {
|
572 | subrsIndex = globalSubrIndex;
|
573 | }
|
574 |
|
575 | if (!subrsIndex) {
|
576 | validationCommand = CharstringValidationData[value];
|
577 | (0, _util.warn)("Missing subrsIndex for " + validationCommand.id);
|
578 | return false;
|
579 | }
|
580 |
|
581 | let bias = 32768;
|
582 |
|
583 | if (subrsIndex.count < 1240) {
|
584 | bias = 107;
|
585 | } else if (subrsIndex.count < 33900) {
|
586 | bias = 1131;
|
587 | }
|
588 |
|
589 | const subrNumber = stack[--stackSize] + bias;
|
590 |
|
591 | if (subrNumber < 0 || subrNumber >= subrsIndex.count || isNaN(subrNumber)) {
|
592 | validationCommand = CharstringValidationData[value];
|
593 | (0, _util.warn)("Out of bounds subrIndex for " + validationCommand.id);
|
594 | return false;
|
595 | }
|
596 |
|
597 | state.stackSize = stackSize;
|
598 | state.callDepth++;
|
599 | const valid = this.parseCharString(state, subrsIndex.get(subrNumber), localSubrIndex, globalSubrIndex);
|
600 |
|
601 | if (!valid) {
|
602 | return false;
|
603 | }
|
604 |
|
605 | state.callDepth--;
|
606 | stackSize = state.stackSize;
|
607 | continue;
|
608 | } else if (value === 11) {
|
609 | state.stackSize = stackSize;
|
610 | return true;
|
611 | } else if (value === 0 && j === data.length) {
|
612 | data[j - 1] = 14;
|
613 | validationCommand = CharstringValidationData[14];
|
614 | } else {
|
615 | validationCommand = CharstringValidationData[value];
|
616 | }
|
617 |
|
618 | if (validationCommand) {
|
619 | if (validationCommand.stem) {
|
620 | state.hints += stackSize >> 1;
|
621 |
|
622 | if (value === 3 || value === 23) {
|
623 | state.hasVStems = true;
|
624 | } else if (state.hasVStems && (value === 1 || value === 18)) {
|
625 | (0, _util.warn)("CFF stem hints are in wrong order");
|
626 | data[j - 1] = value === 1 ? 3 : 23;
|
627 | }
|
628 | }
|
629 |
|
630 | if ("min" in validationCommand) {
|
631 | if (!state.undefStack && stackSize < validationCommand.min) {
|
632 | (0, _util.warn)("Not enough parameters for " + validationCommand.id + "; actual: " + stackSize + ", expected: " + validationCommand.min);
|
633 |
|
634 | if (stackSize === 0) {
|
635 | data[j - 1] = 14;
|
636 | return true;
|
637 | }
|
638 |
|
639 | return false;
|
640 | }
|
641 | }
|
642 |
|
643 | if (state.firstStackClearing && validationCommand.stackClearing) {
|
644 | state.firstStackClearing = false;
|
645 | stackSize -= validationCommand.min;
|
646 |
|
647 | if (stackSize >= 2 && validationCommand.stem) {
|
648 | stackSize %= 2;
|
649 | } else if (stackSize > 1) {
|
650 | (0, _util.warn)("Found too many parameters for stack-clearing command");
|
651 | }
|
652 |
|
653 | if (stackSize > 0) {
|
654 | state.width = stack[stackSize - 1];
|
655 | }
|
656 | }
|
657 |
|
658 | if ("stackDelta" in validationCommand) {
|
659 | if ("stackFn" in validationCommand) {
|
660 | validationCommand.stackFn(stack, stackSize);
|
661 | }
|
662 |
|
663 | stackSize += validationCommand.stackDelta;
|
664 | } else if (validationCommand.stackClearing) {
|
665 | stackSize = 0;
|
666 | } else if (validationCommand.resetStack) {
|
667 | stackSize = 0;
|
668 | state.undefStack = false;
|
669 | } else if (validationCommand.undefStack) {
|
670 | stackSize = 0;
|
671 | state.undefStack = true;
|
672 | state.firstStackClearing = false;
|
673 | }
|
674 | }
|
675 | }
|
676 |
|
677 | state.stackSize = stackSize;
|
678 | return true;
|
679 | }
|
680 |
|
681 | parseCharStrings({
|
682 | charStrings,
|
683 | localSubrIndex,
|
684 | globalSubrIndex,
|
685 | fdSelect,
|
686 | fdArray,
|
687 | privateDict
|
688 | }) {
|
689 | const seacs = [];
|
690 | const widths = [];
|
691 | const count = charStrings.count;
|
692 |
|
693 | for (let i = 0; i < count; i++) {
|
694 | const charstring = charStrings.get(i);
|
695 | const state = {
|
696 | callDepth: 0,
|
697 | stackSize: 0,
|
698 | stack: [],
|
699 | undefStack: true,
|
700 | hints: 0,
|
701 | firstStackClearing: true,
|
702 | seac: null,
|
703 | width: null,
|
704 | hasVStems: false
|
705 | };
|
706 | let valid = true;
|
707 | let localSubrToUse = null;
|
708 | let privateDictToUse = privateDict;
|
709 |
|
710 | if (fdSelect && fdArray.length) {
|
711 | const fdIndex = fdSelect.getFDIndex(i);
|
712 |
|
713 | if (fdIndex === -1) {
|
714 | (0, _util.warn)("Glyph index is not in fd select.");
|
715 | valid = false;
|
716 | }
|
717 |
|
718 | if (fdIndex >= fdArray.length) {
|
719 | (0, _util.warn)("Invalid fd index for glyph index.");
|
720 | valid = false;
|
721 | }
|
722 |
|
723 | if (valid) {
|
724 | privateDictToUse = fdArray[fdIndex].privateDict;
|
725 | localSubrToUse = privateDictToUse.subrsIndex;
|
726 | }
|
727 | } else if (localSubrIndex) {
|
728 | localSubrToUse = localSubrIndex;
|
729 | }
|
730 |
|
731 | if (valid) {
|
732 | valid = this.parseCharString(state, charstring, localSubrToUse, globalSubrIndex);
|
733 | }
|
734 |
|
735 | if (state.width !== null) {
|
736 | const nominalWidth = privateDictToUse.getByName("nominalWidthX");
|
737 | widths[i] = nominalWidth + state.width;
|
738 | } else {
|
739 | const defaultWidth = privateDictToUse.getByName("defaultWidthX");
|
740 | widths[i] = defaultWidth;
|
741 | }
|
742 |
|
743 | if (state.seac !== null) {
|
744 | seacs[i] = state.seac;
|
745 | }
|
746 |
|
747 | if (!valid) {
|
748 | charStrings.set(i, new Uint8Array([14]));
|
749 | }
|
750 | }
|
751 |
|
752 | return {
|
753 | charStrings,
|
754 | seacs,
|
755 | widths
|
756 | };
|
757 | }
|
758 |
|
759 | emptyPrivateDictionary(parentDict) {
|
760 | const privateDict = this.createDict(CFFPrivateDict, [], parentDict.strings);
|
761 | parentDict.setByKey(18, [0, 0]);
|
762 | parentDict.privateDict = privateDict;
|
763 | }
|
764 |
|
765 | parsePrivateDict(parentDict) {
|
766 | if (!parentDict.hasName("Private")) {
|
767 | this.emptyPrivateDictionary(parentDict);
|
768 | return;
|
769 | }
|
770 |
|
771 | const privateOffset = parentDict.getByName("Private");
|
772 |
|
773 | if (!Array.isArray(privateOffset) || privateOffset.length !== 2) {
|
774 | parentDict.removeByName("Private");
|
775 | return;
|
776 | }
|
777 |
|
778 | const size = privateOffset[0];
|
779 | const offset = privateOffset[1];
|
780 |
|
781 | if (size === 0 || offset >= this.bytes.length) {
|
782 | this.emptyPrivateDictionary(parentDict);
|
783 | return;
|
784 | }
|
785 |
|
786 | const privateDictEnd = offset + size;
|
787 | const dictData = this.bytes.subarray(offset, privateDictEnd);
|
788 | const dict = this.parseDict(dictData);
|
789 | const privateDict = this.createDict(CFFPrivateDict, dict, parentDict.strings);
|
790 | parentDict.privateDict = privateDict;
|
791 |
|
792 | if (!privateDict.getByName("Subrs")) {
|
793 | return;
|
794 | }
|
795 |
|
796 | const subrsOffset = privateDict.getByName("Subrs");
|
797 | const relativeOffset = offset + subrsOffset;
|
798 |
|
799 | if (subrsOffset === 0 || relativeOffset >= this.bytes.length) {
|
800 | this.emptyPrivateDictionary(parentDict);
|
801 | return;
|
802 | }
|
803 |
|
804 | const subrsIndex = this.parseIndex(relativeOffset);
|
805 | privateDict.subrsIndex = subrsIndex.obj;
|
806 | }
|
807 |
|
808 | parseCharsets(pos, length, strings, cid) {
|
809 | if (pos === 0) {
|
810 | return new CFFCharset(true, CFFCharsetPredefinedTypes.ISO_ADOBE, _charsets.ISOAdobeCharset);
|
811 | } else if (pos === 1) {
|
812 | return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT, _charsets.ExpertCharset);
|
813 | } else if (pos === 2) {
|
814 | return new CFFCharset(true, CFFCharsetPredefinedTypes.EXPERT_SUBSET, _charsets.ExpertSubsetCharset);
|
815 | }
|
816 |
|
817 | const bytes = this.bytes;
|
818 | const start = pos;
|
819 | const format = bytes[pos++];
|
820 | const charset = [cid ? 0 : ".notdef"];
|
821 | let id, count, i;
|
822 | length -= 1;
|
823 |
|
824 | switch (format) {
|
825 | case 0:
|
826 | for (i = 0; i < length; i++) {
|
827 | id = bytes[pos++] << 8 | bytes[pos++];
|
828 | charset.push(cid ? id : strings.get(id));
|
829 | }
|
830 |
|
831 | break;
|
832 |
|
833 | case 1:
|
834 | while (charset.length <= length) {
|
835 | id = bytes[pos++] << 8 | bytes[pos++];
|
836 | count = bytes[pos++];
|
837 |
|
838 | for (i = 0; i <= count; i++) {
|
839 | charset.push(cid ? id++ : strings.get(id++));
|
840 | }
|
841 | }
|
842 |
|
843 | break;
|
844 |
|
845 | case 2:
|
846 | while (charset.length <= length) {
|
847 | id = bytes[pos++] << 8 | bytes[pos++];
|
848 | count = bytes[pos++] << 8 | bytes[pos++];
|
849 |
|
850 | for (i = 0; i <= count; i++) {
|
851 | charset.push(cid ? id++ : strings.get(id++));
|
852 | }
|
853 | }
|
854 |
|
855 | break;
|
856 |
|
857 | default:
|
858 | throw new _util.FormatError("Unknown charset format");
|
859 | }
|
860 |
|
861 | const end = pos;
|
862 | const raw = bytes.subarray(start, end);
|
863 | return new CFFCharset(false, format, charset, raw);
|
864 | }
|
865 |
|
866 | parseEncoding(pos, properties, strings, charset) {
|
867 | const encoding = Object.create(null);
|
868 | const bytes = this.bytes;
|
869 | let predefined = false;
|
870 | let format, i, ii;
|
871 | let raw = null;
|
872 |
|
873 | function readSupplement() {
|
874 | const supplementsCount = bytes[pos++];
|
875 |
|
876 | for (i = 0; i < supplementsCount; i++) {
|
877 | const code = bytes[pos++];
|
878 | const sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
|
879 | encoding[code] = charset.indexOf(strings.get(sid));
|
880 | }
|
881 | }
|
882 |
|
883 | if (pos === 0 || pos === 1) {
|
884 | predefined = true;
|
885 | format = pos;
|
886 | const baseEncoding = pos ? _encodings.ExpertEncoding : _encodings.StandardEncoding;
|
887 |
|
888 | for (i = 0, ii = charset.length; i < ii; i++) {
|
889 | const index = baseEncoding.indexOf(charset[i]);
|
890 |
|
891 | if (index !== -1) {
|
892 | encoding[index] = i;
|
893 | }
|
894 | }
|
895 | } else {
|
896 | const dataStart = pos;
|
897 | format = bytes[pos++];
|
898 |
|
899 | switch (format & 0x7f) {
|
900 | case 0:
|
901 | const glyphsCount = bytes[pos++];
|
902 |
|
903 | for (i = 1; i <= glyphsCount; i++) {
|
904 | encoding[bytes[pos++]] = i;
|
905 | }
|
906 |
|
907 | break;
|
908 |
|
909 | case 1:
|
910 | const rangesCount = bytes[pos++];
|
911 | let gid = 1;
|
912 |
|
913 | for (i = 0; i < rangesCount; i++) {
|
914 | const start = bytes[pos++];
|
915 | const left = bytes[pos++];
|
916 |
|
917 | for (let j = start; j <= start + left; j++) {
|
918 | encoding[j] = gid++;
|
919 | }
|
920 | }
|
921 |
|
922 | break;
|
923 |
|
924 | default:
|
925 | throw new _util.FormatError(`Unknown encoding format: ${format} in CFF`);
|
926 | }
|
927 |
|
928 | const dataEnd = pos;
|
929 |
|
930 | if (format & 0x80) {
|
931 | bytes[dataStart] &= 0x7f;
|
932 | readSupplement();
|
933 | }
|
934 |
|
935 | raw = bytes.subarray(dataStart, dataEnd);
|
936 | }
|
937 |
|
938 | format &= 0x7f;
|
939 | return new CFFEncoding(predefined, format, encoding, raw);
|
940 | }
|
941 |
|
942 | parseFDSelect(pos, length) {
|
943 | const bytes = this.bytes;
|
944 | const format = bytes[pos++];
|
945 | const fdSelect = [];
|
946 | let i;
|
947 |
|
948 | switch (format) {
|
949 | case 0:
|
950 | for (i = 0; i < length; ++i) {
|
951 | const id = bytes[pos++];
|
952 | fdSelect.push(id);
|
953 | }
|
954 |
|
955 | break;
|
956 |
|
957 | case 3:
|
958 | const rangesCount = bytes[pos++] << 8 | bytes[pos++];
|
959 |
|
960 | for (i = 0; i < rangesCount; ++i) {
|
961 | let first = bytes[pos++] << 8 | bytes[pos++];
|
962 |
|
963 | if (i === 0 && first !== 0) {
|
964 | (0, _util.warn)("parseFDSelect: The first range must have a first GID of 0" + " -- trying to recover.");
|
965 | first = 0;
|
966 | }
|
967 |
|
968 | const fdIndex = bytes[pos++];
|
969 | const next = bytes[pos] << 8 | bytes[pos + 1];
|
970 |
|
971 | for (let j = first; j < next; ++j) {
|
972 | fdSelect.push(fdIndex);
|
973 | }
|
974 | }
|
975 |
|
976 | pos += 2;
|
977 | break;
|
978 |
|
979 | default:
|
980 | throw new _util.FormatError(`parseFDSelect: Unknown format "${format}".`);
|
981 | }
|
982 |
|
983 | if (fdSelect.length !== length) {
|
984 | throw new _util.FormatError("parseFDSelect: Invalid font data.");
|
985 | }
|
986 |
|
987 | return new CFFFDSelect(format, fdSelect);
|
988 | }
|
989 |
|
990 | }
|
991 |
|
992 | return CFFParser;
|
993 | }();
|
994 |
|
995 | exports.CFFParser = CFFParser;
|
996 |
|
997 | class CFF {
|
998 | constructor() {
|
999 | this.header = null;
|
1000 | this.names = [];
|
1001 | this.topDict = null;
|
1002 | this.strings = new CFFStrings();
|
1003 | this.globalSubrIndex = null;
|
1004 | this.encoding = null;
|
1005 | this.charset = null;
|
1006 | this.charStrings = null;
|
1007 | this.fdArray = [];
|
1008 | this.fdSelect = null;
|
1009 | this.isCIDFont = false;
|
1010 | }
|
1011 |
|
1012 | duplicateFirstGlyph() {
|
1013 | if (this.charStrings.count >= 65535) {
|
1014 | (0, _util.warn)("Not enough space in charstrings to duplicate first glyph.");
|
1015 | return;
|
1016 | }
|
1017 |
|
1018 | const glyphZero = this.charStrings.get(0);
|
1019 | this.charStrings.add(glyphZero);
|
1020 |
|
1021 | if (this.isCIDFont) {
|
1022 | this.fdSelect.fdSelect.push(this.fdSelect.fdSelect[0]);
|
1023 | }
|
1024 | }
|
1025 |
|
1026 | hasGlyphId(id) {
|
1027 | if (id < 0 || id >= this.charStrings.count) {
|
1028 | return false;
|
1029 | }
|
1030 |
|
1031 | const glyph = this.charStrings.get(id);
|
1032 | return glyph.length > 0;
|
1033 | }
|
1034 |
|
1035 | }
|
1036 |
|
1037 | exports.CFF = CFF;
|
1038 |
|
1039 | class CFFHeader {
|
1040 | constructor(major, minor, hdrSize, offSize) {
|
1041 | this.major = major;
|
1042 | this.minor = minor;
|
1043 | this.hdrSize = hdrSize;
|
1044 | this.offSize = offSize;
|
1045 | }
|
1046 |
|
1047 | }
|
1048 |
|
1049 | exports.CFFHeader = CFFHeader;
|
1050 |
|
1051 | class CFFStrings {
|
1052 | constructor() {
|
1053 | this.strings = [];
|
1054 | }
|
1055 |
|
1056 | get(index) {
|
1057 | if (index >= 0 && index <= NUM_STANDARD_CFF_STRINGS - 1) {
|
1058 | return CFFStandardStrings[index];
|
1059 | }
|
1060 |
|
1061 | if (index - NUM_STANDARD_CFF_STRINGS <= this.strings.length) {
|
1062 | return this.strings[index - NUM_STANDARD_CFF_STRINGS];
|
1063 | }
|
1064 |
|
1065 | return CFFStandardStrings[0];
|
1066 | }
|
1067 |
|
1068 | getSID(str) {
|
1069 | let index = CFFStandardStrings.indexOf(str);
|
1070 |
|
1071 | if (index !== -1) {
|
1072 | return index;
|
1073 | }
|
1074 |
|
1075 | index = this.strings.indexOf(str);
|
1076 |
|
1077 | if (index !== -1) {
|
1078 | return index + NUM_STANDARD_CFF_STRINGS;
|
1079 | }
|
1080 |
|
1081 | return -1;
|
1082 | }
|
1083 |
|
1084 | add(value) {
|
1085 | this.strings.push(value);
|
1086 | }
|
1087 |
|
1088 | get count() {
|
1089 | return this.strings.length;
|
1090 | }
|
1091 |
|
1092 | }
|
1093 |
|
1094 | exports.CFFStrings = CFFStrings;
|
1095 |
|
1096 | class CFFIndex {
|
1097 | constructor() {
|
1098 | this.objects = [];
|
1099 | this.length = 0;
|
1100 | }
|
1101 |
|
1102 | add(data) {
|
1103 | this.length += data.length;
|
1104 | this.objects.push(data);
|
1105 | }
|
1106 |
|
1107 | set(index, data) {
|
1108 | this.length += data.length - this.objects[index].length;
|
1109 | this.objects[index] = data;
|
1110 | }
|
1111 |
|
1112 | get(index) {
|
1113 | return this.objects[index];
|
1114 | }
|
1115 |
|
1116 | get count() {
|
1117 | return this.objects.length;
|
1118 | }
|
1119 |
|
1120 | }
|
1121 |
|
1122 | exports.CFFIndex = CFFIndex;
|
1123 |
|
1124 | class CFFDict {
|
1125 | constructor(tables, strings) {
|
1126 | this.keyToNameMap = tables.keyToNameMap;
|
1127 | this.nameToKeyMap = tables.nameToKeyMap;
|
1128 | this.defaults = tables.defaults;
|
1129 | this.types = tables.types;
|
1130 | this.opcodes = tables.opcodes;
|
1131 | this.order = tables.order;
|
1132 | this.strings = strings;
|
1133 | this.values = Object.create(null);
|
1134 | }
|
1135 |
|
1136 | setByKey(key, value) {
|
1137 | if (!(key in this.keyToNameMap)) {
|
1138 | return false;
|
1139 | }
|
1140 |
|
1141 | const valueLength = value.length;
|
1142 |
|
1143 | if (valueLength === 0) {
|
1144 | return true;
|
1145 | }
|
1146 |
|
1147 | for (let i = 0; i < valueLength; i++) {
|
1148 | if (isNaN(value[i])) {
|
1149 | (0, _util.warn)('Invalid CFFDict value: "' + value + '" for key "' + key + '".');
|
1150 | return true;
|
1151 | }
|
1152 | }
|
1153 |
|
1154 | const type = this.types[key];
|
1155 |
|
1156 | if (type === "num" || type === "sid" || type === "offset") {
|
1157 | value = value[0];
|
1158 | }
|
1159 |
|
1160 | this.values[key] = value;
|
1161 | return true;
|
1162 | }
|
1163 |
|
1164 | setByName(name, value) {
|
1165 | if (!(name in this.nameToKeyMap)) {
|
1166 | throw new _util.FormatError(`Invalid dictionary name "${name}"`);
|
1167 | }
|
1168 |
|
1169 | this.values[this.nameToKeyMap[name]] = value;
|
1170 | }
|
1171 |
|
1172 | hasName(name) {
|
1173 | return this.nameToKeyMap[name] in this.values;
|
1174 | }
|
1175 |
|
1176 | getByName(name) {
|
1177 | if (!(name in this.nameToKeyMap)) {
|
1178 | throw new _util.FormatError(`Invalid dictionary name ${name}"`);
|
1179 | }
|
1180 |
|
1181 | const key = this.nameToKeyMap[name];
|
1182 |
|
1183 | if (!(key in this.values)) {
|
1184 | return this.defaults[key];
|
1185 | }
|
1186 |
|
1187 | return this.values[key];
|
1188 | }
|
1189 |
|
1190 | removeByName(name) {
|
1191 | delete this.values[this.nameToKeyMap[name]];
|
1192 | }
|
1193 |
|
1194 | static createTables(layout) {
|
1195 | const tables = {
|
1196 | keyToNameMap: {},
|
1197 | nameToKeyMap: {},
|
1198 | defaults: {},
|
1199 | types: {},
|
1200 | opcodes: {},
|
1201 | order: []
|
1202 | };
|
1203 |
|
1204 | for (let i = 0, ii = layout.length; i < ii; ++i) {
|
1205 | const entry = layout[i];
|
1206 | const key = Array.isArray(entry[0]) ? (entry[0][0] << 8) + entry[0][1] : entry[0];
|
1207 | tables.keyToNameMap[key] = entry[1];
|
1208 | tables.nameToKeyMap[entry[1]] = key;
|
1209 | tables.types[key] = entry[2];
|
1210 | tables.defaults[key] = entry[3];
|
1211 | tables.opcodes[key] = Array.isArray(entry[0]) ? entry[0] : [entry[0]];
|
1212 | tables.order.push(key);
|
1213 | }
|
1214 |
|
1215 | return tables;
|
1216 | }
|
1217 |
|
1218 | }
|
1219 |
|
1220 | const CFFTopDict = function CFFTopDictClosure() {
|
1221 | const layout = [[[12, 30], "ROS", ["sid", "sid", "num"], null], [[12, 20], "SyntheticBase", "num", null], [0, "version", "sid", null], [1, "Notice", "sid", null], [[12, 0], "Copyright", "sid", null], [2, "FullName", "sid", null], [3, "FamilyName", "sid", null], [4, "Weight", "sid", null], [[12, 1], "isFixedPitch", "num", 0], [[12, 2], "ItalicAngle", "num", 0], [[12, 3], "UnderlinePosition", "num", -100], [[12, 4], "UnderlineThickness", "num", 50], [[12, 5], "PaintType", "num", 0], [[12, 6], "CharstringType", "num", 2], [[12, 7], "FontMatrix", ["num", "num", "num", "num", "num", "num"], [0.001, 0, 0, 0.001, 0, 0]], [13, "UniqueID", "num", null], [5, "FontBBox", ["num", "num", "num", "num"], [0, 0, 0, 0]], [[12, 8], "StrokeWidth", "num", 0], [14, "XUID", "array", null], [15, "charset", "offset", 0], [16, "Encoding", "offset", 0], [17, "CharStrings", "offset", 0], [18, "Private", ["offset", "offset"], null], [[12, 21], "PostScript", "sid", null], [[12, 22], "BaseFontName", "sid", null], [[12, 23], "BaseFontBlend", "delta", null], [[12, 31], "CIDFontVersion", "num", 0], [[12, 32], "CIDFontRevision", "num", 0], [[12, 33], "CIDFontType", "num", 0], [[12, 34], "CIDCount", "num", 8720], [[12, 35], "UIDBase", "num", null], [[12, 37], "FDSelect", "offset", null], [[12, 36], "FDArray", "offset", null], [[12, 38], "FontName", "sid", null]];
|
1222 | let tables = null;
|
1223 |
|
1224 | class CFFTopDict extends CFFDict {
|
1225 | constructor(strings) {
|
1226 | if (tables === null) {
|
1227 | tables = CFFDict.createTables(layout);
|
1228 | }
|
1229 |
|
1230 | super(tables, strings);
|
1231 | this.privateDict = null;
|
1232 | }
|
1233 |
|
1234 | }
|
1235 |
|
1236 | return CFFTopDict;
|
1237 | }();
|
1238 |
|
1239 | exports.CFFTopDict = CFFTopDict;
|
1240 |
|
1241 | const CFFPrivateDict = function CFFPrivateDictClosure() {
|
1242 | const layout = [[6, "BlueValues", "delta", null], [7, "OtherBlues", "delta", null], [8, "FamilyBlues", "delta", null], [9, "FamilyOtherBlues", "delta", null], [[12, 9], "BlueScale", "num", 0.039625], [[12, 10], "BlueShift", "num", 7], [[12, 11], "BlueFuzz", "num", 1], [10, "StdHW", "num", null], [11, "StdVW", "num", null], [[12, 12], "StemSnapH", "delta", null], [[12, 13], "StemSnapV", "delta", null], [[12, 14], "ForceBold", "num", 0], [[12, 17], "LanguageGroup", "num", 0], [[12, 18], "ExpansionFactor", "num", 0.06], [[12, 19], "initialRandomSeed", "num", 0], [20, "defaultWidthX", "num", 0], [21, "nominalWidthX", "num", 0], [19, "Subrs", "offset", null]];
|
1243 | let tables = null;
|
1244 |
|
1245 | class CFFPrivateDict extends CFFDict {
|
1246 | constructor(strings) {
|
1247 | if (tables === null) {
|
1248 | tables = CFFDict.createTables(layout);
|
1249 | }
|
1250 |
|
1251 | super(tables, strings);
|
1252 | this.subrsIndex = null;
|
1253 | }
|
1254 |
|
1255 | }
|
1256 |
|
1257 | return CFFPrivateDict;
|
1258 | }();
|
1259 |
|
1260 | exports.CFFPrivateDict = CFFPrivateDict;
|
1261 | const CFFCharsetPredefinedTypes = {
|
1262 | ISO_ADOBE: 0,
|
1263 | EXPERT: 1,
|
1264 | EXPERT_SUBSET: 2
|
1265 | };
|
1266 |
|
1267 | class CFFCharset {
|
1268 | constructor(predefined, format, charset, raw) {
|
1269 | this.predefined = predefined;
|
1270 | this.format = format;
|
1271 | this.charset = charset;
|
1272 | this.raw = raw;
|
1273 | }
|
1274 |
|
1275 | }
|
1276 |
|
1277 | exports.CFFCharset = CFFCharset;
|
1278 |
|
1279 | class CFFEncoding {
|
1280 | constructor(predefined, format, encoding, raw) {
|
1281 | this.predefined = predefined;
|
1282 | this.format = format;
|
1283 | this.encoding = encoding;
|
1284 | this.raw = raw;
|
1285 | }
|
1286 |
|
1287 | }
|
1288 |
|
1289 | class CFFFDSelect {
|
1290 | constructor(format, fdSelect) {
|
1291 | this.format = format;
|
1292 | this.fdSelect = fdSelect;
|
1293 | }
|
1294 |
|
1295 | getFDIndex(glyphIndex) {
|
1296 | if (glyphIndex < 0 || glyphIndex >= this.fdSelect.length) {
|
1297 | return -1;
|
1298 | }
|
1299 |
|
1300 | return this.fdSelect[glyphIndex];
|
1301 | }
|
1302 |
|
1303 | }
|
1304 |
|
1305 | exports.CFFFDSelect = CFFFDSelect;
|
1306 |
|
1307 | class CFFOffsetTracker {
|
1308 | constructor() {
|
1309 | this.offsets = Object.create(null);
|
1310 | }
|
1311 |
|
1312 | isTracking(key) {
|
1313 | return key in this.offsets;
|
1314 | }
|
1315 |
|
1316 | track(key, location) {
|
1317 | if (key in this.offsets) {
|
1318 | throw new _util.FormatError(`Already tracking location of ${key}`);
|
1319 | }
|
1320 |
|
1321 | this.offsets[key] = location;
|
1322 | }
|
1323 |
|
1324 | offset(value) {
|
1325 | for (const key in this.offsets) {
|
1326 | this.offsets[key] += value;
|
1327 | }
|
1328 | }
|
1329 |
|
1330 | setEntryLocation(key, values, output) {
|
1331 | if (!(key in this.offsets)) {
|
1332 | throw new _util.FormatError(`Not tracking location of ${key}`);
|
1333 | }
|
1334 |
|
1335 | const data = output.data;
|
1336 | const dataOffset = this.offsets[key];
|
1337 | const size = 5;
|
1338 |
|
1339 | for (let i = 0, ii = values.length; i < ii; ++i) {
|
1340 | const offset0 = i * size + dataOffset;
|
1341 | const offset1 = offset0 + 1;
|
1342 | const offset2 = offset0 + 2;
|
1343 | const offset3 = offset0 + 3;
|
1344 | const offset4 = offset0 + 4;
|
1345 |
|
1346 | if (data[offset0] !== 0x1d || data[offset1] !== 0 || data[offset2] !== 0 || data[offset3] !== 0 || data[offset4] !== 0) {
|
1347 | throw new _util.FormatError("writing to an offset that is not empty");
|
1348 | }
|
1349 |
|
1350 | const value = values[i];
|
1351 | data[offset0] = 0x1d;
|
1352 | data[offset1] = value >> 24 & 0xff;
|
1353 | data[offset2] = value >> 16 & 0xff;
|
1354 | data[offset3] = value >> 8 & 0xff;
|
1355 | data[offset4] = value & 0xff;
|
1356 | }
|
1357 | }
|
1358 |
|
1359 | }
|
1360 |
|
1361 | class CFFCompiler {
|
1362 | constructor(cff) {
|
1363 | this.cff = cff;
|
1364 | }
|
1365 |
|
1366 | compile() {
|
1367 | const cff = this.cff;
|
1368 | const output = {
|
1369 | data: [],
|
1370 | length: 0,
|
1371 |
|
1372 | add(data) {
|
1373 | this.data = this.data.concat(data);
|
1374 | this.length = this.data.length;
|
1375 | }
|
1376 |
|
1377 | };
|
1378 | const header = this.compileHeader(cff.header);
|
1379 | output.add(header);
|
1380 | const nameIndex = this.compileNameIndex(cff.names);
|
1381 | output.add(nameIndex);
|
1382 |
|
1383 | if (cff.isCIDFont) {
|
1384 | if (cff.topDict.hasName("FontMatrix")) {
|
1385 | const base = cff.topDict.getByName("FontMatrix");
|
1386 | cff.topDict.removeByName("FontMatrix");
|
1387 |
|
1388 | for (let i = 0, ii = cff.fdArray.length; i < ii; i++) {
|
1389 | const subDict = cff.fdArray[i];
|
1390 | let matrix = base.slice(0);
|
1391 |
|
1392 | if (subDict.hasName("FontMatrix")) {
|
1393 | matrix = _util.Util.transform(matrix, subDict.getByName("FontMatrix"));
|
1394 | }
|
1395 |
|
1396 | subDict.setByName("FontMatrix", matrix);
|
1397 | }
|
1398 | }
|
1399 | }
|
1400 |
|
1401 | const xuid = cff.topDict.getByName("XUID");
|
1402 |
|
1403 | if (xuid && xuid.length > 16) {
|
1404 | cff.topDict.removeByName("XUID");
|
1405 | }
|
1406 |
|
1407 | cff.topDict.setByName("charset", 0);
|
1408 | let compiled = this.compileTopDicts([cff.topDict], output.length, cff.isCIDFont);
|
1409 | output.add(compiled.output);
|
1410 | const topDictTracker = compiled.trackers[0];
|
1411 | const stringIndex = this.compileStringIndex(cff.strings.strings);
|
1412 | output.add(stringIndex);
|
1413 | const globalSubrIndex = this.compileIndex(cff.globalSubrIndex);
|
1414 | output.add(globalSubrIndex);
|
1415 |
|
1416 | if (cff.encoding && cff.topDict.hasName("Encoding")) {
|
1417 | if (cff.encoding.predefined) {
|
1418 | topDictTracker.setEntryLocation("Encoding", [cff.encoding.format], output);
|
1419 | } else {
|
1420 | const encoding = this.compileEncoding(cff.encoding);
|
1421 | topDictTracker.setEntryLocation("Encoding", [output.length], output);
|
1422 | output.add(encoding);
|
1423 | }
|
1424 | }
|
1425 |
|
1426 | const charset = this.compileCharset(cff.charset, cff.charStrings.count, cff.strings, cff.isCIDFont);
|
1427 | topDictTracker.setEntryLocation("charset", [output.length], output);
|
1428 | output.add(charset);
|
1429 | const charStrings = this.compileCharStrings(cff.charStrings);
|
1430 | topDictTracker.setEntryLocation("CharStrings", [output.length], output);
|
1431 | output.add(charStrings);
|
1432 |
|
1433 | if (cff.isCIDFont) {
|
1434 | topDictTracker.setEntryLocation("FDSelect", [output.length], output);
|
1435 | const fdSelect = this.compileFDSelect(cff.fdSelect);
|
1436 | output.add(fdSelect);
|
1437 | compiled = this.compileTopDicts(cff.fdArray, output.length, true);
|
1438 | topDictTracker.setEntryLocation("FDArray", [output.length], output);
|
1439 | output.add(compiled.output);
|
1440 | const fontDictTrackers = compiled.trackers;
|
1441 | this.compilePrivateDicts(cff.fdArray, fontDictTrackers, output);
|
1442 | }
|
1443 |
|
1444 | this.compilePrivateDicts([cff.topDict], [topDictTracker], output);
|
1445 | output.add([0]);
|
1446 | return output.data;
|
1447 | }
|
1448 |
|
1449 | encodeNumber(value) {
|
1450 | if (Number.isInteger(value)) {
|
1451 | return this.encodeInteger(value);
|
1452 | }
|
1453 |
|
1454 | return this.encodeFloat(value);
|
1455 | }
|
1456 |
|
1457 | static get EncodeFloatRegExp() {
|
1458 | return (0, _util.shadow)(this, "EncodeFloatRegExp", /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/);
|
1459 | }
|
1460 |
|
1461 | encodeFloat(num) {
|
1462 | let value = num.toString();
|
1463 | const m = CFFCompiler.EncodeFloatRegExp.exec(value);
|
1464 |
|
1465 | if (m) {
|
1466 | const epsilon = parseFloat("1e" + ((m[2] ? +m[2] : 0) + m[1].length));
|
1467 | value = (Math.round(num * epsilon) / epsilon).toString();
|
1468 | }
|
1469 |
|
1470 | let nibbles = "";
|
1471 | let i, ii;
|
1472 |
|
1473 | for (i = 0, ii = value.length; i < ii; ++i) {
|
1474 | const a = value[i];
|
1475 |
|
1476 | if (a === "e") {
|
1477 | nibbles += value[++i] === "-" ? "c" : "b";
|
1478 | } else if (a === ".") {
|
1479 | nibbles += "a";
|
1480 | } else if (a === "-") {
|
1481 | nibbles += "e";
|
1482 | } else {
|
1483 | nibbles += a;
|
1484 | }
|
1485 | }
|
1486 |
|
1487 | nibbles += nibbles.length & 1 ? "f" : "ff";
|
1488 | const out = [30];
|
1489 |
|
1490 | for (i = 0, ii = nibbles.length; i < ii; i += 2) {
|
1491 | out.push(parseInt(nibbles.substring(i, i + 2), 16));
|
1492 | }
|
1493 |
|
1494 | return out;
|
1495 | }
|
1496 |
|
1497 | encodeInteger(value) {
|
1498 | let code;
|
1499 |
|
1500 | if (value >= -107 && value <= 107) {
|
1501 | code = [value + 139];
|
1502 | } else if (value >= 108 && value <= 1131) {
|
1503 | value -= 108;
|
1504 | code = [(value >> 8) + 247, value & 0xff];
|
1505 | } else if (value >= -1131 && value <= -108) {
|
1506 | value = -value - 108;
|
1507 | code = [(value >> 8) + 251, value & 0xff];
|
1508 | } else if (value >= -32768 && value <= 32767) {
|
1509 | code = [0x1c, value >> 8 & 0xff, value & 0xff];
|
1510 | } else {
|
1511 | code = [0x1d, value >> 24 & 0xff, value >> 16 & 0xff, value >> 8 & 0xff, value & 0xff];
|
1512 | }
|
1513 |
|
1514 | return code;
|
1515 | }
|
1516 |
|
1517 | compileHeader(header) {
|
1518 | return [header.major, header.minor, 4, header.offSize];
|
1519 | }
|
1520 |
|
1521 | compileNameIndex(names) {
|
1522 | const nameIndex = new CFFIndex();
|
1523 |
|
1524 | for (let i = 0, ii = names.length; i < ii; ++i) {
|
1525 | const name = names[i];
|
1526 | const length = Math.min(name.length, 127);
|
1527 | let sanitizedName = new Array(length);
|
1528 |
|
1529 | for (let j = 0; j < length; j++) {
|
1530 | let char = name[j];
|
1531 |
|
1532 | if (char < "!" || char > "~" || char === "[" || char === "]" || char === "(" || char === ")" || char === "{" || char === "}" || char === "<" || char === ">" || char === "/" || char === "%") {
|
1533 | char = "_";
|
1534 | }
|
1535 |
|
1536 | sanitizedName[j] = char;
|
1537 | }
|
1538 |
|
1539 | sanitizedName = sanitizedName.join("");
|
1540 |
|
1541 | if (sanitizedName === "") {
|
1542 | sanitizedName = "Bad_Font_Name";
|
1543 | }
|
1544 |
|
1545 | nameIndex.add((0, _util.stringToBytes)(sanitizedName));
|
1546 | }
|
1547 |
|
1548 | return this.compileIndex(nameIndex);
|
1549 | }
|
1550 |
|
1551 | compileTopDicts(dicts, length, removeCidKeys) {
|
1552 | const fontDictTrackers = [];
|
1553 | let fdArrayIndex = new CFFIndex();
|
1554 |
|
1555 | for (let i = 0, ii = dicts.length; i < ii; ++i) {
|
1556 | const fontDict = dicts[i];
|
1557 |
|
1558 | if (removeCidKeys) {
|
1559 | fontDict.removeByName("CIDFontVersion");
|
1560 | fontDict.removeByName("CIDFontRevision");
|
1561 | fontDict.removeByName("CIDFontType");
|
1562 | fontDict.removeByName("CIDCount");
|
1563 | fontDict.removeByName("UIDBase");
|
1564 | }
|
1565 |
|
1566 | const fontDictTracker = new CFFOffsetTracker();
|
1567 | const fontDictData = this.compileDict(fontDict, fontDictTracker);
|
1568 | fontDictTrackers.push(fontDictTracker);
|
1569 | fdArrayIndex.add(fontDictData);
|
1570 | fontDictTracker.offset(length);
|
1571 | }
|
1572 |
|
1573 | fdArrayIndex = this.compileIndex(fdArrayIndex, fontDictTrackers);
|
1574 | return {
|
1575 | trackers: fontDictTrackers,
|
1576 | output: fdArrayIndex
|
1577 | };
|
1578 | }
|
1579 |
|
1580 | compilePrivateDicts(dicts, trackers, output) {
|
1581 | for (let i = 0, ii = dicts.length; i < ii; ++i) {
|
1582 | const fontDict = dicts[i];
|
1583 | const privateDict = fontDict.privateDict;
|
1584 |
|
1585 | if (!privateDict || !fontDict.hasName("Private")) {
|
1586 | throw new _util.FormatError("There must be a private dictionary.");
|
1587 | }
|
1588 |
|
1589 | const privateDictTracker = new CFFOffsetTracker();
|
1590 | const privateDictData = this.compileDict(privateDict, privateDictTracker);
|
1591 | let outputLength = output.length;
|
1592 | privateDictTracker.offset(outputLength);
|
1593 |
|
1594 | if (!privateDictData.length) {
|
1595 | outputLength = 0;
|
1596 | }
|
1597 |
|
1598 | trackers[i].setEntryLocation("Private", [privateDictData.length, outputLength], output);
|
1599 | output.add(privateDictData);
|
1600 |
|
1601 | if (privateDict.subrsIndex && privateDict.hasName("Subrs")) {
|
1602 | const subrs = this.compileIndex(privateDict.subrsIndex);
|
1603 | privateDictTracker.setEntryLocation("Subrs", [privateDictData.length], output);
|
1604 | output.add(subrs);
|
1605 | }
|
1606 | }
|
1607 | }
|
1608 |
|
1609 | compileDict(dict, offsetTracker) {
|
1610 | const out = [];
|
1611 |
|
1612 | for (const key of dict.order) {
|
1613 | if (!(key in dict.values)) {
|
1614 | continue;
|
1615 | }
|
1616 |
|
1617 | let values = dict.values[key];
|
1618 | let types = dict.types[key];
|
1619 |
|
1620 | if (!Array.isArray(types)) {
|
1621 | types = [types];
|
1622 | }
|
1623 |
|
1624 | if (!Array.isArray(values)) {
|
1625 | values = [values];
|
1626 | }
|
1627 |
|
1628 | if (values.length === 0) {
|
1629 | continue;
|
1630 | }
|
1631 |
|
1632 | for (let j = 0, jj = types.length; j < jj; ++j) {
|
1633 | const type = types[j];
|
1634 | const value = values[j];
|
1635 |
|
1636 | switch (type) {
|
1637 | case "num":
|
1638 | case "sid":
|
1639 | out.push(...this.encodeNumber(value));
|
1640 | break;
|
1641 |
|
1642 | case "offset":
|
1643 | const name = dict.keyToNameMap[key];
|
1644 |
|
1645 | if (!offsetTracker.isTracking(name)) {
|
1646 | offsetTracker.track(name, out.length);
|
1647 | }
|
1648 |
|
1649 | out.push(0x1d, 0, 0, 0, 0);
|
1650 | break;
|
1651 |
|
1652 | case "array":
|
1653 | case "delta":
|
1654 | out.push(...this.encodeNumber(value));
|
1655 |
|
1656 | for (let k = 1, kk = values.length; k < kk; ++k) {
|
1657 | out.push(...this.encodeNumber(values[k]));
|
1658 | }
|
1659 |
|
1660 | break;
|
1661 |
|
1662 | default:
|
1663 | throw new _util.FormatError(`Unknown data type of ${type}`);
|
1664 | }
|
1665 | }
|
1666 |
|
1667 | out.push(...dict.opcodes[key]);
|
1668 | }
|
1669 |
|
1670 | return out;
|
1671 | }
|
1672 |
|
1673 | compileStringIndex(strings) {
|
1674 | const stringIndex = new CFFIndex();
|
1675 |
|
1676 | for (let i = 0, ii = strings.length; i < ii; ++i) {
|
1677 | stringIndex.add((0, _util.stringToBytes)(strings[i]));
|
1678 | }
|
1679 |
|
1680 | return this.compileIndex(stringIndex);
|
1681 | }
|
1682 |
|
1683 | compileGlobalSubrIndex() {
|
1684 | const globalSubrIndex = this.cff.globalSubrIndex;
|
1685 | this.out.writeByteArray(this.compileIndex(globalSubrIndex));
|
1686 | }
|
1687 |
|
1688 | compileCharStrings(charStrings) {
|
1689 | const charStringsIndex = new CFFIndex();
|
1690 |
|
1691 | for (let i = 0; i < charStrings.count; i++) {
|
1692 | const glyph = charStrings.get(i);
|
1693 |
|
1694 | if (glyph.length === 0) {
|
1695 | charStringsIndex.add(new Uint8Array([0x8b, 0x0e]));
|
1696 | continue;
|
1697 | }
|
1698 |
|
1699 | charStringsIndex.add(glyph);
|
1700 | }
|
1701 |
|
1702 | return this.compileIndex(charStringsIndex);
|
1703 | }
|
1704 |
|
1705 | compileCharset(charset, numGlyphs, strings, isCIDFont) {
|
1706 | let out;
|
1707 | const numGlyphsLessNotDef = numGlyphs - 1;
|
1708 |
|
1709 | if (isCIDFont) {
|
1710 | out = new Uint8Array([2, 0, 0, numGlyphsLessNotDef >> 8 & 0xff, numGlyphsLessNotDef & 0xff]);
|
1711 | } else {
|
1712 | const length = 1 + numGlyphsLessNotDef * 2;
|
1713 | out = new Uint8Array(length);
|
1714 | out[0] = 0;
|
1715 | let charsetIndex = 0;
|
1716 | const numCharsets = charset.charset.length;
|
1717 | let warned = false;
|
1718 |
|
1719 | for (let i = 1; i < out.length; i += 2) {
|
1720 | let sid = 0;
|
1721 |
|
1722 | if (charsetIndex < numCharsets) {
|
1723 | const name = charset.charset[charsetIndex++];
|
1724 | sid = strings.getSID(name);
|
1725 |
|
1726 | if (sid === -1) {
|
1727 | sid = 0;
|
1728 |
|
1729 | if (!warned) {
|
1730 | warned = true;
|
1731 | (0, _util.warn)(`Couldn't find ${name} in CFF strings`);
|
1732 | }
|
1733 | }
|
1734 | }
|
1735 |
|
1736 | out[i] = sid >> 8 & 0xff;
|
1737 | out[i + 1] = sid & 0xff;
|
1738 | }
|
1739 | }
|
1740 |
|
1741 | return this.compileTypedArray(out);
|
1742 | }
|
1743 |
|
1744 | compileEncoding(encoding) {
|
1745 | return this.compileTypedArray(encoding.raw);
|
1746 | }
|
1747 |
|
1748 | compileFDSelect(fdSelect) {
|
1749 | const format = fdSelect.format;
|
1750 | let out, i;
|
1751 |
|
1752 | switch (format) {
|
1753 | case 0:
|
1754 | out = new Uint8Array(1 + fdSelect.fdSelect.length);
|
1755 | out[0] = format;
|
1756 |
|
1757 | for (i = 0; i < fdSelect.fdSelect.length; i++) {
|
1758 | out[i + 1] = fdSelect.fdSelect[i];
|
1759 | }
|
1760 |
|
1761 | break;
|
1762 |
|
1763 | case 3:
|
1764 | const start = 0;
|
1765 | let lastFD = fdSelect.fdSelect[0];
|
1766 | const ranges = [format, 0, 0, start >> 8 & 0xff, start & 0xff, lastFD];
|
1767 |
|
1768 | for (i = 1; i < fdSelect.fdSelect.length; i++) {
|
1769 | const currentFD = fdSelect.fdSelect[i];
|
1770 |
|
1771 | if (currentFD !== lastFD) {
|
1772 | ranges.push(i >> 8 & 0xff, i & 0xff, currentFD);
|
1773 | lastFD = currentFD;
|
1774 | }
|
1775 | }
|
1776 |
|
1777 | const numRanges = (ranges.length - 3) / 3;
|
1778 | ranges[1] = numRanges >> 8 & 0xff;
|
1779 | ranges[2] = numRanges & 0xff;
|
1780 | ranges.push(i >> 8 & 0xff, i & 0xff);
|
1781 | out = new Uint8Array(ranges);
|
1782 | break;
|
1783 | }
|
1784 |
|
1785 | return this.compileTypedArray(out);
|
1786 | }
|
1787 |
|
1788 | compileTypedArray(data) {
|
1789 | const out = [];
|
1790 |
|
1791 | for (let i = 0, ii = data.length; i < ii; ++i) {
|
1792 | out[i] = data[i];
|
1793 | }
|
1794 |
|
1795 | return out;
|
1796 | }
|
1797 |
|
1798 | compileIndex(index, trackers = []) {
|
1799 | const objects = index.objects;
|
1800 | const count = objects.length;
|
1801 |
|
1802 | if (count === 0) {
|
1803 | return [0, 0, 0];
|
1804 | }
|
1805 |
|
1806 | const data = [count >> 8 & 0xff, count & 0xff];
|
1807 | let lastOffset = 1,
|
1808 | i;
|
1809 |
|
1810 | for (i = 0; i < count; ++i) {
|
1811 | lastOffset += objects[i].length;
|
1812 | }
|
1813 |
|
1814 | let offsetSize;
|
1815 |
|
1816 | if (lastOffset < 0x100) {
|
1817 | offsetSize = 1;
|
1818 | } else if (lastOffset < 0x10000) {
|
1819 | offsetSize = 2;
|
1820 | } else if (lastOffset < 0x1000000) {
|
1821 | offsetSize = 3;
|
1822 | } else {
|
1823 | offsetSize = 4;
|
1824 | }
|
1825 |
|
1826 | data.push(offsetSize);
|
1827 | let relativeOffset = 1;
|
1828 |
|
1829 | for (i = 0; i < count + 1; i++) {
|
1830 | if (offsetSize === 1) {
|
1831 | data.push(relativeOffset & 0xff);
|
1832 | } else if (offsetSize === 2) {
|
1833 | data.push(relativeOffset >> 8 & 0xff, relativeOffset & 0xff);
|
1834 | } else if (offsetSize === 3) {
|
1835 | data.push(relativeOffset >> 16 & 0xff, relativeOffset >> 8 & 0xff, relativeOffset & 0xff);
|
1836 | } else {
|
1837 | data.push(relativeOffset >>> 24 & 0xff, relativeOffset >> 16 & 0xff, relativeOffset >> 8 & 0xff, relativeOffset & 0xff);
|
1838 | }
|
1839 |
|
1840 | if (objects[i]) {
|
1841 | relativeOffset += objects[i].length;
|
1842 | }
|
1843 | }
|
1844 |
|
1845 | for (i = 0; i < count; i++) {
|
1846 | if (trackers[i]) {
|
1847 | trackers[i].offset(data.length);
|
1848 | }
|
1849 |
|
1850 | for (let j = 0, jj = objects[i].length; j < jj; j++) {
|
1851 | data.push(objects[i][j]);
|
1852 | }
|
1853 | }
|
1854 |
|
1855 | return data;
|
1856 | }
|
1857 |
|
1858 | }
|
1859 |
|
1860 | exports.CFFCompiler = CFFCompiler; |
\ | No newline at end of file |