source: imaps-frontend/node_modules/canvg/lib/index.es.js@ 79a0317

main
Last change on this file since 79a0317 was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 3 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 176.0 KB
Line 
1import 'core-js/modules/es.promise.js';
2import _asyncToGenerator from '@babel/runtime/helpers/asyncToGenerator';
3import 'core-js/modules/es.string.match.js';
4import 'core-js/modules/es.string.replace.js';
5import 'core-js/modules/es.string.starts-with.js';
6import 'core-js/modules/es.array.iterator.js';
7import 'core-js/modules/web.dom-collections.iterator.js';
8import _defineProperty from '@babel/runtime/helpers/defineProperty';
9import 'core-js/modules/es.array.reduce.js';
10import 'core-js/modules/es.string.ends-with.js';
11import 'core-js/modules/es.string.split.js';
12import requestAnimationFrame from 'raf';
13import 'core-js/modules/es.string.trim.js';
14import RGBColor from 'rgbcolor';
15import 'core-js/modules/es.array.index-of.js';
16import 'core-js/modules/es.string.includes.js';
17import 'core-js/modules/es.array.reverse.js';
18import { SVGPathData } from 'svg-pathdata';
19import 'core-js/modules/es.regexp.to-string.js';
20import { canvasRGBA } from 'stackblur-canvas';
21
22/**
23 * Options preset for `OffscreenCanvas`.
24 * @param config - Preset requirements.
25 * @param config.DOMParser - XML/HTML parser from string into DOM Document.
26 * @returns Preset object.
27 */
28function offscreen() {
29 var {
30 DOMParser: DOMParserFallback
31 } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
32 var preset = {
33 window: null,
34 ignoreAnimation: true,
35 ignoreMouse: true,
36 DOMParser: DOMParserFallback,
37
38 createCanvas(width, height) {
39 return new OffscreenCanvas(width, height);
40 },
41
42 createImage(url) {
43 return _asyncToGenerator(function* () {
44 var response = yield fetch(url);
45 var blob = yield response.blob();
46 var img = yield createImageBitmap(blob);
47 return img;
48 })();
49 }
50
51 };
52
53 if (typeof DOMParser !== 'undefined' || typeof DOMParserFallback === 'undefined') {
54 Reflect.deleteProperty(preset, 'DOMParser');
55 }
56
57 return preset;
58}
59
60/**
61 * Options preset for `node-canvas`.
62 * @param config - Preset requirements.
63 * @param config.DOMParser - XML/HTML parser from string into DOM Document.
64 * @param config.canvas - `node-canvas` exports.
65 * @param config.fetch - WHATWG-compatible `fetch` function.
66 * @returns Preset object.
67 */
68function node(_ref) {
69 var {
70 DOMParser,
71 canvas,
72 fetch
73 } = _ref;
74 return {
75 window: null,
76 ignoreAnimation: true,
77 ignoreMouse: true,
78 DOMParser,
79 fetch,
80 createCanvas: canvas.createCanvas,
81 createImage: canvas.loadImage
82 };
83}
84
85var index = /*#__PURE__*/Object.freeze({
86 __proto__: null,
87 offscreen: offscreen,
88 node: node
89});
90
91/**
92 * HTML-safe compress white-spaces.
93 * @param str - String to compress.
94 * @returns String.
95 */
96function compressSpaces(str) {
97 return str.replace(/(?!\u3000)\s+/gm, ' ');
98}
99/**
100 * HTML-safe left trim.
101 * @param str - String to trim.
102 * @returns String.
103 */
104
105function trimLeft(str) {
106 return str.replace(/^[\n \t]+/, '');
107}
108/**
109 * HTML-safe right trim.
110 * @param str - String to trim.
111 * @returns String.
112 */
113
114function trimRight(str) {
115 return str.replace(/[\n \t]+$/, '');
116}
117/**
118 * String to numbers array.
119 * @param str - Numbers string.
120 * @returns Numbers array.
121 */
122
123function toNumbers(str) {
124 var matches = (str || '').match(/-?(\d+(?:\.\d*(?:[eE][+-]?\d+)?)?|\.\d+)(?=\D|$)/gm) || [];
125 return matches.map(parseFloat);
126} // Microsoft Edge fix
127
128var allUppercase = /^[A-Z-]+$/;
129/**
130 * Normalize attribute name.
131 * @param name - Attribute name.
132 * @returns Normalized attribute name.
133 */
134
135function normalizeAttributeName(name) {
136 if (allUppercase.test(name)) {
137 return name.toLowerCase();
138 }
139
140 return name;
141}
142/**
143 * Parse external URL.
144 * @param url - CSS url string.
145 * @returns Parsed URL.
146 */
147
148function parseExternalUrl(url) {
149 // single quotes [2]
150 // v double quotes [3]
151 // v v no quotes [4]
152 // v v v
153 var urlMatch = /url\(('([^']+)'|"([^"]+)"|([^'")]+))\)/.exec(url) || [];
154 return urlMatch[2] || urlMatch[3] || urlMatch[4];
155}
156/**
157 * Transform floats to integers in rgb colors.
158 * @param color - Color to normalize.
159 * @returns Normalized color.
160 */
161
162function normalizeColor(color) {
163 if (!color.startsWith('rgb')) {
164 return color;
165 }
166
167 var rgbParts = 3;
168 var normalizedColor = color.replace(/\d+(\.\d+)?/g, (num, isFloat) => rgbParts-- && isFloat ? String(Math.round(parseFloat(num))) : num);
169 return normalizedColor;
170}
171
172// slightly modified version of https://github.com/keeganstreet/specificity/blob/master/specificity.js
173var attributeRegex = /(\[[^\]]+\])/g;
174var idRegex = /(#[^\s+>~.[:]+)/g;
175var classRegex = /(\.[^\s+>~.[:]+)/g;
176var pseudoElementRegex = /(::[^\s+>~.[:]+|:first-line|:first-letter|:before|:after)/gi;
177var pseudoClassWithBracketsRegex = /(:[\w-]+\([^)]*\))/gi;
178var pseudoClassRegex = /(:[^\s+>~.[:]+)/g;
179var elementRegex = /([^\s+>~.[:]+)/g;
180
181function findSelectorMatch(selector, regex) {
182 var matches = regex.exec(selector);
183
184 if (!matches) {
185 return [selector, 0];
186 }
187
188 return [selector.replace(regex, ' '), matches.length];
189}
190/**
191 * Measure selector specificity.
192 * @param selector - Selector to measure.
193 * @returns Specificity.
194 */
195
196
197function getSelectorSpecificity(selector) {
198 var specificity = [0, 0, 0];
199 var currentSelector = selector.replace(/:not\(([^)]*)\)/g, ' $1 ').replace(/{[\s\S]*/gm, ' ');
200 var delta = 0;
201 [currentSelector, delta] = findSelectorMatch(currentSelector, attributeRegex);
202 specificity[1] += delta;
203 [currentSelector, delta] = findSelectorMatch(currentSelector, idRegex);
204 specificity[0] += delta;
205 [currentSelector, delta] = findSelectorMatch(currentSelector, classRegex);
206 specificity[1] += delta;
207 [currentSelector, delta] = findSelectorMatch(currentSelector, pseudoElementRegex);
208 specificity[2] += delta;
209 [currentSelector, delta] = findSelectorMatch(currentSelector, pseudoClassWithBracketsRegex);
210 specificity[1] += delta;
211 [currentSelector, delta] = findSelectorMatch(currentSelector, pseudoClassRegex);
212 specificity[1] += delta;
213 currentSelector = currentSelector.replace(/[*\s+>~]/g, ' ').replace(/[#.]/g, ' ');
214 [currentSelector, delta] = findSelectorMatch(currentSelector, elementRegex); // lgtm [js/useless-assignment-to-local]
215
216 specificity[2] += delta;
217 return specificity.join('');
218}
219
220var PSEUDO_ZERO = .00000001;
221/**
222 * Vector magnitude.
223 * @param v
224 * @returns Number result.
225 */
226
227function vectorMagnitude(v) {
228 return Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2));
229}
230/**
231 * Ratio between two vectors.
232 * @param u
233 * @param v
234 * @returns Number result.
235 */
236
237function vectorsRatio(u, v) {
238 return (u[0] * v[0] + u[1] * v[1]) / (vectorMagnitude(u) * vectorMagnitude(v));
239}
240/**
241 * Angle between two vectors.
242 * @param u
243 * @param v
244 * @returns Number result.
245 */
246
247function vectorsAngle(u, v) {
248 return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vectorsRatio(u, v));
249}
250function CB1(t) {
251 return t * t * t;
252}
253function CB2(t) {
254 return 3 * t * t * (1 - t);
255}
256function CB3(t) {
257 return 3 * t * (1 - t) * (1 - t);
258}
259function CB4(t) {
260 return (1 - t) * (1 - t) * (1 - t);
261}
262function QB1(t) {
263 return t * t;
264}
265function QB2(t) {
266 return 2 * t * (1 - t);
267}
268function QB3(t) {
269 return (1 - t) * (1 - t);
270}
271
272class Property {
273 constructor(document, name, value) {
274 this.document = document;
275 this.name = name;
276 this.value = value;
277 this.isNormalizedColor = false;
278 }
279
280 static empty(document) {
281 return new Property(document, 'EMPTY', '');
282 }
283
284 split() {
285 var separator = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ' ';
286 var {
287 document,
288 name
289 } = this;
290 return compressSpaces(this.getString()).trim().split(separator).map(value => new Property(document, name, value));
291 }
292
293 hasValue(zeroIsValue) {
294 var {
295 value
296 } = this;
297 return value !== null && value !== '' && (zeroIsValue || value !== 0) && typeof value !== 'undefined';
298 }
299
300 isString(regexp) {
301 var {
302 value
303 } = this;
304 var result = typeof value === 'string';
305
306 if (!result || !regexp) {
307 return result;
308 }
309
310 return regexp.test(value);
311 }
312
313 isUrlDefinition() {
314 return this.isString(/^url\(/);
315 }
316
317 isPixels() {
318 if (!this.hasValue()) {
319 return false;
320 }
321
322 var asString = this.getString();
323
324 switch (true) {
325 case asString.endsWith('px'):
326 case /^[0-9]+$/.test(asString):
327 return true;
328
329 default:
330 return false;
331 }
332 }
333
334 setValue(value) {
335 this.value = value;
336 return this;
337 }
338
339 getValue(def) {
340 if (typeof def === 'undefined' || this.hasValue()) {
341 return this.value;
342 }
343
344 return def;
345 }
346
347 getNumber(def) {
348 if (!this.hasValue()) {
349 if (typeof def === 'undefined') {
350 return 0;
351 }
352
353 return parseFloat(def);
354 }
355
356 var {
357 value
358 } = this;
359 var n = parseFloat(value);
360
361 if (this.isString(/%$/)) {
362 n /= 100.0;
363 }
364
365 return n;
366 }
367
368 getString(def) {
369 if (typeof def === 'undefined' || this.hasValue()) {
370 return typeof this.value === 'undefined' ? '' : String(this.value);
371 }
372
373 return String(def);
374 }
375
376 getColor(def) {
377 var color = this.getString(def);
378
379 if (this.isNormalizedColor) {
380 return color;
381 }
382
383 this.isNormalizedColor = true;
384 color = normalizeColor(color);
385 this.value = color;
386 return color;
387 }
388
389 getDpi() {
390 return 96.0; // TODO: compute?
391 }
392
393 getRem() {
394 return this.document.rootEmSize;
395 }
396
397 getEm() {
398 return this.document.emSize;
399 }
400
401 getUnits() {
402 return this.getString().replace(/[0-9.-]/g, '');
403 }
404
405 getPixels(axisOrIsFontSize) {
406 var processPercent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
407
408 if (!this.hasValue()) {
409 return 0;
410 }
411
412 var [axis, isFontSize] = typeof axisOrIsFontSize === 'boolean' ? [undefined, axisOrIsFontSize] : [axisOrIsFontSize];
413 var {
414 viewPort
415 } = this.document.screen;
416
417 switch (true) {
418 case this.isString(/vmin$/):
419 return this.getNumber() / 100.0 * Math.min(viewPort.computeSize('x'), viewPort.computeSize('y'));
420
421 case this.isString(/vmax$/):
422 return this.getNumber() / 100.0 * Math.max(viewPort.computeSize('x'), viewPort.computeSize('y'));
423
424 case this.isString(/vw$/):
425 return this.getNumber() / 100.0 * viewPort.computeSize('x');
426
427 case this.isString(/vh$/):
428 return this.getNumber() / 100.0 * viewPort.computeSize('y');
429
430 case this.isString(/rem$/):
431 return this.getNumber() * this.getRem();
432
433 case this.isString(/em$/):
434 return this.getNumber() * this.getEm();
435
436 case this.isString(/ex$/):
437 return this.getNumber() * this.getEm() / 2.0;
438
439 case this.isString(/px$/):
440 return this.getNumber();
441
442 case this.isString(/pt$/):
443 return this.getNumber() * this.getDpi() * (1.0 / 72.0);
444
445 case this.isString(/pc$/):
446 return this.getNumber() * 15;
447
448 case this.isString(/cm$/):
449 return this.getNumber() * this.getDpi() / 2.54;
450
451 case this.isString(/mm$/):
452 return this.getNumber() * this.getDpi() / 25.4;
453
454 case this.isString(/in$/):
455 return this.getNumber() * this.getDpi();
456
457 case this.isString(/%$/) && isFontSize:
458 return this.getNumber() * this.getEm();
459
460 case this.isString(/%$/):
461 return this.getNumber() * viewPort.computeSize(axis);
462
463 default:
464 {
465 var n = this.getNumber();
466
467 if (processPercent && n < 1.0) {
468 return n * viewPort.computeSize(axis);
469 }
470
471 return n;
472 }
473 }
474 }
475
476 getMilliseconds() {
477 if (!this.hasValue()) {
478 return 0;
479 }
480
481 if (this.isString(/ms$/)) {
482 return this.getNumber();
483 }
484
485 return this.getNumber() * 1000;
486 }
487
488 getRadians() {
489 if (!this.hasValue()) {
490 return 0;
491 }
492
493 switch (true) {
494 case this.isString(/deg$/):
495 return this.getNumber() * (Math.PI / 180.0);
496
497 case this.isString(/grad$/):
498 return this.getNumber() * (Math.PI / 200.0);
499
500 case this.isString(/rad$/):
501 return this.getNumber();
502
503 default:
504 return this.getNumber() * (Math.PI / 180.0);
505 }
506 }
507
508 getDefinition() {
509 var asString = this.getString();
510 var name = /#([^)'"]+)/.exec(asString);
511
512 if (name) {
513 name = name[1];
514 }
515
516 if (!name) {
517 name = asString;
518 }
519
520 return this.document.definitions[name];
521 }
522
523 getFillStyleDefinition(element, opacity) {
524 var def = this.getDefinition();
525
526 if (!def) {
527 return null;
528 } // gradient
529
530
531 if (typeof def.createGradient === 'function') {
532 return def.createGradient(this.document.ctx, element, opacity);
533 } // pattern
534
535
536 if (typeof def.createPattern === 'function') {
537 if (def.getHrefAttribute().hasValue()) {
538 var patternTransform = def.getAttribute('patternTransform');
539 def = def.getHrefAttribute().getDefinition();
540
541 if (patternTransform.hasValue()) {
542 def.getAttribute('patternTransform', true).setValue(patternTransform.value);
543 }
544 }
545
546 return def.createPattern(this.document.ctx, element, opacity);
547 }
548
549 return null;
550 }
551
552 getTextBaseline() {
553 if (!this.hasValue()) {
554 return null;
555 }
556
557 return Property.textBaselineMapping[this.getString()];
558 }
559
560 addOpacity(opacity) {
561 var value = this.getColor();
562 var len = value.length;
563 var commas = 0; // Simulate old RGBColor version, which can't parse rgba.
564
565 for (var i = 0; i < len; i++) {
566 if (value[i] === ',') {
567 commas++;
568 }
569
570 if (commas === 3) {
571 break;
572 }
573 }
574
575 if (opacity.hasValue() && this.isString() && commas !== 3) {
576 var color = new RGBColor(value);
577
578 if (color.ok) {
579 color.alpha = opacity.getNumber();
580 value = color.toRGBA();
581 }
582 }
583
584 return new Property(this.document, this.name, value);
585 }
586
587}
588Property.textBaselineMapping = {
589 'baseline': 'alphabetic',
590 'before-edge': 'top',
591 'text-before-edge': 'top',
592 'middle': 'middle',
593 'central': 'middle',
594 'after-edge': 'bottom',
595 'text-after-edge': 'bottom',
596 'ideographic': 'ideographic',
597 'alphabetic': 'alphabetic',
598 'hanging': 'hanging',
599 'mathematical': 'alphabetic'
600};
601
602class ViewPort {
603 constructor() {
604 this.viewPorts = [];
605 }
606
607 clear() {
608 this.viewPorts = [];
609 }
610
611 setCurrent(width, height) {
612 this.viewPorts.push({
613 width,
614 height
615 });
616 }
617
618 removeCurrent() {
619 this.viewPorts.pop();
620 }
621
622 getCurrent() {
623 var {
624 viewPorts
625 } = this;
626 return viewPorts[viewPorts.length - 1];
627 }
628
629 get width() {
630 return this.getCurrent().width;
631 }
632
633 get height() {
634 return this.getCurrent().height;
635 }
636
637 computeSize(d) {
638 if (typeof d === 'number') {
639 return d;
640 }
641
642 if (d === 'x') {
643 return this.width;
644 }
645
646 if (d === 'y') {
647 return this.height;
648 }
649
650 return Math.sqrt(Math.pow(this.width, 2) + Math.pow(this.height, 2)) / Math.sqrt(2);
651 }
652
653}
654
655class Point {
656 constructor(x, y) {
657 this.x = x;
658 this.y = y;
659 }
660
661 static parse(point) {
662 var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
663 var [x = defaultValue, y = defaultValue] = toNumbers(point);
664 return new Point(x, y);
665 }
666
667 static parseScale(scale) {
668 var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
669 var [x = defaultValue, y = x] = toNumbers(scale);
670 return new Point(x, y);
671 }
672
673 static parsePath(path) {
674 var points = toNumbers(path);
675 var len = points.length;
676 var pathPoints = [];
677
678 for (var i = 0; i < len; i += 2) {
679 pathPoints.push(new Point(points[i], points[i + 1]));
680 }
681
682 return pathPoints;
683 }
684
685 angleTo(point) {
686 return Math.atan2(point.y - this.y, point.x - this.x);
687 }
688
689 applyTransform(transform) {
690 var {
691 x,
692 y
693 } = this;
694 var xp = x * transform[0] + y * transform[2] + transform[4];
695 var yp = x * transform[1] + y * transform[3] + transform[5];
696 this.x = xp;
697 this.y = yp;
698 }
699
700}
701
702class Mouse {
703 constructor(screen) {
704 this.screen = screen;
705 this.working = false;
706 this.events = [];
707 this.eventElements = []; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
708
709 this.onClick = this.onClick.bind(this); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
710
711 this.onMouseMove = this.onMouseMove.bind(this);
712 }
713
714 isWorking() {
715 return this.working;
716 }
717
718 start() {
719 if (this.working) {
720 return;
721 }
722
723 var {
724 screen,
725 onClick,
726 onMouseMove
727 } = this;
728 var canvas = screen.ctx.canvas;
729 canvas.onclick = onClick;
730 canvas.onmousemove = onMouseMove;
731 this.working = true;
732 }
733
734 stop() {
735 if (!this.working) {
736 return;
737 }
738
739 var canvas = this.screen.ctx.canvas;
740 this.working = false;
741 canvas.onclick = null;
742 canvas.onmousemove = null;
743 }
744
745 hasEvents() {
746 return this.working && this.events.length > 0;
747 }
748
749 runEvents() {
750 if (!this.working) {
751 return;
752 }
753
754 var {
755 screen: document,
756 events,
757 eventElements
758 } = this;
759 var {
760 style
761 } = document.ctx.canvas;
762
763 if (style) {
764 style.cursor = '';
765 }
766
767 events.forEach((_ref, i) => {
768 var {
769 run
770 } = _ref;
771 var element = eventElements[i];
772
773 while (element) {
774 run(element);
775 element = element.parent;
776 }
777 }); // done running, clear
778
779 this.events = [];
780 this.eventElements = [];
781 }
782
783 checkPath(element, ctx) {
784 if (!this.working || !ctx) {
785 return;
786 }
787
788 var {
789 events,
790 eventElements
791 } = this;
792 events.forEach((_ref2, i) => {
793 var {
794 x,
795 y
796 } = _ref2;
797
798 if (!eventElements[i] && ctx.isPointInPath && ctx.isPointInPath(x, y)) {
799 eventElements[i] = element;
800 }
801 });
802 }
803
804 checkBoundingBox(element, boundingBox) {
805 if (!this.working || !boundingBox) {
806 return;
807 }
808
809 var {
810 events,
811 eventElements
812 } = this;
813 events.forEach((_ref3, i) => {
814 var {
815 x,
816 y
817 } = _ref3;
818
819 if (!eventElements[i] && boundingBox.isPointInBox(x, y)) {
820 eventElements[i] = element;
821 }
822 });
823 }
824
825 mapXY(x, y) {
826 var {
827 window,
828 ctx
829 } = this.screen;
830 var point = new Point(x, y);
831 var element = ctx.canvas;
832
833 while (element) {
834 point.x -= element.offsetLeft;
835 point.y -= element.offsetTop;
836 element = element.offsetParent;
837 }
838
839 if (window.scrollX) {
840 point.x += window.scrollX;
841 }
842
843 if (window.scrollY) {
844 point.y += window.scrollY;
845 }
846
847 return point;
848 }
849
850 onClick(event) {
851 var {
852 x,
853 y
854 } = this.mapXY(event.clientX, event.clientY);
855 this.events.push({
856 type: 'onclick',
857 x,
858 y,
859
860 run(eventTarget) {
861 if (eventTarget.onClick) {
862 eventTarget.onClick();
863 }
864 }
865
866 });
867 }
868
869 onMouseMove(event) {
870 var {
871 x,
872 y
873 } = this.mapXY(event.clientX, event.clientY);
874 this.events.push({
875 type: 'onmousemove',
876 x,
877 y,
878
879 run(eventTarget) {
880 if (eventTarget.onMouseMove) {
881 eventTarget.onMouseMove();
882 }
883 }
884
885 });
886 }
887
888}
889
890var defaultWindow = typeof window !== 'undefined' ? window : null;
891var defaultFetch$1 = typeof fetch !== 'undefined' ? fetch.bind(undefined) // `fetch` depends on context: `someObject.fetch(...)` will throw error.
892: null;
893class Screen {
894 constructor(ctx) {
895 var {
896 fetch = defaultFetch$1,
897 window = defaultWindow
898 } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
899 this.ctx = ctx;
900 this.FRAMERATE = 30;
901 this.MAX_VIRTUAL_PIXELS = 30000;
902 this.CLIENT_WIDTH = 800;
903 this.CLIENT_HEIGHT = 600;
904 this.viewPort = new ViewPort();
905 this.mouse = new Mouse(this);
906 this.animations = [];
907 this.waits = [];
908 this.frameDuration = 0;
909 this.isReadyLock = false;
910 this.isFirstRender = true;
911 this.intervalId = null;
912 this.window = window;
913 this.fetch = fetch;
914 }
915
916 wait(checker) {
917 this.waits.push(checker);
918 }
919
920 ready() {
921 // eslint-disable-next-line @typescript-eslint/no-misused-promises
922 if (!this.readyPromise) {
923 return Promise.resolve();
924 }
925
926 return this.readyPromise;
927 }
928
929 isReady() {
930 if (this.isReadyLock) {
931 return true;
932 }
933
934 var isReadyLock = this.waits.every(_ => _());
935
936 if (isReadyLock) {
937 this.waits = [];
938
939 if (this.resolveReady) {
940 this.resolveReady();
941 }
942 }
943
944 this.isReadyLock = isReadyLock;
945 return isReadyLock;
946 }
947
948 setDefaults(ctx) {
949 // initial values and defaults
950 ctx.strokeStyle = 'rgba(0,0,0,0)';
951 ctx.lineCap = 'butt';
952 ctx.lineJoin = 'miter';
953 ctx.miterLimit = 4;
954 }
955
956 setViewBox(_ref) {
957 var {
958 document,
959 ctx,
960 aspectRatio,
961 width,
962 desiredWidth,
963 height,
964 desiredHeight,
965 minX = 0,
966 minY = 0,
967 refX,
968 refY,
969 clip = false,
970 clipX = 0,
971 clipY = 0
972 } = _ref;
973 // aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
974 var cleanAspectRatio = compressSpaces(aspectRatio).replace(/^defer\s/, ''); // ignore defer
975
976 var [aspectRatioAlign, aspectRatioMeetOrSlice] = cleanAspectRatio.split(' ');
977 var align = aspectRatioAlign || 'xMidYMid';
978 var meetOrSlice = aspectRatioMeetOrSlice || 'meet'; // calculate scale
979
980 var scaleX = width / desiredWidth;
981 var scaleY = height / desiredHeight;
982 var scaleMin = Math.min(scaleX, scaleY);
983 var scaleMax = Math.max(scaleX, scaleY);
984 var finalDesiredWidth = desiredWidth;
985 var finalDesiredHeight = desiredHeight;
986
987 if (meetOrSlice === 'meet') {
988 finalDesiredWidth *= scaleMin;
989 finalDesiredHeight *= scaleMin;
990 }
991
992 if (meetOrSlice === 'slice') {
993 finalDesiredWidth *= scaleMax;
994 finalDesiredHeight *= scaleMax;
995 }
996
997 var refXProp = new Property(document, 'refX', refX);
998 var refYProp = new Property(document, 'refY', refY);
999 var hasRefs = refXProp.hasValue() && refYProp.hasValue();
1000
1001 if (hasRefs) {
1002 ctx.translate(-scaleMin * refXProp.getPixels('x'), -scaleMin * refYProp.getPixels('y'));
1003 }
1004
1005 if (clip) {
1006 var scaledClipX = scaleMin * clipX;
1007 var scaledClipY = scaleMin * clipY;
1008 ctx.beginPath();
1009 ctx.moveTo(scaledClipX, scaledClipY);
1010 ctx.lineTo(width, scaledClipY);
1011 ctx.lineTo(width, height);
1012 ctx.lineTo(scaledClipX, height);
1013 ctx.closePath();
1014 ctx.clip();
1015 }
1016
1017 if (!hasRefs) {
1018 var isMeetMinY = meetOrSlice === 'meet' && scaleMin === scaleY;
1019 var isSliceMaxY = meetOrSlice === 'slice' && scaleMax === scaleY;
1020 var isMeetMinX = meetOrSlice === 'meet' && scaleMin === scaleX;
1021 var isSliceMaxX = meetOrSlice === 'slice' && scaleMax === scaleX;
1022
1023 if (align.startsWith('xMid') && (isMeetMinY || isSliceMaxY)) {
1024 ctx.translate(width / 2.0 - finalDesiredWidth / 2.0, 0);
1025 }
1026
1027 if (align.endsWith('YMid') && (isMeetMinX || isSliceMaxX)) {
1028 ctx.translate(0, height / 2.0 - finalDesiredHeight / 2.0);
1029 }
1030
1031 if (align.startsWith('xMax') && (isMeetMinY || isSliceMaxY)) {
1032 ctx.translate(width - finalDesiredWidth, 0);
1033 }
1034
1035 if (align.endsWith('YMax') && (isMeetMinX || isSliceMaxX)) {
1036 ctx.translate(0, height - finalDesiredHeight);
1037 }
1038 } // scale
1039
1040
1041 switch (true) {
1042 case align === 'none':
1043 ctx.scale(scaleX, scaleY);
1044 break;
1045
1046 case meetOrSlice === 'meet':
1047 ctx.scale(scaleMin, scaleMin);
1048 break;
1049
1050 case meetOrSlice === 'slice':
1051 ctx.scale(scaleMax, scaleMax);
1052 break;
1053 } // translate
1054
1055
1056 ctx.translate(-minX, -minY);
1057 }
1058
1059 start(element) {
1060 var {
1061 enableRedraw = false,
1062 ignoreMouse = false,
1063 ignoreAnimation = false,
1064 ignoreDimensions = false,
1065 ignoreClear = false,
1066 forceRedraw,
1067 scaleWidth,
1068 scaleHeight,
1069 offsetX,
1070 offsetY
1071 } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
1072 var {
1073 FRAMERATE,
1074 mouse
1075 } = this;
1076 var frameDuration = 1000 / FRAMERATE;
1077 this.frameDuration = frameDuration;
1078 this.readyPromise = new Promise(resolve => {
1079 this.resolveReady = resolve;
1080 });
1081
1082 if (this.isReady()) {
1083 this.render(element, ignoreDimensions, ignoreClear, scaleWidth, scaleHeight, offsetX, offsetY);
1084 }
1085
1086 if (!enableRedraw) {
1087 return;
1088 }
1089
1090 var now = Date.now();
1091 var then = now;
1092 var delta = 0;
1093
1094 var tick = () => {
1095 now = Date.now();
1096 delta = now - then;
1097
1098 if (delta >= frameDuration) {
1099 then = now - delta % frameDuration;
1100
1101 if (this.shouldUpdate(ignoreAnimation, forceRedraw)) {
1102 this.render(element, ignoreDimensions, ignoreClear, scaleWidth, scaleHeight, offsetX, offsetY);
1103 mouse.runEvents();
1104 }
1105 }
1106
1107 this.intervalId = requestAnimationFrame(tick);
1108 };
1109
1110 if (!ignoreMouse) {
1111 mouse.start();
1112 }
1113
1114 this.intervalId = requestAnimationFrame(tick);
1115 }
1116
1117 stop() {
1118 if (this.intervalId) {
1119 requestAnimationFrame.cancel(this.intervalId);
1120 this.intervalId = null;
1121 }
1122
1123 this.mouse.stop();
1124 }
1125
1126 shouldUpdate(ignoreAnimation, forceRedraw) {
1127 // need update from animations?
1128 if (!ignoreAnimation) {
1129 var {
1130 frameDuration
1131 } = this;
1132 var shouldUpdate = this.animations.reduce((shouldUpdate, animation) => animation.update(frameDuration) || shouldUpdate, false);
1133
1134 if (shouldUpdate) {
1135 return true;
1136 }
1137 } // need update from redraw?
1138
1139
1140 if (typeof forceRedraw === 'function' && forceRedraw()) {
1141 return true;
1142 }
1143
1144 if (!this.isReadyLock && this.isReady()) {
1145 return true;
1146 } // need update from mouse events?
1147
1148
1149 if (this.mouse.hasEvents()) {
1150 return true;
1151 }
1152
1153 return false;
1154 }
1155
1156 render(element, ignoreDimensions, ignoreClear, scaleWidth, scaleHeight, offsetX, offsetY) {
1157 var {
1158 CLIENT_WIDTH,
1159 CLIENT_HEIGHT,
1160 viewPort,
1161 ctx,
1162 isFirstRender
1163 } = this;
1164 var canvas = ctx.canvas;
1165 viewPort.clear();
1166
1167 if (canvas.width && canvas.height) {
1168 viewPort.setCurrent(canvas.width, canvas.height);
1169 } else {
1170 viewPort.setCurrent(CLIENT_WIDTH, CLIENT_HEIGHT);
1171 }
1172
1173 var widthStyle = element.getStyle('width');
1174 var heightStyle = element.getStyle('height');
1175
1176 if (!ignoreDimensions && (isFirstRender || typeof scaleWidth !== 'number' && typeof scaleHeight !== 'number')) {
1177 // set canvas size
1178 if (widthStyle.hasValue()) {
1179 canvas.width = widthStyle.getPixels('x');
1180
1181 if (canvas.style) {
1182 canvas.style.width = "".concat(canvas.width, "px");
1183 }
1184 }
1185
1186 if (heightStyle.hasValue()) {
1187 canvas.height = heightStyle.getPixels('y');
1188
1189 if (canvas.style) {
1190 canvas.style.height = "".concat(canvas.height, "px");
1191 }
1192 }
1193 }
1194
1195 var cWidth = canvas.clientWidth || canvas.width;
1196 var cHeight = canvas.clientHeight || canvas.height;
1197
1198 if (ignoreDimensions && widthStyle.hasValue() && heightStyle.hasValue()) {
1199 cWidth = widthStyle.getPixels('x');
1200 cHeight = heightStyle.getPixels('y');
1201 }
1202
1203 viewPort.setCurrent(cWidth, cHeight);
1204
1205 if (typeof offsetX === 'number') {
1206 element.getAttribute('x', true).setValue(offsetX);
1207 }
1208
1209 if (typeof offsetY === 'number') {
1210 element.getAttribute('y', true).setValue(offsetY);
1211 }
1212
1213 if (typeof scaleWidth === 'number' || typeof scaleHeight === 'number') {
1214 var viewBox = toNumbers(element.getAttribute('viewBox').getString());
1215 var xRatio = 0;
1216 var yRatio = 0;
1217
1218 if (typeof scaleWidth === 'number') {
1219 var _widthStyle = element.getStyle('width');
1220
1221 if (_widthStyle.hasValue()) {
1222 xRatio = _widthStyle.getPixels('x') / scaleWidth;
1223 } else if (!isNaN(viewBox[2])) {
1224 xRatio = viewBox[2] / scaleWidth;
1225 }
1226 }
1227
1228 if (typeof scaleHeight === 'number') {
1229 var _heightStyle = element.getStyle('height');
1230
1231 if (_heightStyle.hasValue()) {
1232 yRatio = _heightStyle.getPixels('y') / scaleHeight;
1233 } else if (!isNaN(viewBox[3])) {
1234 yRatio = viewBox[3] / scaleHeight;
1235 }
1236 }
1237
1238 if (!xRatio) {
1239 xRatio = yRatio;
1240 }
1241
1242 if (!yRatio) {
1243 yRatio = xRatio;
1244 }
1245
1246 element.getAttribute('width', true).setValue(scaleWidth);
1247 element.getAttribute('height', true).setValue(scaleHeight);
1248 var transformStyle = element.getStyle('transform', true, true);
1249 transformStyle.setValue("".concat(transformStyle.getString(), " scale(").concat(1.0 / xRatio, ", ").concat(1.0 / yRatio, ")"));
1250 } // clear and render
1251
1252
1253 if (!ignoreClear) {
1254 ctx.clearRect(0, 0, cWidth, cHeight);
1255 }
1256
1257 element.render(ctx);
1258
1259 if (isFirstRender) {
1260 this.isFirstRender = false;
1261 }
1262 }
1263
1264}
1265Screen.defaultWindow = defaultWindow;
1266Screen.defaultFetch = defaultFetch$1;
1267
1268var {
1269 defaultFetch
1270} = Screen;
1271var DefaultDOMParser = typeof DOMParser !== 'undefined' ? DOMParser : null;
1272class Parser {
1273 constructor() {
1274 var {
1275 fetch = defaultFetch,
1276 DOMParser = DefaultDOMParser
1277 } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
1278 this.fetch = fetch;
1279 this.DOMParser = DOMParser;
1280 }
1281
1282 parse(resource) {
1283 var _this = this;
1284
1285 return _asyncToGenerator(function* () {
1286 if (resource.startsWith('<')) {
1287 return _this.parseFromString(resource);
1288 }
1289
1290 return _this.load(resource);
1291 })();
1292 }
1293
1294 parseFromString(xml) {
1295 var parser = new this.DOMParser();
1296
1297 try {
1298 return this.checkDocument(parser.parseFromString(xml, 'image/svg+xml'));
1299 } catch (err) {
1300 return this.checkDocument(parser.parseFromString(xml, 'text/xml'));
1301 }
1302 }
1303
1304 checkDocument(document) {
1305 var parserError = document.getElementsByTagName('parsererror')[0];
1306
1307 if (parserError) {
1308 throw new Error(parserError.textContent);
1309 }
1310
1311 return document;
1312 }
1313
1314 load(url) {
1315 var _this2 = this;
1316
1317 return _asyncToGenerator(function* () {
1318 var response = yield _this2.fetch(url);
1319 var xml = yield response.text();
1320 return _this2.parseFromString(xml);
1321 })();
1322 }
1323
1324}
1325
1326class Translate {
1327 constructor(_, point) {
1328 this.type = 'translate';
1329 this.point = null;
1330 this.point = Point.parse(point);
1331 }
1332
1333 apply(ctx) {
1334 var {
1335 x,
1336 y
1337 } = this.point;
1338 ctx.translate(x || 0.0, y || 0.0);
1339 }
1340
1341 unapply(ctx) {
1342 var {
1343 x,
1344 y
1345 } = this.point;
1346 ctx.translate(-1.0 * x || 0.0, -1.0 * y || 0.0);
1347 }
1348
1349 applyToPoint(point) {
1350 var {
1351 x,
1352 y
1353 } = this.point;
1354 point.applyTransform([1, 0, 0, 1, x || 0.0, y || 0.0]);
1355 }
1356
1357}
1358
1359class Rotate {
1360 constructor(document, rotate, transformOrigin) {
1361 this.type = 'rotate';
1362 this.angle = null;
1363 this.originX = null;
1364 this.originY = null;
1365 this.cx = 0;
1366 this.cy = 0;
1367 var numbers = toNumbers(rotate);
1368 this.angle = new Property(document, 'angle', numbers[0]);
1369 this.originX = transformOrigin[0];
1370 this.originY = transformOrigin[1];
1371 this.cx = numbers[1] || 0;
1372 this.cy = numbers[2] || 0;
1373 }
1374
1375 apply(ctx) {
1376 var {
1377 cx,
1378 cy,
1379 originX,
1380 originY,
1381 angle
1382 } = this;
1383 var tx = cx + originX.getPixels('x');
1384 var ty = cy + originY.getPixels('y');
1385 ctx.translate(tx, ty);
1386 ctx.rotate(angle.getRadians());
1387 ctx.translate(-tx, -ty);
1388 }
1389
1390 unapply(ctx) {
1391 var {
1392 cx,
1393 cy,
1394 originX,
1395 originY,
1396 angle
1397 } = this;
1398 var tx = cx + originX.getPixels('x');
1399 var ty = cy + originY.getPixels('y');
1400 ctx.translate(tx, ty);
1401 ctx.rotate(-1.0 * angle.getRadians());
1402 ctx.translate(-tx, -ty);
1403 }
1404
1405 applyToPoint(point) {
1406 var {
1407 cx,
1408 cy,
1409 angle
1410 } = this;
1411 var rad = angle.getRadians();
1412 point.applyTransform([1, 0, 0, 1, cx || 0.0, cy || 0.0 // this.p.y
1413 ]);
1414 point.applyTransform([Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), 0, 0]);
1415 point.applyTransform([1, 0, 0, 1, -cx || 0.0, -cy || 0.0 // -this.p.y
1416 ]);
1417 }
1418
1419}
1420
1421class Scale {
1422 constructor(_, scale, transformOrigin) {
1423 this.type = 'scale';
1424 this.scale = null;
1425 this.originX = null;
1426 this.originY = null;
1427 var scaleSize = Point.parseScale(scale); // Workaround for node-canvas
1428
1429 if (scaleSize.x === 0 || scaleSize.y === 0) {
1430 scaleSize.x = PSEUDO_ZERO;
1431 scaleSize.y = PSEUDO_ZERO;
1432 }
1433
1434 this.scale = scaleSize;
1435 this.originX = transformOrigin[0];
1436 this.originY = transformOrigin[1];
1437 }
1438
1439 apply(ctx) {
1440 var {
1441 scale: {
1442 x,
1443 y
1444 },
1445 originX,
1446 originY
1447 } = this;
1448 var tx = originX.getPixels('x');
1449 var ty = originY.getPixels('y');
1450 ctx.translate(tx, ty);
1451 ctx.scale(x, y || x);
1452 ctx.translate(-tx, -ty);
1453 }
1454
1455 unapply(ctx) {
1456 var {
1457 scale: {
1458 x,
1459 y
1460 },
1461 originX,
1462 originY
1463 } = this;
1464 var tx = originX.getPixels('x');
1465 var ty = originY.getPixels('y');
1466 ctx.translate(tx, ty);
1467 ctx.scale(1.0 / x, 1.0 / y || x);
1468 ctx.translate(-tx, -ty);
1469 }
1470
1471 applyToPoint(point) {
1472 var {
1473 x,
1474 y
1475 } = this.scale;
1476 point.applyTransform([x || 0.0, 0, 0, y || 0.0, 0, 0]);
1477 }
1478
1479}
1480
1481class Matrix {
1482 constructor(_, matrix, transformOrigin) {
1483 this.type = 'matrix';
1484 this.matrix = [];
1485 this.originX = null;
1486 this.originY = null;
1487 this.matrix = toNumbers(matrix);
1488 this.originX = transformOrigin[0];
1489 this.originY = transformOrigin[1];
1490 }
1491
1492 apply(ctx) {
1493 var {
1494 originX,
1495 originY,
1496 matrix
1497 } = this;
1498 var tx = originX.getPixels('x');
1499 var ty = originY.getPixels('y');
1500 ctx.translate(tx, ty);
1501 ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
1502 ctx.translate(-tx, -ty);
1503 }
1504
1505 unapply(ctx) {
1506 var {
1507 originX,
1508 originY,
1509 matrix
1510 } = this;
1511 var a = matrix[0];
1512 var b = matrix[2];
1513 var c = matrix[4];
1514 var d = matrix[1];
1515 var e = matrix[3];
1516 var f = matrix[5];
1517 var g = 0.0;
1518 var h = 0.0;
1519 var i = 1.0;
1520 var det = 1 / (a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g));
1521 var tx = originX.getPixels('x');
1522 var ty = originY.getPixels('y');
1523 ctx.translate(tx, ty);
1524 ctx.transform(det * (e * i - f * h), det * (f * g - d * i), det * (c * h - b * i), det * (a * i - c * g), det * (b * f - c * e), det * (c * d - a * f));
1525 ctx.translate(-tx, -ty);
1526 }
1527
1528 applyToPoint(point) {
1529 point.applyTransform(this.matrix);
1530 }
1531
1532}
1533
1534class Skew extends Matrix {
1535 constructor(document, skew, transformOrigin) {
1536 super(document, skew, transformOrigin);
1537 this.type = 'skew';
1538 this.angle = null;
1539 this.angle = new Property(document, 'angle', skew);
1540 }
1541
1542}
1543
1544class SkewX extends Skew {
1545 constructor(document, skew, transformOrigin) {
1546 super(document, skew, transformOrigin);
1547 this.type = 'skewX';
1548 this.matrix = [1, 0, Math.tan(this.angle.getRadians()), 1, 0, 0];
1549 }
1550
1551}
1552
1553class SkewY extends Skew {
1554 constructor(document, skew, transformOrigin) {
1555 super(document, skew, transformOrigin);
1556 this.type = 'skewY';
1557 this.matrix = [1, Math.tan(this.angle.getRadians()), 0, 1, 0, 0];
1558 }
1559
1560}
1561
1562function parseTransforms(transform) {
1563 return compressSpaces(transform).trim().replace(/\)([a-zA-Z])/g, ') $1').replace(/\)(\s?,\s?)/g, ') ').split(/\s(?=[a-z])/);
1564}
1565
1566function parseTransform(transform) {
1567 var [type, value] = transform.split('(');
1568 return [type.trim(), value.trim().replace(')', '')];
1569}
1570
1571class Transform {
1572 constructor(document, transform, transformOrigin) {
1573 this.document = document;
1574 this.transforms = [];
1575 var data = parseTransforms(transform);
1576 data.forEach(transform => {
1577 if (transform === 'none') {
1578 return;
1579 }
1580
1581 var [type, value] = parseTransform(transform);
1582 var TransformType = Transform.transformTypes[type];
1583
1584 if (typeof TransformType !== 'undefined') {
1585 this.transforms.push(new TransformType(this.document, value, transformOrigin));
1586 }
1587 });
1588 }
1589
1590 static fromElement(document, element) {
1591 var transformStyle = element.getStyle('transform', false, true);
1592 var [transformOriginXProperty, transformOriginYProperty = transformOriginXProperty] = element.getStyle('transform-origin', false, true).split();
1593 var transformOrigin = [transformOriginXProperty, transformOriginYProperty];
1594
1595 if (transformStyle.hasValue()) {
1596 return new Transform(document, transformStyle.getString(), transformOrigin);
1597 }
1598
1599 return null;
1600 }
1601
1602 apply(ctx) {
1603 var {
1604 transforms
1605 } = this;
1606 var len = transforms.length;
1607
1608 for (var i = 0; i < len; i++) {
1609 transforms[i].apply(ctx);
1610 }
1611 }
1612
1613 unapply(ctx) {
1614 var {
1615 transforms
1616 } = this;
1617 var len = transforms.length;
1618
1619 for (var i = len - 1; i >= 0; i--) {
1620 transforms[i].unapply(ctx);
1621 }
1622 } // TODO: applyToPoint unused ... remove?
1623
1624
1625 applyToPoint(point) {
1626 var {
1627 transforms
1628 } = this;
1629 var len = transforms.length;
1630
1631 for (var i = 0; i < len; i++) {
1632 transforms[i].applyToPoint(point);
1633 }
1634 }
1635
1636}
1637Transform.transformTypes = {
1638 translate: Translate,
1639 rotate: Rotate,
1640 scale: Scale,
1641 matrix: Matrix,
1642 skewX: SkewX,
1643 skewY: SkewY
1644};
1645
1646class Element {
1647 constructor(document, node) {
1648 var captureTextNodes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
1649 this.document = document;
1650 this.node = node;
1651 this.captureTextNodes = captureTextNodes;
1652 this.attributes = {};
1653 this.styles = {};
1654 this.stylesSpecificity = {};
1655 this.animationFrozen = false;
1656 this.animationFrozenValue = '';
1657 this.parent = null;
1658 this.children = [];
1659
1660 if (!node || node.nodeType !== 1) {
1661 // ELEMENT_NODE
1662 return;
1663 } // add attributes
1664
1665
1666 Array.from(node.attributes).forEach(attribute => {
1667 var nodeName = normalizeAttributeName(attribute.nodeName);
1668 this.attributes[nodeName] = new Property(document, nodeName, attribute.value);
1669 });
1670 this.addStylesFromStyleDefinition(); // add inline styles
1671
1672 if (this.getAttribute('style').hasValue()) {
1673 var styles = this.getAttribute('style').getString().split(';').map(_ => _.trim());
1674 styles.forEach(style => {
1675 if (!style) {
1676 return;
1677 }
1678
1679 var [name, value] = style.split(':').map(_ => _.trim());
1680 this.styles[name] = new Property(document, name, value);
1681 });
1682 }
1683
1684 var {
1685 definitions
1686 } = document;
1687 var id = this.getAttribute('id'); // add id
1688
1689 if (id.hasValue()) {
1690 if (!definitions[id.getString()]) {
1691 definitions[id.getString()] = this;
1692 }
1693 }
1694
1695 Array.from(node.childNodes).forEach(childNode => {
1696 if (childNode.nodeType === 1) {
1697 this.addChild(childNode); // ELEMENT_NODE
1698 } else if (captureTextNodes && (childNode.nodeType === 3 || childNode.nodeType === 4)) {
1699 var textNode = document.createTextNode(childNode);
1700
1701 if (textNode.getText().length > 0) {
1702 this.addChild(textNode); // TEXT_NODE
1703 }
1704 }
1705 });
1706 }
1707
1708 getAttribute(name) {
1709 var createIfNotExists = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1710 var attr = this.attributes[name];
1711
1712 if (!attr && createIfNotExists) {
1713 var _attr = new Property(this.document, name, '');
1714
1715 this.attributes[name] = _attr;
1716 return _attr;
1717 }
1718
1719 return attr || Property.empty(this.document);
1720 }
1721
1722 getHrefAttribute() {
1723 for (var key in this.attributes) {
1724 if (key === 'href' || key.endsWith(':href')) {
1725 return this.attributes[key];
1726 }
1727 }
1728
1729 return Property.empty(this.document);
1730 }
1731
1732 getStyle(name) {
1733 var createIfNotExists = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
1734 var skipAncestors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
1735 var style = this.styles[name];
1736
1737 if (style) {
1738 return style;
1739 }
1740
1741 var attr = this.getAttribute(name);
1742
1743 if (attr !== null && attr !== void 0 && attr.hasValue()) {
1744 this.styles[name] = attr; // move up to me to cache
1745
1746 return attr;
1747 }
1748
1749 if (!skipAncestors) {
1750 var {
1751 parent
1752 } = this;
1753
1754 if (parent) {
1755 var parentStyle = parent.getStyle(name);
1756
1757 if (parentStyle !== null && parentStyle !== void 0 && parentStyle.hasValue()) {
1758 return parentStyle;
1759 }
1760 }
1761 }
1762
1763 if (createIfNotExists) {
1764 var _style = new Property(this.document, name, '');
1765
1766 this.styles[name] = _style;
1767 return _style;
1768 }
1769
1770 return style || Property.empty(this.document);
1771 }
1772
1773 render(ctx) {
1774 // don't render display=none
1775 // don't render visibility=hidden
1776 if (this.getStyle('display').getString() === 'none' || this.getStyle('visibility').getString() === 'hidden') {
1777 return;
1778 }
1779
1780 ctx.save();
1781
1782 if (this.getStyle('mask').hasValue()) {
1783 // mask
1784 var mask = this.getStyle('mask').getDefinition();
1785
1786 if (mask) {
1787 this.applyEffects(ctx);
1788 mask.apply(ctx, this);
1789 }
1790 } else if (this.getStyle('filter').getValue('none') !== 'none') {
1791 // filter
1792 var filter = this.getStyle('filter').getDefinition();
1793
1794 if (filter) {
1795 this.applyEffects(ctx);
1796 filter.apply(ctx, this);
1797 }
1798 } else {
1799 this.setContext(ctx);
1800 this.renderChildren(ctx);
1801 this.clearContext(ctx);
1802 }
1803
1804 ctx.restore();
1805 }
1806
1807 setContext(_) {// NO RENDER
1808 }
1809
1810 applyEffects(ctx) {
1811 // transform
1812 var transform = Transform.fromElement(this.document, this);
1813
1814 if (transform) {
1815 transform.apply(ctx);
1816 } // clip
1817
1818
1819 var clipPathStyleProp = this.getStyle('clip-path', false, true);
1820
1821 if (clipPathStyleProp.hasValue()) {
1822 var clip = clipPathStyleProp.getDefinition();
1823
1824 if (clip) {
1825 clip.apply(ctx);
1826 }
1827 }
1828 }
1829
1830 clearContext(_) {// NO RENDER
1831 }
1832
1833 renderChildren(ctx) {
1834 this.children.forEach(child => {
1835 child.render(ctx);
1836 });
1837 }
1838
1839 addChild(childNode) {
1840 var child = childNode instanceof Element ? childNode : this.document.createElement(childNode);
1841 child.parent = this;
1842
1843 if (!Element.ignoreChildTypes.includes(child.type)) {
1844 this.children.push(child);
1845 }
1846 }
1847
1848 matchesSelector(selector) {
1849 var _node$getAttribute;
1850
1851 var {
1852 node
1853 } = this;
1854
1855 if (typeof node.matches === 'function') {
1856 return node.matches(selector);
1857 }
1858
1859 var styleClasses = (_node$getAttribute = node.getAttribute) === null || _node$getAttribute === void 0 ? void 0 : _node$getAttribute.call(node, 'class');
1860
1861 if (!styleClasses || styleClasses === '') {
1862 return false;
1863 }
1864
1865 return styleClasses.split(' ').some(styleClass => ".".concat(styleClass) === selector);
1866 }
1867
1868 addStylesFromStyleDefinition() {
1869 var {
1870 styles,
1871 stylesSpecificity
1872 } = this.document;
1873
1874 for (var selector in styles) {
1875 if (!selector.startsWith('@') && this.matchesSelector(selector)) {
1876 var style = styles[selector];
1877 var specificity = stylesSpecificity[selector];
1878
1879 if (style) {
1880 for (var name in style) {
1881 var existingSpecificity = this.stylesSpecificity[name];
1882
1883 if (typeof existingSpecificity === 'undefined') {
1884 existingSpecificity = '000';
1885 }
1886
1887 if (specificity >= existingSpecificity) {
1888 this.styles[name] = style[name];
1889 this.stylesSpecificity[name] = specificity;
1890 }
1891 }
1892 }
1893 }
1894 }
1895 }
1896
1897 removeStyles(element, ignoreStyles) {
1898 var toRestore = ignoreStyles.reduce((toRestore, name) => {
1899 var styleProp = element.getStyle(name);
1900
1901 if (!styleProp.hasValue()) {
1902 return toRestore;
1903 }
1904
1905 var value = styleProp.getString();
1906 styleProp.setValue('');
1907 return [...toRestore, [name, value]];
1908 }, []);
1909 return toRestore;
1910 }
1911
1912 restoreStyles(element, styles) {
1913 styles.forEach(_ref => {
1914 var [name, value] = _ref;
1915 element.getStyle(name, true).setValue(value);
1916 });
1917 }
1918
1919 isFirstChild() {
1920 var _this$parent;
1921
1922 return ((_this$parent = this.parent) === null || _this$parent === void 0 ? void 0 : _this$parent.children.indexOf(this)) === 0;
1923 }
1924
1925}
1926Element.ignoreChildTypes = ['title'];
1927
1928class UnknownElement extends Element {
1929 constructor(document, node, captureTextNodes) {
1930 super(document, node, captureTextNodes);
1931 }
1932
1933}
1934
1935function wrapFontFamily(fontFamily) {
1936 var trimmed = fontFamily.trim();
1937 return /^('|")/.test(trimmed) ? trimmed : "\"".concat(trimmed, "\"");
1938}
1939
1940function prepareFontFamily(fontFamily) {
1941 return typeof process === 'undefined' ? fontFamily : fontFamily.trim().split(',').map(wrapFontFamily).join(',');
1942}
1943/**
1944 * https://developer.mozilla.org/en-US/docs/Web/CSS/font-style
1945 * @param fontStyle
1946 * @returns CSS font style.
1947 */
1948
1949
1950function prepareFontStyle(fontStyle) {
1951 if (!fontStyle) {
1952 return '';
1953 }
1954
1955 var targetFontStyle = fontStyle.trim().toLowerCase();
1956
1957 switch (targetFontStyle) {
1958 case 'normal':
1959 case 'italic':
1960 case 'oblique':
1961 case 'inherit':
1962 case 'initial':
1963 case 'unset':
1964 return targetFontStyle;
1965
1966 default:
1967 if (/^oblique\s+(-|)\d+deg$/.test(targetFontStyle)) {
1968 return targetFontStyle;
1969 }
1970
1971 return '';
1972 }
1973}
1974/**
1975 * https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
1976 * @param fontWeight
1977 * @returns CSS font weight.
1978 */
1979
1980
1981function prepareFontWeight(fontWeight) {
1982 if (!fontWeight) {
1983 return '';
1984 }
1985
1986 var targetFontWeight = fontWeight.trim().toLowerCase();
1987
1988 switch (targetFontWeight) {
1989 case 'normal':
1990 case 'bold':
1991 case 'lighter':
1992 case 'bolder':
1993 case 'inherit':
1994 case 'initial':
1995 case 'unset':
1996 return targetFontWeight;
1997
1998 default:
1999 if (/^[\d.]+$/.test(targetFontWeight)) {
2000 return targetFontWeight;
2001 }
2002
2003 return '';
2004 }
2005}
2006
2007class Font {
2008 constructor(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) {
2009 var inheritFont = inherit ? typeof inherit === 'string' ? Font.parse(inherit) : inherit : {};
2010 this.fontFamily = fontFamily || inheritFont.fontFamily;
2011 this.fontSize = fontSize || inheritFont.fontSize;
2012 this.fontStyle = fontStyle || inheritFont.fontStyle;
2013 this.fontWeight = fontWeight || inheritFont.fontWeight;
2014 this.fontVariant = fontVariant || inheritFont.fontVariant;
2015 }
2016
2017 static parse() {
2018 var font = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
2019 var inherit = arguments.length > 1 ? arguments[1] : undefined;
2020 var fontStyle = '';
2021 var fontVariant = '';
2022 var fontWeight = '';
2023 var fontSize = '';
2024 var fontFamily = '';
2025 var parts = compressSpaces(font).trim().split(' ');
2026 var set = {
2027 fontSize: false,
2028 fontStyle: false,
2029 fontWeight: false,
2030 fontVariant: false
2031 };
2032 parts.forEach(part => {
2033 switch (true) {
2034 case !set.fontStyle && Font.styles.includes(part):
2035 if (part !== 'inherit') {
2036 fontStyle = part;
2037 }
2038
2039 set.fontStyle = true;
2040 break;
2041
2042 case !set.fontVariant && Font.variants.includes(part):
2043 if (part !== 'inherit') {
2044 fontVariant = part;
2045 }
2046
2047 set.fontStyle = true;
2048 set.fontVariant = true;
2049 break;
2050
2051 case !set.fontWeight && Font.weights.includes(part):
2052 if (part !== 'inherit') {
2053 fontWeight = part;
2054 }
2055
2056 set.fontStyle = true;
2057 set.fontVariant = true;
2058 set.fontWeight = true;
2059 break;
2060
2061 case !set.fontSize:
2062 if (part !== 'inherit') {
2063 [fontSize] = part.split('/');
2064 }
2065
2066 set.fontStyle = true;
2067 set.fontVariant = true;
2068 set.fontWeight = true;
2069 set.fontSize = true;
2070 break;
2071
2072 default:
2073 if (part !== 'inherit') {
2074 fontFamily += part;
2075 }
2076
2077 }
2078 });
2079 return new Font(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit);
2080 }
2081
2082 toString() {
2083 return [prepareFontStyle(this.fontStyle), this.fontVariant, prepareFontWeight(this.fontWeight), this.fontSize, // Wrap fontFamily only on nodejs and only for canvas.ctx
2084 prepareFontFamily(this.fontFamily)].join(' ').trim();
2085 }
2086
2087}
2088Font.styles = 'normal|italic|oblique|inherit';
2089Font.variants = 'normal|small-caps|inherit';
2090Font.weights = 'normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900|inherit';
2091
2092class BoundingBox {
2093 constructor() {
2094 var x1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : Number.NaN;
2095 var y1 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Number.NaN;
2096 var x2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : Number.NaN;
2097 var y2 = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Number.NaN;
2098 this.x1 = x1;
2099 this.y1 = y1;
2100 this.x2 = x2;
2101 this.y2 = y2;
2102 this.addPoint(x1, y1);
2103 this.addPoint(x2, y2);
2104 }
2105
2106 get x() {
2107 return this.x1;
2108 }
2109
2110 get y() {
2111 return this.y1;
2112 }
2113
2114 get width() {
2115 return this.x2 - this.x1;
2116 }
2117
2118 get height() {
2119 return this.y2 - this.y1;
2120 }
2121
2122 addPoint(x, y) {
2123 if (typeof x !== 'undefined') {
2124 if (isNaN(this.x1) || isNaN(this.x2)) {
2125 this.x1 = x;
2126 this.x2 = x;
2127 }
2128
2129 if (x < this.x1) {
2130 this.x1 = x;
2131 }
2132
2133 if (x > this.x2) {
2134 this.x2 = x;
2135 }
2136 }
2137
2138 if (typeof y !== 'undefined') {
2139 if (isNaN(this.y1) || isNaN(this.y2)) {
2140 this.y1 = y;
2141 this.y2 = y;
2142 }
2143
2144 if (y < this.y1) {
2145 this.y1 = y;
2146 }
2147
2148 if (y > this.y2) {
2149 this.y2 = y;
2150 }
2151 }
2152 }
2153
2154 addX(x) {
2155 this.addPoint(x, null);
2156 }
2157
2158 addY(y) {
2159 this.addPoint(null, y);
2160 }
2161
2162 addBoundingBox(boundingBox) {
2163 if (!boundingBox) {
2164 return;
2165 }
2166
2167 var {
2168 x1,
2169 y1,
2170 x2,
2171 y2
2172 } = boundingBox;
2173 this.addPoint(x1, y1);
2174 this.addPoint(x2, y2);
2175 }
2176
2177 sumCubic(t, p0, p1, p2, p3) {
2178 return Math.pow(1 - t, 3) * p0 + 3 * Math.pow(1 - t, 2) * t * p1 + 3 * (1 - t) * Math.pow(t, 2) * p2 + Math.pow(t, 3) * p3;
2179 }
2180
2181 bezierCurveAdd(forX, p0, p1, p2, p3) {
2182 var b = 6 * p0 - 12 * p1 + 6 * p2;
2183 var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3;
2184 var c = 3 * p1 - 3 * p0;
2185
2186 if (a === 0) {
2187 if (b === 0) {
2188 return;
2189 }
2190
2191 var t = -c / b;
2192
2193 if (0 < t && t < 1) {
2194 if (forX) {
2195 this.addX(this.sumCubic(t, p0, p1, p2, p3));
2196 } else {
2197 this.addY(this.sumCubic(t, p0, p1, p2, p3));
2198 }
2199 }
2200
2201 return;
2202 }
2203
2204 var b2ac = Math.pow(b, 2) - 4 * c * a;
2205
2206 if (b2ac < 0) {
2207 return;
2208 }
2209
2210 var t1 = (-b + Math.sqrt(b2ac)) / (2 * a);
2211
2212 if (0 < t1 && t1 < 1) {
2213 if (forX) {
2214 this.addX(this.sumCubic(t1, p0, p1, p2, p3));
2215 } else {
2216 this.addY(this.sumCubic(t1, p0, p1, p2, p3));
2217 }
2218 }
2219
2220 var t2 = (-b - Math.sqrt(b2ac)) / (2 * a);
2221
2222 if (0 < t2 && t2 < 1) {
2223 if (forX) {
2224 this.addX(this.sumCubic(t2, p0, p1, p2, p3));
2225 } else {
2226 this.addY(this.sumCubic(t2, p0, p1, p2, p3));
2227 }
2228 }
2229 } // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
2230
2231
2232 addBezierCurve(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) {
2233 this.addPoint(p0x, p0y);
2234 this.addPoint(p3x, p3y);
2235 this.bezierCurveAdd(true, p0x, p1x, p2x, p3x);
2236 this.bezierCurveAdd(false, p0y, p1y, p2y, p3y);
2237 }
2238
2239 addQuadraticCurve(p0x, p0y, p1x, p1y, p2x, p2y) {
2240 var cp1x = p0x + 2 / 3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0)
2241
2242 var cp1y = p0y + 2 / 3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0)
2243
2244 var cp2x = cp1x + 1 / 3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0)
2245
2246 var cp2y = cp1y + 1 / 3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0)
2247
2248 this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y);
2249 }
2250
2251 isPointInBox(x, y) {
2252 var {
2253 x1,
2254 y1,
2255 x2,
2256 y2
2257 } = this;
2258 return x1 <= x && x <= x2 && y1 <= y && y <= y2;
2259 }
2260
2261}
2262
2263class PathParser extends SVGPathData {
2264 constructor(path) {
2265 super(path // Fix spaces after signs.
2266 .replace(/([+\-.])\s+/gm, '$1') // Remove invalid part.
2267 .replace(/[^MmZzLlHhVvCcSsQqTtAae\d\s.,+-].*/g, ''));
2268 this.control = null;
2269 this.start = null;
2270 this.current = null;
2271 this.command = null;
2272 this.commands = this.commands;
2273 this.i = -1;
2274 this.previousCommand = null;
2275 this.points = [];
2276 this.angles = [];
2277 }
2278
2279 reset() {
2280 this.i = -1;
2281 this.command = null;
2282 this.previousCommand = null;
2283 this.start = new Point(0, 0);
2284 this.control = new Point(0, 0);
2285 this.current = new Point(0, 0);
2286 this.points = [];
2287 this.angles = [];
2288 }
2289
2290 isEnd() {
2291 var {
2292 i,
2293 commands
2294 } = this;
2295 return i >= commands.length - 1;
2296 }
2297
2298 next() {
2299 var command = this.commands[++this.i];
2300 this.previousCommand = this.command;
2301 this.command = command;
2302 return command;
2303 }
2304
2305 getPoint() {
2306 var xProp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'x';
2307 var yProp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'y';
2308 var point = new Point(this.command[xProp], this.command[yProp]);
2309 return this.makeAbsolute(point);
2310 }
2311
2312 getAsControlPoint(xProp, yProp) {
2313 var point = this.getPoint(xProp, yProp);
2314 this.control = point;
2315 return point;
2316 }
2317
2318 getAsCurrentPoint(xProp, yProp) {
2319 var point = this.getPoint(xProp, yProp);
2320 this.current = point;
2321 return point;
2322 }
2323
2324 getReflectedControlPoint() {
2325 var previousCommand = this.previousCommand.type;
2326
2327 if (previousCommand !== SVGPathData.CURVE_TO && previousCommand !== SVGPathData.SMOOTH_CURVE_TO && previousCommand !== SVGPathData.QUAD_TO && previousCommand !== SVGPathData.SMOOTH_QUAD_TO) {
2328 return this.current;
2329 } // reflect point
2330
2331
2332 var {
2333 current: {
2334 x: cx,
2335 y: cy
2336 },
2337 control: {
2338 x: ox,
2339 y: oy
2340 }
2341 } = this;
2342 var point = new Point(2 * cx - ox, 2 * cy - oy);
2343 return point;
2344 }
2345
2346 makeAbsolute(point) {
2347 if (this.command.relative) {
2348 var {
2349 x,
2350 y
2351 } = this.current;
2352 point.x += x;
2353 point.y += y;
2354 }
2355
2356 return point;
2357 }
2358
2359 addMarker(point, from, priorTo) {
2360 var {
2361 points,
2362 angles
2363 } = this; // if the last angle isn't filled in because we didn't have this point yet ...
2364
2365 if (priorTo && angles.length > 0 && !angles[angles.length - 1]) {
2366 angles[angles.length - 1] = points[points.length - 1].angleTo(priorTo);
2367 }
2368
2369 this.addMarkerAngle(point, from ? from.angleTo(point) : null);
2370 }
2371
2372 addMarkerAngle(point, angle) {
2373 this.points.push(point);
2374 this.angles.push(angle);
2375 }
2376
2377 getMarkerPoints() {
2378 return this.points;
2379 }
2380
2381 getMarkerAngles() {
2382 var {
2383 angles
2384 } = this;
2385 var len = angles.length;
2386
2387 for (var i = 0; i < len; i++) {
2388 if (!angles[i]) {
2389 for (var j = i + 1; j < len; j++) {
2390 if (angles[j]) {
2391 angles[i] = angles[j];
2392 break;
2393 }
2394 }
2395 }
2396 }
2397
2398 return angles;
2399 }
2400
2401}
2402
2403class RenderedElement extends Element {
2404 constructor() {
2405 super(...arguments);
2406 this.modifiedEmSizeStack = false;
2407 }
2408
2409 calculateOpacity() {
2410 var opacity = 1.0; // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
2411
2412 var element = this;
2413
2414 while (element) {
2415 var opacityStyle = element.getStyle('opacity', false, true); // no ancestors on style call
2416
2417 if (opacityStyle.hasValue(true)) {
2418 opacity *= opacityStyle.getNumber();
2419 }
2420
2421 element = element.parent;
2422 }
2423
2424 return opacity;
2425 }
2426
2427 setContext(ctx) {
2428 var fromMeasure = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2429
2430 if (!fromMeasure) {
2431 // causes stack overflow when measuring text with gradients
2432 // fill
2433 var fillStyleProp = this.getStyle('fill');
2434 var fillOpacityStyleProp = this.getStyle('fill-opacity');
2435 var strokeStyleProp = this.getStyle('stroke');
2436 var strokeOpacityProp = this.getStyle('stroke-opacity');
2437
2438 if (fillStyleProp.isUrlDefinition()) {
2439 var fillStyle = fillStyleProp.getFillStyleDefinition(this, fillOpacityStyleProp);
2440
2441 if (fillStyle) {
2442 ctx.fillStyle = fillStyle;
2443 }
2444 } else if (fillStyleProp.hasValue()) {
2445 if (fillStyleProp.getString() === 'currentColor') {
2446 fillStyleProp.setValue(this.getStyle('color').getColor());
2447 }
2448
2449 var _fillStyle = fillStyleProp.getColor();
2450
2451 if (_fillStyle !== 'inherit') {
2452 ctx.fillStyle = _fillStyle === 'none' ? 'rgba(0,0,0,0)' : _fillStyle;
2453 }
2454 }
2455
2456 if (fillOpacityStyleProp.hasValue()) {
2457 var _fillStyle2 = new Property(this.document, 'fill', ctx.fillStyle).addOpacity(fillOpacityStyleProp).getColor();
2458
2459 ctx.fillStyle = _fillStyle2;
2460 } // stroke
2461
2462
2463 if (strokeStyleProp.isUrlDefinition()) {
2464 var strokeStyle = strokeStyleProp.getFillStyleDefinition(this, strokeOpacityProp);
2465
2466 if (strokeStyle) {
2467 ctx.strokeStyle = strokeStyle;
2468 }
2469 } else if (strokeStyleProp.hasValue()) {
2470 if (strokeStyleProp.getString() === 'currentColor') {
2471 strokeStyleProp.setValue(this.getStyle('color').getColor());
2472 }
2473
2474 var _strokeStyle = strokeStyleProp.getString();
2475
2476 if (_strokeStyle !== 'inherit') {
2477 ctx.strokeStyle = _strokeStyle === 'none' ? 'rgba(0,0,0,0)' : _strokeStyle;
2478 }
2479 }
2480
2481 if (strokeOpacityProp.hasValue()) {
2482 var _strokeStyle2 = new Property(this.document, 'stroke', ctx.strokeStyle).addOpacity(strokeOpacityProp).getString();
2483
2484 ctx.strokeStyle = _strokeStyle2;
2485 }
2486
2487 var strokeWidthStyleProp = this.getStyle('stroke-width');
2488
2489 if (strokeWidthStyleProp.hasValue()) {
2490 var newLineWidth = strokeWidthStyleProp.getPixels();
2491 ctx.lineWidth = !newLineWidth ? PSEUDO_ZERO // browsers don't respect 0 (or node-canvas? :-)
2492 : newLineWidth;
2493 }
2494
2495 var strokeLinecapStyleProp = this.getStyle('stroke-linecap');
2496 var strokeLinejoinStyleProp = this.getStyle('stroke-linejoin');
2497 var strokeMiterlimitProp = this.getStyle('stroke-miterlimit'); // NEED TEST
2498 // const pointOrderStyleProp = this.getStyle('paint-order');
2499
2500 var strokeDasharrayStyleProp = this.getStyle('stroke-dasharray');
2501 var strokeDashoffsetProp = this.getStyle('stroke-dashoffset');
2502
2503 if (strokeLinecapStyleProp.hasValue()) {
2504 ctx.lineCap = strokeLinecapStyleProp.getString();
2505 }
2506
2507 if (strokeLinejoinStyleProp.hasValue()) {
2508 ctx.lineJoin = strokeLinejoinStyleProp.getString();
2509 }
2510
2511 if (strokeMiterlimitProp.hasValue()) {
2512 ctx.miterLimit = strokeMiterlimitProp.getNumber();
2513 } // NEED TEST
2514 // if (pointOrderStyleProp.hasValue()) {
2515 // // ?
2516 // ctx.paintOrder = pointOrderStyleProp.getValue();
2517 // }
2518
2519
2520 if (strokeDasharrayStyleProp.hasValue() && strokeDasharrayStyleProp.getString() !== 'none') {
2521 var gaps = toNumbers(strokeDasharrayStyleProp.getString());
2522
2523 if (typeof ctx.setLineDash !== 'undefined') {
2524 ctx.setLineDash(gaps);
2525 } else // @ts-expect-error Handle browser prefix.
2526 if (typeof ctx.webkitLineDash !== 'undefined') {
2527 // @ts-expect-error Handle browser prefix.
2528 ctx.webkitLineDash = gaps;
2529 } else // @ts-expect-error Handle browser prefix.
2530 if (typeof ctx.mozDash !== 'undefined' && !(gaps.length === 1 && gaps[0] === 0)) {
2531 // @ts-expect-error Handle browser prefix.
2532 ctx.mozDash = gaps;
2533 }
2534
2535 var offset = strokeDashoffsetProp.getPixels();
2536
2537 if (typeof ctx.lineDashOffset !== 'undefined') {
2538 ctx.lineDashOffset = offset;
2539 } else // @ts-expect-error Handle browser prefix.
2540 if (typeof ctx.webkitLineDashOffset !== 'undefined') {
2541 // @ts-expect-error Handle browser prefix.
2542 ctx.webkitLineDashOffset = offset;
2543 } else // @ts-expect-error Handle browser prefix.
2544 if (typeof ctx.mozDashOffset !== 'undefined') {
2545 // @ts-expect-error Handle browser prefix.
2546 ctx.mozDashOffset = offset;
2547 }
2548 }
2549 } // font
2550
2551
2552 this.modifiedEmSizeStack = false;
2553
2554 if (typeof ctx.font !== 'undefined') {
2555 var fontStyleProp = this.getStyle('font');
2556 var fontStyleStyleProp = this.getStyle('font-style');
2557 var fontVariantStyleProp = this.getStyle('font-variant');
2558 var fontWeightStyleProp = this.getStyle('font-weight');
2559 var fontSizeStyleProp = this.getStyle('font-size');
2560 var fontFamilyStyleProp = this.getStyle('font-family');
2561 var font = new Font(fontStyleStyleProp.getString(), fontVariantStyleProp.getString(), fontWeightStyleProp.getString(), fontSizeStyleProp.hasValue() ? "".concat(fontSizeStyleProp.getPixels(true), "px") : '', fontFamilyStyleProp.getString(), Font.parse(fontStyleProp.getString(), ctx.font));
2562 fontStyleStyleProp.setValue(font.fontStyle);
2563 fontVariantStyleProp.setValue(font.fontVariant);
2564 fontWeightStyleProp.setValue(font.fontWeight);
2565 fontSizeStyleProp.setValue(font.fontSize);
2566 fontFamilyStyleProp.setValue(font.fontFamily);
2567 ctx.font = font.toString();
2568
2569 if (fontSizeStyleProp.isPixels()) {
2570 this.document.emSize = fontSizeStyleProp.getPixels();
2571 this.modifiedEmSizeStack = true;
2572 }
2573 }
2574
2575 if (!fromMeasure) {
2576 // effects
2577 this.applyEffects(ctx); // opacity
2578
2579 ctx.globalAlpha = this.calculateOpacity();
2580 }
2581 }
2582
2583 clearContext(ctx) {
2584 super.clearContext(ctx);
2585
2586 if (this.modifiedEmSizeStack) {
2587 this.document.popEmSize();
2588 }
2589 }
2590
2591}
2592
2593class PathElement extends RenderedElement {
2594 constructor(document, node, captureTextNodes) {
2595 super(document, node, captureTextNodes);
2596 this.type = 'path';
2597 this.pathParser = null;
2598 this.pathParser = new PathParser(this.getAttribute('d').getString());
2599 }
2600
2601 path(ctx) {
2602 var {
2603 pathParser
2604 } = this;
2605 var boundingBox = new BoundingBox();
2606 pathParser.reset();
2607
2608 if (ctx) {
2609 ctx.beginPath();
2610 }
2611
2612 while (!pathParser.isEnd()) {
2613 switch (pathParser.next().type) {
2614 case PathParser.MOVE_TO:
2615 this.pathM(ctx, boundingBox);
2616 break;
2617
2618 case PathParser.LINE_TO:
2619 this.pathL(ctx, boundingBox);
2620 break;
2621
2622 case PathParser.HORIZ_LINE_TO:
2623 this.pathH(ctx, boundingBox);
2624 break;
2625
2626 case PathParser.VERT_LINE_TO:
2627 this.pathV(ctx, boundingBox);
2628 break;
2629
2630 case PathParser.CURVE_TO:
2631 this.pathC(ctx, boundingBox);
2632 break;
2633
2634 case PathParser.SMOOTH_CURVE_TO:
2635 this.pathS(ctx, boundingBox);
2636 break;
2637
2638 case PathParser.QUAD_TO:
2639 this.pathQ(ctx, boundingBox);
2640 break;
2641
2642 case PathParser.SMOOTH_QUAD_TO:
2643 this.pathT(ctx, boundingBox);
2644 break;
2645
2646 case PathParser.ARC:
2647 this.pathA(ctx, boundingBox);
2648 break;
2649
2650 case PathParser.CLOSE_PATH:
2651 this.pathZ(ctx, boundingBox);
2652 break;
2653 }
2654 }
2655
2656 return boundingBox;
2657 }
2658
2659 getBoundingBox(_) {
2660 return this.path();
2661 }
2662
2663 getMarkers() {
2664 var {
2665 pathParser
2666 } = this;
2667 var points = pathParser.getMarkerPoints();
2668 var angles = pathParser.getMarkerAngles();
2669 var markers = points.map((point, i) => [point, angles[i]]);
2670 return markers;
2671 }
2672
2673 renderChildren(ctx) {
2674 this.path(ctx);
2675 this.document.screen.mouse.checkPath(this, ctx);
2676 var fillRuleStyleProp = this.getStyle('fill-rule');
2677
2678 if (ctx.fillStyle !== '') {
2679 if (fillRuleStyleProp.getString('inherit') !== 'inherit') {
2680 ctx.fill(fillRuleStyleProp.getString());
2681 } else {
2682 ctx.fill();
2683 }
2684 }
2685
2686 if (ctx.strokeStyle !== '') {
2687 if (this.getAttribute('vector-effect').getString() === 'non-scaling-stroke') {
2688 ctx.save();
2689 ctx.setTransform(1, 0, 0, 1, 0, 0);
2690 ctx.stroke();
2691 ctx.restore();
2692 } else {
2693 ctx.stroke();
2694 }
2695 }
2696
2697 var markers = this.getMarkers();
2698
2699 if (markers) {
2700 var markersLastIndex = markers.length - 1;
2701 var markerStartStyleProp = this.getStyle('marker-start');
2702 var markerMidStyleProp = this.getStyle('marker-mid');
2703 var markerEndStyleProp = this.getStyle('marker-end');
2704
2705 if (markerStartStyleProp.isUrlDefinition()) {
2706 var marker = markerStartStyleProp.getDefinition();
2707 var [point, angle] = markers[0];
2708 marker.render(ctx, point, angle);
2709 }
2710
2711 if (markerMidStyleProp.isUrlDefinition()) {
2712 var _marker = markerMidStyleProp.getDefinition();
2713
2714 for (var i = 1; i < markersLastIndex; i++) {
2715 var [_point, _angle] = markers[i];
2716
2717 _marker.render(ctx, _point, _angle);
2718 }
2719 }
2720
2721 if (markerEndStyleProp.isUrlDefinition()) {
2722 var _marker2 = markerEndStyleProp.getDefinition();
2723
2724 var [_point2, _angle2] = markers[markersLastIndex];
2725
2726 _marker2.render(ctx, _point2, _angle2);
2727 }
2728 }
2729 }
2730
2731 static pathM(pathParser) {
2732 var point = pathParser.getAsCurrentPoint();
2733 pathParser.start = pathParser.current;
2734 return {
2735 point
2736 };
2737 }
2738
2739 pathM(ctx, boundingBox) {
2740 var {
2741 pathParser
2742 } = this;
2743 var {
2744 point
2745 } = PathElement.pathM(pathParser);
2746 var {
2747 x,
2748 y
2749 } = point;
2750 pathParser.addMarker(point);
2751 boundingBox.addPoint(x, y);
2752
2753 if (ctx) {
2754 ctx.moveTo(x, y);
2755 }
2756 }
2757
2758 static pathL(pathParser) {
2759 var {
2760 current
2761 } = pathParser;
2762 var point = pathParser.getAsCurrentPoint();
2763 return {
2764 current,
2765 point
2766 };
2767 }
2768
2769 pathL(ctx, boundingBox) {
2770 var {
2771 pathParser
2772 } = this;
2773 var {
2774 current,
2775 point
2776 } = PathElement.pathL(pathParser);
2777 var {
2778 x,
2779 y
2780 } = point;
2781 pathParser.addMarker(point, current);
2782 boundingBox.addPoint(x, y);
2783
2784 if (ctx) {
2785 ctx.lineTo(x, y);
2786 }
2787 }
2788
2789 static pathH(pathParser) {
2790 var {
2791 current,
2792 command
2793 } = pathParser;
2794 var point = new Point((command.relative ? current.x : 0) + command.x, current.y);
2795 pathParser.current = point;
2796 return {
2797 current,
2798 point
2799 };
2800 }
2801
2802 pathH(ctx, boundingBox) {
2803 var {
2804 pathParser
2805 } = this;
2806 var {
2807 current,
2808 point
2809 } = PathElement.pathH(pathParser);
2810 var {
2811 x,
2812 y
2813 } = point;
2814 pathParser.addMarker(point, current);
2815 boundingBox.addPoint(x, y);
2816
2817 if (ctx) {
2818 ctx.lineTo(x, y);
2819 }
2820 }
2821
2822 static pathV(pathParser) {
2823 var {
2824 current,
2825 command
2826 } = pathParser;
2827 var point = new Point(current.x, (command.relative ? current.y : 0) + command.y);
2828 pathParser.current = point;
2829 return {
2830 current,
2831 point
2832 };
2833 }
2834
2835 pathV(ctx, boundingBox) {
2836 var {
2837 pathParser
2838 } = this;
2839 var {
2840 current,
2841 point
2842 } = PathElement.pathV(pathParser);
2843 var {
2844 x,
2845 y
2846 } = point;
2847 pathParser.addMarker(point, current);
2848 boundingBox.addPoint(x, y);
2849
2850 if (ctx) {
2851 ctx.lineTo(x, y);
2852 }
2853 }
2854
2855 static pathC(pathParser) {
2856 var {
2857 current
2858 } = pathParser;
2859 var point = pathParser.getPoint('x1', 'y1');
2860 var controlPoint = pathParser.getAsControlPoint('x2', 'y2');
2861 var currentPoint = pathParser.getAsCurrentPoint();
2862 return {
2863 current,
2864 point,
2865 controlPoint,
2866 currentPoint
2867 };
2868 }
2869
2870 pathC(ctx, boundingBox) {
2871 var {
2872 pathParser
2873 } = this;
2874 var {
2875 current,
2876 point,
2877 controlPoint,
2878 currentPoint
2879 } = PathElement.pathC(pathParser);
2880 pathParser.addMarker(currentPoint, controlPoint, point);
2881 boundingBox.addBezierCurve(current.x, current.y, point.x, point.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2882
2883 if (ctx) {
2884 ctx.bezierCurveTo(point.x, point.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2885 }
2886 }
2887
2888 static pathS(pathParser) {
2889 var {
2890 current
2891 } = pathParser;
2892 var point = pathParser.getReflectedControlPoint();
2893 var controlPoint = pathParser.getAsControlPoint('x2', 'y2');
2894 var currentPoint = pathParser.getAsCurrentPoint();
2895 return {
2896 current,
2897 point,
2898 controlPoint,
2899 currentPoint
2900 };
2901 }
2902
2903 pathS(ctx, boundingBox) {
2904 var {
2905 pathParser
2906 } = this;
2907 var {
2908 current,
2909 point,
2910 controlPoint,
2911 currentPoint
2912 } = PathElement.pathS(pathParser);
2913 pathParser.addMarker(currentPoint, controlPoint, point);
2914 boundingBox.addBezierCurve(current.x, current.y, point.x, point.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2915
2916 if (ctx) {
2917 ctx.bezierCurveTo(point.x, point.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2918 }
2919 }
2920
2921 static pathQ(pathParser) {
2922 var {
2923 current
2924 } = pathParser;
2925 var controlPoint = pathParser.getAsControlPoint('x1', 'y1');
2926 var currentPoint = pathParser.getAsCurrentPoint();
2927 return {
2928 current,
2929 controlPoint,
2930 currentPoint
2931 };
2932 }
2933
2934 pathQ(ctx, boundingBox) {
2935 var {
2936 pathParser
2937 } = this;
2938 var {
2939 current,
2940 controlPoint,
2941 currentPoint
2942 } = PathElement.pathQ(pathParser);
2943 pathParser.addMarker(currentPoint, controlPoint, controlPoint);
2944 boundingBox.addQuadraticCurve(current.x, current.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2945
2946 if (ctx) {
2947 ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2948 }
2949 }
2950
2951 static pathT(pathParser) {
2952 var {
2953 current
2954 } = pathParser;
2955 var controlPoint = pathParser.getReflectedControlPoint();
2956 pathParser.control = controlPoint;
2957 var currentPoint = pathParser.getAsCurrentPoint();
2958 return {
2959 current,
2960 controlPoint,
2961 currentPoint
2962 };
2963 }
2964
2965 pathT(ctx, boundingBox) {
2966 var {
2967 pathParser
2968 } = this;
2969 var {
2970 current,
2971 controlPoint,
2972 currentPoint
2973 } = PathElement.pathT(pathParser);
2974 pathParser.addMarker(currentPoint, controlPoint, controlPoint);
2975 boundingBox.addQuadraticCurve(current.x, current.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2976
2977 if (ctx) {
2978 ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
2979 }
2980 }
2981
2982 static pathA(pathParser) {
2983 var {
2984 current,
2985 command
2986 } = pathParser;
2987 var {
2988 rX,
2989 rY,
2990 xRot,
2991 lArcFlag,
2992 sweepFlag
2993 } = command;
2994 var xAxisRotation = xRot * (Math.PI / 180.0);
2995 var currentPoint = pathParser.getAsCurrentPoint(); // Conversion from endpoint to center parameterization
2996 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
2997 // x1', y1'
2998
2999 var currp = new Point(Math.cos(xAxisRotation) * (current.x - currentPoint.x) / 2.0 + Math.sin(xAxisRotation) * (current.y - currentPoint.y) / 2.0, -Math.sin(xAxisRotation) * (current.x - currentPoint.x) / 2.0 + Math.cos(xAxisRotation) * (current.y - currentPoint.y) / 2.0); // adjust radii
3000
3001 var l = Math.pow(currp.x, 2) / Math.pow(rX, 2) + Math.pow(currp.y, 2) / Math.pow(rY, 2);
3002
3003 if (l > 1) {
3004 rX *= Math.sqrt(l);
3005 rY *= Math.sqrt(l);
3006 } // cx', cy'
3007
3008
3009 var s = (lArcFlag === sweepFlag ? -1 : 1) * Math.sqrt((Math.pow(rX, 2) * Math.pow(rY, 2) - Math.pow(rX, 2) * Math.pow(currp.y, 2) - Math.pow(rY, 2) * Math.pow(currp.x, 2)) / (Math.pow(rX, 2) * Math.pow(currp.y, 2) + Math.pow(rY, 2) * Math.pow(currp.x, 2)));
3010
3011 if (isNaN(s)) {
3012 s = 0;
3013 }
3014
3015 var cpp = new Point(s * rX * currp.y / rY, s * -rY * currp.x / rX); // cx, cy
3016
3017 var centp = new Point((current.x + currentPoint.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, (current.y + currentPoint.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y); // initial angle
3018
3019 var a1 = vectorsAngle([1, 0], [(currp.x - cpp.x) / rX, (currp.y - cpp.y) / rY]); // θ1
3020 // angle delta
3021
3022 var u = [(currp.x - cpp.x) / rX, (currp.y - cpp.y) / rY];
3023 var v = [(-currp.x - cpp.x) / rX, (-currp.y - cpp.y) / rY];
3024 var ad = vectorsAngle(u, v); // Δθ
3025
3026 if (vectorsRatio(u, v) <= -1) {
3027 ad = Math.PI;
3028 }
3029
3030 if (vectorsRatio(u, v) >= 1) {
3031 ad = 0;
3032 }
3033
3034 return {
3035 currentPoint,
3036 rX,
3037 rY,
3038 sweepFlag,
3039 xAxisRotation,
3040 centp,
3041 a1,
3042 ad
3043 };
3044 }
3045
3046 pathA(ctx, boundingBox) {
3047 var {
3048 pathParser
3049 } = this;
3050 var {
3051 currentPoint,
3052 rX,
3053 rY,
3054 sweepFlag,
3055 xAxisRotation,
3056 centp,
3057 a1,
3058 ad
3059 } = PathElement.pathA(pathParser); // for markers
3060
3061 var dir = 1 - sweepFlag ? 1.0 : -1.0;
3062 var ah = a1 + dir * (ad / 2.0);
3063 var halfWay = new Point(centp.x + rX * Math.cos(ah), centp.y + rY * Math.sin(ah));
3064 pathParser.addMarkerAngle(halfWay, ah - dir * Math.PI / 2);
3065 pathParser.addMarkerAngle(currentPoint, ah - dir * Math.PI);
3066 boundingBox.addPoint(currentPoint.x, currentPoint.y); // TODO: this is too naive, make it better
3067
3068 if (ctx && !isNaN(a1) && !isNaN(ad)) {
3069 var r = rX > rY ? rX : rY;
3070 var sx = rX > rY ? 1 : rX / rY;
3071 var sy = rX > rY ? rY / rX : 1;
3072 ctx.translate(centp.x, centp.y);
3073 ctx.rotate(xAxisRotation);
3074 ctx.scale(sx, sy);
3075 ctx.arc(0, 0, r, a1, a1 + ad, Boolean(1 - sweepFlag));
3076 ctx.scale(1 / sx, 1 / sy);
3077 ctx.rotate(-xAxisRotation);
3078 ctx.translate(-centp.x, -centp.y);
3079 }
3080 }
3081
3082 static pathZ(pathParser) {
3083 pathParser.current = pathParser.start;
3084 }
3085
3086 pathZ(ctx, boundingBox) {
3087 PathElement.pathZ(this.pathParser);
3088
3089 if (ctx) {
3090 // only close path if it is not a straight line
3091 if (boundingBox.x1 !== boundingBox.x2 && boundingBox.y1 !== boundingBox.y2) {
3092 ctx.closePath();
3093 }
3094 }
3095 }
3096
3097}
3098
3099class GlyphElement extends PathElement {
3100 constructor(document, node, captureTextNodes) {
3101 super(document, node, captureTextNodes);
3102 this.type = 'glyph';
3103 this.horizAdvX = this.getAttribute('horiz-adv-x').getNumber();
3104 this.unicode = this.getAttribute('unicode').getString();
3105 this.arabicForm = this.getAttribute('arabic-form').getString();
3106 }
3107
3108}
3109
3110class TextElement extends RenderedElement {
3111 constructor(document, node, captureTextNodes) {
3112 super(document, node, new.target === TextElement ? true : captureTextNodes);
3113 this.type = 'text';
3114 this.x = 0;
3115 this.y = 0;
3116 this.measureCache = -1;
3117 }
3118
3119 setContext(ctx) {
3120 var fromMeasure = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
3121 super.setContext(ctx, fromMeasure);
3122 var textBaseline = this.getStyle('dominant-baseline').getTextBaseline() || this.getStyle('alignment-baseline').getTextBaseline();
3123
3124 if (textBaseline) {
3125 ctx.textBaseline = textBaseline;
3126 }
3127 }
3128
3129 initializeCoordinates() {
3130 this.x = 0;
3131 this.y = 0;
3132 this.leafTexts = [];
3133 this.textChunkStart = 0;
3134 this.minX = Number.POSITIVE_INFINITY;
3135 this.maxX = Number.NEGATIVE_INFINITY;
3136 }
3137
3138 getBoundingBox(ctx) {
3139 if (this.type !== 'text') {
3140 return this.getTElementBoundingBox(ctx);
3141 } // first, calculate child positions
3142
3143
3144 this.initializeCoordinates();
3145 this.adjustChildCoordinatesRecursive(ctx);
3146 var boundingBox = null; // then calculate bounding box
3147
3148 this.children.forEach((_, i) => {
3149 var childBoundingBox = this.getChildBoundingBox(ctx, this, this, i);
3150
3151 if (!boundingBox) {
3152 boundingBox = childBoundingBox;
3153 } else {
3154 boundingBox.addBoundingBox(childBoundingBox);
3155 }
3156 });
3157 return boundingBox;
3158 }
3159
3160 getFontSize() {
3161 var {
3162 document,
3163 parent
3164 } = this;
3165 var inheritFontSize = Font.parse(document.ctx.font).fontSize;
3166 var fontSize = parent.getStyle('font-size').getNumber(inheritFontSize);
3167 return fontSize;
3168 }
3169
3170 getTElementBoundingBox(ctx) {
3171 var fontSize = this.getFontSize();
3172 return new BoundingBox(this.x, this.y - fontSize, this.x + this.measureText(ctx), this.y);
3173 }
3174
3175 getGlyph(font, text, i) {
3176 var char = text[i];
3177 var glyph = null;
3178
3179 if (font.isArabic) {
3180 var len = text.length;
3181 var prevChar = text[i - 1];
3182 var nextChar = text[i + 1];
3183 var arabicForm = 'isolated';
3184
3185 if ((i === 0 || prevChar === ' ') && i < len - 1 && nextChar !== ' ') {
3186 arabicForm = 'terminal';
3187 }
3188
3189 if (i > 0 && prevChar !== ' ' && i < len - 1 && nextChar !== ' ') {
3190 arabicForm = 'medial';
3191 }
3192
3193 if (i > 0 && prevChar !== ' ' && (i === len - 1 || nextChar === ' ')) {
3194 arabicForm = 'initial';
3195 }
3196
3197 if (typeof font.glyphs[char] !== 'undefined') {
3198 // NEED TEST
3199 var maybeGlyph = font.glyphs[char];
3200 glyph = maybeGlyph instanceof GlyphElement ? maybeGlyph : maybeGlyph[arabicForm];
3201 }
3202 } else {
3203 glyph = font.glyphs[char];
3204 }
3205
3206 if (!glyph) {
3207 glyph = font.missingGlyph;
3208 }
3209
3210 return glyph;
3211 }
3212
3213 getText() {
3214 return '';
3215 }
3216
3217 getTextFromNode(node) {
3218 var textNode = node || this.node;
3219 var childNodes = Array.from(textNode.parentNode.childNodes);
3220 var index = childNodes.indexOf(textNode);
3221 var lastIndex = childNodes.length - 1;
3222 var text = compressSpaces( // textNode.value
3223 // || textNode.text
3224 textNode.textContent || '');
3225
3226 if (index === 0) {
3227 text = trimLeft(text);
3228 }
3229
3230 if (index === lastIndex) {
3231 text = trimRight(text);
3232 }
3233
3234 return text;
3235 }
3236
3237 renderChildren(ctx) {
3238 if (this.type !== 'text') {
3239 this.renderTElementChildren(ctx);
3240 return;
3241 } // first, calculate child positions
3242
3243
3244 this.initializeCoordinates();
3245 this.adjustChildCoordinatesRecursive(ctx); // then render
3246
3247 this.children.forEach((_, i) => {
3248 this.renderChild(ctx, this, this, i);
3249 });
3250 var {
3251 mouse
3252 } = this.document.screen; // Do not calc bounding box if mouse is not working.
3253
3254 if (mouse.isWorking()) {
3255 mouse.checkBoundingBox(this, this.getBoundingBox(ctx));
3256 }
3257 }
3258
3259 renderTElementChildren(ctx) {
3260 var {
3261 document,
3262 parent
3263 } = this;
3264 var renderText = this.getText();
3265 var customFont = parent.getStyle('font-family').getDefinition();
3266
3267 if (customFont) {
3268 var {
3269 unitsPerEm
3270 } = customFont.fontFace;
3271 var ctxFont = Font.parse(document.ctx.font);
3272 var fontSize = parent.getStyle('font-size').getNumber(ctxFont.fontSize);
3273 var fontStyle = parent.getStyle('font-style').getString(ctxFont.fontStyle);
3274 var scale = fontSize / unitsPerEm;
3275 var text = customFont.isRTL ? renderText.split('').reverse().join('') : renderText;
3276 var dx = toNumbers(parent.getAttribute('dx').getString());
3277 var len = text.length;
3278
3279 for (var i = 0; i < len; i++) {
3280 var glyph = this.getGlyph(customFont, text, i);
3281 ctx.translate(this.x, this.y);
3282 ctx.scale(scale, -scale);
3283 var lw = ctx.lineWidth;
3284 ctx.lineWidth = ctx.lineWidth * unitsPerEm / fontSize;
3285
3286 if (fontStyle === 'italic') {
3287 ctx.transform(1, 0, .4, 1, 0, 0);
3288 }
3289
3290 glyph.render(ctx);
3291
3292 if (fontStyle === 'italic') {
3293 ctx.transform(1, 0, -.4, 1, 0, 0);
3294 }
3295
3296 ctx.lineWidth = lw;
3297 ctx.scale(1 / scale, -1 / scale);
3298 ctx.translate(-this.x, -this.y);
3299 this.x += fontSize * (glyph.horizAdvX || customFont.horizAdvX) / unitsPerEm;
3300
3301 if (typeof dx[i] !== 'undefined' && !isNaN(dx[i])) {
3302 this.x += dx[i];
3303 }
3304 }
3305
3306 return;
3307 }
3308
3309 var {
3310 x,
3311 y
3312 } = this; // NEED TEST
3313 // if (ctx.paintOrder === 'stroke') {
3314 // if (ctx.strokeStyle) {
3315 // ctx.strokeText(renderText, x, y);
3316 // }
3317 // if (ctx.fillStyle) {
3318 // ctx.fillText(renderText, x, y);
3319 // }
3320 // } else {
3321
3322 if (ctx.fillStyle) {
3323 ctx.fillText(renderText, x, y);
3324 }
3325
3326 if (ctx.strokeStyle) {
3327 ctx.strokeText(renderText, x, y);
3328 } // }
3329
3330 }
3331
3332 applyAnchoring() {
3333 if (this.textChunkStart >= this.leafTexts.length) {
3334 return;
3335 } // This is basically the "Apply anchoring" part of https://www.w3.org/TR/SVG2/text.html#TextLayoutAlgorithm.
3336 // The difference is that we apply the anchoring as soon as a chunk is finished. This saves some extra looping.
3337 // Vertical text is not supported.
3338
3339
3340 var firstElement = this.leafTexts[this.textChunkStart];
3341 var textAnchor = firstElement.getStyle('text-anchor').getString('start');
3342 var isRTL = false; // we treat RTL like LTR
3343
3344 var shift = 0;
3345
3346 if (textAnchor === 'start' && !isRTL || textAnchor === 'end' && isRTL) {
3347 shift = firstElement.x - this.minX;
3348 } else if (textAnchor === 'end' && !isRTL || textAnchor === 'start' && isRTL) {
3349 shift = firstElement.x - this.maxX;
3350 } else {
3351 shift = firstElement.x - (this.minX + this.maxX) / 2;
3352 }
3353
3354 for (var i = this.textChunkStart; i < this.leafTexts.length; i++) {
3355 this.leafTexts[i].x += shift;
3356 } // start new chunk
3357
3358
3359 this.minX = Number.POSITIVE_INFINITY;
3360 this.maxX = Number.NEGATIVE_INFINITY;
3361 this.textChunkStart = this.leafTexts.length;
3362 }
3363
3364 adjustChildCoordinatesRecursive(ctx) {
3365 this.children.forEach((_, i) => {
3366 this.adjustChildCoordinatesRecursiveCore(ctx, this, this, i);
3367 });
3368 this.applyAnchoring();
3369 }
3370
3371 adjustChildCoordinatesRecursiveCore(ctx, textParent, parent, i) {
3372 var child = parent.children[i];
3373
3374 if (child.children.length > 0) {
3375 child.children.forEach((_, i) => {
3376 textParent.adjustChildCoordinatesRecursiveCore(ctx, textParent, child, i);
3377 });
3378 } else {
3379 // only leafs are relevant
3380 this.adjustChildCoordinates(ctx, textParent, parent, i);
3381 }
3382 }
3383
3384 adjustChildCoordinates(ctx, textParent, parent, i) {
3385 var child = parent.children[i];
3386
3387 if (typeof child.measureText !== 'function') {
3388 return child;
3389 }
3390
3391 ctx.save();
3392 child.setContext(ctx, true);
3393 var xAttr = child.getAttribute('x');
3394 var yAttr = child.getAttribute('y');
3395 var dxAttr = child.getAttribute('dx');
3396 var dyAttr = child.getAttribute('dy');
3397 var customFont = child.getStyle('font-family').getDefinition();
3398 var isRTL = Boolean(customFont) && customFont.isRTL;
3399
3400 if (i === 0) {
3401 // First children inherit attributes from parent(s). Positional attributes
3402 // are only inherited from a parent to it's first child.
3403 if (!xAttr.hasValue()) {
3404 xAttr.setValue(child.getInheritedAttribute('x'));
3405 }
3406
3407 if (!yAttr.hasValue()) {
3408 yAttr.setValue(child.getInheritedAttribute('y'));
3409 }
3410
3411 if (!dxAttr.hasValue()) {
3412 dxAttr.setValue(child.getInheritedAttribute('dx'));
3413 }
3414
3415 if (!dyAttr.hasValue()) {
3416 dyAttr.setValue(child.getInheritedAttribute('dy'));
3417 }
3418 }
3419
3420 var width = child.measureText(ctx);
3421
3422 if (isRTL) {
3423 textParent.x -= width;
3424 }
3425
3426 if (xAttr.hasValue()) {
3427 // an "x" attribute marks the start of a new chunk
3428 textParent.applyAnchoring();
3429 child.x = xAttr.getPixels('x');
3430
3431 if (dxAttr.hasValue()) {
3432 child.x += dxAttr.getPixels('x');
3433 }
3434 } else {
3435 if (dxAttr.hasValue()) {
3436 textParent.x += dxAttr.getPixels('x');
3437 }
3438
3439 child.x = textParent.x;
3440 }
3441
3442 textParent.x = child.x;
3443
3444 if (!isRTL) {
3445 textParent.x += width;
3446 }
3447
3448 if (yAttr.hasValue()) {
3449 child.y = yAttr.getPixels('y');
3450
3451 if (dyAttr.hasValue()) {
3452 child.y += dyAttr.getPixels('y');
3453 }
3454 } else {
3455 if (dyAttr.hasValue()) {
3456 textParent.y += dyAttr.getPixels('y');
3457 }
3458
3459 child.y = textParent.y;
3460 }
3461
3462 textParent.y = child.y; // update the current chunk and it's bounds
3463
3464 textParent.leafTexts.push(child);
3465 textParent.minX = Math.min(textParent.minX, child.x, child.x + width);
3466 textParent.maxX = Math.max(textParent.maxX, child.x, child.x + width);
3467 child.clearContext(ctx);
3468 ctx.restore();
3469 return child;
3470 }
3471
3472 getChildBoundingBox(ctx, textParent, parent, i) {
3473 var child = parent.children[i]; // not a text node?
3474
3475 if (typeof child.getBoundingBox !== 'function') {
3476 return null;
3477 }
3478
3479 var boundingBox = child.getBoundingBox(ctx);
3480
3481 if (!boundingBox) {
3482 return null;
3483 }
3484
3485 child.children.forEach((_, i) => {
3486 var childBoundingBox = textParent.getChildBoundingBox(ctx, textParent, child, i);
3487 boundingBox.addBoundingBox(childBoundingBox);
3488 });
3489 return boundingBox;
3490 }
3491
3492 renderChild(ctx, textParent, parent, i) {
3493 var child = parent.children[i];
3494 child.render(ctx);
3495 child.children.forEach((_, i) => {
3496 textParent.renderChild(ctx, textParent, child, i);
3497 });
3498 }
3499
3500 measureText(ctx) {
3501 var {
3502 measureCache
3503 } = this;
3504
3505 if (~measureCache) {
3506 return measureCache;
3507 }
3508
3509 var renderText = this.getText();
3510 var measure = this.measureTargetText(ctx, renderText);
3511 this.measureCache = measure;
3512 return measure;
3513 }
3514
3515 measureTargetText(ctx, targetText) {
3516 if (!targetText.length) {
3517 return 0;
3518 }
3519
3520 var {
3521 parent
3522 } = this;
3523 var customFont = parent.getStyle('font-family').getDefinition();
3524
3525 if (customFont) {
3526 var fontSize = this.getFontSize();
3527 var text = customFont.isRTL ? targetText.split('').reverse().join('') : targetText;
3528 var dx = toNumbers(parent.getAttribute('dx').getString());
3529 var len = text.length;
3530 var _measure = 0;
3531
3532 for (var i = 0; i < len; i++) {
3533 var glyph = this.getGlyph(customFont, text, i);
3534 _measure += (glyph.horizAdvX || customFont.horizAdvX) * fontSize / customFont.fontFace.unitsPerEm;
3535
3536 if (typeof dx[i] !== 'undefined' && !isNaN(dx[i])) {
3537 _measure += dx[i];
3538 }
3539 }
3540
3541 return _measure;
3542 }
3543
3544 if (!ctx.measureText) {
3545 return targetText.length * 10;
3546 }
3547
3548 ctx.save();
3549 this.setContext(ctx, true);
3550 var {
3551 width: measure
3552 } = ctx.measureText(targetText);
3553 this.clearContext(ctx);
3554 ctx.restore();
3555 return measure;
3556 }
3557 /**
3558 * Inherits positional attributes from {@link TextElement} parent(s). Attributes
3559 * are only inherited from a parent to its first child.
3560 * @param name - The attribute name.
3561 * @returns The attribute value or null.
3562 */
3563
3564
3565 getInheritedAttribute(name) {
3566 // eslint-disable-next-line @typescript-eslint/no-this-alias,consistent-this
3567 var current = this;
3568
3569 while (current instanceof TextElement && current.isFirstChild()) {
3570 var parentAttr = current.parent.getAttribute(name);
3571
3572 if (parentAttr.hasValue(true)) {
3573 return parentAttr.getValue('0');
3574 }
3575
3576 current = current.parent;
3577 }
3578
3579 return null;
3580 }
3581
3582}
3583
3584class TSpanElement extends TextElement {
3585 constructor(document, node, captureTextNodes) {
3586 super(document, node, new.target === TSpanElement ? true : captureTextNodes);
3587 this.type = 'tspan'; // if this node has children, then they own the text
3588
3589 this.text = this.children.length > 0 ? '' : this.getTextFromNode();
3590 }
3591
3592 getText() {
3593 return this.text;
3594 }
3595
3596}
3597
3598class TextNode extends TSpanElement {
3599 constructor() {
3600 super(...arguments);
3601 this.type = 'textNode';
3602 }
3603
3604}
3605
3606class SVGElement extends RenderedElement {
3607 constructor() {
3608 super(...arguments);
3609 this.type = 'svg';
3610 this.root = false;
3611 }
3612
3613 setContext(ctx) {
3614 var _this$node$parentNode;
3615
3616 var {
3617 document
3618 } = this;
3619 var {
3620 screen,
3621 window
3622 } = document;
3623 var canvas = ctx.canvas;
3624 screen.setDefaults(ctx);
3625
3626 if (canvas.style && typeof ctx.font !== 'undefined' && window && typeof window.getComputedStyle !== 'undefined') {
3627 ctx.font = window.getComputedStyle(canvas).getPropertyValue('font');
3628 var fontSizeProp = new Property(document, 'fontSize', Font.parse(ctx.font).fontSize);
3629
3630 if (fontSizeProp.hasValue()) {
3631 document.rootEmSize = fontSizeProp.getPixels('y');
3632 document.emSize = document.rootEmSize;
3633 }
3634 } // create new view port
3635
3636
3637 if (!this.getAttribute('x').hasValue()) {
3638 this.getAttribute('x', true).setValue(0);
3639 }
3640
3641 if (!this.getAttribute('y').hasValue()) {
3642 this.getAttribute('y', true).setValue(0);
3643 }
3644
3645 var {
3646 width,
3647 height
3648 } = screen.viewPort;
3649
3650 if (!this.getStyle('width').hasValue()) {
3651 this.getStyle('width', true).setValue('100%');
3652 }
3653
3654 if (!this.getStyle('height').hasValue()) {
3655 this.getStyle('height', true).setValue('100%');
3656 }
3657
3658 if (!this.getStyle('color').hasValue()) {
3659 this.getStyle('color', true).setValue('black');
3660 }
3661
3662 var refXAttr = this.getAttribute('refX');
3663 var refYAttr = this.getAttribute('refY');
3664 var viewBoxAttr = this.getAttribute('viewBox');
3665 var viewBox = viewBoxAttr.hasValue() ? toNumbers(viewBoxAttr.getString()) : null;
3666 var clip = !this.root && this.getStyle('overflow').getValue('hidden') !== 'visible';
3667 var minX = 0;
3668 var minY = 0;
3669 var clipX = 0;
3670 var clipY = 0;
3671
3672 if (viewBox) {
3673 minX = viewBox[0];
3674 minY = viewBox[1];
3675 }
3676
3677 if (!this.root) {
3678 width = this.getStyle('width').getPixels('x');
3679 height = this.getStyle('height').getPixels('y');
3680
3681 if (this.type === 'marker') {
3682 clipX = minX;
3683 clipY = minY;
3684 minX = 0;
3685 minY = 0;
3686 }
3687 }
3688
3689 screen.viewPort.setCurrent(width, height); // Default value of transform-origin is center only for root SVG elements
3690 // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform-origin
3691
3692 if (this.node // is not temporary SVGElement
3693 && (!this.parent || ((_this$node$parentNode = this.node.parentNode) === null || _this$node$parentNode === void 0 ? void 0 : _this$node$parentNode.nodeName) === 'foreignObject') && this.getStyle('transform', false, true).hasValue() && !this.getStyle('transform-origin', false, true).hasValue()) {
3694 this.getStyle('transform-origin', true, true).setValue('50% 50%');
3695 }
3696
3697 super.setContext(ctx);
3698 ctx.translate(this.getAttribute('x').getPixels('x'), this.getAttribute('y').getPixels('y'));
3699
3700 if (viewBox) {
3701 width = viewBox[2];
3702 height = viewBox[3];
3703 }
3704
3705 document.setViewBox({
3706 ctx,
3707 aspectRatio: this.getAttribute('preserveAspectRatio').getString(),
3708 width: screen.viewPort.width,
3709 desiredWidth: width,
3710 height: screen.viewPort.height,
3711 desiredHeight: height,
3712 minX,
3713 minY,
3714 refX: refXAttr.getValue(),
3715 refY: refYAttr.getValue(),
3716 clip,
3717 clipX,
3718 clipY
3719 });
3720
3721 if (viewBox) {
3722 screen.viewPort.removeCurrent();
3723 screen.viewPort.setCurrent(width, height);
3724 }
3725 }
3726
3727 clearContext(ctx) {
3728 super.clearContext(ctx);
3729 this.document.screen.viewPort.removeCurrent();
3730 }
3731 /**
3732 * Resize SVG to fit in given size.
3733 * @param width
3734 * @param height
3735 * @param preserveAspectRatio
3736 */
3737
3738
3739 resize(width) {
3740 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : width;
3741 var preserveAspectRatio = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
3742 var widthAttr = this.getAttribute('width', true);
3743 var heightAttr = this.getAttribute('height', true);
3744 var viewBoxAttr = this.getAttribute('viewBox');
3745 var styleAttr = this.getAttribute('style');
3746 var originWidth = widthAttr.getNumber(0);
3747 var originHeight = heightAttr.getNumber(0);
3748
3749 if (preserveAspectRatio) {
3750 if (typeof preserveAspectRatio === 'string') {
3751 this.getAttribute('preserveAspectRatio', true).setValue(preserveAspectRatio);
3752 } else {
3753 var preserveAspectRatioAttr = this.getAttribute('preserveAspectRatio');
3754
3755 if (preserveAspectRatioAttr.hasValue()) {
3756 preserveAspectRatioAttr.setValue(preserveAspectRatioAttr.getString().replace(/^\s*(\S.*\S)\s*$/, '$1'));
3757 }
3758 }
3759 }
3760
3761 widthAttr.setValue(width);
3762 heightAttr.setValue(height);
3763
3764 if (!viewBoxAttr.hasValue()) {
3765 viewBoxAttr.setValue("0 0 ".concat(originWidth || width, " ").concat(originHeight || height));
3766 }
3767
3768 if (styleAttr.hasValue()) {
3769 var widthStyle = this.getStyle('width');
3770 var heightStyle = this.getStyle('height');
3771
3772 if (widthStyle.hasValue()) {
3773 widthStyle.setValue("".concat(width, "px"));
3774 }
3775
3776 if (heightStyle.hasValue()) {
3777 heightStyle.setValue("".concat(height, "px"));
3778 }
3779 }
3780 }
3781
3782}
3783
3784class RectElement extends PathElement {
3785 constructor() {
3786 super(...arguments);
3787 this.type = 'rect';
3788 }
3789
3790 path(ctx) {
3791 var x = this.getAttribute('x').getPixels('x');
3792 var y = this.getAttribute('y').getPixels('y');
3793 var width = this.getStyle('width', false, true).getPixels('x');
3794 var height = this.getStyle('height', false, true).getPixels('y');
3795 var rxAttr = this.getAttribute('rx');
3796 var ryAttr = this.getAttribute('ry');
3797 var rx = rxAttr.getPixels('x');
3798 var ry = ryAttr.getPixels('y');
3799
3800 if (rxAttr.hasValue() && !ryAttr.hasValue()) {
3801 ry = rx;
3802 }
3803
3804 if (ryAttr.hasValue() && !rxAttr.hasValue()) {
3805 rx = ry;
3806 }
3807
3808 rx = Math.min(rx, width / 2.0);
3809 ry = Math.min(ry, height / 2.0);
3810
3811 if (ctx) {
3812 var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
3813 ctx.beginPath(); // always start the path so we don't fill prior paths
3814
3815 if (height > 0 && width > 0) {
3816 ctx.moveTo(x + rx, y);
3817 ctx.lineTo(x + width - rx, y);
3818 ctx.bezierCurveTo(x + width - rx + KAPPA * rx, y, x + width, y + ry - KAPPA * ry, x + width, y + ry);
3819 ctx.lineTo(x + width, y + height - ry);
3820 ctx.bezierCurveTo(x + width, y + height - ry + KAPPA * ry, x + width - rx + KAPPA * rx, y + height, x + width - rx, y + height);
3821 ctx.lineTo(x + rx, y + height);
3822 ctx.bezierCurveTo(x + rx - KAPPA * rx, y + height, x, y + height - ry + KAPPA * ry, x, y + height - ry);
3823 ctx.lineTo(x, y + ry);
3824 ctx.bezierCurveTo(x, y + ry - KAPPA * ry, x + rx - KAPPA * rx, y, x + rx, y);
3825 ctx.closePath();
3826 }
3827 }
3828
3829 return new BoundingBox(x, y, x + width, y + height);
3830 }
3831
3832 getMarkers() {
3833 return null;
3834 }
3835
3836}
3837
3838class CircleElement extends PathElement {
3839 constructor() {
3840 super(...arguments);
3841 this.type = 'circle';
3842 }
3843
3844 path(ctx) {
3845 var cx = this.getAttribute('cx').getPixels('x');
3846 var cy = this.getAttribute('cy').getPixels('y');
3847 var r = this.getAttribute('r').getPixels();
3848
3849 if (ctx && r > 0) {
3850 ctx.beginPath();
3851 ctx.arc(cx, cy, r, 0, Math.PI * 2, false);
3852 ctx.closePath();
3853 }
3854
3855 return new BoundingBox(cx - r, cy - r, cx + r, cy + r);
3856 }
3857
3858 getMarkers() {
3859 return null;
3860 }
3861
3862}
3863
3864class EllipseElement extends PathElement {
3865 constructor() {
3866 super(...arguments);
3867 this.type = 'ellipse';
3868 }
3869
3870 path(ctx) {
3871 var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
3872 var rx = this.getAttribute('rx').getPixels('x');
3873 var ry = this.getAttribute('ry').getPixels('y');
3874 var cx = this.getAttribute('cx').getPixels('x');
3875 var cy = this.getAttribute('cy').getPixels('y');
3876
3877 if (ctx && rx > 0 && ry > 0) {
3878 ctx.beginPath();
3879 ctx.moveTo(cx + rx, cy);
3880 ctx.bezierCurveTo(cx + rx, cy + KAPPA * ry, cx + KAPPA * rx, cy + ry, cx, cy + ry);
3881 ctx.bezierCurveTo(cx - KAPPA * rx, cy + ry, cx - rx, cy + KAPPA * ry, cx - rx, cy);
3882 ctx.bezierCurveTo(cx - rx, cy - KAPPA * ry, cx - KAPPA * rx, cy - ry, cx, cy - ry);
3883 ctx.bezierCurveTo(cx + KAPPA * rx, cy - ry, cx + rx, cy - KAPPA * ry, cx + rx, cy);
3884 ctx.closePath();
3885 }
3886
3887 return new BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry);
3888 }
3889
3890 getMarkers() {
3891 return null;
3892 }
3893
3894}
3895
3896class LineElement extends PathElement {
3897 constructor() {
3898 super(...arguments);
3899 this.type = 'line';
3900 }
3901
3902 getPoints() {
3903 return [new Point(this.getAttribute('x1').getPixels('x'), this.getAttribute('y1').getPixels('y')), new Point(this.getAttribute('x2').getPixels('x'), this.getAttribute('y2').getPixels('y'))];
3904 }
3905
3906 path(ctx) {
3907 var [{
3908 x: x0,
3909 y: y0
3910 }, {
3911 x: x1,
3912 y: y1
3913 }] = this.getPoints();
3914
3915 if (ctx) {
3916 ctx.beginPath();
3917 ctx.moveTo(x0, y0);
3918 ctx.lineTo(x1, y1);
3919 }
3920
3921 return new BoundingBox(x0, y0, x1, y1);
3922 }
3923
3924 getMarkers() {
3925 var [p0, p1] = this.getPoints();
3926 var a = p0.angleTo(p1);
3927 return [[p0, a], [p1, a]];
3928 }
3929
3930}
3931
3932class PolylineElement extends PathElement {
3933 constructor(document, node, captureTextNodes) {
3934 super(document, node, captureTextNodes);
3935 this.type = 'polyline';
3936 this.points = [];
3937 this.points = Point.parsePath(this.getAttribute('points').getString());
3938 }
3939
3940 path(ctx) {
3941 var {
3942 points
3943 } = this;
3944 var [{
3945 x: x0,
3946 y: y0
3947 }] = points;
3948 var boundingBox = new BoundingBox(x0, y0);
3949
3950 if (ctx) {
3951 ctx.beginPath();
3952 ctx.moveTo(x0, y0);
3953 }
3954
3955 points.forEach(_ref => {
3956 var {
3957 x,
3958 y
3959 } = _ref;
3960 boundingBox.addPoint(x, y);
3961
3962 if (ctx) {
3963 ctx.lineTo(x, y);
3964 }
3965 });
3966 return boundingBox;
3967 }
3968
3969 getMarkers() {
3970 var {
3971 points
3972 } = this;
3973 var lastIndex = points.length - 1;
3974 var markers = [];
3975 points.forEach((point, i) => {
3976 if (i === lastIndex) {
3977 return;
3978 }
3979
3980 markers.push([point, point.angleTo(points[i + 1])]);
3981 });
3982
3983 if (markers.length > 0) {
3984 markers.push([points[points.length - 1], markers[markers.length - 1][1]]);
3985 }
3986
3987 return markers;
3988 }
3989
3990}
3991
3992class PolygonElement extends PolylineElement {
3993 constructor() {
3994 super(...arguments);
3995 this.type = 'polygon';
3996 }
3997
3998 path(ctx) {
3999 var boundingBox = super.path(ctx);
4000 var [{
4001 x,
4002 y
4003 }] = this.points;
4004
4005 if (ctx) {
4006 ctx.lineTo(x, y);
4007 ctx.closePath();
4008 }
4009
4010 return boundingBox;
4011 }
4012
4013}
4014
4015class PatternElement extends Element {
4016 constructor() {
4017 super(...arguments);
4018 this.type = 'pattern';
4019 }
4020
4021 createPattern(ctx, _, parentOpacityProp) {
4022 var width = this.getStyle('width').getPixels('x', true);
4023 var height = this.getStyle('height').getPixels('y', true); // render me using a temporary svg element
4024
4025 var patternSvg = new SVGElement(this.document, null);
4026 patternSvg.attributes.viewBox = new Property(this.document, 'viewBox', this.getAttribute('viewBox').getValue());
4027 patternSvg.attributes.width = new Property(this.document, 'width', "".concat(width, "px"));
4028 patternSvg.attributes.height = new Property(this.document, 'height', "".concat(height, "px"));
4029 patternSvg.attributes.transform = new Property(this.document, 'transform', this.getAttribute('patternTransform').getValue());
4030 patternSvg.children = this.children;
4031 var patternCanvas = this.document.createCanvas(width, height);
4032 var patternCtx = patternCanvas.getContext('2d');
4033 var xAttr = this.getAttribute('x');
4034 var yAttr = this.getAttribute('y');
4035
4036 if (xAttr.hasValue() && yAttr.hasValue()) {
4037 patternCtx.translate(xAttr.getPixels('x', true), yAttr.getPixels('y', true));
4038 }
4039
4040 if (parentOpacityProp.hasValue()) {
4041 this.styles['fill-opacity'] = parentOpacityProp;
4042 } else {
4043 Reflect.deleteProperty(this.styles, 'fill-opacity');
4044 } // render 3x3 grid so when we transform there's no white space on edges
4045
4046
4047 for (var x = -1; x <= 1; x++) {
4048 for (var y = -1; y <= 1; y++) {
4049 patternCtx.save();
4050 patternSvg.attributes.x = new Property(this.document, 'x', x * patternCanvas.width);
4051 patternSvg.attributes.y = new Property(this.document, 'y', y * patternCanvas.height);
4052 patternSvg.render(patternCtx);
4053 patternCtx.restore();
4054 }
4055 }
4056
4057 var pattern = ctx.createPattern(patternCanvas, 'repeat');
4058 return pattern;
4059 }
4060
4061}
4062
4063class MarkerElement extends Element {
4064 constructor() {
4065 super(...arguments);
4066 this.type = 'marker';
4067 }
4068
4069 render(ctx, point, angle) {
4070 if (!point) {
4071 return;
4072 }
4073
4074 var {
4075 x,
4076 y
4077 } = point;
4078 var orient = this.getAttribute('orient').getString('auto');
4079 var markerUnits = this.getAttribute('markerUnits').getString('strokeWidth');
4080 ctx.translate(x, y);
4081
4082 if (orient === 'auto') {
4083 ctx.rotate(angle);
4084 }
4085
4086 if (markerUnits === 'strokeWidth') {
4087 ctx.scale(ctx.lineWidth, ctx.lineWidth);
4088 }
4089
4090 ctx.save(); // render me using a temporary svg element
4091
4092 var markerSvg = new SVGElement(this.document, null);
4093 markerSvg.type = this.type;
4094 markerSvg.attributes.viewBox = new Property(this.document, 'viewBox', this.getAttribute('viewBox').getValue());
4095 markerSvg.attributes.refX = new Property(this.document, 'refX', this.getAttribute('refX').getValue());
4096 markerSvg.attributes.refY = new Property(this.document, 'refY', this.getAttribute('refY').getValue());
4097 markerSvg.attributes.width = new Property(this.document, 'width', this.getAttribute('markerWidth').getValue());
4098 markerSvg.attributes.height = new Property(this.document, 'height', this.getAttribute('markerHeight').getValue());
4099 markerSvg.attributes.overflow = new Property(this.document, 'overflow', this.getAttribute('overflow').getValue());
4100 markerSvg.attributes.fill = new Property(this.document, 'fill', this.getAttribute('fill').getColor('black'));
4101 markerSvg.attributes.stroke = new Property(this.document, 'stroke', this.getAttribute('stroke').getValue('none'));
4102 markerSvg.children = this.children;
4103 markerSvg.render(ctx);
4104 ctx.restore();
4105
4106 if (markerUnits === 'strokeWidth') {
4107 ctx.scale(1 / ctx.lineWidth, 1 / ctx.lineWidth);
4108 }
4109
4110 if (orient === 'auto') {
4111 ctx.rotate(-angle);
4112 }
4113
4114 ctx.translate(-x, -y);
4115 }
4116
4117}
4118
4119class DefsElement extends Element {
4120 constructor() {
4121 super(...arguments);
4122 this.type = 'defs';
4123 }
4124
4125 render() {// NOOP
4126 }
4127
4128}
4129
4130class GElement extends RenderedElement {
4131 constructor() {
4132 super(...arguments);
4133 this.type = 'g';
4134 }
4135
4136 getBoundingBox(ctx) {
4137 var boundingBox = new BoundingBox();
4138 this.children.forEach(child => {
4139 boundingBox.addBoundingBox(child.getBoundingBox(ctx));
4140 });
4141 return boundingBox;
4142 }
4143
4144}
4145
4146class GradientElement extends Element {
4147 constructor(document, node, captureTextNodes) {
4148 super(document, node, captureTextNodes);
4149 this.attributesToInherit = ['gradientUnits'];
4150 this.stops = [];
4151 var {
4152 stops,
4153 children
4154 } = this;
4155 children.forEach(child => {
4156 if (child.type === 'stop') {
4157 stops.push(child);
4158 }
4159 });
4160 }
4161
4162 getGradientUnits() {
4163 return this.getAttribute('gradientUnits').getString('objectBoundingBox');
4164 }
4165
4166 createGradient(ctx, element, parentOpacityProp) {
4167 // eslint-disable-next-line @typescript-eslint/no-this-alias, consistent-this
4168 var stopsContainer = this;
4169
4170 if (this.getHrefAttribute().hasValue()) {
4171 stopsContainer = this.getHrefAttribute().getDefinition();
4172 this.inheritStopContainer(stopsContainer);
4173 }
4174
4175 var {
4176 stops
4177 } = stopsContainer;
4178 var gradient = this.getGradient(ctx, element);
4179
4180 if (!gradient) {
4181 return this.addParentOpacity(parentOpacityProp, stops[stops.length - 1].color);
4182 }
4183
4184 stops.forEach(stop => {
4185 gradient.addColorStop(stop.offset, this.addParentOpacity(parentOpacityProp, stop.color));
4186 });
4187
4188 if (this.getAttribute('gradientTransform').hasValue()) {
4189 // render as transformed pattern on temporary canvas
4190 var {
4191 document
4192 } = this;
4193 var {
4194 MAX_VIRTUAL_PIXELS,
4195 viewPort
4196 } = document.screen;
4197 var [rootView] = viewPort.viewPorts;
4198 var rect = new RectElement(document, null);
4199 rect.attributes.x = new Property(document, 'x', -MAX_VIRTUAL_PIXELS / 3.0);
4200 rect.attributes.y = new Property(document, 'y', -MAX_VIRTUAL_PIXELS / 3.0);
4201 rect.attributes.width = new Property(document, 'width', MAX_VIRTUAL_PIXELS);
4202 rect.attributes.height = new Property(document, 'height', MAX_VIRTUAL_PIXELS);
4203 var group = new GElement(document, null);
4204 group.attributes.transform = new Property(document, 'transform', this.getAttribute('gradientTransform').getValue());
4205 group.children = [rect];
4206 var patternSvg = new SVGElement(document, null);
4207 patternSvg.attributes.x = new Property(document, 'x', 0);
4208 patternSvg.attributes.y = new Property(document, 'y', 0);
4209 patternSvg.attributes.width = new Property(document, 'width', rootView.width);
4210 patternSvg.attributes.height = new Property(document, 'height', rootView.height);
4211 patternSvg.children = [group];
4212 var patternCanvas = document.createCanvas(rootView.width, rootView.height);
4213 var patternCtx = patternCanvas.getContext('2d');
4214 patternCtx.fillStyle = gradient;
4215 patternSvg.render(patternCtx);
4216 return patternCtx.createPattern(patternCanvas, 'no-repeat');
4217 }
4218
4219 return gradient;
4220 }
4221
4222 inheritStopContainer(stopsContainer) {
4223 this.attributesToInherit.forEach(attributeToInherit => {
4224 if (!this.getAttribute(attributeToInherit).hasValue() && stopsContainer.getAttribute(attributeToInherit).hasValue()) {
4225 this.getAttribute(attributeToInherit, true).setValue(stopsContainer.getAttribute(attributeToInherit).getValue());
4226 }
4227 });
4228 }
4229
4230 addParentOpacity(parentOpacityProp, color) {
4231 if (parentOpacityProp.hasValue()) {
4232 var colorProp = new Property(this.document, 'color', color);
4233 return colorProp.addOpacity(parentOpacityProp).getColor();
4234 }
4235
4236 return color;
4237 }
4238
4239}
4240
4241class LinearGradientElement extends GradientElement {
4242 constructor(document, node, captureTextNodes) {
4243 super(document, node, captureTextNodes);
4244 this.type = 'linearGradient';
4245 this.attributesToInherit.push('x1', 'y1', 'x2', 'y2');
4246 }
4247
4248 getGradient(ctx, element) {
4249 var isBoundingBoxUnits = this.getGradientUnits() === 'objectBoundingBox';
4250 var boundingBox = isBoundingBoxUnits ? element.getBoundingBox(ctx) : null;
4251
4252 if (isBoundingBoxUnits && !boundingBox) {
4253 return null;
4254 }
4255
4256 if (!this.getAttribute('x1').hasValue() && !this.getAttribute('y1').hasValue() && !this.getAttribute('x2').hasValue() && !this.getAttribute('y2').hasValue()) {
4257 this.getAttribute('x1', true).setValue(0);
4258 this.getAttribute('y1', true).setValue(0);
4259 this.getAttribute('x2', true).setValue(1);
4260 this.getAttribute('y2', true).setValue(0);
4261 }
4262
4263 var x1 = isBoundingBoxUnits ? boundingBox.x + boundingBox.width * this.getAttribute('x1').getNumber() : this.getAttribute('x1').getPixels('x');
4264 var y1 = isBoundingBoxUnits ? boundingBox.y + boundingBox.height * this.getAttribute('y1').getNumber() : this.getAttribute('y1').getPixels('y');
4265 var x2 = isBoundingBoxUnits ? boundingBox.x + boundingBox.width * this.getAttribute('x2').getNumber() : this.getAttribute('x2').getPixels('x');
4266 var y2 = isBoundingBoxUnits ? boundingBox.y + boundingBox.height * this.getAttribute('y2').getNumber() : this.getAttribute('y2').getPixels('y');
4267
4268 if (x1 === x2 && y1 === y2) {
4269 return null;
4270 }
4271
4272 return ctx.createLinearGradient(x1, y1, x2, y2);
4273 }
4274
4275}
4276
4277class RadialGradientElement extends GradientElement {
4278 constructor(document, node, captureTextNodes) {
4279 super(document, node, captureTextNodes);
4280 this.type = 'radialGradient';
4281 this.attributesToInherit.push('cx', 'cy', 'r', 'fx', 'fy', 'fr');
4282 }
4283
4284 getGradient(ctx, element) {
4285 var isBoundingBoxUnits = this.getGradientUnits() === 'objectBoundingBox';
4286 var boundingBox = element.getBoundingBox(ctx);
4287
4288 if (isBoundingBoxUnits && !boundingBox) {
4289 return null;
4290 }
4291
4292 if (!this.getAttribute('cx').hasValue()) {
4293 this.getAttribute('cx', true).setValue('50%');
4294 }
4295
4296 if (!this.getAttribute('cy').hasValue()) {
4297 this.getAttribute('cy', true).setValue('50%');
4298 }
4299
4300 if (!this.getAttribute('r').hasValue()) {
4301 this.getAttribute('r', true).setValue('50%');
4302 }
4303
4304 var cx = isBoundingBoxUnits ? boundingBox.x + boundingBox.width * this.getAttribute('cx').getNumber() : this.getAttribute('cx').getPixels('x');
4305 var cy = isBoundingBoxUnits ? boundingBox.y + boundingBox.height * this.getAttribute('cy').getNumber() : this.getAttribute('cy').getPixels('y');
4306 var fx = cx;
4307 var fy = cy;
4308
4309 if (this.getAttribute('fx').hasValue()) {
4310 fx = isBoundingBoxUnits ? boundingBox.x + boundingBox.width * this.getAttribute('fx').getNumber() : this.getAttribute('fx').getPixels('x');
4311 }
4312
4313 if (this.getAttribute('fy').hasValue()) {
4314 fy = isBoundingBoxUnits ? boundingBox.y + boundingBox.height * this.getAttribute('fy').getNumber() : this.getAttribute('fy').getPixels('y');
4315 }
4316
4317 var r = isBoundingBoxUnits ? (boundingBox.width + boundingBox.height) / 2.0 * this.getAttribute('r').getNumber() : this.getAttribute('r').getPixels();
4318 var fr = this.getAttribute('fr').getPixels();
4319 return ctx.createRadialGradient(fx, fy, fr, cx, cy, r);
4320 }
4321
4322}
4323
4324class StopElement extends Element {
4325 constructor(document, node, captureTextNodes) {
4326 super(document, node, captureTextNodes);
4327 this.type = 'stop';
4328 var offset = Math.max(0, Math.min(1, this.getAttribute('offset').getNumber()));
4329 var stopOpacity = this.getStyle('stop-opacity');
4330 var stopColor = this.getStyle('stop-color', true);
4331
4332 if (stopColor.getString() === '') {
4333 stopColor.setValue('#000');
4334 }
4335
4336 if (stopOpacity.hasValue()) {
4337 stopColor = stopColor.addOpacity(stopOpacity);
4338 }
4339
4340 this.offset = offset;
4341 this.color = stopColor.getColor();
4342 }
4343
4344}
4345
4346class AnimateElement extends Element {
4347 constructor(document, node, captureTextNodes) {
4348 super(document, node, captureTextNodes);
4349 this.type = 'animate';
4350 this.duration = 0;
4351 this.initialValue = null;
4352 this.initialUnits = '';
4353 this.removed = false;
4354 this.frozen = false;
4355 document.screen.animations.push(this);
4356 this.begin = this.getAttribute('begin').getMilliseconds();
4357 this.maxDuration = this.begin + this.getAttribute('dur').getMilliseconds();
4358 this.from = this.getAttribute('from');
4359 this.to = this.getAttribute('to');
4360 this.values = new Property(document, 'values', null);
4361 var valuesAttr = this.getAttribute('values');
4362
4363 if (valuesAttr.hasValue()) {
4364 this.values.setValue(valuesAttr.getString().split(';'));
4365 }
4366 }
4367
4368 getProperty() {
4369 var attributeType = this.getAttribute('attributeType').getString();
4370 var attributeName = this.getAttribute('attributeName').getString();
4371
4372 if (attributeType === 'CSS') {
4373 return this.parent.getStyle(attributeName, true);
4374 }
4375
4376 return this.parent.getAttribute(attributeName, true);
4377 }
4378
4379 calcValue() {
4380 var {
4381 initialUnits
4382 } = this;
4383 var {
4384 progress,
4385 from,
4386 to
4387 } = this.getProgress(); // tween value linearly
4388
4389 var newValue = from.getNumber() + (to.getNumber() - from.getNumber()) * progress;
4390
4391 if (initialUnits === '%') {
4392 newValue *= 100.0; // numValue() returns 0-1 whereas properties are 0-100
4393 }
4394
4395 return "".concat(newValue).concat(initialUnits);
4396 }
4397
4398 update(delta) {
4399 var {
4400 parent
4401 } = this;
4402 var prop = this.getProperty(); // set initial value
4403
4404 if (!this.initialValue) {
4405 this.initialValue = prop.getString();
4406 this.initialUnits = prop.getUnits();
4407 } // if we're past the end time
4408
4409
4410 if (this.duration > this.maxDuration) {
4411 var fill = this.getAttribute('fill').getString('remove'); // loop for indefinitely repeating animations
4412
4413 if (this.getAttribute('repeatCount').getString() === 'indefinite' || this.getAttribute('repeatDur').getString() === 'indefinite') {
4414 this.duration = 0;
4415 } else if (fill === 'freeze' && !this.frozen) {
4416 this.frozen = true;
4417 parent.animationFrozen = true;
4418 parent.animationFrozenValue = prop.getString();
4419 } else if (fill === 'remove' && !this.removed) {
4420 this.removed = true;
4421 prop.setValue(parent.animationFrozen ? parent.animationFrozenValue : this.initialValue);
4422 return true;
4423 }
4424
4425 return false;
4426 }
4427
4428 this.duration += delta; // if we're past the begin time
4429
4430 var updated = false;
4431
4432 if (this.begin < this.duration) {
4433 var newValue = this.calcValue(); // tween
4434
4435 var typeAttr = this.getAttribute('type');
4436
4437 if (typeAttr.hasValue()) {
4438 // for transform, etc.
4439 var type = typeAttr.getString();
4440 newValue = "".concat(type, "(").concat(newValue, ")");
4441 }
4442
4443 prop.setValue(newValue);
4444 updated = true;
4445 }
4446
4447 return updated;
4448 }
4449
4450 getProgress() {
4451 var {
4452 document,
4453 values
4454 } = this;
4455 var result = {
4456 progress: (this.duration - this.begin) / (this.maxDuration - this.begin)
4457 };
4458
4459 if (values.hasValue()) {
4460 var p = result.progress * (values.getValue().length - 1);
4461 var lb = Math.floor(p);
4462 var ub = Math.ceil(p);
4463 result.from = new Property(document, 'from', parseFloat(values.getValue()[lb]));
4464 result.to = new Property(document, 'to', parseFloat(values.getValue()[ub]));
4465 result.progress = (p - lb) / (ub - lb);
4466 } else {
4467 result.from = this.from;
4468 result.to = this.to;
4469 }
4470
4471 return result;
4472 }
4473
4474}
4475
4476class AnimateColorElement extends AnimateElement {
4477 constructor() {
4478 super(...arguments);
4479 this.type = 'animateColor';
4480 }
4481
4482 calcValue() {
4483 var {
4484 progress,
4485 from,
4486 to
4487 } = this.getProgress();
4488 var colorFrom = new RGBColor(from.getColor());
4489 var colorTo = new RGBColor(to.getColor());
4490
4491 if (colorFrom.ok && colorTo.ok) {
4492 // tween color linearly
4493 var r = colorFrom.r + (colorTo.r - colorFrom.r) * progress;
4494 var g = colorFrom.g + (colorTo.g - colorFrom.g) * progress;
4495 var b = colorFrom.b + (colorTo.b - colorFrom.b) * progress; // ? alpha
4496
4497 return "rgb(".concat(Math.floor(r), ", ").concat(Math.floor(g), ", ").concat(Math.floor(b), ")");
4498 }
4499
4500 return this.getAttribute('from').getColor();
4501 }
4502
4503}
4504
4505class AnimateTransformElement extends AnimateElement {
4506 constructor() {
4507 super(...arguments);
4508 this.type = 'animateTransform';
4509 }
4510
4511 calcValue() {
4512 var {
4513 progress,
4514 from,
4515 to
4516 } = this.getProgress(); // tween value linearly
4517
4518 var transformFrom = toNumbers(from.getString());
4519 var transformTo = toNumbers(to.getString());
4520 var newValue = transformFrom.map((from, i) => {
4521 var to = transformTo[i];
4522 return from + (to - from) * progress;
4523 }).join(' ');
4524 return newValue;
4525 }
4526
4527}
4528
4529class FontElement extends Element {
4530 constructor(document, node, captureTextNodes) {
4531 super(document, node, captureTextNodes);
4532 this.type = 'font';
4533 this.glyphs = {};
4534 this.horizAdvX = this.getAttribute('horiz-adv-x').getNumber();
4535 var {
4536 definitions
4537 } = document;
4538 var {
4539 children
4540 } = this;
4541
4542 for (var child of children) {
4543 switch (child.type) {
4544 case 'font-face':
4545 {
4546 this.fontFace = child;
4547 var fontFamilyStyle = child.getStyle('font-family');
4548
4549 if (fontFamilyStyle.hasValue()) {
4550 definitions[fontFamilyStyle.getString()] = this;
4551 }
4552
4553 break;
4554 }
4555
4556 case 'missing-glyph':
4557 this.missingGlyph = child;
4558 break;
4559
4560 case 'glyph':
4561 {
4562 var glyph = child;
4563
4564 if (glyph.arabicForm) {
4565 this.isRTL = true;
4566 this.isArabic = true;
4567
4568 if (typeof this.glyphs[glyph.unicode] === 'undefined') {
4569 this.glyphs[glyph.unicode] = {};
4570 }
4571
4572 this.glyphs[glyph.unicode][glyph.arabicForm] = glyph;
4573 } else {
4574 this.glyphs[glyph.unicode] = glyph;
4575 }
4576
4577 break;
4578 }
4579 }
4580 }
4581 }
4582
4583 render() {// NO RENDER
4584 }
4585
4586}
4587
4588class FontFaceElement extends Element {
4589 constructor(document, node, captureTextNodes) {
4590 super(document, node, captureTextNodes);
4591 this.type = 'font-face';
4592 this.ascent = this.getAttribute('ascent').getNumber();
4593 this.descent = this.getAttribute('descent').getNumber();
4594 this.unitsPerEm = this.getAttribute('units-per-em').getNumber();
4595 }
4596
4597}
4598
4599class MissingGlyphElement extends PathElement {
4600 constructor() {
4601 super(...arguments);
4602 this.type = 'missing-glyph';
4603 this.horizAdvX = 0;
4604 }
4605
4606}
4607
4608class TRefElement extends TextElement {
4609 constructor() {
4610 super(...arguments);
4611 this.type = 'tref';
4612 }
4613
4614 getText() {
4615 var element = this.getHrefAttribute().getDefinition();
4616
4617 if (element) {
4618 var firstChild = element.children[0];
4619
4620 if (firstChild) {
4621 return firstChild.getText();
4622 }
4623 }
4624
4625 return '';
4626 }
4627
4628}
4629
4630class AElement extends TextElement {
4631 constructor(document, node, captureTextNodes) {
4632 super(document, node, captureTextNodes);
4633 this.type = 'a';
4634 var {
4635 childNodes
4636 } = node;
4637 var firstChild = childNodes[0];
4638 var hasText = childNodes.length > 0 && Array.from(childNodes).every(node => node.nodeType === 3);
4639 this.hasText = hasText;
4640 this.text = hasText ? this.getTextFromNode(firstChild) : '';
4641 }
4642
4643 getText() {
4644 return this.text;
4645 }
4646
4647 renderChildren(ctx) {
4648 if (this.hasText) {
4649 // render as text element
4650 super.renderChildren(ctx);
4651 var {
4652 document,
4653 x,
4654 y
4655 } = this;
4656 var {
4657 mouse
4658 } = document.screen;
4659 var fontSize = new Property(document, 'fontSize', Font.parse(document.ctx.font).fontSize); // Do not calc bounding box if mouse is not working.
4660
4661 if (mouse.isWorking()) {
4662 mouse.checkBoundingBox(this, new BoundingBox(x, y - fontSize.getPixels('y'), x + this.measureText(ctx), y));
4663 }
4664 } else if (this.children.length > 0) {
4665 // render as temporary group
4666 var g = new GElement(this.document, null);
4667 g.children = this.children;
4668 g.parent = this;
4669 g.render(ctx);
4670 }
4671 }
4672
4673 onClick() {
4674 var {
4675 window
4676 } = this.document;
4677
4678 if (window) {
4679 window.open(this.getHrefAttribute().getString());
4680 }
4681 }
4682
4683 onMouseMove() {
4684 var ctx = this.document.ctx;
4685 ctx.canvas.style.cursor = 'pointer';
4686 }
4687
4688}
4689
4690function ownKeys$2(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
4691
4692function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$2(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$2(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4693class TextPathElement extends TextElement {
4694 constructor(document, node, captureTextNodes) {
4695 super(document, node, captureTextNodes);
4696 this.type = 'textPath';
4697 this.textWidth = 0;
4698 this.textHeight = 0;
4699 this.pathLength = -1;
4700 this.glyphInfo = null;
4701 this.letterSpacingCache = [];
4702 this.measuresCache = new Map([['', 0]]);
4703 var pathElement = this.getHrefAttribute().getDefinition();
4704 this.text = this.getTextFromNode();
4705 this.dataArray = this.parsePathData(pathElement);
4706 }
4707
4708 getText() {
4709 return this.text;
4710 }
4711
4712 path(ctx) {
4713 var {
4714 dataArray
4715 } = this;
4716
4717 if (ctx) {
4718 ctx.beginPath();
4719 }
4720
4721 dataArray.forEach(_ref => {
4722 var {
4723 type,
4724 points
4725 } = _ref;
4726
4727 switch (type) {
4728 case PathParser.LINE_TO:
4729 if (ctx) {
4730 ctx.lineTo(points[0], points[1]);
4731 }
4732
4733 break;
4734
4735 case PathParser.MOVE_TO:
4736 if (ctx) {
4737 ctx.moveTo(points[0], points[1]);
4738 }
4739
4740 break;
4741
4742 case PathParser.CURVE_TO:
4743 if (ctx) {
4744 ctx.bezierCurveTo(points[0], points[1], points[2], points[3], points[4], points[5]);
4745 }
4746
4747 break;
4748
4749 case PathParser.QUAD_TO:
4750 if (ctx) {
4751 ctx.quadraticCurveTo(points[0], points[1], points[2], points[3]);
4752 }
4753
4754 break;
4755
4756 case PathParser.ARC:
4757 {
4758 var [cx, cy, rx, ry, theta, dTheta, psi, fs] = points;
4759 var r = rx > ry ? rx : ry;
4760 var scaleX = rx > ry ? 1 : rx / ry;
4761 var scaleY = rx > ry ? ry / rx : 1;
4762
4763 if (ctx) {
4764 ctx.translate(cx, cy);
4765 ctx.rotate(psi);
4766 ctx.scale(scaleX, scaleY);
4767 ctx.arc(0, 0, r, theta, theta + dTheta, Boolean(1 - fs));
4768 ctx.scale(1 / scaleX, 1 / scaleY);
4769 ctx.rotate(-psi);
4770 ctx.translate(-cx, -cy);
4771 }
4772
4773 break;
4774 }
4775
4776 case PathParser.CLOSE_PATH:
4777 if (ctx) {
4778 ctx.closePath();
4779 }
4780
4781 break;
4782 }
4783 });
4784 }
4785
4786 renderChildren(ctx) {
4787 this.setTextData(ctx);
4788 ctx.save();
4789 var textDecoration = this.parent.getStyle('text-decoration').getString();
4790 var fontSize = this.getFontSize();
4791 var {
4792 glyphInfo
4793 } = this;
4794 var fill = ctx.fillStyle;
4795
4796 if (textDecoration === 'underline') {
4797 ctx.beginPath();
4798 }
4799
4800 glyphInfo.forEach((glyph, i) => {
4801 var {
4802 p0,
4803 p1,
4804 rotation,
4805 text: partialText
4806 } = glyph;
4807 ctx.save();
4808 ctx.translate(p0.x, p0.y);
4809 ctx.rotate(rotation);
4810
4811 if (ctx.fillStyle) {
4812 ctx.fillText(partialText, 0, 0);
4813 }
4814
4815 if (ctx.strokeStyle) {
4816 ctx.strokeText(partialText, 0, 0);
4817 }
4818
4819 ctx.restore();
4820
4821 if (textDecoration === 'underline') {
4822 if (i === 0) {
4823 ctx.moveTo(p0.x, p0.y + fontSize / 8);
4824 }
4825
4826 ctx.lineTo(p1.x, p1.y + fontSize / 5);
4827 } // // To assist with debugging visually, uncomment following
4828 //
4829 // ctx.beginPath();
4830 // if (i % 2)
4831 // ctx.strokeStyle = 'red';
4832 // else
4833 // ctx.strokeStyle = 'green';
4834 // ctx.moveTo(p0.x, p0.y);
4835 // ctx.lineTo(p1.x, p1.y);
4836 // ctx.stroke();
4837 // ctx.closePath();
4838
4839 });
4840
4841 if (textDecoration === 'underline') {
4842 ctx.lineWidth = fontSize / 20;
4843 ctx.strokeStyle = fill;
4844 ctx.stroke();
4845 ctx.closePath();
4846 }
4847
4848 ctx.restore();
4849 }
4850
4851 getLetterSpacingAt() {
4852 var idx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
4853 return this.letterSpacingCache[idx] || 0;
4854 }
4855
4856 findSegmentToFitChar(ctx, anchor, textFullWidth, fullPathWidth, spacesNumber, inputOffset, dy, c, charI) {
4857 var offset = inputOffset;
4858 var glyphWidth = this.measureText(ctx, c);
4859
4860 if (c === ' ' && anchor === 'justify' && textFullWidth < fullPathWidth) {
4861 glyphWidth += (fullPathWidth - textFullWidth) / spacesNumber;
4862 }
4863
4864 if (charI > -1) {
4865 offset += this.getLetterSpacingAt(charI);
4866 }
4867
4868 var splineStep = this.textHeight / 20;
4869 var p0 = this.getEquidistantPointOnPath(offset, splineStep, 0);
4870 var p1 = this.getEquidistantPointOnPath(offset + glyphWidth, splineStep, 0);
4871 var segment = {
4872 p0,
4873 p1
4874 };
4875 var rotation = p0 && p1 ? Math.atan2(p1.y - p0.y, p1.x - p0.x) : 0;
4876
4877 if (dy) {
4878 var dyX = Math.cos(Math.PI / 2 + rotation) * dy;
4879 var dyY = Math.cos(-rotation) * dy;
4880 segment.p0 = _objectSpread$2(_objectSpread$2({}, p0), {}, {
4881 x: p0.x + dyX,
4882 y: p0.y + dyY
4883 });
4884 segment.p1 = _objectSpread$2(_objectSpread$2({}, p1), {}, {
4885 x: p1.x + dyX,
4886 y: p1.y + dyY
4887 });
4888 }
4889
4890 offset += glyphWidth;
4891 return {
4892 offset,
4893 segment,
4894 rotation
4895 };
4896 }
4897
4898 measureText(ctx, text) {
4899 var {
4900 measuresCache
4901 } = this;
4902 var targetText = text || this.getText();
4903
4904 if (measuresCache.has(targetText)) {
4905 return measuresCache.get(targetText);
4906 }
4907
4908 var measure = this.measureTargetText(ctx, targetText);
4909 measuresCache.set(targetText, measure);
4910 return measure;
4911 } // This method supposes what all custom fonts already loaded.
4912 // If some font will be loaded after this method call, <textPath> will not be rendered correctly.
4913 // You need to call this method manually to update glyphs cache.
4914
4915
4916 setTextData(ctx) {
4917 if (this.glyphInfo) {
4918 return;
4919 }
4920
4921 var renderText = this.getText();
4922 var chars = renderText.split('');
4923 var spacesNumber = renderText.split(' ').length - 1;
4924 var dx = this.parent.getAttribute('dx').split().map(_ => _.getPixels('x'));
4925 var dy = this.parent.getAttribute('dy').getPixels('y');
4926 var anchor = this.parent.getStyle('text-anchor').getString('start');
4927 var thisSpacing = this.getStyle('letter-spacing');
4928 var parentSpacing = this.parent.getStyle('letter-spacing');
4929 var letterSpacing = 0;
4930
4931 if (!thisSpacing.hasValue() || thisSpacing.getValue() === 'inherit') {
4932 letterSpacing = parentSpacing.getPixels();
4933 } else if (thisSpacing.hasValue()) {
4934 if (thisSpacing.getValue() !== 'initial' && thisSpacing.getValue() !== 'unset') {
4935 letterSpacing = thisSpacing.getPixels();
4936 }
4937 } // fill letter-spacing cache
4938
4939
4940 var letterSpacingCache = [];
4941 var textLen = renderText.length;
4942 this.letterSpacingCache = letterSpacingCache;
4943
4944 for (var i = 0; i < textLen; i++) {
4945 letterSpacingCache.push(typeof dx[i] !== 'undefined' ? dx[i] : letterSpacing);
4946 }
4947
4948 var dxSum = letterSpacingCache.reduce((acc, cur, i) => i === 0 ? 0 : acc + cur || 0, 0);
4949 var textWidth = this.measureText(ctx);
4950 var textFullWidth = Math.max(textWidth + dxSum, 0);
4951 this.textWidth = textWidth;
4952 this.textHeight = this.getFontSize();
4953 this.glyphInfo = [];
4954 var fullPathWidth = this.getPathLength();
4955 var startOffset = this.getStyle('startOffset').getNumber(0) * fullPathWidth;
4956 var offset = 0;
4957
4958 if (anchor === 'middle' || anchor === 'center') {
4959 offset = -textFullWidth / 2;
4960 }
4961
4962 if (anchor === 'end' || anchor === 'right') {
4963 offset = -textFullWidth;
4964 }
4965
4966 offset += startOffset;
4967 chars.forEach((char, i) => {
4968 // Find such segment what distance between p0 and p1 is approx. width of glyph
4969 var {
4970 offset: nextOffset,
4971 segment,
4972 rotation
4973 } = this.findSegmentToFitChar(ctx, anchor, textFullWidth, fullPathWidth, spacesNumber, offset, dy, char, i);
4974 offset = nextOffset;
4975
4976 if (!segment.p0 || !segment.p1) {
4977 return;
4978 } // const width = this.getLineLength(
4979 // segment.p0.x,
4980 // segment.p0.y,
4981 // segment.p1.x,
4982 // segment.p1.y
4983 // );
4984 // Note: Since glyphs are rendered one at a time, any kerning pair data built into the font will not be used.
4985 // Can foresee having a rough pair table built in that the developer can override as needed.
4986 // Or use "dx" attribute of the <text> node as a naive replacement
4987 // const kern = 0;
4988 // placeholder for future implementation
4989 // const midpoint = this.getPointOnLine(
4990 // kern + width / 2.0,
4991 // segment.p0.x, segment.p0.y, segment.p1.x, segment.p1.y
4992 // );
4993
4994
4995 this.glyphInfo.push({
4996 // transposeX: midpoint.x,
4997 // transposeY: midpoint.y,
4998 text: chars[i],
4999 p0: segment.p0,
5000 p1: segment.p1,
5001 rotation
5002 });
5003 });
5004 }
5005
5006 parsePathData(path) {
5007 this.pathLength = -1; // reset path length
5008
5009 if (!path) {
5010 return [];
5011 }
5012
5013 var pathCommands = [];
5014 var {
5015 pathParser
5016 } = path;
5017 pathParser.reset(); // convert l, H, h, V, and v to L
5018
5019 while (!pathParser.isEnd()) {
5020 var {
5021 current
5022 } = pathParser;
5023 var startX = current ? current.x : 0;
5024 var startY = current ? current.y : 0;
5025 var command = pathParser.next();
5026 var nextCommandType = command.type;
5027 var points = [];
5028
5029 switch (command.type) {
5030 case PathParser.MOVE_TO:
5031 this.pathM(pathParser, points);
5032 break;
5033
5034 case PathParser.LINE_TO:
5035 nextCommandType = this.pathL(pathParser, points);
5036 break;
5037
5038 case PathParser.HORIZ_LINE_TO:
5039 nextCommandType = this.pathH(pathParser, points);
5040 break;
5041
5042 case PathParser.VERT_LINE_TO:
5043 nextCommandType = this.pathV(pathParser, points);
5044 break;
5045
5046 case PathParser.CURVE_TO:
5047 this.pathC(pathParser, points);
5048 break;
5049
5050 case PathParser.SMOOTH_CURVE_TO:
5051 nextCommandType = this.pathS(pathParser, points);
5052 break;
5053
5054 case PathParser.QUAD_TO:
5055 this.pathQ(pathParser, points);
5056 break;
5057
5058 case PathParser.SMOOTH_QUAD_TO:
5059 nextCommandType = this.pathT(pathParser, points);
5060 break;
5061
5062 case PathParser.ARC:
5063 points = this.pathA(pathParser);
5064 break;
5065
5066 case PathParser.CLOSE_PATH:
5067 PathElement.pathZ(pathParser);
5068 break;
5069 }
5070
5071 if (command.type !== PathParser.CLOSE_PATH) {
5072 pathCommands.push({
5073 type: nextCommandType,
5074 points,
5075 start: {
5076 x: startX,
5077 y: startY
5078 },
5079 pathLength: this.calcLength(startX, startY, nextCommandType, points)
5080 });
5081 } else {
5082 pathCommands.push({
5083 type: PathParser.CLOSE_PATH,
5084 points: [],
5085 pathLength: 0
5086 });
5087 }
5088 }
5089
5090 return pathCommands;
5091 }
5092
5093 pathM(pathParser, points) {
5094 var {
5095 x,
5096 y
5097 } = PathElement.pathM(pathParser).point;
5098 points.push(x, y);
5099 }
5100
5101 pathL(pathParser, points) {
5102 var {
5103 x,
5104 y
5105 } = PathElement.pathL(pathParser).point;
5106 points.push(x, y);
5107 return PathParser.LINE_TO;
5108 }
5109
5110 pathH(pathParser, points) {
5111 var {
5112 x,
5113 y
5114 } = PathElement.pathH(pathParser).point;
5115 points.push(x, y);
5116 return PathParser.LINE_TO;
5117 }
5118
5119 pathV(pathParser, points) {
5120 var {
5121 x,
5122 y
5123 } = PathElement.pathV(pathParser).point;
5124 points.push(x, y);
5125 return PathParser.LINE_TO;
5126 }
5127
5128 pathC(pathParser, points) {
5129 var {
5130 point,
5131 controlPoint,
5132 currentPoint
5133 } = PathElement.pathC(pathParser);
5134 points.push(point.x, point.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
5135 }
5136
5137 pathS(pathParser, points) {
5138 var {
5139 point,
5140 controlPoint,
5141 currentPoint
5142 } = PathElement.pathS(pathParser);
5143 points.push(point.x, point.y, controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
5144 return PathParser.CURVE_TO;
5145 }
5146
5147 pathQ(pathParser, points) {
5148 var {
5149 controlPoint,
5150 currentPoint
5151 } = PathElement.pathQ(pathParser);
5152 points.push(controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
5153 }
5154
5155 pathT(pathParser, points) {
5156 var {
5157 controlPoint,
5158 currentPoint
5159 } = PathElement.pathT(pathParser);
5160 points.push(controlPoint.x, controlPoint.y, currentPoint.x, currentPoint.y);
5161 return PathParser.QUAD_TO;
5162 }
5163
5164 pathA(pathParser) {
5165 var {
5166 rX,
5167 rY,
5168 sweepFlag,
5169 xAxisRotation,
5170 centp,
5171 a1,
5172 ad
5173 } = PathElement.pathA(pathParser);
5174
5175 if (sweepFlag === 0 && ad > 0) {
5176 ad -= 2 * Math.PI;
5177 }
5178
5179 if (sweepFlag === 1 && ad < 0) {
5180 ad += 2 * Math.PI;
5181 }
5182
5183 return [centp.x, centp.y, rX, rY, a1, ad, xAxisRotation, sweepFlag];
5184 }
5185
5186 calcLength(x, y, commandType, points) {
5187 var len = 0;
5188 var p1 = null;
5189 var p2 = null;
5190 var t = 0;
5191
5192 switch (commandType) {
5193 case PathParser.LINE_TO:
5194 return this.getLineLength(x, y, points[0], points[1]);
5195
5196 case PathParser.CURVE_TO:
5197 // Approximates by breaking curve into 100 line segments
5198 len = 0.0;
5199 p1 = this.getPointOnCubicBezier(0, x, y, points[0], points[1], points[2], points[3], points[4], points[5]);
5200
5201 for (t = 0.01; t <= 1; t += 0.01) {
5202 p2 = this.getPointOnCubicBezier(t, x, y, points[0], points[1], points[2], points[3], points[4], points[5]);
5203 len += this.getLineLength(p1.x, p1.y, p2.x, p2.y);
5204 p1 = p2;
5205 }
5206
5207 return len;
5208
5209 case PathParser.QUAD_TO:
5210 // Approximates by breaking curve into 100 line segments
5211 len = 0.0;
5212 p1 = this.getPointOnQuadraticBezier(0, x, y, points[0], points[1], points[2], points[3]);
5213
5214 for (t = 0.01; t <= 1; t += 0.01) {
5215 p2 = this.getPointOnQuadraticBezier(t, x, y, points[0], points[1], points[2], points[3]);
5216 len += this.getLineLength(p1.x, p1.y, p2.x, p2.y);
5217 p1 = p2;
5218 }
5219
5220 return len;
5221
5222 case PathParser.ARC:
5223 {
5224 // Approximates by breaking curve into line segments
5225 len = 0.0;
5226 var start = points[4]; // 4 = theta
5227
5228 var dTheta = points[5]; // 5 = dTheta
5229
5230 var end = points[4] + dTheta;
5231 var inc = Math.PI / 180.0; // 1 degree resolution
5232
5233 if (Math.abs(start - end) < inc) {
5234 inc = Math.abs(start - end);
5235 } // Note: for purpose of calculating arc length, not going to worry about rotating X-axis by angle psi
5236
5237
5238 p1 = this.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], start, 0);
5239
5240 if (dTheta < 0) {
5241 // clockwise
5242 for (t = start - inc; t > end; t -= inc) {
5243 p2 = this.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0);
5244 len += this.getLineLength(p1.x, p1.y, p2.x, p2.y);
5245 p1 = p2;
5246 }
5247 } else {
5248 // counter-clockwise
5249 for (t = start + inc; t < end; t += inc) {
5250 p2 = this.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0);
5251 len += this.getLineLength(p1.x, p1.y, p2.x, p2.y);
5252 p1 = p2;
5253 }
5254 }
5255
5256 p2 = this.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], end, 0);
5257 len += this.getLineLength(p1.x, p1.y, p2.x, p2.y);
5258 return len;
5259 }
5260 }
5261
5262 return 0;
5263 }
5264
5265 getPointOnLine(dist, p1x, p1y, p2x, p2y) {
5266 var fromX = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : p1x;
5267 var fromY = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : p1y;
5268 var m = (p2y - p1y) / (p2x - p1x + PSEUDO_ZERO);
5269 var run = Math.sqrt(dist * dist / (1 + m * m));
5270
5271 if (p2x < p1x) {
5272 run *= -1;
5273 }
5274
5275 var rise = m * run;
5276 var pt = null;
5277
5278 if (p2x === p1x) {
5279 // vertical line
5280 pt = {
5281 x: fromX,
5282 y: fromY + rise
5283 };
5284 } else if ((fromY - p1y) / (fromX - p1x + PSEUDO_ZERO) === m) {
5285 pt = {
5286 x: fromX + run,
5287 y: fromY + rise
5288 };
5289 } else {
5290 var ix = 0;
5291 var iy = 0;
5292 var len = this.getLineLength(p1x, p1y, p2x, p2y);
5293
5294 if (len < PSEUDO_ZERO) {
5295 return null;
5296 }
5297
5298 var u = (fromX - p1x) * (p2x - p1x) + (fromY - p1y) * (p2y - p1y);
5299 u /= len * len;
5300 ix = p1x + u * (p2x - p1x);
5301 iy = p1y + u * (p2y - p1y);
5302 var pRise = this.getLineLength(fromX, fromY, ix, iy);
5303 var pRun = Math.sqrt(dist * dist - pRise * pRise);
5304 run = Math.sqrt(pRun * pRun / (1 + m * m));
5305
5306 if (p2x < p1x) {
5307 run *= -1;
5308 }
5309
5310 rise = m * run;
5311 pt = {
5312 x: ix + run,
5313 y: iy + rise
5314 };
5315 }
5316
5317 return pt;
5318 }
5319
5320 getPointOnPath(distance) {
5321 var fullLen = this.getPathLength();
5322 var cumulativePathLength = 0;
5323 var p = null;
5324
5325 if (distance < -0.00005 || distance - 0.00005 > fullLen) {
5326 return null;
5327 }
5328
5329 var {
5330 dataArray
5331 } = this;
5332
5333 for (var command of dataArray) {
5334 if (command && (command.pathLength < 0.00005 || cumulativePathLength + command.pathLength + 0.00005 < distance)) {
5335 cumulativePathLength += command.pathLength;
5336 continue;
5337 }
5338
5339 var delta = distance - cumulativePathLength;
5340 var currentT = 0;
5341
5342 switch (command.type) {
5343 case PathParser.LINE_TO:
5344 p = this.getPointOnLine(delta, command.start.x, command.start.y, command.points[0], command.points[1], command.start.x, command.start.y);
5345 break;
5346
5347 case PathParser.ARC:
5348 {
5349 var start = command.points[4]; // 4 = theta
5350
5351 var dTheta = command.points[5]; // 5 = dTheta
5352
5353 var end = command.points[4] + dTheta;
5354 currentT = start + delta / command.pathLength * dTheta;
5355
5356 if (dTheta < 0 && currentT < end || dTheta >= 0 && currentT > end) {
5357 break;
5358 }
5359
5360 p = this.getPointOnEllipticalArc(command.points[0], command.points[1], command.points[2], command.points[3], currentT, command.points[6]);
5361 break;
5362 }
5363
5364 case PathParser.CURVE_TO:
5365 currentT = delta / command.pathLength;
5366
5367 if (currentT > 1) {
5368 currentT = 1;
5369 }
5370
5371 p = this.getPointOnCubicBezier(currentT, command.start.x, command.start.y, command.points[0], command.points[1], command.points[2], command.points[3], command.points[4], command.points[5]);
5372 break;
5373
5374 case PathParser.QUAD_TO:
5375 currentT = delta / command.pathLength;
5376
5377 if (currentT > 1) {
5378 currentT = 1;
5379 }
5380
5381 p = this.getPointOnQuadraticBezier(currentT, command.start.x, command.start.y, command.points[0], command.points[1], command.points[2], command.points[3]);
5382 break;
5383 }
5384
5385 if (p) {
5386 return p;
5387 }
5388
5389 break;
5390 }
5391
5392 return null;
5393 }
5394
5395 getLineLength(x1, y1, x2, y2) {
5396 return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
5397 }
5398
5399 getPathLength() {
5400 if (this.pathLength === -1) {
5401 this.pathLength = this.dataArray.reduce((length, command) => command.pathLength > 0 ? length + command.pathLength : length, 0);
5402 }
5403
5404 return this.pathLength;
5405 }
5406
5407 getPointOnCubicBezier(pct, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {
5408 var x = p4x * CB1(pct) + p3x * CB2(pct) + p2x * CB3(pct) + p1x * CB4(pct);
5409 var y = p4y * CB1(pct) + p3y * CB2(pct) + p2y * CB3(pct) + p1y * CB4(pct);
5410 return {
5411 x,
5412 y
5413 };
5414 }
5415
5416 getPointOnQuadraticBezier(pct, p1x, p1y, p2x, p2y, p3x, p3y) {
5417 var x = p3x * QB1(pct) + p2x * QB2(pct) + p1x * QB3(pct);
5418 var y = p3y * QB1(pct) + p2y * QB2(pct) + p1y * QB3(pct);
5419 return {
5420 x,
5421 y
5422 };
5423 }
5424
5425 getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi) {
5426 var cosPsi = Math.cos(psi);
5427 var sinPsi = Math.sin(psi);
5428 var pt = {
5429 x: rx * Math.cos(theta),
5430 y: ry * Math.sin(theta)
5431 };
5432 return {
5433 x: cx + (pt.x * cosPsi - pt.y * sinPsi),
5434 y: cy + (pt.x * sinPsi + pt.y * cosPsi)
5435 };
5436 } // TODO need some optimisations. possibly build cache only for curved segments?
5437
5438
5439 buildEquidistantCache(inputStep, inputPrecision) {
5440 var fullLen = this.getPathLength();
5441 var precision = inputPrecision || 0.25; // accuracy vs performance
5442
5443 var step = inputStep || fullLen / 100;
5444
5445 if (!this.equidistantCache || this.equidistantCache.step !== step || this.equidistantCache.precision !== precision) {
5446 // Prepare cache
5447 this.equidistantCache = {
5448 step,
5449 precision,
5450 points: []
5451 }; // Calculate points
5452
5453 var s = 0;
5454
5455 for (var l = 0; l <= fullLen; l += precision) {
5456 var p0 = this.getPointOnPath(l);
5457 var p1 = this.getPointOnPath(l + precision);
5458
5459 if (!p0 || !p1) {
5460 continue;
5461 }
5462
5463 s += this.getLineLength(p0.x, p0.y, p1.x, p1.y);
5464
5465 if (s >= step) {
5466 this.equidistantCache.points.push({
5467 x: p0.x,
5468 y: p0.y,
5469 distance: l
5470 });
5471 s -= step;
5472 }
5473 }
5474 }
5475 }
5476
5477 getEquidistantPointOnPath(targetDistance, step, precision) {
5478 this.buildEquidistantCache(step, precision);
5479
5480 if (targetDistance < 0 || targetDistance - this.getPathLength() > 0.00005) {
5481 return null;
5482 }
5483
5484 var idx = Math.round(targetDistance / this.getPathLength() * (this.equidistantCache.points.length - 1));
5485 return this.equidistantCache.points[idx] || null;
5486 }
5487
5488}
5489
5490var dataUriRegex = /^\s*data:(([^/,;]+\/[^/,;]+)(?:;([^,;=]+=[^,;=]+))?)?(?:;(base64))?,(.*)$/i;
5491class ImageElement extends RenderedElement {
5492 constructor(document, node, captureTextNodes) {
5493 super(document, node, captureTextNodes);
5494 this.type = 'image';
5495 this.loaded = false;
5496 var href = this.getHrefAttribute().getString();
5497
5498 if (!href) {
5499 return;
5500 }
5501
5502 var isSvg = href.endsWith('.svg') || /^\s*data:image\/svg\+xml/i.test(href);
5503 document.images.push(this);
5504
5505 if (!isSvg) {
5506 void this.loadImage(href);
5507 } else {
5508 void this.loadSvg(href);
5509 }
5510
5511 this.isSvg = isSvg;
5512 }
5513
5514 loadImage(href) {
5515 var _this = this;
5516
5517 return _asyncToGenerator(function* () {
5518 try {
5519 var image = yield _this.document.createImage(href);
5520 _this.image = image;
5521 } catch (err) {
5522 console.error("Error while loading image \"".concat(href, "\":"), err);
5523 }
5524
5525 _this.loaded = true;
5526 })();
5527 }
5528
5529 loadSvg(href) {
5530 var _this2 = this;
5531
5532 return _asyncToGenerator(function* () {
5533 var match = dataUriRegex.exec(href);
5534
5535 if (match) {
5536 var data = match[5];
5537
5538 if (match[4] === 'base64') {
5539 _this2.image = atob(data);
5540 } else {
5541 _this2.image = decodeURIComponent(data);
5542 }
5543 } else {
5544 try {
5545 var response = yield _this2.document.fetch(href);
5546 var svg = yield response.text();
5547 _this2.image = svg;
5548 } catch (err) {
5549 console.error("Error while loading image \"".concat(href, "\":"), err);
5550 }
5551 }
5552
5553 _this2.loaded = true;
5554 })();
5555 }
5556
5557 renderChildren(ctx) {
5558 var {
5559 document,
5560 image,
5561 loaded
5562 } = this;
5563 var x = this.getAttribute('x').getPixels('x');
5564 var y = this.getAttribute('y').getPixels('y');
5565 var width = this.getStyle('width').getPixels('x');
5566 var height = this.getStyle('height').getPixels('y');
5567
5568 if (!loaded || !image || !width || !height) {
5569 return;
5570 }
5571
5572 ctx.save();
5573 ctx.translate(x, y);
5574
5575 if (this.isSvg) {
5576 var subDocument = document.canvg.forkString(ctx, this.image, {
5577 ignoreMouse: true,
5578 ignoreAnimation: true,
5579 ignoreDimensions: true,
5580 ignoreClear: true,
5581 offsetX: 0,
5582 offsetY: 0,
5583 scaleWidth: width,
5584 scaleHeight: height
5585 });
5586 subDocument.document.documentElement.parent = this;
5587 void subDocument.render();
5588 } else {
5589 var _image = this.image;
5590 document.setViewBox({
5591 ctx,
5592 aspectRatio: this.getAttribute('preserveAspectRatio').getString(),
5593 width,
5594 desiredWidth: _image.width,
5595 height,
5596 desiredHeight: _image.height
5597 });
5598
5599 if (this.loaded) {
5600 if (typeof _image.complete === 'undefined' || _image.complete) {
5601 ctx.drawImage(_image, 0, 0);
5602 }
5603 }
5604 }
5605
5606 ctx.restore();
5607 }
5608
5609 getBoundingBox() {
5610 var x = this.getAttribute('x').getPixels('x');
5611 var y = this.getAttribute('y').getPixels('y');
5612 var width = this.getStyle('width').getPixels('x');
5613 var height = this.getStyle('height').getPixels('y');
5614 return new BoundingBox(x, y, x + width, y + height);
5615 }
5616
5617}
5618
5619class SymbolElement extends RenderedElement {
5620 constructor() {
5621 super(...arguments);
5622 this.type = 'symbol';
5623 }
5624
5625 render(_) {// NO RENDER
5626 }
5627
5628}
5629
5630class SVGFontLoader {
5631 constructor(document) {
5632 this.document = document;
5633 this.loaded = false;
5634 document.fonts.push(this);
5635 }
5636
5637 load(fontFamily, url) {
5638 var _this = this;
5639
5640 return _asyncToGenerator(function* () {
5641 try {
5642 var {
5643 document
5644 } = _this;
5645 var svgDocument = yield document.canvg.parser.load(url);
5646 var fonts = svgDocument.getElementsByTagName('font');
5647 Array.from(fonts).forEach(fontNode => {
5648 var font = document.createElement(fontNode);
5649 document.definitions[fontFamily] = font;
5650 });
5651 } catch (err) {
5652 console.error("Error while loading font \"".concat(url, "\":"), err);
5653 }
5654
5655 _this.loaded = true;
5656 })();
5657 }
5658
5659}
5660
5661class StyleElement extends Element {
5662 constructor(document, node, captureTextNodes) {
5663 super(document, node, captureTextNodes);
5664 this.type = 'style';
5665 var css = compressSpaces(Array.from(node.childNodes) // NEED TEST
5666 .map(_ => _.textContent).join('').replace(/(\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, '') // remove comments
5667 .replace(/@import.*;/g, '') // remove imports
5668 );
5669 var cssDefs = css.split('}');
5670 cssDefs.forEach(_ => {
5671 var def = _.trim();
5672
5673 if (!def) {
5674 return;
5675 }
5676
5677 var cssParts = def.split('{');
5678 var cssClasses = cssParts[0].split(',');
5679 var cssProps = cssParts[1].split(';');
5680 cssClasses.forEach(_ => {
5681 var cssClass = _.trim();
5682
5683 if (!cssClass) {
5684 return;
5685 }
5686
5687 var props = document.styles[cssClass] || {};
5688 cssProps.forEach(cssProp => {
5689 var prop = cssProp.indexOf(':');
5690 var name = cssProp.substr(0, prop).trim();
5691 var value = cssProp.substr(prop + 1, cssProp.length - prop).trim();
5692
5693 if (name && value) {
5694 props[name] = new Property(document, name, value);
5695 }
5696 });
5697 document.styles[cssClass] = props;
5698 document.stylesSpecificity[cssClass] = getSelectorSpecificity(cssClass);
5699
5700 if (cssClass === '@font-face') {
5701 // && !nodeEnv
5702 var fontFamily = props['font-family'].getString().replace(/"|'/g, '');
5703 var srcs = props.src.getString().split(',');
5704 srcs.forEach(src => {
5705 if (src.indexOf('format("svg")') > 0) {
5706 var url = parseExternalUrl(src);
5707
5708 if (url) {
5709 void new SVGFontLoader(document).load(fontFamily, url);
5710 }
5711 }
5712 });
5713 }
5714 });
5715 });
5716 }
5717
5718}
5719StyleElement.parseExternalUrl = parseExternalUrl;
5720
5721class UseElement extends RenderedElement {
5722 constructor() {
5723 super(...arguments);
5724 this.type = 'use';
5725 }
5726
5727 setContext(ctx) {
5728 super.setContext(ctx);
5729 var xAttr = this.getAttribute('x');
5730 var yAttr = this.getAttribute('y');
5731
5732 if (xAttr.hasValue()) {
5733 ctx.translate(xAttr.getPixels('x'), 0);
5734 }
5735
5736 if (yAttr.hasValue()) {
5737 ctx.translate(0, yAttr.getPixels('y'));
5738 }
5739 }
5740
5741 path(ctx) {
5742 var {
5743 element
5744 } = this;
5745
5746 if (element) {
5747 element.path(ctx);
5748 }
5749 }
5750
5751 renderChildren(ctx) {
5752 var {
5753 document,
5754 element
5755 } = this;
5756
5757 if (element) {
5758 var tempSvg = element;
5759
5760 if (element.type === 'symbol') {
5761 // render me using a temporary svg element in symbol cases (http://www.w3.org/TR/SVG/struct.html#UseElement)
5762 tempSvg = new SVGElement(document, null);
5763 tempSvg.attributes.viewBox = new Property(document, 'viewBox', element.getAttribute('viewBox').getString());
5764 tempSvg.attributes.preserveAspectRatio = new Property(document, 'preserveAspectRatio', element.getAttribute('preserveAspectRatio').getString());
5765 tempSvg.attributes.overflow = new Property(document, 'overflow', element.getAttribute('overflow').getString());
5766 tempSvg.children = element.children; // element is still the parent of the children
5767
5768 element.styles.opacity = new Property(document, 'opacity', this.calculateOpacity());
5769 }
5770
5771 if (tempSvg.type === 'svg') {
5772 var widthStyle = this.getStyle('width', false, true);
5773 var heightStyle = this.getStyle('height', false, true); // if symbol or svg, inherit width/height from me
5774
5775 if (widthStyle.hasValue()) {
5776 tempSvg.attributes.width = new Property(document, 'width', widthStyle.getString());
5777 }
5778
5779 if (heightStyle.hasValue()) {
5780 tempSvg.attributes.height = new Property(document, 'height', heightStyle.getString());
5781 }
5782 }
5783
5784 var oldParent = tempSvg.parent;
5785 tempSvg.parent = this;
5786 tempSvg.render(ctx);
5787 tempSvg.parent = oldParent;
5788 }
5789 }
5790
5791 getBoundingBox(ctx) {
5792 var {
5793 element
5794 } = this;
5795
5796 if (element) {
5797 return element.getBoundingBox(ctx);
5798 }
5799
5800 return null;
5801 }
5802
5803 elementTransform() {
5804 var {
5805 document,
5806 element
5807 } = this;
5808 return Transform.fromElement(document, element);
5809 }
5810
5811 get element() {
5812 if (!this.cachedElement) {
5813 this.cachedElement = this.getHrefAttribute().getDefinition();
5814 }
5815
5816 return this.cachedElement;
5817 }
5818
5819}
5820
5821function imGet(img, x, y, width, _height, rgba) {
5822 return img[y * width * 4 + x * 4 + rgba];
5823}
5824
5825function imSet(img, x, y, width, _height, rgba, val) {
5826 img[y * width * 4 + x * 4 + rgba] = val;
5827}
5828
5829function m(matrix, i, v) {
5830 var mi = matrix[i];
5831 return mi * v;
5832}
5833
5834function c(a, m1, m2, m3) {
5835 return m1 + Math.cos(a) * m2 + Math.sin(a) * m3;
5836}
5837
5838class FeColorMatrixElement extends Element {
5839 constructor(document, node, captureTextNodes) {
5840 super(document, node, captureTextNodes);
5841 this.type = 'feColorMatrix';
5842 var matrix = toNumbers(this.getAttribute('values').getString());
5843
5844 switch (this.getAttribute('type').getString('matrix')) {
5845 // http://www.w3.org/TR/SVG/filters.html#feColorMatrixElement
5846 case 'saturate':
5847 {
5848 var s = matrix[0];
5849 /* eslint-disable array-element-newline */
5850
5851 matrix = [0.213 + 0.787 * s, 0.715 - 0.715 * s, 0.072 - 0.072 * s, 0, 0, 0.213 - 0.213 * s, 0.715 + 0.285 * s, 0.072 - 0.072 * s, 0, 0, 0.213 - 0.213 * s, 0.715 - 0.715 * s, 0.072 + 0.928 * s, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1];
5852 /* eslint-enable array-element-newline */
5853
5854 break;
5855 }
5856
5857 case 'hueRotate':
5858 {
5859 var a = matrix[0] * Math.PI / 180.0;
5860 /* eslint-disable array-element-newline */
5861
5862 matrix = [c(a, 0.213, 0.787, -0.213), c(a, 0.715, -0.715, -0.715), c(a, 0.072, -0.072, 0.928), 0, 0, c(a, 0.213, -0.213, 0.143), c(a, 0.715, 0.285, 0.140), c(a, 0.072, -0.072, -0.283), 0, 0, c(a, 0.213, -0.213, -0.787), c(a, 0.715, -0.715, 0.715), c(a, 0.072, 0.928, 0.072), 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1];
5863 /* eslint-enable array-element-newline */
5864
5865 break;
5866 }
5867
5868 case 'luminanceToAlpha':
5869 /* eslint-disable array-element-newline */
5870 matrix = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2125, 0.7154, 0.0721, 0, 0, 0, 0, 0, 0, 1];
5871 /* eslint-enable array-element-newline */
5872
5873 break;
5874 }
5875
5876 this.matrix = matrix;
5877 this.includeOpacity = this.getAttribute('includeOpacity').hasValue();
5878 }
5879
5880 apply(ctx, _x, _y, width, height) {
5881 // assuming x==0 && y==0 for now
5882 var {
5883 includeOpacity,
5884 matrix
5885 } = this;
5886 var srcData = ctx.getImageData(0, 0, width, height);
5887
5888 for (var y = 0; y < height; y++) {
5889 for (var x = 0; x < width; x++) {
5890 var r = imGet(srcData.data, x, y, width, height, 0);
5891 var g = imGet(srcData.data, x, y, width, height, 1);
5892 var b = imGet(srcData.data, x, y, width, height, 2);
5893 var a = imGet(srcData.data, x, y, width, height, 3);
5894 var nr = m(matrix, 0, r) + m(matrix, 1, g) + m(matrix, 2, b) + m(matrix, 3, a) + m(matrix, 4, 1);
5895 var ng = m(matrix, 5, r) + m(matrix, 6, g) + m(matrix, 7, b) + m(matrix, 8, a) + m(matrix, 9, 1);
5896 var nb = m(matrix, 10, r) + m(matrix, 11, g) + m(matrix, 12, b) + m(matrix, 13, a) + m(matrix, 14, 1);
5897 var na = m(matrix, 15, r) + m(matrix, 16, g) + m(matrix, 17, b) + m(matrix, 18, a) + m(matrix, 19, 1);
5898
5899 if (includeOpacity) {
5900 nr = 0;
5901 ng = 0;
5902 nb = 0;
5903 na *= a / 255;
5904 }
5905
5906 imSet(srcData.data, x, y, width, height, 0, nr);
5907 imSet(srcData.data, x, y, width, height, 1, ng);
5908 imSet(srcData.data, x, y, width, height, 2, nb);
5909 imSet(srcData.data, x, y, width, height, 3, na);
5910 }
5911 }
5912
5913 ctx.clearRect(0, 0, width, height);
5914 ctx.putImageData(srcData, 0, 0);
5915 }
5916
5917}
5918
5919class MaskElement extends Element {
5920 constructor() {
5921 super(...arguments);
5922 this.type = 'mask';
5923 }
5924
5925 apply(ctx, element) {
5926 var {
5927 document
5928 } = this; // render as temp svg
5929
5930 var x = this.getAttribute('x').getPixels('x');
5931 var y = this.getAttribute('y').getPixels('y');
5932 var width = this.getStyle('width').getPixels('x');
5933 var height = this.getStyle('height').getPixels('y');
5934
5935 if (!width && !height) {
5936 var boundingBox = new BoundingBox();
5937 this.children.forEach(child => {
5938 boundingBox.addBoundingBox(child.getBoundingBox(ctx));
5939 });
5940 x = Math.floor(boundingBox.x1);
5941 y = Math.floor(boundingBox.y1);
5942 width = Math.floor(boundingBox.width);
5943 height = Math.floor(boundingBox.height);
5944 }
5945
5946 var ignoredStyles = this.removeStyles(element, MaskElement.ignoreStyles);
5947 var maskCanvas = document.createCanvas(x + width, y + height);
5948 var maskCtx = maskCanvas.getContext('2d');
5949 document.screen.setDefaults(maskCtx);
5950 this.renderChildren(maskCtx); // convert mask to alpha with a fake node
5951 // TODO: refactor out apply from feColorMatrix
5952
5953 new FeColorMatrixElement(document, {
5954 nodeType: 1,
5955 childNodes: [],
5956 attributes: [{
5957 nodeName: 'type',
5958 value: 'luminanceToAlpha'
5959 }, {
5960 nodeName: 'includeOpacity',
5961 value: 'true'
5962 }]
5963 }).apply(maskCtx, 0, 0, x + width, y + height);
5964 var tmpCanvas = document.createCanvas(x + width, y + height);
5965 var tmpCtx = tmpCanvas.getContext('2d');
5966 document.screen.setDefaults(tmpCtx);
5967 element.render(tmpCtx);
5968 tmpCtx.globalCompositeOperation = 'destination-in';
5969 tmpCtx.fillStyle = maskCtx.createPattern(maskCanvas, 'no-repeat');
5970 tmpCtx.fillRect(0, 0, x + width, y + height);
5971 ctx.fillStyle = tmpCtx.createPattern(tmpCanvas, 'no-repeat');
5972 ctx.fillRect(0, 0, x + width, y + height); // reassign mask
5973
5974 this.restoreStyles(element, ignoredStyles);
5975 }
5976
5977 render(_) {// NO RENDER
5978 }
5979
5980}
5981MaskElement.ignoreStyles = ['mask', 'transform', 'clip-path'];
5982
5983var noop = () => {// NOOP
5984};
5985
5986class ClipPathElement extends Element {
5987 constructor() {
5988 super(...arguments);
5989 this.type = 'clipPath';
5990 }
5991
5992 apply(ctx) {
5993 var {
5994 document
5995 } = this;
5996 var contextProto = Reflect.getPrototypeOf(ctx);
5997 var {
5998 beginPath,
5999 closePath
6000 } = ctx;
6001
6002 if (contextProto) {
6003 contextProto.beginPath = noop;
6004 contextProto.closePath = noop;
6005 }
6006
6007 Reflect.apply(beginPath, ctx, []);
6008 this.children.forEach(child => {
6009 if (typeof child.path === 'undefined') {
6010 return;
6011 }
6012
6013 var transform = typeof child.elementTransform !== 'undefined' ? child.elementTransform() : null; // handle <use />
6014
6015 if (!transform) {
6016 transform = Transform.fromElement(document, child);
6017 }
6018
6019 if (transform) {
6020 transform.apply(ctx);
6021 }
6022
6023 child.path(ctx);
6024
6025 if (contextProto) {
6026 contextProto.closePath = closePath;
6027 }
6028
6029 if (transform) {
6030 transform.unapply(ctx);
6031 }
6032 });
6033 Reflect.apply(closePath, ctx, []);
6034 ctx.clip();
6035
6036 if (contextProto) {
6037 contextProto.beginPath = beginPath;
6038 contextProto.closePath = closePath;
6039 }
6040 }
6041
6042 render(_) {// NO RENDER
6043 }
6044
6045}
6046
6047class FilterElement extends Element {
6048 constructor() {
6049 super(...arguments);
6050 this.type = 'filter';
6051 }
6052
6053 apply(ctx, element) {
6054 // render as temp svg
6055 var {
6056 document,
6057 children
6058 } = this;
6059 var boundingBox = element.getBoundingBox(ctx);
6060
6061 if (!boundingBox) {
6062 return;
6063 }
6064
6065 var px = 0;
6066 var py = 0;
6067 children.forEach(child => {
6068 var efd = child.extraFilterDistance || 0;
6069 px = Math.max(px, efd);
6070 py = Math.max(py, efd);
6071 });
6072 var width = Math.floor(boundingBox.width);
6073 var height = Math.floor(boundingBox.height);
6074 var tmpCanvasWidth = width + 2 * px;
6075 var tmpCanvasHeight = height + 2 * py;
6076
6077 if (tmpCanvasWidth < 1 || tmpCanvasHeight < 1) {
6078 return;
6079 }
6080
6081 var x = Math.floor(boundingBox.x);
6082 var y = Math.floor(boundingBox.y);
6083 var ignoredStyles = this.removeStyles(element, FilterElement.ignoreStyles);
6084 var tmpCanvas = document.createCanvas(tmpCanvasWidth, tmpCanvasHeight);
6085 var tmpCtx = tmpCanvas.getContext('2d');
6086 document.screen.setDefaults(tmpCtx);
6087 tmpCtx.translate(-x + px, -y + py);
6088 element.render(tmpCtx); // apply filters
6089
6090 children.forEach(child => {
6091 if (typeof child.apply === 'function') {
6092 child.apply(tmpCtx, 0, 0, tmpCanvasWidth, tmpCanvasHeight);
6093 }
6094 }); // render on me
6095
6096 ctx.drawImage(tmpCanvas, 0, 0, tmpCanvasWidth, tmpCanvasHeight, x - px, y - py, tmpCanvasWidth, tmpCanvasHeight);
6097 this.restoreStyles(element, ignoredStyles);
6098 }
6099
6100 render(_) {// NO RENDER
6101 }
6102
6103}
6104FilterElement.ignoreStyles = ['filter', 'transform', 'clip-path'];
6105
6106class FeDropShadowElement extends Element {
6107 constructor(document, node, captureTextNodes) {
6108 super(document, node, captureTextNodes);
6109 this.type = 'feDropShadow';
6110 this.addStylesFromStyleDefinition();
6111 }
6112
6113 apply(_, _x, _y, _width, _height) {// TODO: implement
6114 }
6115
6116}
6117
6118class FeMorphologyElement extends Element {
6119 constructor() {
6120 super(...arguments);
6121 this.type = 'feMorphology';
6122 }
6123
6124 apply(_, _x, _y, _width, _height) {// TODO: implement
6125 }
6126
6127}
6128
6129class FeCompositeElement extends Element {
6130 constructor() {
6131 super(...arguments);
6132 this.type = 'feComposite';
6133 }
6134
6135 apply(_, _x, _y, _width, _height) {// TODO: implement
6136 }
6137
6138}
6139
6140class FeGaussianBlurElement extends Element {
6141 constructor(document, node, captureTextNodes) {
6142 super(document, node, captureTextNodes);
6143 this.type = 'feGaussianBlur';
6144 this.blurRadius = Math.floor(this.getAttribute('stdDeviation').getNumber());
6145 this.extraFilterDistance = this.blurRadius;
6146 }
6147
6148 apply(ctx, x, y, width, height) {
6149 var {
6150 document,
6151 blurRadius
6152 } = this;
6153 var body = document.window ? document.window.document.body : null;
6154 var canvas = ctx.canvas; // StackBlur requires canvas be on document
6155
6156 canvas.id = document.getUniqueId();
6157
6158 if (body) {
6159 canvas.style.display = 'none';
6160 body.appendChild(canvas);
6161 }
6162
6163 canvasRGBA(canvas, x, y, width, height, blurRadius);
6164
6165 if (body) {
6166 body.removeChild(canvas);
6167 }
6168 }
6169
6170}
6171
6172class TitleElement extends Element {
6173 constructor() {
6174 super(...arguments);
6175 this.type = 'title';
6176 }
6177
6178}
6179
6180class DescElement extends Element {
6181 constructor() {
6182 super(...arguments);
6183 this.type = 'desc';
6184 }
6185
6186}
6187
6188var elements = {
6189 'svg': SVGElement,
6190 'rect': RectElement,
6191 'circle': CircleElement,
6192 'ellipse': EllipseElement,
6193 'line': LineElement,
6194 'polyline': PolylineElement,
6195 'polygon': PolygonElement,
6196 'path': PathElement,
6197 'pattern': PatternElement,
6198 'marker': MarkerElement,
6199 'defs': DefsElement,
6200 'linearGradient': LinearGradientElement,
6201 'radialGradient': RadialGradientElement,
6202 'stop': StopElement,
6203 'animate': AnimateElement,
6204 'animateColor': AnimateColorElement,
6205 'animateTransform': AnimateTransformElement,
6206 'font': FontElement,
6207 'font-face': FontFaceElement,
6208 'missing-glyph': MissingGlyphElement,
6209 'glyph': GlyphElement,
6210 'text': TextElement,
6211 'tspan': TSpanElement,
6212 'tref': TRefElement,
6213 'a': AElement,
6214 'textPath': TextPathElement,
6215 'image': ImageElement,
6216 'g': GElement,
6217 'symbol': SymbolElement,
6218 'style': StyleElement,
6219 'use': UseElement,
6220 'mask': MaskElement,
6221 'clipPath': ClipPathElement,
6222 'filter': FilterElement,
6223 'feDropShadow': FeDropShadowElement,
6224 'feMorphology': FeMorphologyElement,
6225 'feComposite': FeCompositeElement,
6226 'feColorMatrix': FeColorMatrixElement,
6227 'feGaussianBlur': FeGaussianBlurElement,
6228 'title': TitleElement,
6229 'desc': DescElement
6230};
6231
6232function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
6233
6234function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
6235
6236function createCanvas(width, height) {
6237 var canvas = document.createElement('canvas');
6238 canvas.width = width;
6239 canvas.height = height;
6240 return canvas;
6241}
6242
6243function createImage(_x) {
6244 return _createImage.apply(this, arguments);
6245}
6246
6247function _createImage() {
6248 _createImage = _asyncToGenerator(function* (src) {
6249 var anonymousCrossOrigin = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
6250 var image = document.createElement('img');
6251
6252 if (anonymousCrossOrigin) {
6253 image.crossOrigin = 'Anonymous';
6254 }
6255
6256 return new Promise((resolve, reject) => {
6257 image.onload = () => {
6258 resolve(image);
6259 };
6260
6261 image.onerror = (_event, _source, _lineno, _colno, error) => {
6262 reject(error);
6263 };
6264
6265 image.src = src;
6266 });
6267 });
6268 return _createImage.apply(this, arguments);
6269}
6270
6271class Document {
6272 constructor(canvg) {
6273 var {
6274 rootEmSize = 12,
6275 emSize = 12,
6276 createCanvas = Document.createCanvas,
6277 createImage = Document.createImage,
6278 anonymousCrossOrigin
6279 } = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6280 this.canvg = canvg;
6281 this.definitions = {};
6282 this.styles = {};
6283 this.stylesSpecificity = {};
6284 this.images = [];
6285 this.fonts = [];
6286 this.emSizeStack = [];
6287 this.uniqueId = 0;
6288 this.screen = canvg.screen;
6289 this.rootEmSize = rootEmSize;
6290 this.emSize = emSize;
6291 this.createCanvas = createCanvas;
6292 this.createImage = this.bindCreateImage(createImage, anonymousCrossOrigin);
6293 this.screen.wait(this.isImagesLoaded.bind(this));
6294 this.screen.wait(this.isFontsLoaded.bind(this));
6295 }
6296
6297 bindCreateImage(createImage, anonymousCrossOrigin) {
6298 if (typeof anonymousCrossOrigin === 'boolean') {
6299 return (source, forceAnonymousCrossOrigin) => createImage(source, typeof forceAnonymousCrossOrigin === 'boolean' ? forceAnonymousCrossOrigin : anonymousCrossOrigin);
6300 }
6301
6302 return createImage;
6303 }
6304
6305 get window() {
6306 return this.screen.window;
6307 }
6308
6309 get fetch() {
6310 return this.screen.fetch;
6311 }
6312
6313 get ctx() {
6314 return this.screen.ctx;
6315 }
6316
6317 get emSize() {
6318 var {
6319 emSizeStack
6320 } = this;
6321 return emSizeStack[emSizeStack.length - 1];
6322 }
6323
6324 set emSize(value) {
6325 var {
6326 emSizeStack
6327 } = this;
6328 emSizeStack.push(value);
6329 }
6330
6331 popEmSize() {
6332 var {
6333 emSizeStack
6334 } = this;
6335 emSizeStack.pop();
6336 }
6337
6338 getUniqueId() {
6339 return "canvg".concat(++this.uniqueId);
6340 }
6341
6342 isImagesLoaded() {
6343 return this.images.every(_ => _.loaded);
6344 }
6345
6346 isFontsLoaded() {
6347 return this.fonts.every(_ => _.loaded);
6348 }
6349
6350 createDocumentElement(document) {
6351 var documentElement = this.createElement(document.documentElement);
6352 documentElement.root = true;
6353 documentElement.addStylesFromStyleDefinition();
6354 this.documentElement = documentElement;
6355 return documentElement;
6356 }
6357
6358 createElement(node) {
6359 var elementType = node.nodeName.replace(/^[^:]+:/, '');
6360 var ElementType = Document.elementTypes[elementType];
6361
6362 if (typeof ElementType !== 'undefined') {
6363 return new ElementType(this, node);
6364 }
6365
6366 return new UnknownElement(this, node);
6367 }
6368
6369 createTextNode(node) {
6370 return new TextNode(this, node);
6371 }
6372
6373 setViewBox(config) {
6374 this.screen.setViewBox(_objectSpread$1({
6375 document: this
6376 }, config));
6377 }
6378
6379}
6380Document.createCanvas = createCanvas;
6381Document.createImage = createImage;
6382Document.elementTypes = elements;
6383
6384function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
6385
6386function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
6387/**
6388 * SVG renderer on canvas.
6389 */
6390
6391class Canvg {
6392 /**
6393 * Main constructor.
6394 * @param ctx - Rendering context.
6395 * @param svg - SVG Document.
6396 * @param options - Rendering options.
6397 */
6398 constructor(ctx, svg) {
6399 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6400 this.parser = new Parser(options);
6401 this.screen = new Screen(ctx, options);
6402 this.options = options;
6403 var document = new Document(this, options);
6404 var documentElement = document.createDocumentElement(svg);
6405 this.document = document;
6406 this.documentElement = documentElement;
6407 }
6408 /**
6409 * Create Canvg instance from SVG source string or URL.
6410 * @param ctx - Rendering context.
6411 * @param svg - SVG source string or URL.
6412 * @param options - Rendering options.
6413 * @returns Canvg instance.
6414 */
6415
6416
6417 static from(ctx, svg) {
6418 var _arguments = arguments;
6419 return _asyncToGenerator(function* () {
6420 var options = _arguments.length > 2 && _arguments[2] !== undefined ? _arguments[2] : {};
6421 var parser = new Parser(options);
6422 var svgDocument = yield parser.parse(svg);
6423 return new Canvg(ctx, svgDocument, options);
6424 })();
6425 }
6426 /**
6427 * Create Canvg instance from SVG source string.
6428 * @param ctx - Rendering context.
6429 * @param svg - SVG source string.
6430 * @param options - Rendering options.
6431 * @returns Canvg instance.
6432 */
6433
6434
6435 static fromString(ctx, svg) {
6436 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6437 var parser = new Parser(options);
6438 var svgDocument = parser.parseFromString(svg);
6439 return new Canvg(ctx, svgDocument, options);
6440 }
6441 /**
6442 * Create new Canvg instance with inherited options.
6443 * @param ctx - Rendering context.
6444 * @param svg - SVG source string or URL.
6445 * @param options - Rendering options.
6446 * @returns Canvg instance.
6447 */
6448
6449
6450 fork(ctx, svg) {
6451 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6452 return Canvg.from(ctx, svg, _objectSpread(_objectSpread({}, this.options), options));
6453 }
6454 /**
6455 * Create new Canvg instance with inherited options.
6456 * @param ctx - Rendering context.
6457 * @param svg - SVG source string.
6458 * @param options - Rendering options.
6459 * @returns Canvg instance.
6460 */
6461
6462
6463 forkString(ctx, svg) {
6464 var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
6465 return Canvg.fromString(ctx, svg, _objectSpread(_objectSpread({}, this.options), options));
6466 }
6467 /**
6468 * Document is ready promise.
6469 * @returns Ready promise.
6470 */
6471
6472
6473 ready() {
6474 return this.screen.ready();
6475 }
6476 /**
6477 * Document is ready value.
6478 * @returns Is ready or not.
6479 */
6480
6481
6482 isReady() {
6483 return this.screen.isReady();
6484 }
6485 /**
6486 * Render only first frame, ignoring animations and mouse.
6487 * @param options - Rendering options.
6488 */
6489
6490
6491 render() {
6492 var _arguments2 = arguments,
6493 _this = this;
6494
6495 return _asyncToGenerator(function* () {
6496 var options = _arguments2.length > 0 && _arguments2[0] !== undefined ? _arguments2[0] : {};
6497
6498 _this.start(_objectSpread({
6499 enableRedraw: true,
6500 ignoreAnimation: true,
6501 ignoreMouse: true
6502 }, options));
6503
6504 yield _this.ready();
6505
6506 _this.stop();
6507 })();
6508 }
6509 /**
6510 * Start rendering.
6511 * @param options - Render options.
6512 */
6513
6514
6515 start() {
6516 var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
6517 var {
6518 documentElement,
6519 screen,
6520 options: baseOptions
6521 } = this;
6522 screen.start(documentElement, _objectSpread(_objectSpread({
6523 enableRedraw: true
6524 }, baseOptions), options));
6525 }
6526 /**
6527 * Stop rendering.
6528 */
6529
6530
6531 stop() {
6532 this.screen.stop();
6533 }
6534 /**
6535 * Resize SVG to fit in given size.
6536 * @param width
6537 * @param height
6538 * @param preserveAspectRatio
6539 */
6540
6541
6542 resize(width) {
6543 var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : width;
6544 var preserveAspectRatio = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
6545 this.documentElement.resize(width, height, preserveAspectRatio);
6546 }
6547
6548}
6549
6550export { AElement, AnimateColorElement, AnimateElement, AnimateTransformElement, BoundingBox, CB1, CB2, CB3, CB4, Canvg, CircleElement, ClipPathElement, DefsElement, DescElement, Document, Element, EllipseElement, FeColorMatrixElement, FeCompositeElement, FeDropShadowElement, FeGaussianBlurElement, FeMorphologyElement, FilterElement, Font, FontElement, FontFaceElement, GElement, GlyphElement, GradientElement, ImageElement, LineElement, LinearGradientElement, MarkerElement, MaskElement, Matrix, MissingGlyphElement, Mouse, PSEUDO_ZERO, Parser, PathElement, PathParser, PatternElement, Point, PolygonElement, PolylineElement, Property, QB1, QB2, QB3, RadialGradientElement, RectElement, RenderedElement, Rotate, SVGElement, SVGFontLoader, Scale, Screen, Skew, SkewX, SkewY, StopElement, StyleElement, SymbolElement, TRefElement, TSpanElement, TextElement, TextPathElement, TitleElement, Transform, Translate, UnknownElement, UseElement, ViewPort, compressSpaces, Canvg as default, getSelectorSpecificity, normalizeAttributeName, normalizeColor, parseExternalUrl, index as presets, toNumbers, trimLeft, trimRight, vectorMagnitude, vectorsAngle, vectorsRatio };
6551//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZXMuanMiLCJzb3VyY2VzIjpbXSwic291cmNlc0NvbnRlbnQiOltdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzsifQ==
Note: See TracBrowser for help on using the repository browser.