UNPKG

25 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * JavaScript code in this page
4 *
5 * Copyright 2022 Mozilla Foundation
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * @licend The above is the entire license notice for the
20 * JavaScript code in this page
21 */
22"use strict";
23
24Object.defineProperty(exports, "__esModule", {
25 value: true
26});
27exports.FontRendererFactory = void 0;
28
29var _util = require("../shared/util.js");
30
31var _cff_parser = require("./cff_parser.js");
32
33var _glyphlist = require("./glyphlist.js");
34
35var _encodings = require("./encodings.js");
36
37var _stream = require("./stream.js");
38
39function getUint32(data, offset) {
40 return (data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3]) >>> 0;
41}
42
43function getUint16(data, offset) {
44 return data[offset] << 8 | data[offset + 1];
45}
46
47function getInt16(data, offset) {
48 return (data[offset] << 24 | data[offset + 1] << 16) >> 16;
49}
50
51function getInt8(data, offset) {
52 return data[offset] << 24 >> 24;
53}
54
55function getFloat214(data, offset) {
56 return getInt16(data, offset) / 16384;
57}
58
59function getSubroutineBias(subrs) {
60 const numSubrs = subrs.length;
61 let bias = 32768;
62
63 if (numSubrs < 1240) {
64 bias = 107;
65 } else if (numSubrs < 33900) {
66 bias = 1131;
67 }
68
69 return bias;
70}
71
72function parseCmap(data, start, end) {
73 const offset = getUint16(data, start + 2) === 1 ? getUint32(data, start + 8) : getUint32(data, start + 16);
74 const format = getUint16(data, start + offset);
75 let ranges, p, i;
76
77 if (format === 4) {
78 getUint16(data, start + offset + 2);
79 const segCount = getUint16(data, start + offset + 6) >> 1;
80 p = start + offset + 14;
81 ranges = [];
82
83 for (i = 0; i < segCount; i++, p += 2) {
84 ranges[i] = {
85 end: getUint16(data, p)
86 };
87 }
88
89 p += 2;
90
91 for (i = 0; i < segCount; i++, p += 2) {
92 ranges[i].start = getUint16(data, p);
93 }
94
95 for (i = 0; i < segCount; i++, p += 2) {
96 ranges[i].idDelta = getUint16(data, p);
97 }
98
99 for (i = 0; i < segCount; i++, p += 2) {
100 let idOffset = getUint16(data, p);
101
102 if (idOffset === 0) {
103 continue;
104 }
105
106 ranges[i].ids = [];
107
108 for (let j = 0, jj = ranges[i].end - ranges[i].start + 1; j < jj; j++) {
109 ranges[i].ids[j] = getUint16(data, p + idOffset);
110 idOffset += 2;
111 }
112 }
113
114 return ranges;
115 } else if (format === 12) {
116 const groups = getUint32(data, start + offset + 12);
117 p = start + offset + 16;
118 ranges = [];
119
120 for (i = 0; i < groups; i++) {
121 start = getUint32(data, p);
122 ranges.push({
123 start,
124 end: getUint32(data, p + 4),
125 idDelta: getUint32(data, p + 8) - start
126 });
127 p += 12;
128 }
129
130 return ranges;
131 }
132
133 throw new _util.FormatError(`unsupported cmap: ${format}`);
134}
135
136function parseCff(data, start, end, seacAnalysisEnabled) {
137 const properties = {};
138 const parser = new _cff_parser.CFFParser(new _stream.Stream(data, start, end - start), properties, seacAnalysisEnabled);
139 const cff = parser.parse();
140 return {
141 glyphs: cff.charStrings.objects,
142 subrs: cff.topDict.privateDict && cff.topDict.privateDict.subrsIndex && cff.topDict.privateDict.subrsIndex.objects,
143 gsubrs: cff.globalSubrIndex && cff.globalSubrIndex.objects,
144 isCFFCIDFont: cff.isCIDFont,
145 fdSelect: cff.fdSelect,
146 fdArray: cff.fdArray
147 };
148}
149
150function parseGlyfTable(glyf, loca, isGlyphLocationsLong) {
151 let itemSize, itemDecode;
152
153 if (isGlyphLocationsLong) {
154 itemSize = 4;
155 itemDecode = getUint32;
156 } else {
157 itemSize = 2;
158
159 itemDecode = (data, offset) => 2 * getUint16(data, offset);
160 }
161
162 const glyphs = [];
163 let startOffset = itemDecode(loca, 0);
164
165 for (let j = itemSize; j < loca.length; j += itemSize) {
166 const endOffset = itemDecode(loca, j);
167 glyphs.push(glyf.subarray(startOffset, endOffset));
168 startOffset = endOffset;
169 }
170
171 return glyphs;
172}
173
174function lookupCmap(ranges, unicode) {
175 const code = unicode.codePointAt(0);
176 let gid = 0,
177 l = 0,
178 r = ranges.length - 1;
179
180 while (l < r) {
181 const c = l + r + 1 >> 1;
182
183 if (code < ranges[c].start) {
184 r = c - 1;
185 } else {
186 l = c;
187 }
188 }
189
190 if (ranges[l].start <= code && code <= ranges[l].end) {
191 gid = ranges[l].idDelta + (ranges[l].ids ? ranges[l].ids[code - ranges[l].start] : code) & 0xffff;
192 }
193
194 return {
195 charCode: code,
196 glyphId: gid
197 };
198}
199
200function compileGlyf(code, cmds, font) {
201 function moveTo(x, y) {
202 cmds.push({
203 cmd: "moveTo",
204 args: [x, y]
205 });
206 }
207
208 function lineTo(x, y) {
209 cmds.push({
210 cmd: "lineTo",
211 args: [x, y]
212 });
213 }
214
215 function quadraticCurveTo(xa, ya, x, y) {
216 cmds.push({
217 cmd: "quadraticCurveTo",
218 args: [xa, ya, x, y]
219 });
220 }
221
222 let i = 0;
223 const numberOfContours = getInt16(code, i);
224 let flags;
225 let x = 0,
226 y = 0;
227 i += 10;
228
229 if (numberOfContours < 0) {
230 do {
231 flags = getUint16(code, i);
232 const glyphIndex = getUint16(code, i + 2);
233 i += 4;
234 let arg1, arg2;
235
236 if (flags & 0x01) {
237 if (flags & 0x02) {
238 arg1 = getInt16(code, i);
239 arg2 = getInt16(code, i + 2);
240 } else {
241 arg1 = getUint16(code, i);
242 arg2 = getUint16(code, i + 2);
243 }
244
245 i += 4;
246 } else {
247 if (flags & 0x02) {
248 arg1 = getInt8(code, i++);
249 arg2 = getInt8(code, i++);
250 } else {
251 arg1 = code[i++];
252 arg2 = code[i++];
253 }
254 }
255
256 if (flags & 0x02) {
257 x = arg1;
258 y = arg2;
259 } else {
260 x = 0;
261 y = 0;
262 }
263
264 let scaleX = 1,
265 scaleY = 1,
266 scale01 = 0,
267 scale10 = 0;
268
269 if (flags & 0x08) {
270 scaleX = scaleY = getFloat214(code, i);
271 i += 2;
272 } else if (flags & 0x40) {
273 scaleX = getFloat214(code, i);
274 scaleY = getFloat214(code, i + 2);
275 i += 4;
276 } else if (flags & 0x80) {
277 scaleX = getFloat214(code, i);
278 scale01 = getFloat214(code, i + 2);
279 scale10 = getFloat214(code, i + 4);
280 scaleY = getFloat214(code, i + 6);
281 i += 8;
282 }
283
284 const subglyph = font.glyphs[glyphIndex];
285
286 if (subglyph) {
287 cmds.push({
288 cmd: "save"
289 }, {
290 cmd: "transform",
291 args: [scaleX, scale01, scale10, scaleY, x, y]
292 });
293
294 if (!(flags & 0x02)) {}
295
296 compileGlyf(subglyph, cmds, font);
297 cmds.push({
298 cmd: "restore"
299 });
300 }
301 } while (flags & 0x20);
302 } else {
303 const endPtsOfContours = [];
304 let j, jj;
305
306 for (j = 0; j < numberOfContours; j++) {
307 endPtsOfContours.push(getUint16(code, i));
308 i += 2;
309 }
310
311 const instructionLength = getUint16(code, i);
312 i += 2 + instructionLength;
313 const numberOfPoints = endPtsOfContours.at(-1) + 1;
314 const points = [];
315
316 while (points.length < numberOfPoints) {
317 flags = code[i++];
318 let repeat = 1;
319
320 if (flags & 0x08) {
321 repeat += code[i++];
322 }
323
324 while (repeat-- > 0) {
325 points.push({
326 flags
327 });
328 }
329 }
330
331 for (j = 0; j < numberOfPoints; j++) {
332 switch (points[j].flags & 0x12) {
333 case 0x00:
334 x += getInt16(code, i);
335 i += 2;
336 break;
337
338 case 0x02:
339 x -= code[i++];
340 break;
341
342 case 0x12:
343 x += code[i++];
344 break;
345 }
346
347 points[j].x = x;
348 }
349
350 for (j = 0; j < numberOfPoints; j++) {
351 switch (points[j].flags & 0x24) {
352 case 0x00:
353 y += getInt16(code, i);
354 i += 2;
355 break;
356
357 case 0x04:
358 y -= code[i++];
359 break;
360
361 case 0x24:
362 y += code[i++];
363 break;
364 }
365
366 points[j].y = y;
367 }
368
369 let startPoint = 0;
370
371 for (i = 0; i < numberOfContours; i++) {
372 const endPoint = endPtsOfContours[i];
373 const contour = points.slice(startPoint, endPoint + 1);
374
375 if (contour[0].flags & 1) {
376 contour.push(contour[0]);
377 } else if (contour.at(-1).flags & 1) {
378 contour.unshift(contour.at(-1));
379 } else {
380 const p = {
381 flags: 1,
382 x: (contour[0].x + contour.at(-1).x) / 2,
383 y: (contour[0].y + contour.at(-1).y) / 2
384 };
385 contour.unshift(p);
386 contour.push(p);
387 }
388
389 moveTo(contour[0].x, contour[0].y);
390
391 for (j = 1, jj = contour.length; j < jj; j++) {
392 if (contour[j].flags & 1) {
393 lineTo(contour[j].x, contour[j].y);
394 } else if (contour[j + 1].flags & 1) {
395 quadraticCurveTo(contour[j].x, contour[j].y, contour[j + 1].x, contour[j + 1].y);
396 j++;
397 } else {
398 quadraticCurveTo(contour[j].x, contour[j].y, (contour[j].x + contour[j + 1].x) / 2, (contour[j].y + contour[j + 1].y) / 2);
399 }
400 }
401
402 startPoint = endPoint + 1;
403 }
404 }
405}
406
407function compileCharString(charStringCode, cmds, font, glyphId) {
408 function moveTo(x, y) {
409 cmds.push({
410 cmd: "moveTo",
411 args: [x, y]
412 });
413 }
414
415 function lineTo(x, y) {
416 cmds.push({
417 cmd: "lineTo",
418 args: [x, y]
419 });
420 }
421
422 function bezierCurveTo(x1, y1, x2, y2, x, y) {
423 cmds.push({
424 cmd: "bezierCurveTo",
425 args: [x1, y1, x2, y2, x, y]
426 });
427 }
428
429 const stack = [];
430 let x = 0,
431 y = 0;
432 let stems = 0;
433
434 function parse(code) {
435 let i = 0;
436
437 while (i < code.length) {
438 let stackClean = false;
439 let v = code[i++];
440 let xa, xb, ya, yb, y1, y2, y3, n, subrCode;
441
442 switch (v) {
443 case 1:
444 stems += stack.length >> 1;
445 stackClean = true;
446 break;
447
448 case 3:
449 stems += stack.length >> 1;
450 stackClean = true;
451 break;
452
453 case 4:
454 y += stack.pop();
455 moveTo(x, y);
456 stackClean = true;
457 break;
458
459 case 5:
460 while (stack.length > 0) {
461 x += stack.shift();
462 y += stack.shift();
463 lineTo(x, y);
464 }
465
466 break;
467
468 case 6:
469 while (stack.length > 0) {
470 x += stack.shift();
471 lineTo(x, y);
472
473 if (stack.length === 0) {
474 break;
475 }
476
477 y += stack.shift();
478 lineTo(x, y);
479 }
480
481 break;
482
483 case 7:
484 while (stack.length > 0) {
485 y += stack.shift();
486 lineTo(x, y);
487
488 if (stack.length === 0) {
489 break;
490 }
491
492 x += stack.shift();
493 lineTo(x, y);
494 }
495
496 break;
497
498 case 8:
499 while (stack.length > 0) {
500 xa = x + stack.shift();
501 ya = y + stack.shift();
502 xb = xa + stack.shift();
503 yb = ya + stack.shift();
504 x = xb + stack.shift();
505 y = yb + stack.shift();
506 bezierCurveTo(xa, ya, xb, yb, x, y);
507 }
508
509 break;
510
511 case 10:
512 n = stack.pop();
513 subrCode = null;
514
515 if (font.isCFFCIDFont) {
516 const fdIndex = font.fdSelect.getFDIndex(glyphId);
517
518 if (fdIndex >= 0 && fdIndex < font.fdArray.length) {
519 const fontDict = font.fdArray[fdIndex];
520 let subrs;
521
522 if (fontDict.privateDict && fontDict.privateDict.subrsIndex) {
523 subrs = fontDict.privateDict.subrsIndex.objects;
524 }
525
526 if (subrs) {
527 n += getSubroutineBias(subrs);
528 subrCode = subrs[n];
529 }
530 } else {
531 (0, _util.warn)("Invalid fd index for glyph index.");
532 }
533 } else {
534 subrCode = font.subrs[n + font.subrsBias];
535 }
536
537 if (subrCode) {
538 parse(subrCode);
539 }
540
541 break;
542
543 case 11:
544 return;
545
546 case 12:
547 v = code[i++];
548
549 switch (v) {
550 case 34:
551 xa = x + stack.shift();
552 xb = xa + stack.shift();
553 y1 = y + stack.shift();
554 x = xb + stack.shift();
555 bezierCurveTo(xa, y, xb, y1, x, y1);
556 xa = x + stack.shift();
557 xb = xa + stack.shift();
558 x = xb + stack.shift();
559 bezierCurveTo(xa, y1, xb, y, x, y);
560 break;
561
562 case 35:
563 xa = x + stack.shift();
564 ya = y + stack.shift();
565 xb = xa + stack.shift();
566 yb = ya + stack.shift();
567 x = xb + stack.shift();
568 y = yb + stack.shift();
569 bezierCurveTo(xa, ya, xb, yb, x, y);
570 xa = x + stack.shift();
571 ya = y + stack.shift();
572 xb = xa + stack.shift();
573 yb = ya + stack.shift();
574 x = xb + stack.shift();
575 y = yb + stack.shift();
576 bezierCurveTo(xa, ya, xb, yb, x, y);
577 stack.pop();
578 break;
579
580 case 36:
581 xa = x + stack.shift();
582 y1 = y + stack.shift();
583 xb = xa + stack.shift();
584 y2 = y1 + stack.shift();
585 x = xb + stack.shift();
586 bezierCurveTo(xa, y1, xb, y2, x, y2);
587 xa = x + stack.shift();
588 xb = xa + stack.shift();
589 y3 = y2 + stack.shift();
590 x = xb + stack.shift();
591 bezierCurveTo(xa, y2, xb, y3, x, y);
592 break;
593
594 case 37:
595 const x0 = x,
596 y0 = y;
597 xa = x + stack.shift();
598 ya = y + stack.shift();
599 xb = xa + stack.shift();
600 yb = ya + stack.shift();
601 x = xb + stack.shift();
602 y = yb + stack.shift();
603 bezierCurveTo(xa, ya, xb, yb, x, y);
604 xa = x + stack.shift();
605 ya = y + stack.shift();
606 xb = xa + stack.shift();
607 yb = ya + stack.shift();
608 x = xb;
609 y = yb;
610
611 if (Math.abs(x - x0) > Math.abs(y - y0)) {
612 x += stack.shift();
613 } else {
614 y += stack.shift();
615 }
616
617 bezierCurveTo(xa, ya, xb, yb, x, y);
618 break;
619
620 default:
621 throw new _util.FormatError(`unknown operator: 12 ${v}`);
622 }
623
624 break;
625
626 case 14:
627 if (stack.length >= 4) {
628 const achar = stack.pop();
629 const bchar = stack.pop();
630 y = stack.pop();
631 x = stack.pop();
632 cmds.push({
633 cmd: "save"
634 }, {
635 cmd: "translate",
636 args: [x, y]
637 });
638 let cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[achar]]));
639 compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
640 cmds.push({
641 cmd: "restore"
642 });
643 cmap = lookupCmap(font.cmap, String.fromCharCode(font.glyphNameMap[_encodings.StandardEncoding[bchar]]));
644 compileCharString(font.glyphs[cmap.glyphId], cmds, font, cmap.glyphId);
645 }
646
647 return;
648
649 case 18:
650 stems += stack.length >> 1;
651 stackClean = true;
652 break;
653
654 case 19:
655 stems += stack.length >> 1;
656 i += stems + 7 >> 3;
657 stackClean = true;
658 break;
659
660 case 20:
661 stems += stack.length >> 1;
662 i += stems + 7 >> 3;
663 stackClean = true;
664 break;
665
666 case 21:
667 y += stack.pop();
668 x += stack.pop();
669 moveTo(x, y);
670 stackClean = true;
671 break;
672
673 case 22:
674 x += stack.pop();
675 moveTo(x, y);
676 stackClean = true;
677 break;
678
679 case 23:
680 stems += stack.length >> 1;
681 stackClean = true;
682 break;
683
684 case 24:
685 while (stack.length > 2) {
686 xa = x + stack.shift();
687 ya = y + stack.shift();
688 xb = xa + stack.shift();
689 yb = ya + stack.shift();
690 x = xb + stack.shift();
691 y = yb + stack.shift();
692 bezierCurveTo(xa, ya, xb, yb, x, y);
693 }
694
695 x += stack.shift();
696 y += stack.shift();
697 lineTo(x, y);
698 break;
699
700 case 25:
701 while (stack.length > 6) {
702 x += stack.shift();
703 y += stack.shift();
704 lineTo(x, y);
705 }
706
707 xa = x + stack.shift();
708 ya = y + stack.shift();
709 xb = xa + stack.shift();
710 yb = ya + stack.shift();
711 x = xb + stack.shift();
712 y = yb + stack.shift();
713 bezierCurveTo(xa, ya, xb, yb, x, y);
714 break;
715
716 case 26:
717 if (stack.length % 2) {
718 x += stack.shift();
719 }
720
721 while (stack.length > 0) {
722 xa = x;
723 ya = y + stack.shift();
724 xb = xa + stack.shift();
725 yb = ya + stack.shift();
726 x = xb;
727 y = yb + stack.shift();
728 bezierCurveTo(xa, ya, xb, yb, x, y);
729 }
730
731 break;
732
733 case 27:
734 if (stack.length % 2) {
735 y += stack.shift();
736 }
737
738 while (stack.length > 0) {
739 xa = x + stack.shift();
740 ya = y;
741 xb = xa + stack.shift();
742 yb = ya + stack.shift();
743 x = xb + stack.shift();
744 y = yb;
745 bezierCurveTo(xa, ya, xb, yb, x, y);
746 }
747
748 break;
749
750 case 28:
751 stack.push((code[i] << 24 | code[i + 1] << 16) >> 16);
752 i += 2;
753 break;
754
755 case 29:
756 n = stack.pop() + font.gsubrsBias;
757 subrCode = font.gsubrs[n];
758
759 if (subrCode) {
760 parse(subrCode);
761 }
762
763 break;
764
765 case 30:
766 while (stack.length > 0) {
767 xa = x;
768 ya = y + stack.shift();
769 xb = xa + stack.shift();
770 yb = ya + stack.shift();
771 x = xb + stack.shift();
772 y = yb + (stack.length === 1 ? stack.shift() : 0);
773 bezierCurveTo(xa, ya, xb, yb, x, y);
774
775 if (stack.length === 0) {
776 break;
777 }
778
779 xa = x + stack.shift();
780 ya = y;
781 xb = xa + stack.shift();
782 yb = ya + stack.shift();
783 y = yb + stack.shift();
784 x = xb + (stack.length === 1 ? stack.shift() : 0);
785 bezierCurveTo(xa, ya, xb, yb, x, y);
786 }
787
788 break;
789
790 case 31:
791 while (stack.length > 0) {
792 xa = x + stack.shift();
793 ya = y;
794 xb = xa + stack.shift();
795 yb = ya + stack.shift();
796 y = yb + stack.shift();
797 x = xb + (stack.length === 1 ? stack.shift() : 0);
798 bezierCurveTo(xa, ya, xb, yb, x, y);
799
800 if (stack.length === 0) {
801 break;
802 }
803
804 xa = x;
805 ya = y + stack.shift();
806 xb = xa + stack.shift();
807 yb = ya + stack.shift();
808 x = xb + stack.shift();
809 y = yb + (stack.length === 1 ? stack.shift() : 0);
810 bezierCurveTo(xa, ya, xb, yb, x, y);
811 }
812
813 break;
814
815 default:
816 if (v < 32) {
817 throw new _util.FormatError(`unknown operator: ${v}`);
818 }
819
820 if (v < 247) {
821 stack.push(v - 139);
822 } else if (v < 251) {
823 stack.push((v - 247) * 256 + code[i++] + 108);
824 } else if (v < 255) {
825 stack.push(-(v - 251) * 256 - code[i++] - 108);
826 } else {
827 stack.push((code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3]) / 65536);
828 i += 4;
829 }
830
831 break;
832 }
833
834 if (stackClean) {
835 stack.length = 0;
836 }
837 }
838 }
839
840 parse(charStringCode);
841}
842
843const NOOP = [];
844
845class CompiledFont {
846 constructor(fontMatrix) {
847 if (this.constructor === CompiledFont) {
848 (0, _util.unreachable)("Cannot initialize CompiledFont.");
849 }
850
851 this.fontMatrix = fontMatrix;
852 this.compiledGlyphs = Object.create(null);
853 this.compiledCharCodeToGlyphId = Object.create(null);
854 }
855
856 getPathJs(unicode) {
857 const {
858 charCode,
859 glyphId
860 } = lookupCmap(this.cmap, unicode);
861 let fn = this.compiledGlyphs[glyphId];
862
863 if (!fn) {
864 try {
865 fn = this.compileGlyph(this.glyphs[glyphId], glyphId);
866 this.compiledGlyphs[glyphId] = fn;
867 } catch (ex) {
868 this.compiledGlyphs[glyphId] = NOOP;
869
870 if (this.compiledCharCodeToGlyphId[charCode] === undefined) {
871 this.compiledCharCodeToGlyphId[charCode] = glyphId;
872 }
873
874 throw ex;
875 }
876 }
877
878 if (this.compiledCharCodeToGlyphId[charCode] === undefined) {
879 this.compiledCharCodeToGlyphId[charCode] = glyphId;
880 }
881
882 return fn;
883 }
884
885 compileGlyph(code, glyphId) {
886 if (!code || code.length === 0 || code[0] === 14) {
887 return NOOP;
888 }
889
890 let fontMatrix = this.fontMatrix;
891
892 if (this.isCFFCIDFont) {
893 const fdIndex = this.fdSelect.getFDIndex(glyphId);
894
895 if (fdIndex >= 0 && fdIndex < this.fdArray.length) {
896 const fontDict = this.fdArray[fdIndex];
897 fontMatrix = fontDict.getByName("FontMatrix") || _util.FONT_IDENTITY_MATRIX;
898 } else {
899 (0, _util.warn)("Invalid fd index for glyph index.");
900 }
901 }
902
903 const cmds = [{
904 cmd: "save"
905 }, {
906 cmd: "transform",
907 args: fontMatrix.slice()
908 }, {
909 cmd: "scale",
910 args: ["size", "-size"]
911 }];
912 this.compileGlyphImpl(code, cmds, glyphId);
913 cmds.push({
914 cmd: "restore"
915 });
916 return cmds;
917 }
918
919 compileGlyphImpl() {
920 (0, _util.unreachable)("Children classes should implement this.");
921 }
922
923 hasBuiltPath(unicode) {
924 const {
925 charCode,
926 glyphId
927 } = lookupCmap(this.cmap, unicode);
928 return this.compiledGlyphs[glyphId] !== undefined && this.compiledCharCodeToGlyphId[charCode] !== undefined;
929 }
930
931}
932
933class TrueTypeCompiled extends CompiledFont {
934 constructor(glyphs, cmap, fontMatrix) {
935 super(fontMatrix || [0.000488, 0, 0, 0.000488, 0, 0]);
936 this.glyphs = glyphs;
937 this.cmap = cmap;
938 }
939
940 compileGlyphImpl(code, cmds) {
941 compileGlyf(code, cmds, this);
942 }
943
944}
945
946class Type2Compiled extends CompiledFont {
947 constructor(cffInfo, cmap, fontMatrix, glyphNameMap) {
948 super(fontMatrix || [0.001, 0, 0, 0.001, 0, 0]);
949 this.glyphs = cffInfo.glyphs;
950 this.gsubrs = cffInfo.gsubrs || [];
951 this.subrs = cffInfo.subrs || [];
952 this.cmap = cmap;
953 this.glyphNameMap = glyphNameMap || (0, _glyphlist.getGlyphsUnicode)();
954 this.gsubrsBias = getSubroutineBias(this.gsubrs);
955 this.subrsBias = getSubroutineBias(this.subrs);
956 this.isCFFCIDFont = cffInfo.isCFFCIDFont;
957 this.fdSelect = cffInfo.fdSelect;
958 this.fdArray = cffInfo.fdArray;
959 }
960
961 compileGlyphImpl(code, cmds, glyphId) {
962 compileCharString(code, cmds, this, glyphId);
963 }
964
965}
966
967class FontRendererFactory {
968 static create(font, seacAnalysisEnabled) {
969 const data = new Uint8Array(font.data);
970 let cmap, glyf, loca, cff, indexToLocFormat, unitsPerEm;
971 const numTables = getUint16(data, 4);
972
973 for (let i = 0, p = 12; i < numTables; i++, p += 16) {
974 const tag = (0, _util.bytesToString)(data.subarray(p, p + 4));
975 const offset = getUint32(data, p + 8);
976 const length = getUint32(data, p + 12);
977
978 switch (tag) {
979 case "cmap":
980 cmap = parseCmap(data, offset, offset + length);
981 break;
982
983 case "glyf":
984 glyf = data.subarray(offset, offset + length);
985 break;
986
987 case "loca":
988 loca = data.subarray(offset, offset + length);
989 break;
990
991 case "head":
992 unitsPerEm = getUint16(data, offset + 18);
993 indexToLocFormat = getUint16(data, offset + 50);
994 break;
995
996 case "CFF ":
997 cff = parseCff(data, offset, offset + length, seacAnalysisEnabled);
998 break;
999 }
1000 }
1001
1002 if (glyf) {
1003 const fontMatrix = !unitsPerEm ? font.fontMatrix : [1 / unitsPerEm, 0, 0, 1 / unitsPerEm, 0, 0];
1004 return new TrueTypeCompiled(parseGlyfTable(glyf, loca, indexToLocFormat), cmap, fontMatrix);
1005 }
1006
1007 return new Type2Compiled(cff, cmap, font.fontMatrix, font.glyphNameMap);
1008 }
1009
1010}
1011
1012exports.FontRendererFactory = FontRendererFactory;
\No newline at end of file