UNPKG

45.5 kBJavaScriptView Raw
1/**
2 * @licstart The following is the entire license notice for the
3 * Javascript code in this page
4 *
5 * Copyright 2021 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.SVGGraphics = void 0;
28
29var _util = require("../shared/util.js");
30
31var _display_utils = require("./display_utils.js");
32
33var _is_node = require("../shared/is_node.js");
34
35let SVGGraphics = class {
36 constructor() {
37 (0, _util.unreachable)("Not implemented: SVGGraphics");
38 }
39
40};
41exports.SVGGraphics = SVGGraphics;
42{
43 const SVG_DEFAULTS = {
44 fontStyle: "normal",
45 fontWeight: "normal",
46 fillColor: "#000000"
47 };
48 const XML_NS = "http://www.w3.org/XML/1998/namespace";
49 const XLINK_NS = "http://www.w3.org/1999/xlink";
50 const LINE_CAP_STYLES = ["butt", "round", "square"];
51 const LINE_JOIN_STYLES = ["miter", "round", "bevel"];
52
53 const convertImgDataToPng = function () {
54 const PNG_HEADER = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
55 const CHUNK_WRAPPER_SIZE = 12;
56 const crcTable = new Int32Array(256);
57
58 for (let i = 0; i < 256; i++) {
59 let c = i;
60
61 for (let h = 0; h < 8; h++) {
62 if (c & 1) {
63 c = 0xedb88320 ^ c >> 1 & 0x7fffffff;
64 } else {
65 c = c >> 1 & 0x7fffffff;
66 }
67 }
68
69 crcTable[i] = c;
70 }
71
72 function crc32(data, start, end) {
73 let crc = -1;
74
75 for (let i = start; i < end; i++) {
76 const a = (crc ^ data[i]) & 0xff;
77 const b = crcTable[a];
78 crc = crc >>> 8 ^ b;
79 }
80
81 return crc ^ -1;
82 }
83
84 function writePngChunk(type, body, data, offset) {
85 let p = offset;
86 const len = body.length;
87 data[p] = len >> 24 & 0xff;
88 data[p + 1] = len >> 16 & 0xff;
89 data[p + 2] = len >> 8 & 0xff;
90 data[p + 3] = len & 0xff;
91 p += 4;
92 data[p] = type.charCodeAt(0) & 0xff;
93 data[p + 1] = type.charCodeAt(1) & 0xff;
94 data[p + 2] = type.charCodeAt(2) & 0xff;
95 data[p + 3] = type.charCodeAt(3) & 0xff;
96 p += 4;
97 data.set(body, p);
98 p += body.length;
99 const crc = crc32(data, offset + 4, p);
100 data[p] = crc >> 24 & 0xff;
101 data[p + 1] = crc >> 16 & 0xff;
102 data[p + 2] = crc >> 8 & 0xff;
103 data[p + 3] = crc & 0xff;
104 }
105
106 function adler32(data, start, end) {
107 let a = 1;
108 let b = 0;
109
110 for (let i = start; i < end; ++i) {
111 a = (a + (data[i] & 0xff)) % 65521;
112 b = (b + a) % 65521;
113 }
114
115 return b << 16 | a;
116 }
117
118 function deflateSync(literals) {
119 if (!_is_node.isNodeJS) {
120 return deflateSyncUncompressed(literals);
121 }
122
123 try {
124 let input;
125
126 if (parseInt(process.versions.node) >= 8) {
127 input = literals;
128 } else {
129 input = Buffer.from(literals);
130 }
131
132 const output = require("zlib").deflateSync(input, {
133 level: 9
134 });
135
136 return output instanceof Uint8Array ? output : new Uint8Array(output);
137 } catch (e) {
138 (0, _util.warn)("Not compressing PNG because zlib.deflateSync is unavailable: " + e);
139 }
140
141 return deflateSyncUncompressed(literals);
142 }
143
144 function deflateSyncUncompressed(literals) {
145 let len = literals.length;
146 const maxBlockLength = 0xffff;
147 const deflateBlocks = Math.ceil(len / maxBlockLength);
148 const idat = new Uint8Array(2 + len + deflateBlocks * 5 + 4);
149 let pi = 0;
150 idat[pi++] = 0x78;
151 idat[pi++] = 0x9c;
152 let pos = 0;
153
154 while (len > maxBlockLength) {
155 idat[pi++] = 0x00;
156 idat[pi++] = 0xff;
157 idat[pi++] = 0xff;
158 idat[pi++] = 0x00;
159 idat[pi++] = 0x00;
160 idat.set(literals.subarray(pos, pos + maxBlockLength), pi);
161 pi += maxBlockLength;
162 pos += maxBlockLength;
163 len -= maxBlockLength;
164 }
165
166 idat[pi++] = 0x01;
167 idat[pi++] = len & 0xff;
168 idat[pi++] = len >> 8 & 0xff;
169 idat[pi++] = ~len & 0xffff & 0xff;
170 idat[pi++] = (~len & 0xffff) >> 8 & 0xff;
171 idat.set(literals.subarray(pos), pi);
172 pi += literals.length - pos;
173 const adler = adler32(literals, 0, literals.length);
174 idat[pi++] = adler >> 24 & 0xff;
175 idat[pi++] = adler >> 16 & 0xff;
176 idat[pi++] = adler >> 8 & 0xff;
177 idat[pi++] = adler & 0xff;
178 return idat;
179 }
180
181 function encode(imgData, kind, forceDataSchema, isMask) {
182 const width = imgData.width;
183 const height = imgData.height;
184 let bitDepth, colorType, lineSize;
185 const bytes = imgData.data;
186
187 switch (kind) {
188 case _util.ImageKind.GRAYSCALE_1BPP:
189 colorType = 0;
190 bitDepth = 1;
191 lineSize = width + 7 >> 3;
192 break;
193
194 case _util.ImageKind.RGB_24BPP:
195 colorType = 2;
196 bitDepth = 8;
197 lineSize = width * 3;
198 break;
199
200 case _util.ImageKind.RGBA_32BPP:
201 colorType = 6;
202 bitDepth = 8;
203 lineSize = width * 4;
204 break;
205
206 default:
207 throw new Error("invalid format");
208 }
209
210 const literals = new Uint8Array((1 + lineSize) * height);
211 let offsetLiterals = 0,
212 offsetBytes = 0;
213
214 for (let y = 0; y < height; ++y) {
215 literals[offsetLiterals++] = 0;
216 literals.set(bytes.subarray(offsetBytes, offsetBytes + lineSize), offsetLiterals);
217 offsetBytes += lineSize;
218 offsetLiterals += lineSize;
219 }
220
221 if (kind === _util.ImageKind.GRAYSCALE_1BPP && isMask) {
222 offsetLiterals = 0;
223
224 for (let y = 0; y < height; y++) {
225 offsetLiterals++;
226
227 for (let i = 0; i < lineSize; i++) {
228 literals[offsetLiterals++] ^= 0xff;
229 }
230 }
231 }
232
233 const ihdr = new Uint8Array([width >> 24 & 0xff, width >> 16 & 0xff, width >> 8 & 0xff, width & 0xff, height >> 24 & 0xff, height >> 16 & 0xff, height >> 8 & 0xff, height & 0xff, bitDepth, colorType, 0x00, 0x00, 0x00]);
234 const idat = deflateSync(literals);
235 const pngLength = PNG_HEADER.length + CHUNK_WRAPPER_SIZE * 3 + ihdr.length + idat.length;
236 const data = new Uint8Array(pngLength);
237 let offset = 0;
238 data.set(PNG_HEADER, offset);
239 offset += PNG_HEADER.length;
240 writePngChunk("IHDR", ihdr, data, offset);
241 offset += CHUNK_WRAPPER_SIZE + ihdr.length;
242 writePngChunk("IDATA", idat, data, offset);
243 offset += CHUNK_WRAPPER_SIZE + idat.length;
244 writePngChunk("IEND", new Uint8Array(0), data, offset);
245 return (0, _util.createObjectURL)(data, "image/png", forceDataSchema);
246 }
247
248 return function convertImgDataToPng(imgData, forceDataSchema, isMask) {
249 const kind = imgData.kind === undefined ? _util.ImageKind.GRAYSCALE_1BPP : imgData.kind;
250 return encode(imgData, kind, forceDataSchema, isMask);
251 };
252 }();
253
254 class SVGExtraState {
255 constructor() {
256 this.fontSizeScale = 1;
257 this.fontWeight = SVG_DEFAULTS.fontWeight;
258 this.fontSize = 0;
259 this.textMatrix = _util.IDENTITY_MATRIX;
260 this.fontMatrix = _util.FONT_IDENTITY_MATRIX;
261 this.leading = 0;
262 this.textRenderingMode = _util.TextRenderingMode.FILL;
263 this.textMatrixScale = 1;
264 this.x = 0;
265 this.y = 0;
266 this.lineX = 0;
267 this.lineY = 0;
268 this.charSpacing = 0;
269 this.wordSpacing = 0;
270 this.textHScale = 1;
271 this.textRise = 0;
272 this.fillColor = SVG_DEFAULTS.fillColor;
273 this.strokeColor = "#000000";
274 this.fillAlpha = 1;
275 this.strokeAlpha = 1;
276 this.lineWidth = 1;
277 this.lineJoin = "";
278 this.lineCap = "";
279 this.miterLimit = 0;
280 this.dashArray = [];
281 this.dashPhase = 0;
282 this.dependencies = [];
283 this.activeClipUrl = null;
284 this.clipGroup = null;
285 this.maskId = "";
286 }
287
288 clone() {
289 return Object.create(this);
290 }
291
292 setCurrentPoint(x, y) {
293 this.x = x;
294 this.y = y;
295 }
296
297 }
298
299 function opListToTree(opList) {
300 let opTree = [];
301 const tmp = [];
302
303 for (const opListElement of opList) {
304 if (opListElement.fn === "save") {
305 opTree.push({
306 fnId: 92,
307 fn: "group",
308 items: []
309 });
310 tmp.push(opTree);
311 opTree = opTree[opTree.length - 1].items;
312 continue;
313 }
314
315 if (opListElement.fn === "restore") {
316 opTree = tmp.pop();
317 } else {
318 opTree.push(opListElement);
319 }
320 }
321
322 return opTree;
323 }
324
325 function pf(value) {
326 if (Number.isInteger(value)) {
327 return value.toString();
328 }
329
330 const s = value.toFixed(10);
331 let i = s.length - 1;
332
333 if (s[i] !== "0") {
334 return s;
335 }
336
337 do {
338 i--;
339 } while (s[i] === "0");
340
341 return s.substring(0, s[i] === "." ? i : i + 1);
342 }
343
344 function pm(m) {
345 if (m[4] === 0 && m[5] === 0) {
346 if (m[1] === 0 && m[2] === 0) {
347 if (m[0] === 1 && m[3] === 1) {
348 return "";
349 }
350
351 return `scale(${pf(m[0])} ${pf(m[3])})`;
352 }
353
354 if (m[0] === m[3] && m[1] === -m[2]) {
355 const a = Math.acos(m[0]) * 180 / Math.PI;
356 return `rotate(${pf(a)})`;
357 }
358 } else {
359 if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1) {
360 return `translate(${pf(m[4])} ${pf(m[5])})`;
361 }
362 }
363
364 return `matrix(${pf(m[0])} ${pf(m[1])} ${pf(m[2])} ${pf(m[3])} ${pf(m[4])} ` + `${pf(m[5])})`;
365 }
366
367 let clipCount = 0;
368 let maskCount = 0;
369 let shadingCount = 0;
370 exports.SVGGraphics = SVGGraphics = class {
371 constructor(commonObjs, objs, forceDataSchema = false) {
372 this.svgFactory = new _display_utils.DOMSVGFactory();
373 this.current = new SVGExtraState();
374 this.transformMatrix = _util.IDENTITY_MATRIX;
375 this.transformStack = [];
376 this.extraStack = [];
377 this.commonObjs = commonObjs;
378 this.objs = objs;
379 this.pendingClip = null;
380 this.pendingEOFill = false;
381 this.embedFonts = false;
382 this.embeddedFonts = Object.create(null);
383 this.cssStyle = null;
384 this.forceDataSchema = !!forceDataSchema;
385 this._operatorIdMapping = [];
386
387 for (const op in _util.OPS) {
388 this._operatorIdMapping[_util.OPS[op]] = op;
389 }
390 }
391
392 save() {
393 this.transformStack.push(this.transformMatrix);
394 const old = this.current;
395 this.extraStack.push(old);
396 this.current = old.clone();
397 }
398
399 restore() {
400 this.transformMatrix = this.transformStack.pop();
401 this.current = this.extraStack.pop();
402 this.pendingClip = null;
403 this.tgrp = null;
404 }
405
406 group(items) {
407 this.save();
408 this.executeOpTree(items);
409 this.restore();
410 }
411
412 loadDependencies(operatorList) {
413 const fnArray = operatorList.fnArray;
414 const argsArray = operatorList.argsArray;
415
416 for (let i = 0, ii = fnArray.length; i < ii; i++) {
417 if (fnArray[i] !== _util.OPS.dependency) {
418 continue;
419 }
420
421 for (const obj of argsArray[i]) {
422 const objsPool = obj.startsWith("g_") ? this.commonObjs : this.objs;
423 const promise = new Promise(resolve => {
424 objsPool.get(obj, resolve);
425 });
426 this.current.dependencies.push(promise);
427 }
428 }
429
430 return Promise.all(this.current.dependencies);
431 }
432
433 transform(a, b, c, d, e, f) {
434 const transformMatrix = [a, b, c, d, e, f];
435 this.transformMatrix = _util.Util.transform(this.transformMatrix, transformMatrix);
436 this.tgrp = null;
437 }
438
439 getSVG(operatorList, viewport) {
440 this.viewport = viewport;
441
442 const svgElement = this._initialize(viewport);
443
444 return this.loadDependencies(operatorList).then(() => {
445 this.transformMatrix = _util.IDENTITY_MATRIX;
446 this.executeOpTree(this.convertOpList(operatorList));
447 return svgElement;
448 });
449 }
450
451 convertOpList(operatorList) {
452 const operatorIdMapping = this._operatorIdMapping;
453 const argsArray = operatorList.argsArray;
454 const fnArray = operatorList.fnArray;
455 const opList = [];
456
457 for (let i = 0, ii = fnArray.length; i < ii; i++) {
458 const fnId = fnArray[i];
459 opList.push({
460 fnId,
461 fn: operatorIdMapping[fnId],
462 args: argsArray[i]
463 });
464 }
465
466 return opListToTree(opList);
467 }
468
469 executeOpTree(opTree) {
470 for (const opTreeElement of opTree) {
471 const fn = opTreeElement.fn;
472 const fnId = opTreeElement.fnId;
473 const args = opTreeElement.args;
474
475 switch (fnId | 0) {
476 case _util.OPS.beginText:
477 this.beginText();
478 break;
479
480 case _util.OPS.dependency:
481 break;
482
483 case _util.OPS.setLeading:
484 this.setLeading(args);
485 break;
486
487 case _util.OPS.setLeadingMoveText:
488 this.setLeadingMoveText(args[0], args[1]);
489 break;
490
491 case _util.OPS.setFont:
492 this.setFont(args);
493 break;
494
495 case _util.OPS.showText:
496 this.showText(args[0]);
497 break;
498
499 case _util.OPS.showSpacedText:
500 this.showText(args[0]);
501 break;
502
503 case _util.OPS.endText:
504 this.endText();
505 break;
506
507 case _util.OPS.moveText:
508 this.moveText(args[0], args[1]);
509 break;
510
511 case _util.OPS.setCharSpacing:
512 this.setCharSpacing(args[0]);
513 break;
514
515 case _util.OPS.setWordSpacing:
516 this.setWordSpacing(args[0]);
517 break;
518
519 case _util.OPS.setHScale:
520 this.setHScale(args[0]);
521 break;
522
523 case _util.OPS.setTextMatrix:
524 this.setTextMatrix(args[0], args[1], args[2], args[3], args[4], args[5]);
525 break;
526
527 case _util.OPS.setTextRise:
528 this.setTextRise(args[0]);
529 break;
530
531 case _util.OPS.setTextRenderingMode:
532 this.setTextRenderingMode(args[0]);
533 break;
534
535 case _util.OPS.setLineWidth:
536 this.setLineWidth(args[0]);
537 break;
538
539 case _util.OPS.setLineJoin:
540 this.setLineJoin(args[0]);
541 break;
542
543 case _util.OPS.setLineCap:
544 this.setLineCap(args[0]);
545 break;
546
547 case _util.OPS.setMiterLimit:
548 this.setMiterLimit(args[0]);
549 break;
550
551 case _util.OPS.setFillRGBColor:
552 this.setFillRGBColor(args[0], args[1], args[2]);
553 break;
554
555 case _util.OPS.setStrokeRGBColor:
556 this.setStrokeRGBColor(args[0], args[1], args[2]);
557 break;
558
559 case _util.OPS.setStrokeColorN:
560 this.setStrokeColorN(args);
561 break;
562
563 case _util.OPS.setFillColorN:
564 this.setFillColorN(args);
565 break;
566
567 case _util.OPS.shadingFill:
568 this.shadingFill(args[0]);
569 break;
570
571 case _util.OPS.setDash:
572 this.setDash(args[0], args[1]);
573 break;
574
575 case _util.OPS.setRenderingIntent:
576 this.setRenderingIntent(args[0]);
577 break;
578
579 case _util.OPS.setFlatness:
580 this.setFlatness(args[0]);
581 break;
582
583 case _util.OPS.setGState:
584 this.setGState(args[0]);
585 break;
586
587 case _util.OPS.fill:
588 this.fill();
589 break;
590
591 case _util.OPS.eoFill:
592 this.eoFill();
593 break;
594
595 case _util.OPS.stroke:
596 this.stroke();
597 break;
598
599 case _util.OPS.fillStroke:
600 this.fillStroke();
601 break;
602
603 case _util.OPS.eoFillStroke:
604 this.eoFillStroke();
605 break;
606
607 case _util.OPS.clip:
608 this.clip("nonzero");
609 break;
610
611 case _util.OPS.eoClip:
612 this.clip("evenodd");
613 break;
614
615 case _util.OPS.paintSolidColorImageMask:
616 this.paintSolidColorImageMask();
617 break;
618
619 case _util.OPS.paintImageXObject:
620 this.paintImageXObject(args[0]);
621 break;
622
623 case _util.OPS.paintInlineImageXObject:
624 this.paintInlineImageXObject(args[0]);
625 break;
626
627 case _util.OPS.paintImageMaskXObject:
628 this.paintImageMaskXObject(args[0]);
629 break;
630
631 case _util.OPS.paintFormXObjectBegin:
632 this.paintFormXObjectBegin(args[0], args[1]);
633 break;
634
635 case _util.OPS.paintFormXObjectEnd:
636 this.paintFormXObjectEnd();
637 break;
638
639 case _util.OPS.closePath:
640 this.closePath();
641 break;
642
643 case _util.OPS.closeStroke:
644 this.closeStroke();
645 break;
646
647 case _util.OPS.closeFillStroke:
648 this.closeFillStroke();
649 break;
650
651 case _util.OPS.closeEOFillStroke:
652 this.closeEOFillStroke();
653 break;
654
655 case _util.OPS.nextLine:
656 this.nextLine();
657 break;
658
659 case _util.OPS.transform:
660 this.transform(args[0], args[1], args[2], args[3], args[4], args[5]);
661 break;
662
663 case _util.OPS.constructPath:
664 this.constructPath(args[0], args[1]);
665 break;
666
667 case _util.OPS.endPath:
668 this.endPath();
669 break;
670
671 case 92:
672 this.group(opTreeElement.items);
673 break;
674
675 default:
676 (0, _util.warn)(`Unimplemented operator ${fn}`);
677 break;
678 }
679 }
680 }
681
682 setWordSpacing(wordSpacing) {
683 this.current.wordSpacing = wordSpacing;
684 }
685
686 setCharSpacing(charSpacing) {
687 this.current.charSpacing = charSpacing;
688 }
689
690 nextLine() {
691 this.moveText(0, this.current.leading);
692 }
693
694 setTextMatrix(a, b, c, d, e, f) {
695 const current = this.current;
696 current.textMatrix = current.lineMatrix = [a, b, c, d, e, f];
697 current.textMatrixScale = Math.hypot(a, b);
698 current.x = current.lineX = 0;
699 current.y = current.lineY = 0;
700 current.xcoords = [];
701 current.ycoords = [];
702 current.tspan = this.svgFactory.createElement("svg:tspan");
703 current.tspan.setAttributeNS(null, "font-family", current.fontFamily);
704 current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`);
705 current.tspan.setAttributeNS(null, "y", pf(-current.y));
706 current.txtElement = this.svgFactory.createElement("svg:text");
707 current.txtElement.appendChild(current.tspan);
708 }
709
710 beginText() {
711 const current = this.current;
712 current.x = current.lineX = 0;
713 current.y = current.lineY = 0;
714 current.textMatrix = _util.IDENTITY_MATRIX;
715 current.lineMatrix = _util.IDENTITY_MATRIX;
716 current.textMatrixScale = 1;
717 current.tspan = this.svgFactory.createElement("svg:tspan");
718 current.txtElement = this.svgFactory.createElement("svg:text");
719 current.txtgrp = this.svgFactory.createElement("svg:g");
720 current.xcoords = [];
721 current.ycoords = [];
722 }
723
724 moveText(x, y) {
725 const current = this.current;
726 current.x = current.lineX += x;
727 current.y = current.lineY += y;
728 current.xcoords = [];
729 current.ycoords = [];
730 current.tspan = this.svgFactory.createElement("svg:tspan");
731 current.tspan.setAttributeNS(null, "font-family", current.fontFamily);
732 current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`);
733 current.tspan.setAttributeNS(null, "y", pf(-current.y));
734 }
735
736 showText(glyphs) {
737 const current = this.current;
738 const font = current.font;
739 const fontSize = current.fontSize;
740
741 if (fontSize === 0) {
742 return;
743 }
744
745 const fontSizeScale = current.fontSizeScale;
746 const charSpacing = current.charSpacing;
747 const wordSpacing = current.wordSpacing;
748 const fontDirection = current.fontDirection;
749 const textHScale = current.textHScale * fontDirection;
750 const vertical = font.vertical;
751 const spacingDir = vertical ? 1 : -1;
752 const defaultVMetrics = font.defaultVMetrics;
753 const widthAdvanceScale = fontSize * current.fontMatrix[0];
754 let x = 0;
755
756 for (const glyph of glyphs) {
757 if (glyph === null) {
758 x += fontDirection * wordSpacing;
759 continue;
760 } else if ((0, _util.isNum)(glyph)) {
761 x += spacingDir * glyph * fontSize / 1000;
762 continue;
763 }
764
765 const spacing = (glyph.isSpace ? wordSpacing : 0) + charSpacing;
766 const character = glyph.fontChar;
767 let scaledX, scaledY;
768 let width = glyph.width;
769
770 if (vertical) {
771 let vx;
772 const vmetric = glyph.vmetric || defaultVMetrics;
773 vx = glyph.vmetric ? vmetric[1] : width * 0.5;
774 vx = -vx * widthAdvanceScale;
775 const vy = vmetric[2] * widthAdvanceScale;
776 width = vmetric ? -vmetric[0] : width;
777 scaledX = vx / fontSizeScale;
778 scaledY = (x + vy) / fontSizeScale;
779 } else {
780 scaledX = x / fontSizeScale;
781 scaledY = 0;
782 }
783
784 if (glyph.isInFont || font.missingFile) {
785 current.xcoords.push(current.x + scaledX);
786
787 if (vertical) {
788 current.ycoords.push(-current.y + scaledY);
789 }
790
791 current.tspan.textContent += character;
792 } else {}
793
794 let charWidth;
795
796 if (vertical) {
797 charWidth = width * widthAdvanceScale - spacing * fontDirection;
798 } else {
799 charWidth = width * widthAdvanceScale + spacing * fontDirection;
800 }
801
802 x += charWidth;
803 }
804
805 current.tspan.setAttributeNS(null, "x", current.xcoords.map(pf).join(" "));
806
807 if (vertical) {
808 current.tspan.setAttributeNS(null, "y", current.ycoords.map(pf).join(" "));
809 } else {
810 current.tspan.setAttributeNS(null, "y", pf(-current.y));
811 }
812
813 if (vertical) {
814 current.y -= x;
815 } else {
816 current.x += x * textHScale;
817 }
818
819 current.tspan.setAttributeNS(null, "font-family", current.fontFamily);
820 current.tspan.setAttributeNS(null, "font-size", `${pf(current.fontSize)}px`);
821
822 if (current.fontStyle !== SVG_DEFAULTS.fontStyle) {
823 current.tspan.setAttributeNS(null, "font-style", current.fontStyle);
824 }
825
826 if (current.fontWeight !== SVG_DEFAULTS.fontWeight) {
827 current.tspan.setAttributeNS(null, "font-weight", current.fontWeight);
828 }
829
830 const fillStrokeMode = current.textRenderingMode & _util.TextRenderingMode.FILL_STROKE_MASK;
831
832 if (fillStrokeMode === _util.TextRenderingMode.FILL || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
833 if (current.fillColor !== SVG_DEFAULTS.fillColor) {
834 current.tspan.setAttributeNS(null, "fill", current.fillColor);
835 }
836
837 if (current.fillAlpha < 1) {
838 current.tspan.setAttributeNS(null, "fill-opacity", current.fillAlpha);
839 }
840 } else if (current.textRenderingMode === _util.TextRenderingMode.ADD_TO_PATH) {
841 current.tspan.setAttributeNS(null, "fill", "transparent");
842 } else {
843 current.tspan.setAttributeNS(null, "fill", "none");
844 }
845
846 if (fillStrokeMode === _util.TextRenderingMode.STROKE || fillStrokeMode === _util.TextRenderingMode.FILL_STROKE) {
847 const lineWidthScale = 1 / (current.textMatrixScale || 1);
848
849 this._setStrokeAttributes(current.tspan, lineWidthScale);
850 }
851
852 let textMatrix = current.textMatrix;
853
854 if (current.textRise !== 0) {
855 textMatrix = textMatrix.slice();
856 textMatrix[5] += current.textRise;
857 }
858
859 current.txtElement.setAttributeNS(null, "transform", `${pm(textMatrix)} scale(${pf(textHScale)}, -1)`);
860 current.txtElement.setAttributeNS(XML_NS, "xml:space", "preserve");
861 current.txtElement.appendChild(current.tspan);
862 current.txtgrp.appendChild(current.txtElement);
863
864 this._ensureTransformGroup().appendChild(current.txtElement);
865 }
866
867 setLeadingMoveText(x, y) {
868 this.setLeading(-y);
869 this.moveText(x, y);
870 }
871
872 addFontStyle(fontObj) {
873 if (!fontObj.data) {
874 throw new Error("addFontStyle: No font data available, " + 'ensure that the "fontExtraProperties" API parameter is set.');
875 }
876
877 if (!this.cssStyle) {
878 this.cssStyle = this.svgFactory.createElement("svg:style");
879 this.cssStyle.setAttributeNS(null, "type", "text/css");
880 this.defs.appendChild(this.cssStyle);
881 }
882
883 const url = (0, _util.createObjectURL)(fontObj.data, fontObj.mimetype, this.forceDataSchema);
884 this.cssStyle.textContent += `@font-face { font-family: "${fontObj.loadedName}";` + ` src: url(${url}); }\n`;
885 }
886
887 setFont(details) {
888 const current = this.current;
889 const fontObj = this.commonObjs.get(details[0]);
890 let size = details[1];
891 current.font = fontObj;
892
893 if (this.embedFonts && !fontObj.missingFile && !this.embeddedFonts[fontObj.loadedName]) {
894 this.addFontStyle(fontObj);
895 this.embeddedFonts[fontObj.loadedName] = fontObj;
896 }
897
898 current.fontMatrix = fontObj.fontMatrix || _util.FONT_IDENTITY_MATRIX;
899 let bold = "normal";
900
901 if (fontObj.black) {
902 bold = "900";
903 } else if (fontObj.bold) {
904 bold = "bold";
905 }
906
907 const italic = fontObj.italic ? "italic" : "normal";
908
909 if (size < 0) {
910 size = -size;
911 current.fontDirection = -1;
912 } else {
913 current.fontDirection = 1;
914 }
915
916 current.fontSize = size;
917 current.fontFamily = fontObj.loadedName;
918 current.fontWeight = bold;
919 current.fontStyle = italic;
920 current.tspan = this.svgFactory.createElement("svg:tspan");
921 current.tspan.setAttributeNS(null, "y", pf(-current.y));
922 current.xcoords = [];
923 current.ycoords = [];
924 }
925
926 endText() {
927 const current = this.current;
928
929 if (current.textRenderingMode & _util.TextRenderingMode.ADD_TO_PATH_FLAG && current.txtElement?.hasChildNodes()) {
930 current.element = current.txtElement;
931 this.clip("nonzero");
932 this.endPath();
933 }
934 }
935
936 setLineWidth(width) {
937 if (width > 0) {
938 this.current.lineWidth = width;
939 }
940 }
941
942 setLineCap(style) {
943 this.current.lineCap = LINE_CAP_STYLES[style];
944 }
945
946 setLineJoin(style) {
947 this.current.lineJoin = LINE_JOIN_STYLES[style];
948 }
949
950 setMiterLimit(limit) {
951 this.current.miterLimit = limit;
952 }
953
954 setStrokeAlpha(strokeAlpha) {
955 this.current.strokeAlpha = strokeAlpha;
956 }
957
958 setStrokeRGBColor(r, g, b) {
959 this.current.strokeColor = _util.Util.makeHexColor(r, g, b);
960 }
961
962 setFillAlpha(fillAlpha) {
963 this.current.fillAlpha = fillAlpha;
964 }
965
966 setFillRGBColor(r, g, b) {
967 this.current.fillColor = _util.Util.makeHexColor(r, g, b);
968 this.current.tspan = this.svgFactory.createElement("svg:tspan");
969 this.current.xcoords = [];
970 this.current.ycoords = [];
971 }
972
973 setStrokeColorN(args) {
974 this.current.strokeColor = this._makeColorN_Pattern(args);
975 }
976
977 setFillColorN(args) {
978 this.current.fillColor = this._makeColorN_Pattern(args);
979 }
980
981 shadingFill(args) {
982 const width = this.viewport.width;
983 const height = this.viewport.height;
984
985 const inv = _util.Util.inverseTransform(this.transformMatrix);
986
987 const bl = _util.Util.applyTransform([0, 0], inv);
988
989 const br = _util.Util.applyTransform([0, height], inv);
990
991 const ul = _util.Util.applyTransform([width, 0], inv);
992
993 const ur = _util.Util.applyTransform([width, height], inv);
994
995 const x0 = Math.min(bl[0], br[0], ul[0], ur[0]);
996 const y0 = Math.min(bl[1], br[1], ul[1], ur[1]);
997 const x1 = Math.max(bl[0], br[0], ul[0], ur[0]);
998 const y1 = Math.max(bl[1], br[1], ul[1], ur[1]);
999 const rect = this.svgFactory.createElement("svg:rect");
1000 rect.setAttributeNS(null, "x", x0);
1001 rect.setAttributeNS(null, "y", y0);
1002 rect.setAttributeNS(null, "width", x1 - x0);
1003 rect.setAttributeNS(null, "height", y1 - y0);
1004 rect.setAttributeNS(null, "fill", this._makeShadingPattern(args));
1005
1006 if (this.current.fillAlpha < 1) {
1007 rect.setAttributeNS(null, "fill-opacity", this.current.fillAlpha);
1008 }
1009
1010 this._ensureTransformGroup().appendChild(rect);
1011 }
1012
1013 _makeColorN_Pattern(args) {
1014 if (args[0] === "TilingPattern") {
1015 return this._makeTilingPattern(args);
1016 }
1017
1018 return this._makeShadingPattern(args);
1019 }
1020
1021 _makeTilingPattern(args) {
1022 const color = args[1];
1023 const operatorList = args[2];
1024 const matrix = args[3] || _util.IDENTITY_MATRIX;
1025 const [x0, y0, x1, y1] = args[4];
1026 const xstep = args[5];
1027 const ystep = args[6];
1028 const paintType = args[7];
1029 const tilingId = `shading${shadingCount++}`;
1030
1031 const [tx0, ty0, tx1, ty1] = _util.Util.normalizeRect([..._util.Util.applyTransform([x0, y0], matrix), ..._util.Util.applyTransform([x1, y1], matrix)]);
1032
1033 const [xscale, yscale] = _util.Util.singularValueDecompose2dScale(matrix);
1034
1035 const txstep = xstep * xscale;
1036 const tystep = ystep * yscale;
1037 const tiling = this.svgFactory.createElement("svg:pattern");
1038 tiling.setAttributeNS(null, "id", tilingId);
1039 tiling.setAttributeNS(null, "patternUnits", "userSpaceOnUse");
1040 tiling.setAttributeNS(null, "width", txstep);
1041 tiling.setAttributeNS(null, "height", tystep);
1042 tiling.setAttributeNS(null, "x", `${tx0}`);
1043 tiling.setAttributeNS(null, "y", `${ty0}`);
1044 const svg = this.svg;
1045 const transformMatrix = this.transformMatrix;
1046 const fillColor = this.current.fillColor;
1047 const strokeColor = this.current.strokeColor;
1048 const bbox = this.svgFactory.create(tx1 - tx0, ty1 - ty0);
1049 this.svg = bbox;
1050 this.transformMatrix = matrix;
1051
1052 if (paintType === 2) {
1053 const cssColor = _util.Util.makeHexColor(...color);
1054
1055 this.current.fillColor = cssColor;
1056 this.current.strokeColor = cssColor;
1057 }
1058
1059 this.executeOpTree(this.convertOpList(operatorList));
1060 this.svg = svg;
1061 this.transformMatrix = transformMatrix;
1062 this.current.fillColor = fillColor;
1063 this.current.strokeColor = strokeColor;
1064 tiling.appendChild(bbox.childNodes[0]);
1065 this.defs.appendChild(tiling);
1066 return `url(#${tilingId})`;
1067 }
1068
1069 _makeShadingPattern(args) {
1070 if (typeof args === "string") {
1071 args = this.objs.get(args);
1072 }
1073
1074 switch (args[0]) {
1075 case "RadialAxial":
1076 const shadingId = `shading${shadingCount++}`;
1077 const colorStops = args[3];
1078 let gradient;
1079
1080 switch (args[1]) {
1081 case "axial":
1082 const point0 = args[4];
1083 const point1 = args[5];
1084 gradient = this.svgFactory.createElement("svg:linearGradient");
1085 gradient.setAttributeNS(null, "id", shadingId);
1086 gradient.setAttributeNS(null, "gradientUnits", "userSpaceOnUse");
1087 gradient.setAttributeNS(null, "x1", point0[0]);
1088 gradient.setAttributeNS(null, "y1", point0[1]);
1089 gradient.setAttributeNS(null, "x2", point1[0]);
1090 gradient.setAttributeNS(null, "y2", point1[1]);
1091 break;
1092
1093 case "radial":
1094 const focalPoint = args[4];
1095 const circlePoint = args[5];
1096 const focalRadius = args[6];
1097 const circleRadius = args[7];
1098 gradient = this.svgFactory.createElement("svg:radialGradient");
1099 gradient.setAttributeNS(null, "id", shadingId);
1100 gradient.setAttributeNS(null, "gradientUnits", "userSpaceOnUse");
1101 gradient.setAttributeNS(null, "cx", circlePoint[0]);
1102 gradient.setAttributeNS(null, "cy", circlePoint[1]);
1103 gradient.setAttributeNS(null, "r", circleRadius);
1104 gradient.setAttributeNS(null, "fx", focalPoint[0]);
1105 gradient.setAttributeNS(null, "fy", focalPoint[1]);
1106 gradient.setAttributeNS(null, "fr", focalRadius);
1107 break;
1108
1109 default:
1110 throw new Error(`Unknown RadialAxial type: ${args[1]}`);
1111 }
1112
1113 for (const colorStop of colorStops) {
1114 const stop = this.svgFactory.createElement("svg:stop");
1115 stop.setAttributeNS(null, "offset", colorStop[0]);
1116 stop.setAttributeNS(null, "stop-color", colorStop[1]);
1117 gradient.appendChild(stop);
1118 }
1119
1120 this.defs.appendChild(gradient);
1121 return `url(#${shadingId})`;
1122
1123 case "Mesh":
1124 (0, _util.warn)("Unimplemented pattern Mesh");
1125 return null;
1126
1127 case "Dummy":
1128 return "hotpink";
1129
1130 default:
1131 throw new Error(`Unknown IR type: ${args[0]}`);
1132 }
1133 }
1134
1135 setDash(dashArray, dashPhase) {
1136 this.current.dashArray = dashArray;
1137 this.current.dashPhase = dashPhase;
1138 }
1139
1140 constructPath(ops, args) {
1141 const current = this.current;
1142 let x = current.x,
1143 y = current.y;
1144 let d = [];
1145 let j = 0;
1146
1147 for (const op of ops) {
1148 switch (op | 0) {
1149 case _util.OPS.rectangle:
1150 x = args[j++];
1151 y = args[j++];
1152 const width = args[j++];
1153 const height = args[j++];
1154 const xw = x + width;
1155 const yh = y + height;
1156 d.push("M", pf(x), pf(y), "L", pf(xw), pf(y), "L", pf(xw), pf(yh), "L", pf(x), pf(yh), "Z");
1157 break;
1158
1159 case _util.OPS.moveTo:
1160 x = args[j++];
1161 y = args[j++];
1162 d.push("M", pf(x), pf(y));
1163 break;
1164
1165 case _util.OPS.lineTo:
1166 x = args[j++];
1167 y = args[j++];
1168 d.push("L", pf(x), pf(y));
1169 break;
1170
1171 case _util.OPS.curveTo:
1172 x = args[j + 4];
1173 y = args[j + 5];
1174 d.push("C", pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3]), pf(x), pf(y));
1175 j += 6;
1176 break;
1177
1178 case _util.OPS.curveTo2:
1179 d.push("C", pf(x), pf(y), pf(args[j]), pf(args[j + 1]), pf(args[j + 2]), pf(args[j + 3]));
1180 x = args[j + 2];
1181 y = args[j + 3];
1182 j += 4;
1183 break;
1184
1185 case _util.OPS.curveTo3:
1186 x = args[j + 2];
1187 y = args[j + 3];
1188 d.push("C", pf(args[j]), pf(args[j + 1]), pf(x), pf(y), pf(x), pf(y));
1189 j += 4;
1190 break;
1191
1192 case _util.OPS.closePath:
1193 d.push("Z");
1194 break;
1195 }
1196 }
1197
1198 d = d.join(" ");
1199
1200 if (current.path && ops.length > 0 && ops[0] !== _util.OPS.rectangle && ops[0] !== _util.OPS.moveTo) {
1201 d = current.path.getAttributeNS(null, "d") + d;
1202 } else {
1203 current.path = this.svgFactory.createElement("svg:path");
1204
1205 this._ensureTransformGroup().appendChild(current.path);
1206 }
1207
1208 current.path.setAttributeNS(null, "d", d);
1209 current.path.setAttributeNS(null, "fill", "none");
1210 current.element = current.path;
1211 current.setCurrentPoint(x, y);
1212 }
1213
1214 endPath() {
1215 const current = this.current;
1216 current.path = null;
1217
1218 if (!this.pendingClip) {
1219 return;
1220 }
1221
1222 if (!current.element) {
1223 this.pendingClip = null;
1224 return;
1225 }
1226
1227 const clipId = `clippath${clipCount++}`;
1228 const clipPath = this.svgFactory.createElement("svg:clipPath");
1229 clipPath.setAttributeNS(null, "id", clipId);
1230 clipPath.setAttributeNS(null, "transform", pm(this.transformMatrix));
1231 const clipElement = current.element.cloneNode(true);
1232
1233 if (this.pendingClip === "evenodd") {
1234 clipElement.setAttributeNS(null, "clip-rule", "evenodd");
1235 } else {
1236 clipElement.setAttributeNS(null, "clip-rule", "nonzero");
1237 }
1238
1239 this.pendingClip = null;
1240 clipPath.appendChild(clipElement);
1241 this.defs.appendChild(clipPath);
1242
1243 if (current.activeClipUrl) {
1244 current.clipGroup = null;
1245
1246 for (const prev of this.extraStack) {
1247 prev.clipGroup = null;
1248 }
1249
1250 clipPath.setAttributeNS(null, "clip-path", current.activeClipUrl);
1251 }
1252
1253 current.activeClipUrl = `url(#${clipId})`;
1254 this.tgrp = null;
1255 }
1256
1257 clip(type) {
1258 this.pendingClip = type;
1259 }
1260
1261 closePath() {
1262 const current = this.current;
1263
1264 if (current.path) {
1265 const d = `${current.path.getAttributeNS(null, "d")}Z`;
1266 current.path.setAttributeNS(null, "d", d);
1267 }
1268 }
1269
1270 setLeading(leading) {
1271 this.current.leading = -leading;
1272 }
1273
1274 setTextRise(textRise) {
1275 this.current.textRise = textRise;
1276 }
1277
1278 setTextRenderingMode(textRenderingMode) {
1279 this.current.textRenderingMode = textRenderingMode;
1280 }
1281
1282 setHScale(scale) {
1283 this.current.textHScale = scale / 100;
1284 }
1285
1286 setRenderingIntent(intent) {}
1287
1288 setFlatness(flatness) {}
1289
1290 setGState(states) {
1291 for (const [key, value] of states) {
1292 switch (key) {
1293 case "LW":
1294 this.setLineWidth(value);
1295 break;
1296
1297 case "LC":
1298 this.setLineCap(value);
1299 break;
1300
1301 case "LJ":
1302 this.setLineJoin(value);
1303 break;
1304
1305 case "ML":
1306 this.setMiterLimit(value);
1307 break;
1308
1309 case "D":
1310 this.setDash(value[0], value[1]);
1311 break;
1312
1313 case "RI":
1314 this.setRenderingIntent(value);
1315 break;
1316
1317 case "FL":
1318 this.setFlatness(value);
1319 break;
1320
1321 case "Font":
1322 this.setFont(value);
1323 break;
1324
1325 case "CA":
1326 this.setStrokeAlpha(value);
1327 break;
1328
1329 case "ca":
1330 this.setFillAlpha(value);
1331 break;
1332
1333 default:
1334 (0, _util.warn)(`Unimplemented graphic state operator ${key}`);
1335 break;
1336 }
1337 }
1338 }
1339
1340 fill() {
1341 const current = this.current;
1342
1343 if (current.element) {
1344 current.element.setAttributeNS(null, "fill", current.fillColor);
1345 current.element.setAttributeNS(null, "fill-opacity", current.fillAlpha);
1346 this.endPath();
1347 }
1348 }
1349
1350 stroke() {
1351 const current = this.current;
1352
1353 if (current.element) {
1354 this._setStrokeAttributes(current.element);
1355
1356 current.element.setAttributeNS(null, "fill", "none");
1357 this.endPath();
1358 }
1359 }
1360
1361 _setStrokeAttributes(element, lineWidthScale = 1) {
1362 const current = this.current;
1363 let dashArray = current.dashArray;
1364
1365 if (lineWidthScale !== 1 && dashArray.length > 0) {
1366 dashArray = dashArray.map(function (value) {
1367 return lineWidthScale * value;
1368 });
1369 }
1370
1371 element.setAttributeNS(null, "stroke", current.strokeColor);
1372 element.setAttributeNS(null, "stroke-opacity", current.strokeAlpha);
1373 element.setAttributeNS(null, "stroke-miterlimit", pf(current.miterLimit));
1374 element.setAttributeNS(null, "stroke-linecap", current.lineCap);
1375 element.setAttributeNS(null, "stroke-linejoin", current.lineJoin);
1376 element.setAttributeNS(null, "stroke-width", pf(lineWidthScale * current.lineWidth) + "px");
1377 element.setAttributeNS(null, "stroke-dasharray", dashArray.map(pf).join(" "));
1378 element.setAttributeNS(null, "stroke-dashoffset", pf(lineWidthScale * current.dashPhase) + "px");
1379 }
1380
1381 eoFill() {
1382 if (this.current.element) {
1383 this.current.element.setAttributeNS(null, "fill-rule", "evenodd");
1384 }
1385
1386 this.fill();
1387 }
1388
1389 fillStroke() {
1390 this.stroke();
1391 this.fill();
1392 }
1393
1394 eoFillStroke() {
1395 if (this.current.element) {
1396 this.current.element.setAttributeNS(null, "fill-rule", "evenodd");
1397 }
1398
1399 this.fillStroke();
1400 }
1401
1402 closeStroke() {
1403 this.closePath();
1404 this.stroke();
1405 }
1406
1407 closeFillStroke() {
1408 this.closePath();
1409 this.fillStroke();
1410 }
1411
1412 closeEOFillStroke() {
1413 this.closePath();
1414 this.eoFillStroke();
1415 }
1416
1417 paintSolidColorImageMask() {
1418 const rect = this.svgFactory.createElement("svg:rect");
1419 rect.setAttributeNS(null, "x", "0");
1420 rect.setAttributeNS(null, "y", "0");
1421 rect.setAttributeNS(null, "width", "1px");
1422 rect.setAttributeNS(null, "height", "1px");
1423 rect.setAttributeNS(null, "fill", this.current.fillColor);
1424
1425 this._ensureTransformGroup().appendChild(rect);
1426 }
1427
1428 paintImageXObject(objId) {
1429 const imgData = objId.startsWith("g_") ? this.commonObjs.get(objId) : this.objs.get(objId);
1430
1431 if (!imgData) {
1432 (0, _util.warn)(`Dependent image with object ID ${objId} is not ready yet`);
1433 return;
1434 }
1435
1436 this.paintInlineImageXObject(imgData);
1437 }
1438
1439 paintInlineImageXObject(imgData, mask) {
1440 const width = imgData.width;
1441 const height = imgData.height;
1442 const imgSrc = convertImgDataToPng(imgData, this.forceDataSchema, !!mask);
1443 const cliprect = this.svgFactory.createElement("svg:rect");
1444 cliprect.setAttributeNS(null, "x", "0");
1445 cliprect.setAttributeNS(null, "y", "0");
1446 cliprect.setAttributeNS(null, "width", pf(width));
1447 cliprect.setAttributeNS(null, "height", pf(height));
1448 this.current.element = cliprect;
1449 this.clip("nonzero");
1450 const imgEl = this.svgFactory.createElement("svg:image");
1451 imgEl.setAttributeNS(XLINK_NS, "xlink:href", imgSrc);
1452 imgEl.setAttributeNS(null, "x", "0");
1453 imgEl.setAttributeNS(null, "y", pf(-height));
1454 imgEl.setAttributeNS(null, "width", pf(width) + "px");
1455 imgEl.setAttributeNS(null, "height", pf(height) + "px");
1456 imgEl.setAttributeNS(null, "transform", `scale(${pf(1 / width)} ${pf(-1 / height)})`);
1457
1458 if (mask) {
1459 mask.appendChild(imgEl);
1460 } else {
1461 this._ensureTransformGroup().appendChild(imgEl);
1462 }
1463 }
1464
1465 paintImageMaskXObject(imgData) {
1466 const current = this.current;
1467 const width = imgData.width;
1468 const height = imgData.height;
1469 const fillColor = current.fillColor;
1470 current.maskId = `mask${maskCount++}`;
1471 const mask = this.svgFactory.createElement("svg:mask");
1472 mask.setAttributeNS(null, "id", current.maskId);
1473 const rect = this.svgFactory.createElement("svg:rect");
1474 rect.setAttributeNS(null, "x", "0");
1475 rect.setAttributeNS(null, "y", "0");
1476 rect.setAttributeNS(null, "width", pf(width));
1477 rect.setAttributeNS(null, "height", pf(height));
1478 rect.setAttributeNS(null, "fill", fillColor);
1479 rect.setAttributeNS(null, "mask", `url(#${current.maskId})`);
1480 this.defs.appendChild(mask);
1481
1482 this._ensureTransformGroup().appendChild(rect);
1483
1484 this.paintInlineImageXObject(imgData, mask);
1485 }
1486
1487 paintFormXObjectBegin(matrix, bbox) {
1488 if (Array.isArray(matrix) && matrix.length === 6) {
1489 this.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
1490 }
1491
1492 if (bbox) {
1493 const width = bbox[2] - bbox[0];
1494 const height = bbox[3] - bbox[1];
1495 const cliprect = this.svgFactory.createElement("svg:rect");
1496 cliprect.setAttributeNS(null, "x", bbox[0]);
1497 cliprect.setAttributeNS(null, "y", bbox[1]);
1498 cliprect.setAttributeNS(null, "width", pf(width));
1499 cliprect.setAttributeNS(null, "height", pf(height));
1500 this.current.element = cliprect;
1501 this.clip("nonzero");
1502 this.endPath();
1503 }
1504 }
1505
1506 paintFormXObjectEnd() {}
1507
1508 _initialize(viewport) {
1509 const svg = this.svgFactory.create(viewport.width, viewport.height);
1510 const definitions = this.svgFactory.createElement("svg:defs");
1511 svg.appendChild(definitions);
1512 this.defs = definitions;
1513 const rootGroup = this.svgFactory.createElement("svg:g");
1514 rootGroup.setAttributeNS(null, "transform", pm(viewport.transform));
1515 svg.appendChild(rootGroup);
1516 this.svg = rootGroup;
1517 return svg;
1518 }
1519
1520 _ensureClipGroup() {
1521 if (!this.current.clipGroup) {
1522 const clipGroup = this.svgFactory.createElement("svg:g");
1523 clipGroup.setAttributeNS(null, "clip-path", this.current.activeClipUrl);
1524 this.svg.appendChild(clipGroup);
1525 this.current.clipGroup = clipGroup;
1526 }
1527
1528 return this.current.clipGroup;
1529 }
1530
1531 _ensureTransformGroup() {
1532 if (!this.tgrp) {
1533 this.tgrp = this.svgFactory.createElement("svg:g");
1534 this.tgrp.setAttributeNS(null, "transform", pm(this.transformMatrix));
1535
1536 if (this.current.activeClipUrl) {
1537 this._ensureClipGroup().appendChild(this.tgrp);
1538 } else {
1539 this.svg.appendChild(this.tgrp);
1540 }
1541 }
1542
1543 return this.tgrp;
1544 }
1545
1546 };
1547}
\No newline at end of file