pdfmake-acroforms 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +75 -0
  4. package/build/fonts/Roboto/Roboto-Italic.ttf +0 -0
  5. package/build/fonts/Roboto/Roboto-Medium.ttf +0 -0
  6. package/build/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  7. package/build/fonts/Roboto/Roboto-Regular.ttf +0 -0
  8. package/build/fonts/Roboto.js +27 -0
  9. package/build/pdfmake.js +67806 -0
  10. package/build/pdfmake.js.map +1 -0
  11. package/build/pdfmake.min.js +3 -0
  12. package/build/pdfmake.min.js.map +1 -0
  13. package/build/standard-fonts/Courier.js +27 -0
  14. package/build/standard-fonts/Helvetica.js +27 -0
  15. package/build/standard-fonts/Symbol.js +21 -0
  16. package/build/standard-fonts/Times.js +27 -0
  17. package/build/standard-fonts/ZapfDingbats.js +21 -0
  18. package/build/vfs_fonts.js +6 -0
  19. package/build-vfs.js +44 -0
  20. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  21. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  22. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  23. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  24. package/fonts/Roboto.js +8 -0
  25. package/js/3rd-party/svg-to-pdfkit/source.js +3823 -0
  26. package/js/3rd-party/svg-to-pdfkit.js +7 -0
  27. package/js/DocMeasure.js +675 -0
  28. package/js/DocPreprocessor.js +258 -0
  29. package/js/DocumentContext.js +310 -0
  30. package/js/ElementWriter.js +399 -0
  31. package/js/LayoutBuilder.js +1202 -0
  32. package/js/Line.js +101 -0
  33. package/js/OutputDocument.js +64 -0
  34. package/js/OutputDocumentServer.js +29 -0
  35. package/js/PDFDocument.js +145 -0
  36. package/js/PageElementWriter.js +164 -0
  37. package/js/PageSize.js +74 -0
  38. package/js/Printer.js +288 -0
  39. package/js/Renderer.js +513 -0
  40. package/js/SVGMeasure.js +92 -0
  41. package/js/StyleContextStack.js +191 -0
  42. package/js/TableProcessor.js +562 -0
  43. package/js/TextBreaker.js +179 -0
  44. package/js/TextDecorator.js +152 -0
  45. package/js/TextInlines.js +212 -0
  46. package/js/URLResolver.js +43 -0
  47. package/js/base.js +59 -0
  48. package/js/browser-extensions/OutputDocumentBrowser.js +82 -0
  49. package/js/browser-extensions/fonts/Roboto.js +38 -0
  50. package/js/browser-extensions/index.js +53 -0
  51. package/js/browser-extensions/pdfMake.js +3 -0
  52. package/js/browser-extensions/standard-fonts/Courier.js +38 -0
  53. package/js/browser-extensions/standard-fonts/Helvetica.js +38 -0
  54. package/js/browser-extensions/standard-fonts/Symbol.js +23 -0
  55. package/js/browser-extensions/standard-fonts/Times.js +38 -0
  56. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +23 -0
  57. package/js/browser-extensions/virtual-fs-cjs.js +3 -0
  58. package/js/columnCalculator.js +148 -0
  59. package/js/helpers/node.js +122 -0
  60. package/js/helpers/tools.js +46 -0
  61. package/js/helpers/variableType.js +59 -0
  62. package/js/index.js +15 -0
  63. package/js/qrEnc.js +721 -0
  64. package/js/standardPageSizes.js +56 -0
  65. package/js/tableLayouts.js +98 -0
  66. package/js/virtual-fs.js +60 -0
  67. package/package.json +94 -0
  68. package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -0
  69. package/src/3rd-party/svg-to-pdfkit/source.js +2745 -0
  70. package/src/3rd-party/svg-to-pdfkit.js +3 -0
  71. package/src/DocMeasure.js +768 -0
  72. package/src/DocPreprocessor.js +289 -0
  73. package/src/DocumentContext.js +345 -0
  74. package/src/ElementWriter.js +468 -0
  75. package/src/LayoutBuilder.js +1366 -0
  76. package/src/Line.js +108 -0
  77. package/src/OutputDocument.js +64 -0
  78. package/src/OutputDocumentServer.js +32 -0
  79. package/src/PDFDocument.js +178 -0
  80. package/src/PageElementWriter.js +191 -0
  81. package/src/PageSize.js +53 -0
  82. package/src/Printer.js +306 -0
  83. package/src/Renderer.js +546 -0
  84. package/src/SVGMeasure.js +109 -0
  85. package/src/StyleContextStack.js +208 -0
  86. package/src/TableProcessor.js +620 -0
  87. package/src/TextBreaker.js +181 -0
  88. package/src/TextDecorator.js +175 -0
  89. package/src/TextInlines.js +229 -0
  90. package/src/URLResolver.js +43 -0
  91. package/src/base.js +70 -0
  92. package/src/browser-extensions/OutputDocumentBrowser.js +80 -0
  93. package/src/browser-extensions/fonts/Roboto.js +27 -0
  94. package/src/browser-extensions/index.js +55 -0
  95. package/src/browser-extensions/pdfMake.js +1 -0
  96. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  97. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  98. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  99. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  100. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  101. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  102. package/src/columnCalculator.js +154 -0
  103. package/src/helpers/node.js +134 -0
  104. package/src/helpers/tools.js +44 -0
  105. package/src/helpers/variableType.js +50 -0
  106. package/src/index.js +16 -0
  107. package/src/qrEnc.js +796 -0
  108. package/src/standardPageSizes.js +52 -0
  109. package/src/tableLayouts.js +100 -0
  110. package/src/virtual-fs.js +66 -0
  111. package/standard-fonts/Courier.js +8 -0
  112. package/standard-fonts/Helvetica.js +8 -0
  113. package/standard-fonts/Symbol.js +5 -0
  114. package/standard-fonts/Times.js +8 -0
  115. package/standard-fonts/ZapfDingbats.js +5 -0
@@ -0,0 +1,2745 @@
1
+ var SVGtoPDF = function(doc, svg, x, y, options) {
2
+ "use strict";
3
+
4
+ const NamedColors = {aliceblue: [240,248,255], antiquewhite: [250,235,215], aqua: [0,255,255], aquamarine: [127,255,212], azure: [240,255,255], beige: [245,245,220], bisque: [255,228,196], black: [0,0,0], blanchedalmond: [255,235,205], blue: [0,0,255], blueviolet: [138,43,226], brown: [165,42,42], burlywood: [222,184,135], cadetblue: [95,158,160], chartreuse: [127,255,0],
5
+ chocolate: [210,105,30], coral: [255,127,80], cornflowerblue: [100,149,237], cornsilk: [255,248,220], crimson: [220,20,60], cyan: [0,255,255], darkblue: [0,0,139], darkcyan: [0,139,139], darkgoldenrod: [184,134,11], darkgray: [169,169,169], darkgrey: [169,169,169], darkgreen: [0,100,0], darkkhaki: [189,183,107], darkmagenta: [139,0,139], darkolivegreen: [85,107,47],
6
+ darkorange: [255,140,0], darkorchid: [153,50,204], darkred: [139,0,0], darksalmon: [233,150,122], darkseagreen: [143,188,143], darkslateblue: [72,61,139], darkslategray: [47,79,79], darkslategrey: [47,79,79], darkturquoise: [0,206,209], darkviolet: [148,0,211], deeppink: [255,20,147], deepskyblue: [0,191,255], dimgray: [105,105,105], dimgrey: [105,105,105],
7
+ dodgerblue: [30,144,255], firebrick: [178,34,34], floralwhite: [255,250,240], forestgreen: [34,139,34], fuchsia: [255,0,255], gainsboro: [220,220,220], ghostwhite: [248,248,255], gold: [255,215,0], goldenrod: [218,165,32], gray: [128,128,128], grey: [128,128,128], green: [0,128,0], greenyellow: [173,255,47], honeydew: [240,255,240], hotpink: [255,105,180],
8
+ indianred: [205,92,92], indigo: [75,0,130], ivory: [255,255,240], khaki: [240,230,140], lavender: [230,230,250], lavenderblush: [255,240,245], lawngreen: [124,252,0], lemonchiffon: [255,250,205], lightblue: [173,216,230], lightcoral: [240,128,128], lightcyan: [224,255,255], lightgoldenrodyellow: [250,250,210], lightgray: [211,211,211], lightgrey: [211,211,211],
9
+ lightgreen: [144,238,144], lightpink: [255,182,193], lightsalmon: [255,160,122], lightseagreen: [32,178,170], lightskyblue: [135,206,250], lightslategray: [119,136,153], lightslategrey: [119,136,153], lightsteelblue: [176,196,222], lightyellow: [255,255,224], lime: [0,255,0], limegreen: [50,205,50], linen: [250,240,230], magenta: [255,0,255], maroon: [128,0,0],
10
+ mediumaquamarine: [102,205,170], mediumblue: [0,0,205], mediumorchid: [186,85,211], mediumpurple: [147,112,219], mediumseagreen: [60,179,113], mediumslateblue: [123,104,238], mediumspringgreen: [0,250,154], mediumturquoise: [72,209,204], mediumvioletred: [199,21,133], midnightblue: [25,25,112], mintcream: [245,255,250], mistyrose: [255,228,225], moccasin: [255,228,181],
11
+ navajowhite: [255,222,173], navy: [0,0,128], oldlace: [253,245,230], olive: [128,128,0], olivedrab: [107,142,35], orange: [255,165,0], orangered: [255,69,0], orchid: [218,112,214], palegoldenrod: [238,232,170], palegreen: [152,251,152], paleturquoise: [175,238,238], palevioletred: [219,112,147], papayawhip: [255,239,213], peachpuff: [255,218,185], peru: [205,133,63],
12
+ pink: [255,192,203], plum: [221,160,221], powderblue: [176,224,230], purple: [128,0,128], rebeccapurple: [102,51,153], red: [255,0,0], rosybrown: [188,143,143], royalblue: [65,105,225], saddlebrown: [139,69,19], salmon: [250,128,114], sandybrown: [244,164,96], seagreen: [46,139,87], seashell: [255,245,238], sienna: [160,82,45], silver: [192,192,192], skyblue: [135,206,235],
13
+ slateblue: [106,90,205], slategray: [112,128,144], slategrey: [112,128,144], snow: [255,250,250], springgreen: [0,255,127], steelblue: [70,130,180], tan: [210,180,140], teal: [0,128,128], thistle: [216,191,216], tomato: [255,99,71], turquoise: [64,224,208], violet: [238,130,238], wheat: [245,222,179], white: [255,255,255], whitesmoke: [245,245,245], yellow: [255,255,0]};
14
+ const DefaultColors = {black: [NamedColors.black, 1], white: [NamedColors.white, 1], transparent: [NamedColors.black, 0]};
15
+ const Entities = {quot: 34, amp: 38, lt: 60, gt: 62, apos: 39, OElig: 338, oelig: 339, Scaron: 352, scaron: 353, Yuml: 376, circ: 710, tilde: 732, ensp: 8194, emsp: 8195, thinsp: 8201, zwnj: 8204, zwj: 8205, lrm: 8206, rlm: 8207, ndash: 8211, mdash: 8212, lsquo: 8216, rsquo: 8217, sbquo: 8218, ldquo: 8220, rdquo: 8221, bdquo: 8222, dagger: 8224, Dagger: 8225, permil: 8240, lsaquo: 8249,
16
+ rsaquo: 8250, euro: 8364, nbsp: 160, iexcl: 161, cent: 162, pound: 163, curren: 164, yen: 165, brvbar: 166, sect: 167, uml: 168, copy: 169, ordf: 170, laquo: 171, not: 172, shy: 173, reg: 174, macr: 175, deg: 176, plusmn: 177, sup2: 178, sup3: 179, acute: 180, micro: 181, para: 182, middot: 183, cedil: 184, sup1: 185, ordm: 186, raquo: 187, frac14: 188, frac12: 189, frac34: 190,
17
+ iquest: 191, Agrave: 192, Aacute: 193, Acirc: 194, Atilde: 195, Auml: 196, Aring: 197, AElig: 198, Ccedil: 199, Egrave: 200, Eacute: 201, Ecirc: 202, Euml: 203, Igrave: 204, Iacute: 205, Icirc: 206, Iuml: 207, ETH: 208, Ntilde: 209, Ograve: 210, Oacute: 211, Ocirc: 212, Otilde: 213, Ouml: 214, times: 215, Oslash: 216, Ugrave: 217, Uacute: 218, Ucirc: 219, Uuml: 220, Yacute: 221,
18
+ THORN: 222, szlig: 223, agrave: 224, aacute: 225, acirc: 226, atilde: 227, auml: 228, aring: 229, aelig: 230, ccedil: 231, egrave: 232, eacute: 233, ecirc: 234, euml: 235, igrave: 236, iacute: 237, icirc: 238, iuml: 239, eth: 240, ntilde: 241, ograve: 242, oacute: 243, ocirc: 244, otilde: 245, ouml: 246, divide: 247, oslash: 248, ugrave: 249, uacute: 250, ucirc: 251, uuml: 252,
19
+ yacute: 253, thorn: 254, yuml: 255, fnof: 402, Alpha: 913, Beta: 914, Gamma: 915, Delta: 916, Epsilon: 917, Zeta: 918, Eta: 919, Theta: 920, Iota: 921, Kappa: 922, Lambda: 923, Mu: 924, Nu: 925, Xi: 926, Omicron: 927, Pi: 928, Rho: 929, Sigma: 931, Tau: 932, Upsilon: 933, Phi: 934, Chi: 935, Psi: 936, Omega: 937, alpha: 945, beta: 946, gamma: 947, delta: 948, epsilon: 949,
20
+ zeta: 950, eta: 951, theta: 952, iota: 953, kappa: 954, lambda: 955, mu: 956, nu: 957, xi: 958, omicron: 959, pi: 960, rho: 961, sigmaf: 962, sigma: 963, tau: 964, upsilon: 965, phi: 966, chi: 967, psi: 968, omega: 969, thetasym: 977, upsih: 978, piv: 982, bull: 8226, hellip: 8230, prime: 8242, Prime: 8243, oline: 8254, frasl: 8260, weierp: 8472, image: 8465, real: 8476,
21
+ trade: 8482, alefsym: 8501, larr: 8592, uarr: 8593, rarr: 8594, darr: 8595, harr: 8596, crarr: 8629, lArr: 8656, uArr: 8657, rArr: 8658, dArr: 8659, hArr: 8660, forall: 8704, part: 8706, exist: 8707, empty: 8709, nabla: 8711, isin: 8712, notin: 8713, ni: 8715, prod: 8719, sum: 8721, minus: 8722, lowast: 8727, radic: 8730, prop: 8733, infin: 8734, ang: 8736, and: 8743, or: 8744,
22
+ cap: 8745, cup: 8746, int: 8747, there4: 8756, sim: 8764, cong: 8773, asymp: 8776, ne: 8800, equiv: 8801, le: 8804, ge: 8805, sub: 8834, sup: 8835, nsub: 8836, sube: 8838, supe: 8839, oplus: 8853, otimes: 8855, perp: 8869, sdot: 8901, lceil: 8968, rceil: 8969, lfloor: 8970, rfloor: 8971, lang: 9001, rang: 9002, loz: 9674, spades: 9824, clubs: 9827, hearts: 9829, diams: 9830};
23
+ const PathArguments = {A: 7, a: 7, C: 6, c: 6, H: 1, h: 1, L: 2, l: 2, M: 2, m: 2, Q: 4, q: 4, S: 4, s: 4, T: 2, t: 2, V: 1, v: 1, Z: 0, z: 0};
24
+ const PathFlags = {A3: true, A4: true, a3: true, a4: true};
25
+ const Properties = {
26
+ 'color': {inherit: true, initial: undefined},
27
+ 'visibility': {inherit: true, initial: 'visible', values: {'hidden': 'hidden', 'collapse': 'hidden', 'visible':'visible'}},
28
+ 'fill': {inherit: true, initial: DefaultColors.black},
29
+ 'stroke': {inherit: true, initial: 'none'},
30
+ 'stop-color': {inherit: false, initial: DefaultColors.black},
31
+ 'fill-opacity': {inherit: true, initial: 1},
32
+ 'stroke-opacity': {inherit: true, initial: 1},
33
+ 'stop-opacity': {inherit: false, initial: 1},
34
+ 'fill-rule': {inherit: true, initial: 'nonzero', values: {'nonzero':'nonzero', 'evenodd':'evenodd'}},
35
+ 'clip-rule': {inherit: true, initial: 'nonzero', values: {'nonzero':'nonzero', 'evenodd':'evenodd'}},
36
+ 'stroke-width': {inherit: true, initial: 1},
37
+ 'stroke-dasharray': {inherit: true, initial: []},
38
+ 'stroke-dashoffset': {inherit: true, initial: 0},
39
+ 'stroke-miterlimit': {inherit: true, initial: 4},
40
+ 'stroke-linejoin': {inherit: true, initial: 'miter', values: {'miter':'miter', 'round':'round', 'bevel':'bevel'}},
41
+ 'stroke-linecap': {inherit: true, initial: 'butt', values: {'butt':'butt', 'round':'round', 'square':'square'}},
42
+ 'font-size': {inherit: true, initial: 16, values: {'xx-small':9, 'x-small':10, 'small':13, 'medium':16, 'large':18, 'x-large':24, 'xx-large':32}},
43
+ 'font-family': {inherit: true, initial: 'sans-serif'},
44
+ 'font-weight': {inherit: true, initial: 'normal', values: {'600':'bold', '700':'bold', '800':'bold', '900':'bold', 'bold':'bold', 'bolder':'bold', '500':'normal', '400':'normal', '300':'normal', '200':'normal', '100':'normal', 'normal':'normal', 'lighter':'normal'}},
45
+ 'font-style': {inherit: true, initial: 'normal', values: {'italic':'italic', 'oblique':'italic', 'normal':'normal'}},
46
+ 'text-anchor': {inherit: true, initial: 'start', values: {'start':'start', 'middle':'middle', 'end':'end'}},
47
+ 'direction': {inherit: true, initial: 'ltr', values: {'ltr':'ltr', 'rtl':'rtl'}},
48
+ 'dominant-baseline': {inherit: true, initial: 'baseline', values: {'auto':'baseline', 'baseline':'baseline', 'before-edge':'before-edge', 'text-before-edge':'before-edge', 'middle':'middle', 'central':'central', 'after-edge':'after-edge', 'text-after-edge':'after-edge', 'ideographic':'ideographic', 'alphabetic':'alphabetic', 'hanging':'hanging', 'mathematical':'mathematical'}},
49
+ 'alignment-baseline': {inherit: false, initial: undefined, values: {'auto':'baseline', 'baseline':'baseline', 'before-edge':'before-edge', 'text-before-edge':'before-edge', 'middle':'middle', 'central':'central', 'after-edge':'after-edge', 'text-after-edge':'after-edge', 'ideographic':'ideographic', 'alphabetic':'alphabetic', 'hanging':'hanging', 'mathematical':'mathematical'}},
50
+ 'baseline-shift': {inherit: true, initial: 'baseline', values: {'baseline':'baseline', 'sub':'sub', 'super':'super'}},
51
+ 'word-spacing': {inherit: true, initial: 0, values: {normal:0}},
52
+ 'letter-spacing': {inherit: true, initial: 0, values: {normal:0}},
53
+ 'text-decoration': {inherit: false, initial: 'none', values: {'none':'none', 'underline':'underline', 'overline':'overline', 'line-through':'line-through'}},
54
+ 'xml:space': {inherit: true, initial: 'default', css: 'white-space', values: {'preserve':'preserve', 'default':'default', 'pre':'preserve', 'pre-line':'preserve', 'pre-wrap':'preserve', 'nowrap': 'default'}},
55
+ 'marker-start': {inherit: true, initial: 'none'},
56
+ 'marker-mid': {inherit: true, initial: 'none'},
57
+ 'marker-end': {inherit: true, initial: 'none'},
58
+ 'opacity': {inherit: false, initial: 1},
59
+ 'transform': {inherit: false, initial: [1, 0, 0, 1, 0, 0]},
60
+ 'display': {inherit: false, initial: 'inline', values: {'none':'none', 'inline':'inline', 'block':'inline'}},
61
+ 'clip-path': {inherit: false, initial: 'none'},
62
+ 'mask': {inherit: false, initial: 'none'},
63
+ 'overflow': {inherit: false, initial: 'hidden', values: {'hidden':'hidden', 'scroll':'hidden', 'visible':'visible'}},
64
+ 'vector-effect': {inherit: true, initial: 'none', values: {'none':'none', 'non-scaling-stroke':'non-scaling-stroke'}}
65
+ };
66
+
67
+ function docBeginGroup(bbox) {
68
+ let group = new (function PDFGroup() {})();
69
+ group.name = 'G' + (doc._groupCount = (doc._groupCount || 0) + 1);
70
+ group.resources = doc.ref();
71
+ group.xobj = doc.ref({
72
+ Type: 'XObject',
73
+ Subtype: 'Form',
74
+ FormType: 1,
75
+ BBox: bbox,
76
+ Group: {S: 'Transparency', CS: 'DeviceRGB', I: true, K: false},
77
+ Resources: group.resources
78
+ });
79
+ group.xobj.write('');
80
+ group.savedMatrix = doc._ctm;
81
+ group.savedPage = doc.page;
82
+ groupStack.push(group);
83
+ doc._ctm = [1, 0, 0, 1, 0, 0];
84
+ doc.page = {
85
+ width: doc.page.width, height: doc.page.height,
86
+ write: function(data) {group.xobj.write(data);},
87
+ fonts: {}, xobjects: {}, ext_gstates: {}, patterns: {}
88
+ };
89
+ return group;
90
+ }
91
+ function docEndGroup(group) {
92
+ if (group !== groupStack.pop()) {throw('Group not matching');}
93
+ if (Object.keys(doc.page.fonts).length) {group.resources.data.Font = doc.page.fonts;}
94
+ if (Object.keys(doc.page.xobjects).length) {group.resources.data.XObject = doc.page.xobjects;}
95
+ if (Object.keys(doc.page.ext_gstates).length) {group.resources.data.ExtGState = doc.page.ext_gstates;}
96
+ if (Object.keys(doc.page.patterns).length) {group.resources.data.Pattern = doc.page.patterns;}
97
+ group.resources.end();
98
+ group.xobj.end();
99
+ doc._ctm = group.savedMatrix;
100
+ doc.page = group.savedPage;
101
+ }
102
+ function docInsertGroup(group) {
103
+ doc.page.xobjects[group.name] = group.xobj;
104
+ doc.addContent('/' + group.name + ' Do');
105
+ }
106
+ function docApplyMask(group, clip) {
107
+ let name = 'M' + (doc._maskCount = (doc._maskCount || 0) + 1);
108
+ let gstate = doc.ref({
109
+ Type: 'ExtGState', CA: 1, ca: 1, BM: 'Normal',
110
+ SMask: {S: 'Luminosity', G: group.xobj, BC: (clip ? [0, 0, 0] : [1, 1, 1])}
111
+ });
112
+ gstate.end();
113
+ doc.page.ext_gstates[name] = gstate;
114
+ doc.addContent('/' + name + ' gs');
115
+ }
116
+ function docCreatePattern(group, dx, dy, matrix) {
117
+ let pattern = {
118
+ type: 'PDFPattern',
119
+ group: group,
120
+ dx: dx,
121
+ dy: dy,
122
+ matrix: matrix || [1, 0, 0, 1, 0, 0],
123
+ }
124
+ return pattern;
125
+ }
126
+ function docUsePattern(pattern, stroke) {
127
+ let name = 'P' + (doc._patternCount = (doc._patternCount || 0) + 1);
128
+ let ref = doc.ref({
129
+ Type: 'Pattern', PatternType: 1, PaintType: 1, TilingType: 2,
130
+ BBox: [0, 0, pattern.dx, pattern.dy], XStep: pattern.dx, YStep: pattern.dy,
131
+ Matrix: multiplyMatrix(doc._ctm, pattern.matrix),
132
+ Resources: {
133
+ ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
134
+ XObject: (function() {let temp = {}; temp[pattern.group.name] = pattern.group.xobj; return temp;})()
135
+ }
136
+ });
137
+ ref.write('/' + pattern.group.name + ' Do');
138
+ ref.end();
139
+ doc.page.patterns[name] = ref;
140
+ if (stroke) {
141
+ doc.addContent('/Pattern CS');
142
+ doc.addContent('/' + name + ' SCN');
143
+ } else {
144
+ doc.addContent('/Pattern cs');
145
+ doc.addContent('/' + name + ' scn');
146
+ }
147
+ }
148
+ function docBeginText(font, size) {
149
+ if (!doc.page.fonts[font.id]) {doc.page.fonts[font.id] = font.ref();}
150
+ doc.addContent('BT').addContent('/' + font.id + ' ' + size + ' Tf');
151
+ }
152
+ function docSetTextMatrix(a, b, c, d, e, f) {
153
+ doc.addContent(validateNumber(a) + ' ' + validateNumber(b) + ' ' + validateNumber(-c) + ' ' + validateNumber(-d) + ' ' + validateNumber(e) + ' ' + validateNumber(f) + ' Tm');
154
+ }
155
+ function docSetTextMode(fill, stroke) {
156
+ let mode = fill && stroke ? 2 : stroke ? 1 : fill ? 0 : 3;
157
+ doc.addContent(mode + ' Tr');
158
+ }
159
+ function docWriteGlyphs(positions, font) {
160
+ let commands = [];
161
+ let commandStr = '';
162
+ const skew = font.fauxItalic ? -0.25 : 0;
163
+
164
+ // Add the given character to the 'TJ' command string.
165
+ function addChar(char) {
166
+ commandStr += char.glyph;
167
+ if (char.kern === 0) return;
168
+ commands.push(`<${commandStr}> ${validateNumber(char.kern)}`);
169
+ commandStr = '';
170
+ };
171
+
172
+ // Flush the current TJ command string to the output stream.
173
+ function flush() {
174
+ if (commandStr.length) {
175
+ commands.push(`<${commandStr}> 0`);
176
+ commandStr = '';
177
+ }
178
+ if (commands.length) {
179
+ doc.addContent(`[${commands.join(' ')}] TJ`);
180
+ commands = [];
181
+ }
182
+ };
183
+
184
+ for (let i = 0; i < positions.length; i++) {
185
+ const pos = positions[i];
186
+
187
+ if (pos.hidden || isEqual(pos.width, 0)) {
188
+ flush();
189
+ continue;
190
+ }
191
+
192
+ if (pos.continuous) {
193
+ addChar(pos);
194
+ continue;
195
+ }
196
+
197
+ // If this character is non-continuous, flush the command buffer.
198
+ flush();
199
+
200
+ // Start a new TJ command after writing a Text Matrix (Tm)
201
+ const cos = Math.cos(pos.rotate);
202
+ const sin = Math.sin(pos.rotate);
203
+ docSetTextMatrix(cos * pos.scale, sin * pos.scale, cos * skew - sin, sin * skew + cos, pos.x, pos.y);
204
+ addChar(pos);
205
+ };
206
+
207
+ // Flush any remaining characters in the buffer.
208
+ flush();
209
+ }
210
+ function docEndText() {
211
+ doc.addContent('ET');
212
+ }
213
+ function docFillColor(color) {
214
+ if (color[0].type === 'PDFPattern') {
215
+ doc.fillOpacity(color[1]);
216
+ docUsePattern(color[0], false);
217
+ } else {
218
+ doc.fillColor(color[0], color[1]);
219
+ }
220
+ }
221
+ function docStrokeColor(color) {
222
+ if (color[0].type === 'PDFPattern') {
223
+ doc.strokeOpacity(color[1]);
224
+ docUsePattern(color[0], true);
225
+ } else {
226
+ doc.strokeColor(color[0], color[1]);
227
+ }
228
+ }
229
+ // PDFKit doesn't accept any 0s in the dash array, but that's perfectly
230
+ // valid in SVG. So this function applys a dash array and offset, detecting
231
+ // any 0s in the dash array and updating it and the dash offset as needed to
232
+ // remove the zeros, but preserve the end result.
233
+ //
234
+ // `dashArray` must have an even number of elements
235
+ function docApplyDash(dashArray, dashOffset) {
236
+ let index;
237
+ // Anytime there's a 0 that isn't the first or last element of the array,
238
+ // we can remove it by combining the previous or next value. If it's a
239
+ // dash, then it's a zero-length dash between two spaces, so the dash can
240
+ // be eliminated and spaces combined by summing them, replacing all three
241
+ // values with the sum of the two spaces. If the 0 value is a space, then
242
+ // it's a zero-length space between two dashes, and the dashes can be
243
+ // similarly combined. So first we run that logic iteratively to remove
244
+ // all the 0s from the dash array that aren't the first or last element.
245
+ // Note that because we replace 3 values with one value, this doesn't
246
+ // change the even-ness of the length of dashArray.
247
+ while ((index = dashArray.slice(1, -1).indexOf(0)) !== -1) {
248
+ let actualIndex = index + 1;
249
+ let replacementValue = dashArray[actualIndex - 1] + dashArray[actualIndex + 1];
250
+ dashArray = dashArray
251
+ .slice(0, actualIndex - 1)
252
+ .concat([replacementValue])
253
+ .concat(dashArray.slice(actualIndex + 2));
254
+ }
255
+
256
+ // The stroke array only having two elements (a dash value and space
257
+ // value) is a special case.
258
+ if (dashArray.length === 2) {
259
+ if (dashArray[0] === 0) {
260
+ // Regardless of the space value, the dash length is zero, so we're
261
+ // not actually drawing a stroke. We can't describe that in a
262
+ // doc.dash() call in a way that PDFKit will accept, so we set the
263
+ // stroke opacity to zero as our best approximation.
264
+ doc.strokeOpacity(0);
265
+ return;
266
+ } else if (dashArray[1] === 0) {
267
+ // Regardless of the dash value, the space value is zero, meaning
268
+ // we're actually drawing a solid stroke, not a dashed one. We can
269
+ // make this happen by just emptying out the dash array.
270
+ dashArray = [];
271
+ }
272
+ } else {
273
+ if (dashArray[0] === 0) {
274
+ // The first dash is zero-length. We fix this by combining the first
275
+ // space (just after the first dash) with the last space and updating
276
+ // the dash offset accordingly. For example, if we had
277
+ //
278
+ // [ 0 4 3 2 5 1 ] (dash offset 0)
279
+ //
280
+ // ␣␣␣␣---␣␣-----␣
281
+ // ⎸
282
+ //
283
+ // we'd end up with
284
+ //
285
+ // [ 3 2 5 5 ] (dash offset -4)
286
+ //
287
+ // ---␣␣-----␣␣␣␣␣
288
+ // ⎸
289
+ //
290
+ // Another example where the dash array also ends with a 0:
291
+ //
292
+ // [ 0 4 3 2 5 0 ] (dash offset 0)
293
+ //
294
+ // ␣␣␣␣---␣␣-----
295
+ // ⎸
296
+ //
297
+ // we'd end up with
298
+ //
299
+ // [ 3 2 5 4 ] (dash offset -4)
300
+ //
301
+ // ---␣␣-----␣␣␣␣
302
+ // ⎸
303
+ dashOffset -= dashArray[1];
304
+ dashArray[dashArray.length - 1] += dashArray[1];
305
+ dashArray = dashArray.slice(2);
306
+ }
307
+ if (dashArray[dashArray.length - 1] === 0) {
308
+ // The last space is zero-length. We fix this by combining the last dash
309
+ // (just before the last space) with the first dash and updating the
310
+ // dash offset accordingly. For example, if we had
311
+ //
312
+ // [ 1 4 3 2 5 0 ] (dash offset 0)
313
+ //
314
+ // -␣␣␣␣---␣␣-----
315
+ // ⎸
316
+ //
317
+ // we'd end up with
318
+ //
319
+ // [ 6 4 3 2 ] (dash offset 5)
320
+ //
321
+ // ------␣␣␣␣---␣␣
322
+ // ⎸
323
+ //
324
+ dashOffset += dashArray[dashArray.length - 2];
325
+ dashArray[0] += dashArray[dashArray.length - 2];
326
+ dashArray = dashArray.slice(0, -2);
327
+ }
328
+ }
329
+
330
+ // Ensure the dash offset is non-negative (because of crbug.com/660850).
331
+ // First compute the total length of the dash array so we can add it to
332
+ // dash offset until dash offset is non-negative.
333
+ let length = 0;
334
+ for (let i = 0; i < dashArray.length; i++) {length += dashArray[i];}
335
+ if (length > 0) {
336
+ while (dashOffset < 0) {
337
+ dashOffset += length;
338
+ }
339
+ }
340
+
341
+ doc.dash(dashArray, {phase: dashOffset});
342
+ }
343
+ function docInsertLink(x, y, w, h, url) {
344
+ let ref = doc.ref({
345
+ Type: 'Annot',
346
+ Subtype: 'Link',
347
+ Rect: [x, y, w, h],
348
+ Border: [0, 0, 0],
349
+ A: {
350
+ S: 'URI',
351
+ URI: new String(url)
352
+ }
353
+ });
354
+ ref.end();
355
+ links.push(ref);
356
+ }
357
+ function parseXml(xml) {
358
+ let SvgNode = function(tag, type, value, error) {
359
+ this.error = error;
360
+ this.nodeName = tag;
361
+ this.nodeValue = value;
362
+ this.nodeType = type;
363
+ this.attributes = Object.create(null);
364
+ this.childNodes = [];
365
+ this.parentNode = null;
366
+ this.id = '';
367
+ this.textContent = '';
368
+ this.classList = [];
369
+ };
370
+ SvgNode.prototype.getAttribute = function(attr) {
371
+ return this.attributes[attr] != null ? this.attributes[attr] : null;
372
+ };
373
+ SvgNode.prototype.getElementById = function(id) {
374
+ let result = null;
375
+ (function recursive(node) {
376
+ if (result) {return;}
377
+ if (node.nodeType === 1) {
378
+ if (node.id === id) {result = node;}
379
+ for (let i = 0; i < node.childNodes.length; i++) {
380
+ recursive(node.childNodes[i]);
381
+ }
382
+ }
383
+ })(this);
384
+ return result;
385
+ };
386
+ SvgNode.prototype.getElementsByTagName = function(tag) {
387
+ let result = [];
388
+ (function recursive(node) {
389
+ if (node.nodeType === 1) {
390
+ if (node.nodeName === tag) {result.push(node);}
391
+ for (let i = 0; i < node.childNodes.length; i++) {
392
+ recursive(node.childNodes[i]);
393
+ }
394
+ }
395
+ })(this);
396
+ return result;
397
+ };
398
+ let parser = new StringParser(xml.trim()), result, child, error = false;
399
+ let recursive = function() {
400
+ let temp, child;
401
+ if (temp = parser.match(/^<([\w:.-]+)\s*/, true)) { // Opening tag
402
+ let node = new SvgNode(temp[1], 1, null, error);
403
+ while (temp = parser.match(/^([\w:.-]+)(?:\s*=\s*"([^"]*)"|\s*=\s*'([^']*)')?\s*/, true)) { // Attribute
404
+ let attr = temp[1], value = decodeEntities(temp[2] || temp[3] || '');
405
+ if (!node.attributes[attr]) {
406
+ node.attributes[attr] = value;
407
+ if (attr === 'id') {node.id = value;}
408
+ if (attr === 'class') {node.classList = value.split(' ');}
409
+ } else {
410
+ warningCallback('parseXml: duplicate attribute "' + attr + '"');
411
+ error = true;
412
+ }
413
+ }
414
+ if (parser.match(/^>/)) { // End of opening tag
415
+ while (child = recursive()) {
416
+ node.childNodes.push(child);
417
+ child.parentNode = node;
418
+ node.textContent += (child.nodeType === 3 || child.nodeType === 4 ? child.nodeValue : child.textContent);
419
+ }
420
+ if (temp = parser.match(/^<\/([\w:.-]+)\s*>/, true)) { // Closing tag
421
+ if (temp[1] === node.nodeName) {
422
+ return node;
423
+ } else {
424
+ warningCallback('parseXml: tag not matching, opening "' + node.nodeName + '" & closing "' + temp[1] + '"');
425
+ error = true;
426
+ return node;
427
+ }
428
+ } else {
429
+ warningCallback('parseXml: tag not matching, opening "' + node.nodeName + '" & not closing');
430
+ error = true;
431
+ return node;
432
+ }
433
+ } else if (parser.match(/^\/>/)) { // Self-closing tag
434
+ return node;
435
+ } else {
436
+ warningCallback('parseXml: tag could not be parsed "' + node.nodeName + '"');
437
+ error = true;
438
+ }
439
+ } else if (temp = parser.match(/^<!--[\s\S]*?-->/)) { // Comment
440
+ return new SvgNode(null, 8, temp, error);
441
+ } else if (temp = parser.match(/^<\?[\s\S]*?\?>/)) { // Processing instructions
442
+ return new SvgNode(null, 7, temp, error);
443
+ } else if (temp = parser.match(/^<!DOCTYPE\s*([\s\S]*?)>/)) { // Doctype
444
+ return new SvgNode(null, 10, temp, error);
445
+ } else if (temp = parser.match(/^<!\[CDATA\[([\s\S]*?)\]\]>/, true)) { // Cdata node
446
+ return new SvgNode('#cdata-section', 4, temp[1], error);
447
+ } else if (temp = parser.match(/^([^<]+)/, true)) { // Text node
448
+ return new SvgNode('#text', 3, decodeEntities(temp[1]), error);
449
+ }
450
+ };
451
+ while (child = recursive()) {
452
+ if (child.nodeType === 1 && !result) {
453
+ result = child;
454
+ } else if (child.nodeType === 1 || (child.nodeType === 3 && child.nodeValue.trim() !== '')) {
455
+ warningCallback('parseXml: data after document end has been discarded');
456
+ }
457
+ }
458
+ if (parser.matchAll()) {
459
+ warningCallback('parseXml: parsing error');
460
+ }
461
+ return result;
462
+ };
463
+ function decodeEntities(str) {
464
+ return(str.replace(/&(?:#([0-9]+)|#[xX]([0-9A-Fa-f]+)|([0-9A-Za-z]+));/g, function(mt, m0, m1, m2) {
465
+ if (m0) {return String.fromCharCode(parseInt(m0, 10));}
466
+ else if (m1) {return String.fromCharCode(parseInt(m1, 16));}
467
+ else if (m2 && Entities[m2]) {return String.fromCharCode(Entities[m2]);}
468
+ else {return mt;}
469
+ }));
470
+ }
471
+ function parseColor(raw) {
472
+ let temp, result;
473
+ raw = (raw || '').trim();
474
+ if (temp = NamedColors[raw]) {
475
+ result = [temp.slice(), 1];
476
+ } else if (temp = raw.match(/^cmyk\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
477
+ temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); temp[4] = parseFloat(temp[4]);
478
+ if (temp[1] <= 100 && temp[2] <= 100 && temp[3] <= 100 && temp[4] <= 100) {
479
+ result = [temp.slice(1, 5), 1];
480
+ }
481
+ } else if (temp = raw.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
482
+ temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); temp[4] = parseFloat(temp[4]);
483
+ if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256 && temp[4] <= 1) {
484
+ result = [temp.slice(1, 4), temp[4]];
485
+ }
486
+ } else if (temp = raw.match(/^rgb\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$/i)) {
487
+ temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]);
488
+ if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256) {
489
+ result = [temp.slice(1, 4), 1];
490
+ }
491
+ } else if (temp = raw.match(/^rgb\(\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/i)) {
492
+ temp[1] = 2.55 * parseFloat(temp[1]); temp[2] = 2.55 * parseFloat(temp[2]); temp[3] = 2.55 * parseFloat(temp[3]);
493
+ if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256) {
494
+ result = [temp.slice(1, 4), 1];
495
+ }
496
+ } else if (temp = raw.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i)) {
497
+ result = [[parseInt(temp[1], 16), parseInt(temp[2], 16), parseInt(temp[3], 16)], 1];
498
+ } else if (temp = raw.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i)) {
499
+ result = [[0x11 * parseInt(temp[1], 16), 0x11 * parseInt(temp[2], 16), 0x11 * parseInt(temp[3], 16)], 1];
500
+ }
501
+ return colorCallback ? colorCallback(result, raw) : result;
502
+ }
503
+ function opacityToColor(color, opacity, isMask) {
504
+ let newColor = color[0].slice(),
505
+ newOpacity = color[1] * opacity;
506
+ if (isMask) {
507
+ for (let i = 0; i < color.length; i++) {
508
+ newColor[i] *= newOpacity;
509
+ }
510
+ return [newColor, 1];
511
+ } else {
512
+ return [newColor, newOpacity];
513
+ }
514
+ }
515
+ function multiplyMatrix() {
516
+ function multiply(a, b) {
517
+ return [ a[0]*b[0]+a[2]*b[1], a[1]*b[0]+a[3]*b[1], a[0]*b[2]+a[2]*b[3],
518
+ a[1]*b[2]+a[3]*b[3], a[0]*b[4]+a[2]*b[5]+a[4], a[1]*b[4]+a[3]*b[5]+a[5] ];
519
+ }
520
+ let result = arguments[0];
521
+ for (let i = 1; i < arguments.length; i++) {
522
+ result = multiply(result, arguments[i]);
523
+ }
524
+ return result;
525
+ }
526
+ function transformPoint(p, m) {
527
+ return [m[0] * p[0] + m[2] * p[1] + m[4], m[1] * p[0] + m[3] * p[1] + m[5]];
528
+ }
529
+ function getGlobalMatrix() {
530
+ let ctm = doc._ctm;
531
+ for (let i = groupStack.length - 1; i >= 0; i--) {
532
+ ctm = multiplyMatrix(groupStack[i].savedMatrix, ctm);
533
+ }
534
+ return ctm;
535
+ }
536
+ function getPageBBox() {
537
+ return new SvgShape().M(0, 0).L(doc.page.width, 0).L(doc.page.width, doc.page.height).L(0, doc.page.height)
538
+ .transform(inverseMatrix(getGlobalMatrix())).getBoundingBox();
539
+ }
540
+ function getPageScale() {
541
+ const bbox = getPageBBox();
542
+ const width = doc.page.width;
543
+ return width / bbox[2];
544
+ }
545
+ function inverseMatrix(m) {
546
+ let dt = m[0] * m[3] - m[1] * m[2];
547
+ return [m[3] / dt, -m[1] / dt, -m[2] / dt, m[0] / dt, (m[2]*m[5] - m[3]*m[4]) / dt, (m[1]*m[4] - m[0]*m[5]) / dt];
548
+ }
549
+ function validateMatrix(m) {
550
+ let m0 = validateNumber(m[0]), m1 = validateNumber(m[1]), m2 = validateNumber(m[2]),
551
+ m3 = validateNumber(m[3]), m4 = validateNumber(m[4]), m5 = validateNumber(m[5]);
552
+ if (isNotEqual(m0 * m3 - m1 * m2, 0)) {
553
+ return [m0, m1, m2, m3, m4, m5];
554
+ }
555
+ }
556
+ function solveEquation(curve) {
557
+ let a = curve[2] || 0, b = curve[1] || 0, c = curve[0] || 0;
558
+ if (isEqual(a, 0) && isEqual(b, 0)) {
559
+ return [];
560
+ } else if (isEqual(a, 0)) {
561
+ return [(-c) / b];
562
+ } else {
563
+ let d = b * b - 4 * a * c;
564
+ if (isNotEqual(d, 0) && d > 0) {
565
+ return [(-b + Math.sqrt(d)) / (2 * a), (-b - Math.sqrt(d)) / (2 * a)];
566
+ } else if (isEqual(d, 0)) {
567
+ return [(-b) / (2 * a)];
568
+ } else {
569
+ return [];
570
+ }
571
+ }
572
+ }
573
+ function getCurveValue(t, curve) {
574
+ return (curve[0] || 0) + (curve[1] || 0) * t + (curve[2] || 0) * t * t + (curve[3] || 0) * t * t * t;
575
+ }
576
+ function isEqual(number, ref) {
577
+ return Math.abs(number - ref) < 1e-10;
578
+ }
579
+ function isNotEqual(number, ref) {
580
+ return Math.abs(number - ref) >= 1e-10;
581
+ }
582
+ function validateNumber(n) {
583
+ return n > -1e21 && n < 1e21 ? Math.round(n * 1e6) / 1e6 : 0;
584
+ }
585
+ function isArrayLike(v) {
586
+ return typeof v === 'object' && v !== null && typeof v.length === 'number';
587
+ }
588
+ function parseTranform(v) {
589
+ let parser = new StringParser((v || '').trim()), result = [1, 0, 0, 1, 0, 0], temp;
590
+ while (temp = parser.match(/^([A-Za-z]+)\s*[(]([^(]+)[)]/, true)) {
591
+ let func = temp[1], nums = [], parser2 = new StringParser(temp[2].trim()), temp2;
592
+ while (temp2 = parser2.matchNumber()) {
593
+ nums.push(Number(temp2));
594
+ parser2.matchSeparator();
595
+ }
596
+ if (func === 'matrix' && nums.length === 6) {
597
+ result = multiplyMatrix(result, [nums[0], nums[1], nums[2], nums[3], nums[4], nums[5]]);
598
+ } else if (func === 'translate' && nums.length === 2) {
599
+ result = multiplyMatrix(result, [1, 0, 0, 1, nums[0], nums[1]]);
600
+ } else if (func === 'translate' && nums.length === 1) {
601
+ result = multiplyMatrix(result, [1, 0, 0, 1, nums[0], 0]);
602
+ } else if (func === 'scale' && nums.length === 2) {
603
+ result = multiplyMatrix(result, [nums[0], 0, 0, nums[1], 0, 0]);
604
+ } else if (func === 'scale' && nums.length === 1) {
605
+ result = multiplyMatrix(result, [nums[0], 0, 0, nums[0], 0, 0]);
606
+ } else if (func === 'rotate' && nums.length === 3) {
607
+ let a = nums[0] * Math.PI / 180;
608
+ result = multiplyMatrix(result, [1, 0, 0, 1, nums[1], nums[2]], [Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0], [1, 0, 0, 1, -nums[1], -nums[2]]);
609
+ } else if (func === 'rotate' && nums.length === 1) {
610
+ let a = nums[0] * Math.PI / 180;
611
+ result = multiplyMatrix(result, [Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]);
612
+ } else if (func === 'skewX' && nums.length === 1) {
613
+ let a = nums[0] * Math.PI / 180;
614
+ result = multiplyMatrix(result, [1, 0, Math.tan(a), 1, 0, 0]);
615
+ } else if (func === 'skewY' && nums.length === 1) {
616
+ let a = nums[0] * Math.PI / 180;
617
+ result = multiplyMatrix(result, [1, Math.tan(a), 0, 1, 0, 0]);
618
+ } else {return;}
619
+ parser.matchSeparator();
620
+ }
621
+ if (parser.matchAll()) {return;}
622
+ return result;
623
+ }
624
+ function parseAspectRatio(aspectRatio, availWidth, availHeight, elemWidth, elemHeight, initAlign) {
625
+ let temp = (aspectRatio || '').trim().match(/^(none)$|^x(Min|Mid|Max)Y(Min|Mid|Max)(?:\s+(meet|slice))?$/) || [],
626
+ ratioType = temp[1] || temp[4] || 'meet',
627
+ xAlign = temp[2] || 'Mid',
628
+ yAlign = temp[3] || 'Mid',
629
+ scaleX = availWidth / elemWidth,
630
+ scaleY = availHeight / elemHeight,
631
+ dx = {'Min':0, 'Mid':0.5, 'Max':1}[xAlign] - (initAlign || 0),
632
+ dy = {'Min':0, 'Mid':0.5, 'Max':1}[yAlign] - (initAlign || 0);
633
+ if (ratioType === 'slice') {
634
+ scaleY = scaleX = Math.max(scaleX, scaleY);
635
+ } else if (ratioType === 'meet') {
636
+ scaleY = scaleX = Math.min(scaleX, scaleY);
637
+ }
638
+ return [scaleX, 0, 0, scaleY, dx * (availWidth - elemWidth * scaleX), dy * (availHeight - elemHeight * scaleY)];
639
+ }
640
+ function parseStyleAttr(v) {
641
+ let result = Object.create(null);
642
+ v = (v || '').trim().split(/;/);
643
+ for (let i = 0; i < v.length; i++) {
644
+ let key = (v[i].split(':')[0] || '').trim(),
645
+ value = (v[i].split(':')[1] || '').trim();
646
+ if (key) {
647
+ result[key] = value;
648
+ }
649
+ }
650
+ if (result['marker']) {
651
+ if (!result['marker-start']) {result['marker-start'] = result['marker'];}
652
+ if (!result['marker-mid']) {result['marker-mid'] = result['marker'];}
653
+ if (!result['marker-end']) {result['marker-end'] = result['marker'];}
654
+ }
655
+ if (result['font']) {
656
+ let fontFamily = null, fontSize = null, fontStyle = "normal", fontWeight = "normal", fontVariant = "normal";
657
+ let parts = result['font'].split(/\s+/);
658
+ for (let i = 0; i < parts.length; i++) {
659
+ switch (parts[i]) {
660
+ case "normal":
661
+ break;
662
+ case "italic": case "oblique":
663
+ fontStyle = parts[i];
664
+ break;
665
+ case "small-caps":
666
+ fontVariant = parts[i];
667
+ break;
668
+ case "bold": case "bolder": case "lighter": case "100": case "200": case "300":
669
+ case "400": case "500": case "600": case "700": case "800": case "900":
670
+ fontWeight = parts[i];
671
+ break;
672
+ default:
673
+ if (!fontSize) {
674
+ fontSize = parts[i].split('/')[0];
675
+ } else {
676
+ if (!fontFamily) {
677
+ fontFamily = parts[i];
678
+ } else {
679
+ fontFamily += ' ' + parts[i];
680
+ }
681
+ }
682
+ break;
683
+ }
684
+ }
685
+ if (!result['font-style']) {result['font-style'] = fontStyle;}
686
+ if (!result['font-variant']) {result['font-variant'] = fontVariant;}
687
+ if (!result['font-weight']) {result['font-weight'] = fontWeight;}
688
+ if (!result['font-size']) {result['font-size'] = fontSize;}
689
+ if (!result['font-family']) {result['font-family'] = fontFamily;}
690
+ }
691
+ return result;
692
+ }
693
+ function parseSelector(v) {
694
+ let parts = v.split(/(?=[.#])/g), ids = [], classes = [], tags = [], temp;
695
+ for (let i = 0; i < parts.length; i++) {
696
+ if (temp = parts[i].match(/^[#]([_A-Za-z0-9-]+)$/)) {
697
+ ids.push(temp[1]);
698
+ } else if (temp = parts[i].match(/^[.]([_A-Za-z0-9-]+)$/)) {
699
+ classes.push(temp[1]);
700
+ } else if (temp = parts[i].match(/^([_A-Za-z0-9-]+)$/)) {
701
+ tags.push(temp[1]);
702
+ } else if (parts[i] !== '*') {
703
+ return;
704
+ }
705
+ }
706
+ return {
707
+ tags: tags, ids: ids, classes: classes,
708
+ specificity: ids.length * 10000 + classes.length * 100 + tags.length
709
+ };
710
+ }
711
+ function parseStyleSheet(v) {
712
+ let parser = new StringParser(v.trim()), rules = [], rule;
713
+ while (rule = parser.match(/^\s*([^\{\}]*?)\s*\{([^\{\}]*?)\}/, true)) {
714
+ let selectors = rule[1].split(/\s*,\s*/g),
715
+ css = parseStyleAttr(rule[2]);
716
+ for (let i = 0; i < selectors.length; i++) {
717
+ let selector = parseSelector(selectors[i]);
718
+ if (selector) {
719
+ rules.push({selector: selector, css:css});
720
+ }
721
+ }
722
+ }
723
+ return rules;
724
+ }
725
+ function matchesSelector(elem, selector) {
726
+ if (elem.nodeType !== 1) {return false;}
727
+ for (let i = 0; i < selector.tags.length; i++) {
728
+ if (selector.tags[i] !== elem.nodeName) {return false;}
729
+ }
730
+ for (let i = 0; i < selector.ids.length; i++) {
731
+ if (selector.ids[i] !== elem.id) {return false;}
732
+ }
733
+ for (let i = 0; i < selector.classes.length; i++) {
734
+ if (elem.classList.indexOf(selector.classes[i]) === -1) {return false;}
735
+ }
736
+ return true;
737
+ }
738
+ function getStyle(elem) {
739
+ let result = Object.create(null);
740
+ let specificities = Object.create(null);
741
+ for (let i = 0; i < styleRules.length; i++) {
742
+ let rule = styleRules[i];
743
+ if (matchesSelector(elem, rule.selector)) {
744
+ for (let key in rule.css) {
745
+ if (!(specificities[key] > rule.selector.specificity)) {
746
+ result[key] = rule.css[key];
747
+ specificities[key] = rule.selector.specificity;
748
+ }
749
+ }
750
+ }
751
+ }
752
+ return result;
753
+ }
754
+ function combineArrays(array1, array2) {
755
+ return array1.concat(array2.slice(array1.length));
756
+ }
757
+ function getAscent(font, size) {
758
+ return Math.max(font.ascender, (font.bbox[3] || font.bbox.maxY) * (font.scale || 1)) * size / 1000;
759
+ }
760
+ function getDescent(font, size) {
761
+ return Math.min(font.descender, (font.bbox[1] || font.bbox.minY) * (font.scale || 1)) * size / 1000;
762
+ }
763
+ function getXHeight(font, size) {
764
+ return (font.xHeight || 0.5 * (font.ascender - font.descender)) * size / 1000;
765
+ }
766
+ function getBaseline(font, size, baseline, shift) {
767
+ let dy1, dy2;
768
+ switch (baseline) {
769
+ case 'middle': dy1 = 0.5 * getXHeight(font, size); break;
770
+ case 'central': dy1 = 0.5 * (getDescent(font, size) + getAscent(font, size)); break;
771
+ case 'after-edge': case 'text-after-edge': dy1 = getDescent(font, size); break;
772
+ case 'alphabetic': case 'auto': case 'baseline': dy1 = 0; break;
773
+ case 'mathematical': dy1 = 0.5 * getAscent(font, size); break;
774
+ case 'hanging': dy1 = 0.8 * getAscent(font, size); break;
775
+ case 'before-edge': case 'text-before-edge': dy1 = getAscent(font, size); break;
776
+ default: dy1 = 0; break;
777
+ }
778
+ switch (shift) {
779
+ case 'baseline': dy2 = 0; break;
780
+ case 'super': dy2 = 0.6 * size; break;
781
+ case 'sub': dy2 = -0.6 * size; break;
782
+ default: dy2 = shift; break;
783
+ }
784
+ return dy1 - dy2;
785
+ }
786
+ function getTextPos(font, size, text) {
787
+ let encoded = font.encode('' + text), hex = encoded[0], pos = encoded[1], data = [];
788
+ for (let i = 0; i < hex.length; i++) {
789
+ let unicode = font.unicode ? font.unicode[parseInt(hex[i], 16)] : [text.charCodeAt(i)];
790
+ data.push({
791
+ glyph: hex[i],
792
+ unicode: unicode,
793
+ kern: pos[i].advanceWidth - pos[i].xAdvance,
794
+ width: pos[i].advanceWidth * size / 1000,
795
+ xOffset: pos[i].xOffset * size / 1000,
796
+ yOffset: pos[i].yOffset * size / 1000,
797
+ xAdvance: pos[i].xAdvance * size / 1000,
798
+ yAdvance: pos[i].yAdvance * size / 1000
799
+ });
800
+ }
801
+ return data;
802
+ }
803
+ function createSVGElement(obj, inherits) {
804
+ switch (obj.nodeName) {
805
+ case 'use': return new SvgElemUse(obj, inherits);
806
+ case 'symbol': return new SvgElemSymbol(obj, inherits);
807
+ case 'g': return new SvgElemGroup(obj, inherits);
808
+ case 'a': return new SvgElemLink(obj, inherits);
809
+ case 'svg': return new SvgElemSvg(obj, inherits);
810
+ case 'image': return new SVGElemImage(obj, inherits);
811
+ case 'rect': return new SvgElemRect(obj, inherits);
812
+ case 'circle': return new SvgElemCircle(obj, inherits);
813
+ case 'ellipse': return new SvgElemEllipse(obj, inherits);
814
+ case 'line': return new SvgElemLine(obj, inherits);
815
+ case 'polyline': return new SvgElemPolyline(obj, inherits);
816
+ case 'polygon': return new SvgElemPolygon(obj, inherits);
817
+ case 'path': return new SvgElemPath(obj, inherits);
818
+ case 'text': return new SvgElemText(obj, inherits);
819
+ case 'tspan': return new SvgElemTspan(obj, inherits);
820
+ case 'textPath': return new SvgElemTextPath(obj, inherits);
821
+ case '#text': case '#cdata-section': return new SvgElemTextNode(obj, inherits);
822
+ default: return new SvgElem(obj, inherits);
823
+ }
824
+ }
825
+
826
+ var StringParser = function(str) {
827
+ this.match = function(exp, all) {
828
+ let temp = str.match(exp);
829
+ if (!temp || temp.index !== 0) {return;}
830
+ str = str.substring(temp[0].length);
831
+ return (all ? temp : temp[0]);
832
+ };
833
+ this.matchSeparator = function() {
834
+ return this.match(/^(?:\s*,\s*|\s*|)/);
835
+ };
836
+ this.matchSpace = function() {
837
+ return this.match(/^(?:\s*)/);
838
+ };
839
+ this.matchLengthUnit = function() {
840
+ return this.match(/^(?:px|pt|cm|mm|in|pc|em|ex|%|)/);
841
+ };
842
+ this.matchNumber = function() {
843
+ return this.match(/^(?:[-+]?(?:[0-9]+[.][0-9]+|[0-9]+[.]|[.][0-9]+|[0-9]+)(?:[eE][-+]?[0-9]+)?)/);
844
+ };
845
+ this.matchAll = function() {
846
+ return this.match(/^[\s\S]+/);
847
+ };
848
+ };
849
+
850
+ var BezierSegment = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
851
+ let divisions = 6 * precision;
852
+ let equationX = [p1x, -3 * p1x + 3 * c1x, 3 * p1x - 6 * c1x + 3 * c2x, -p1x + 3 * c1x - 3 * c2x + p2x];
853
+ let equationY = [p1y, -3 * p1y + 3 * c1y, 3 * p1y - 6 * c1y + 3 * c2y, -p1y + 3 * c1y - 3 * c2y + p2y];
854
+ let derivativeX = [-3 * p1x + 3 * c1x, 6 * p1x - 12 * c1x + 6 * c2x, -3 * p1x + 9 * c1x - 9 * c2x + 3 * p2x];
855
+ let derivativeY = [-3 * p1y + 3 * c1y, 6 * p1y - 12 * c1y + 6 * c2y, -3 * p1y + 9 * c1y - 9 * c2y + 3 * p2y];
856
+ let lengthMap = [0];
857
+ for (let i = 1; i <= divisions; i++) {
858
+ let t = (i - 0.5) / divisions;
859
+ let dx = getCurveValue(t, derivativeX) / divisions,
860
+ dy = getCurveValue(t, derivativeY) / divisions,
861
+ l = Math.sqrt(dx * dx + dy * dy);
862
+ lengthMap[i] = lengthMap[i - 1] + l;
863
+ }
864
+ this.totalLength = lengthMap[divisions];
865
+ this.startPoint = [p1x, p1y, isEqual(p1x, c1x) && isEqual(p1y, c1y) ? Math.atan2(c2y - c1y, c2x - c1x) : Math.atan2(c1y - p1y, c1x - p1x)];
866
+ this.endPoint = [p2x, p2y, isEqual(c2x, p2x) && isEqual(c2y, p2y) ? Math.atan2(c2y - c1y, c2x - c1x) : Math.atan2(p2y - c2y, p2x - c2x)];
867
+ this.getBoundingBox = function() {
868
+ let temp;
869
+ let minX = getCurveValue(0, equationX), minY = getCurveValue(0, equationY),
870
+ maxX = getCurveValue(1, equationX), maxY = getCurveValue(1, equationY);
871
+ if (minX > maxX) {temp = maxX; maxX = minX; minX = temp;}
872
+ if (minY > maxY) {temp = maxY; maxY = minY; minY = temp;}
873
+ let rootsX = solveEquation(derivativeX);
874
+ for (let i = 0; i < rootsX.length; i++) {
875
+ if (rootsX[i] >= 0 && rootsX[i] <= 1) {
876
+ let x = getCurveValue(rootsX[i], equationX);
877
+ if (x < minX) {minX = x;}
878
+ if (x > maxX) {maxX = x;}
879
+ }
880
+ }
881
+ let rootsY = solveEquation(derivativeY);
882
+ for (let i = 0; i < rootsY.length; i++) {
883
+ if (rootsY[i] >= 0 && rootsY[i] <= 1) {
884
+ let y = getCurveValue(rootsY[i], equationY);
885
+ if (y < minY) {minY = y;}
886
+ if (y > maxY) {maxY = y;}
887
+ }
888
+ }
889
+ return [minX, minY, maxX, maxY];
890
+ };
891
+ this.getPointAtLength = function(l) {
892
+ if (isEqual(l, 0)) {return this.startPoint;}
893
+ if (isEqual(l, this.totalLength)) {return this.endPoint;}
894
+ if (l < 0 || l > this.totalLength) {return;}
895
+ for (let i = 1; i <= divisions; i++) {
896
+ let l1 = lengthMap[i-1], l2 = lengthMap[i];
897
+ if (l1 <= l && l <= l2) {
898
+ let t = (i - (l2 - l) / (l2 - l1)) / divisions,
899
+ x = getCurveValue(t, equationX), y = getCurveValue(t, equationY),
900
+ dx = getCurveValue(t, derivativeX), dy = getCurveValue(t, derivativeY);
901
+ return [x, y, Math.atan2(dy, dx)];
902
+ }
903
+ }
904
+ };
905
+ };
906
+
907
+ var LineSegment = function(p1x, p1y, p2x, p2y) {
908
+ this.totalLength = Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
909
+ this.startPoint = [p1x, p1y, Math.atan2(p2y - p1y, p2x - p1x)];
910
+ this.endPoint = [p2x, p2y, Math.atan2(p2y - p1y, p2x - p1x)];
911
+ this.getBoundingBox = function() {
912
+ return [Math.min(this.startPoint[0], this.endPoint[0]), Math.min(this.startPoint[1], this.endPoint[1]),
913
+ Math.max(this.startPoint[0], this.endPoint[0]), Math.max(this.startPoint[1], this.endPoint[1])];
914
+ };
915
+ this.getPointAtLength = function(l) {
916
+ if (l >= 0 && l <= this.totalLength) {
917
+ let r = l / this.totalLength || 0,
918
+ x = this.startPoint[0] + r * (this.endPoint[0] - this.startPoint[0]),
919
+ y = this.startPoint[1] + r * (this.endPoint[1] - this.startPoint[1]);
920
+ return [x, y, this.startPoint[2]];
921
+ }
922
+ };
923
+ };
924
+
925
+ var SvgShape = function() {
926
+ this.pathCommands = [];
927
+ this.pathSegments = [];
928
+ this.startPoint = null;
929
+ this.endPoint = null;
930
+ this.totalLength = 0;
931
+ let startX = 0, startY = 0, currX = 0, currY = 0, lastCom, lastCtrlX, lastCtrlY;
932
+ this.move = function(x, y) {
933
+ startX = currX = x; startY = currY = y;
934
+ return null;
935
+ };
936
+ this.line = function(x, y) {
937
+ let segment = new LineSegment(currX, currY, x, y);
938
+ currX = x; currY = y;
939
+ return segment;
940
+ };
941
+ this.curve = function(c1x, c1y, c2x, c2y, x, y) {
942
+ let segment = new BezierSegment(currX, currY, c1x, c1y, c2x, c2y, x, y);
943
+ currX = x; currY = y;
944
+ return segment;
945
+ };
946
+ this.close = function() {
947
+ let segment = new LineSegment(currX, currY, startX, startY);
948
+ currX = startX; currY = startY;
949
+ return segment;
950
+ };
951
+ this.addCommand = function(data) {
952
+ this.pathCommands.push(data);
953
+ let segment = this[data[0]].apply(this, data.slice(3));
954
+ if (segment) {
955
+ segment.hasStart = data[1];
956
+ segment.hasEnd = data[2];
957
+ this.startPoint = this.startPoint || segment.startPoint;
958
+ this.endPoint = segment.endPoint;
959
+ this.pathSegments.push(segment);
960
+ this.totalLength += segment.totalLength;
961
+ }
962
+ };
963
+ this.M = function(x, y) {
964
+ this.addCommand(['move', true, true, x, y]);
965
+ lastCom = 'M';
966
+ return this;
967
+ };
968
+ this.m = function(x, y) {
969
+ return this.M(currX + x, currY + y);
970
+ };
971
+ this.Z = this.z = function() {
972
+ this.addCommand(['close', true, true]);
973
+ lastCom = 'Z';
974
+ return this;
975
+ };
976
+ this.L = function(x, y) {
977
+ this.addCommand(['line', true, true, x, y]);
978
+ lastCom = 'L';
979
+ return this;
980
+ };
981
+ this.l = function(x, y) {
982
+ return this.L(currX + x, currY + y);
983
+ };
984
+ this.H = function(x) {
985
+ return this.L(x, currY);
986
+ };
987
+ this.h = function(x) {
988
+ return this.L(currX + x, currY);
989
+ };
990
+ this.V = function(y) {
991
+ return this.L(currX, y);
992
+ };
993
+ this.v = function(y) {
994
+ return this.L(currX, currY + y);
995
+ };
996
+ this.C = function(c1x, c1y, c2x, c2y, x, y) {
997
+ this.addCommand(['curve', true, true, c1x, c1y, c2x, c2y, x, y]);
998
+ lastCom = 'C'; lastCtrlX = c2x; lastCtrlY = c2y;
999
+ return this;
1000
+ };
1001
+ this.c = function(c1x, c1y, c2x, c2y, x, y) {
1002
+ return this.C(currX + c1x, currY + c1y, currX + c2x, currY + c2y, currX + x, currY + y);
1003
+ };
1004
+ this.S = function(c1x, c1y, x, y) {
1005
+ return this.C(currX + (lastCom === 'C' ? currX - lastCtrlX : 0), currY + (lastCom === 'C' ? currY - lastCtrlY : 0), c1x, c1y, x, y);
1006
+ };
1007
+ this.s = function(c1x, c1y, x, y) {
1008
+ return this.C(currX + (lastCom === 'C' ? currX - lastCtrlX : 0), currY + (lastCom === 'C' ? currY - lastCtrlY : 0), currX + c1x, currY + c1y, currX + x, currY + y);
1009
+ };
1010
+ this.Q = function(cx, cy, x, y) {
1011
+ let c1x = currX + 2 / 3 * (cx - currX), c1y = currY + 2 / 3 * (cy - currY),
1012
+ c2x = x + 2 / 3 * (cx - x), c2y = y + 2 / 3 * (cy - y);
1013
+ this.addCommand(['curve', true, true, c1x, c1y, c2x, c2y, x, y]);
1014
+ lastCom = 'Q'; lastCtrlX = cx; lastCtrlY = cy;
1015
+ return this;
1016
+ };
1017
+ this.q = function(c1x, c1y, x, y) {
1018
+ return this.Q(currX + c1x, currY + c1y, currX + x, currY + y);
1019
+ };
1020
+ this.T = function(x, y) {
1021
+ return this.Q(currX + (lastCom === 'Q' ? currX - lastCtrlX : 0), currY + (lastCom === 'Q' ? currY - lastCtrlY : 0), x, y);
1022
+ };
1023
+ this.t = function(x, y) {
1024
+ return this.Q(currX + (lastCom === 'Q' ? currX - lastCtrlX : 0), currY + (lastCom === 'Q' ? currY - lastCtrlY : 0), currX + x, currY + y);
1025
+ };
1026
+ this.A = function(rx, ry, fi, fa, fs, x, y) {
1027
+ if (isEqual(rx, 0) || isEqual(ry, 0)) {
1028
+ this.addCommand(['line', true, true, x, y]);
1029
+ } else {
1030
+ fi = fi * (Math.PI / 180);
1031
+ rx = Math.abs(rx);
1032
+ ry = Math.abs(ry);
1033
+ fa = 1 * !!fa;
1034
+ fs = 1 * !!fs;
1035
+ let x1 = Math.cos(fi) * (currX - x) / 2 + Math.sin(fi) * (currY - y) / 2,
1036
+ y1 = Math.cos(fi) * (currY - y) / 2 - Math.sin(fi) * (currX - x) / 2,
1037
+ lambda = (x1 * x1) / (rx * rx) + (y1 * y1) / (ry * ry);
1038
+ if (lambda > 1) {
1039
+ rx *= Math.sqrt(lambda);
1040
+ ry *= Math.sqrt(lambda);
1041
+ }
1042
+ let r = Math.sqrt(Math.max(0, rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) / (rx * rx * y1 * y1 + ry * ry * x1 * x1)),
1043
+ x2 = (fa === fs ? -1 : 1) * r * rx * y1 / ry,
1044
+ y2 = (fa === fs ? 1 : -1) * r * ry * x1 / rx;
1045
+ let cx = Math.cos(fi) * x2 - Math.sin(fi) * y2 + (currX + x) / 2,
1046
+ cy = Math.sin(fi) * x2 + Math.cos(fi) * y2 + (currY + y) / 2,
1047
+ th1 = Math.atan2((y1 - y2) / ry, (x1 - x2) / rx),
1048
+ th2 = Math.atan2((-y1 - y2) / ry, (-x1 - x2) / rx);
1049
+ if (fs === 0 && th2 - th1 > 0) {
1050
+ th2 -= 2 * Math.PI;
1051
+ } else if (fs === 1 && th2 - th1 < 0) {
1052
+ th2 += 2 * Math.PI;
1053
+ }
1054
+ let segms = Math.ceil(Math.abs(th2 - th1) / (Math.PI / precision));
1055
+ for (let i = 0; i < segms; i++) {
1056
+ let th3 = th1 + i * (th2 - th1) / segms,
1057
+ th4 = th1 + (i + 1) * (th2 - th1) / segms,
1058
+ t = 4/3 * Math.tan((th4 - th3) / 4);
1059
+ let c1x = cx + Math.cos(fi) * rx * (Math.cos(th3) - t * Math.sin(th3)) - Math.sin(fi) * ry * (Math.sin(th3) + t * Math.cos(th3)),
1060
+ c1y = cy + Math.sin(fi) * rx * (Math.cos(th3) - t * Math.sin(th3)) + Math.cos(fi) * ry * (Math.sin(th3) + t * Math.cos(th3)),
1061
+ c2x = cx + Math.cos(fi) * rx * (Math.cos(th4) + t * Math.sin(th4)) - Math.sin(fi) * ry * (Math.sin(th4) - t * Math.cos(th4)),
1062
+ c2y = cy + Math.sin(fi) * rx * (Math.cos(th4) + t * Math.sin(th4)) + Math.cos(fi) * ry * (Math.sin(th4) - t * Math.cos(th4)),
1063
+ endX = cx + Math.cos(fi) * rx * Math.cos(th4) - Math.sin(fi) * ry * Math.sin(th4),
1064
+ endY = cy + Math.sin(fi) * rx * Math.cos(th4) + Math.cos(fi) * ry * Math.sin(th4);
1065
+ this.addCommand(['curve', (i === 0), (i === segms - 1), c1x, c1y, c2x, c2y, endX, endY]);
1066
+ }
1067
+ }
1068
+ lastCom = 'A';
1069
+ return this;
1070
+ };
1071
+ this.a = function(rx, ry, fi, fa, fs, x, y) {
1072
+ return this.A(rx, ry, fi, fa, fs, currX + x, currY + y);
1073
+ };
1074
+ this.path = function(d) {
1075
+ let command, value, temp,
1076
+ parser = new StringParser((d || '').trim());
1077
+ while (command = parser.match(/^[astvzqmhlcASTVZQMHLC]/)) {
1078
+ parser.matchSeparator();
1079
+ let values = [];
1080
+ while (value = (PathFlags[command + values.length] ? parser.match(/^[01]/) : parser.matchNumber())) {
1081
+ parser.matchSeparator();
1082
+ if (values.length === PathArguments[command]) {
1083
+ this[command].apply(this, values);
1084
+ values = [];
1085
+ if (command === 'M') {command = 'L';}
1086
+ else if (command === 'm') {command = 'l';}
1087
+ }
1088
+ values.push(Number(value));
1089
+ }
1090
+ if (values.length === PathArguments[command]) {
1091
+ this[command].apply(this, values);
1092
+ } else {
1093
+ warningCallback('SvgPath: command ' + command + ' with ' + values.length + ' numbers'); return;
1094
+ }
1095
+ }
1096
+ if (temp = parser.matchAll()) {
1097
+ warningCallback('SvgPath: unexpected string ' + temp);
1098
+ }
1099
+ return this;
1100
+ };
1101
+ this.getBoundingBox = function() {
1102
+ let bbox = [Infinity, Infinity, -Infinity, -Infinity];
1103
+ function addBounds(bbox1) {
1104
+ if (bbox1[0] < bbox[0]) {bbox[0] = bbox1[0];}
1105
+ if (bbox1[2] > bbox[2]) {bbox[2] = bbox1[2];}
1106
+ if (bbox1[1] < bbox[1]) {bbox[1] = bbox1[1];}
1107
+ if (bbox1[3] > bbox[3]) {bbox[3] = bbox1[3];}
1108
+ }
1109
+ for (let i = 0; i < this.pathSegments.length; i++) {
1110
+ addBounds(this.pathSegments[i].getBoundingBox());
1111
+ }
1112
+ if (bbox[0] === Infinity) {bbox[0] = 0;}
1113
+ if (bbox[1] === Infinity) {bbox[1] = 0;}
1114
+ if (bbox[2] === -Infinity) {bbox[2] = 0;}
1115
+ if (bbox[3] === -Infinity) {bbox[3] = 0;}
1116
+ return bbox;
1117
+ };
1118
+ this.getPointAtLength = function(l) {
1119
+ if (l >= 0 && l <= this.totalLength) {
1120
+ let temp;
1121
+ for (let i = 0; i < this.pathSegments.length; i++) {
1122
+ if (temp = this.pathSegments[i].getPointAtLength(l)) {
1123
+ return temp;
1124
+ }
1125
+ l -= this.pathSegments[i].totalLength;
1126
+ }
1127
+ return this.endPoint;
1128
+ }
1129
+ };
1130
+ this.transform = function(m) {
1131
+ this.pathSegments = [];
1132
+ this.startPoint = null;
1133
+ this.endPoint = null;
1134
+ this.totalLength = 0;
1135
+ for (let i = 0; i < this.pathCommands.length; i++) {
1136
+ let data = this.pathCommands.shift();
1137
+ for (let j = 3; j < data.length; j+=2) {
1138
+ let p = transformPoint([data[j], data[j + 1]], m)
1139
+ data[j] = p[0];
1140
+ data[j + 1] = p[1];
1141
+ }
1142
+ this.addCommand(data);
1143
+ }
1144
+ return this;
1145
+ };
1146
+ this.mergeShape = function(shape) {
1147
+ for (let i = 0; i < shape.pathCommands.length; i++) {
1148
+ this.addCommand(shape.pathCommands[i].slice());
1149
+ }
1150
+ return this;
1151
+ };
1152
+ this.clone = function() {
1153
+ return new SvgShape().mergeShape(this);
1154
+ };
1155
+ this.insertInDocument = function() {
1156
+ for (let i = 0; i < this.pathCommands.length; i++) {
1157
+ let command = this.pathCommands[i][0], values = this.pathCommands[i].slice(3);
1158
+ switch(command) {
1159
+ case 'move': doc.moveTo(values[0], values[1]); break;
1160
+ case 'line': doc.lineTo(values[0], values[1]); break;
1161
+ case 'curve': doc.bezierCurveTo(values[0], values[1], values[2], values[3], values[4], values[5]); break;
1162
+ case 'close': doc.closePath(); break;
1163
+ }
1164
+ }
1165
+ };
1166
+ this.getSubPaths = function() {
1167
+ let subPaths = [], shape = new SvgShape();
1168
+ for (let i = 0; i < this.pathCommands.length; i++) {
1169
+ let data = this.pathCommands[i], command = this.pathCommands[i][0];
1170
+ if (command === 'move' && i !== 0) {
1171
+ subPaths.push(shape);
1172
+ shape = new SvgShape();
1173
+ }
1174
+ shape.addCommand(data);
1175
+ }
1176
+ subPaths.push(shape);
1177
+ return subPaths;
1178
+ };
1179
+ this.getMarkers = function() {
1180
+ let markers = [], subPaths = this.getSubPaths();
1181
+ for (let i = 0; i < subPaths.length; i++) {
1182
+ let subPath = subPaths[i], subPathMarkers = [];
1183
+ for (let j = 0; j < subPath.pathSegments.length; j++) {
1184
+ let segment = subPath.pathSegments[j];
1185
+ if (isNotEqual(segment.totalLength, 0) || j === 0 || j === subPath.pathSegments.length - 1) {
1186
+ if (segment.hasStart) {
1187
+ let startMarker = segment.getPointAtLength(0), prevEndMarker = subPathMarkers.pop();
1188
+ if (prevEndMarker) {startMarker[2] = 0.5 * (prevEndMarker[2] + startMarker[2]);}
1189
+ subPathMarkers.push(startMarker);
1190
+ }
1191
+ if (segment.hasEnd) {
1192
+ let endMarker = segment.getPointAtLength(segment.totalLength);
1193
+ subPathMarkers.push(endMarker);
1194
+ }
1195
+ }
1196
+ }
1197
+ markers = markers.concat(subPathMarkers);
1198
+ }
1199
+ return markers;
1200
+ };
1201
+ };
1202
+
1203
+ var SvgElem = function(obj, inherits) {
1204
+ let styleCache = Object.create(null);
1205
+ let childrenCache = null;
1206
+ this.name = obj.nodeName;
1207
+ this.isOuterElement = obj === svg || !obj.parentNode;
1208
+ this.inherits = inherits || (!this.isOuterElement ? createSVGElement(obj.parentNode, null) : null);
1209
+ this.stack = (this.inherits ? this.inherits.stack.concat(obj) : [obj]);
1210
+ this.style = parseStyleAttr(typeof obj.getAttribute === 'function' && obj.getAttribute('style'));
1211
+ this.css = useCSS ? getComputedStyle(obj) : getStyle(obj);
1212
+ this.allowedChildren = [];
1213
+ this.attr = function(key) {
1214
+ if (typeof obj.getAttribute === 'function') {
1215
+ return obj.getAttribute(key);
1216
+ }
1217
+ };
1218
+ this.resolveUrl = function(value) {
1219
+ let temp = (value || '').match(/^\s*(?:url\("(.*)#(.*)"\)|url\('(.*)#(.*)'\)|url\((.*)#(.*)\)|(.*)#(.*))\s*$/) || [];
1220
+ let file = temp[1] || temp[3] || temp[5] || temp[7],
1221
+ id = temp[2] || temp[4] || temp[6] || temp[8];
1222
+ if (id) {
1223
+ if (!file) {
1224
+ let svgObj = svg.getElementById(id);
1225
+ if (svgObj) {
1226
+ if (this.stack.indexOf(svgObj) === -1) {
1227
+ return svgObj;
1228
+ } else {
1229
+ warningCallback('SVGtoPDF: loop of circular references for id "' + id + '"');
1230
+ return;
1231
+ }
1232
+ }
1233
+ }
1234
+ if (documentCallback) {
1235
+ let svgs = documentCache[file];
1236
+ if (!svgs) {
1237
+ svgs = documentCallback(file);
1238
+ if (!isArrayLike(svgs)) {svgs = [svgs];}
1239
+ for (let i = 0; i < svgs.length; i++) {
1240
+ if (typeof svgs[i] === 'string') {svgs[i] = parseXml(svgs[i]);}
1241
+ }
1242
+ documentCache[file] = svgs;
1243
+ }
1244
+ for (let i = 0; i < svgs.length; i++) {
1245
+ let svgObj = svgs[i].getElementById(id);
1246
+ if (svgObj) {
1247
+ if (this.stack.indexOf(svgObj) === -1) {
1248
+ return svgObj;
1249
+ } else {
1250
+ warningCallback('SVGtoPDF: loop of circular references for id "' + file + '#' + id + '"');
1251
+ return;
1252
+ }
1253
+ }
1254
+ }
1255
+ }
1256
+ }
1257
+ };
1258
+ this.computeUnits = function(value, unit, percent, isFontSize) {
1259
+ if (unit === '%') {
1260
+ return parseFloat(value) / 100 * (isFontSize || percent != null ? percent : this.getViewport());
1261
+ } else if (unit === 'ex' || unit === 'em') {
1262
+ return value * {'em':1, 'ex':0.5}[unit] * (isFontSize ? percent : this.get('font-size'));
1263
+ } else {
1264
+ return value * {'':1, 'px':1, 'pt':96/72, 'cm':96/2.54, 'mm':96/25.4, 'in':96, 'pc':96/6}[unit];
1265
+ }
1266
+ };
1267
+ this.computeLength = function(value, percent, initial, isFontSize) {
1268
+ let parser = new StringParser((value || '').trim()), temp1, temp2;
1269
+ if (typeof (temp1 = parser.matchNumber()) === 'string' && typeof (temp2 = parser.matchLengthUnit()) === 'string' && !parser.matchAll()) {
1270
+ return this.computeUnits(temp1, temp2, percent, isFontSize);
1271
+ }
1272
+ return initial;
1273
+ };
1274
+ this.computeLengthList = function(value, percent, strict) {
1275
+ let parser = new StringParser((value || '').trim()), result = [], temp1, temp2;
1276
+ while (typeof (temp1 = parser.matchNumber()) === 'string' && typeof (temp2 = parser.matchLengthUnit()) === 'string') {
1277
+ result.push(this.computeUnits(temp1, temp2, percent));
1278
+ parser.matchSeparator();
1279
+ }
1280
+ if (strict && parser.matchAll()) {return;}
1281
+ return result;
1282
+ };
1283
+ this.getLength = function(key, percent, initial) {
1284
+ return this.computeLength(this.attr(key), percent, initial);
1285
+ };
1286
+ this.getLengthList = function(key, percent) {
1287
+ return this.computeLengthList(this.attr(key), percent);
1288
+ };
1289
+ this.getUrl = function(key) {
1290
+ return this.resolveUrl(this.attr(key))
1291
+ };
1292
+ this.getNumberList = function(key) {
1293
+ let parser = new StringParser((this.attr(key) || '').trim()), result = [], temp;
1294
+ while (temp = parser.matchNumber()) {
1295
+ result.push(Number(temp));
1296
+ parser.matchSeparator();
1297
+ }
1298
+ result.error = parser.matchAll();
1299
+ return result;
1300
+ }
1301
+ this.getViewbox = function(key, initial) {
1302
+ let viewBox = this.getNumberList(key);
1303
+ if (viewBox.length === 4 && viewBox[2] >= 0 && viewBox[3] >= 0) {return viewBox;}
1304
+ return initial;
1305
+ };
1306
+ this.getPercent = function(key, initial) {
1307
+ let value = this.attr(key);
1308
+ let parser = new StringParser((value || '').trim()), temp1, temp2;
1309
+ let number = parser.matchNumber();
1310
+ if (!number) {return initial;}
1311
+ if (parser.match('%')) {number *= 0.01;}
1312
+ if (parser.matchAll()) {return initial;}
1313
+ return Math.max(0, Math.min(1, number));
1314
+ };
1315
+ this.chooseValue = function(args) {
1316
+ for (let i = 0; i < arguments.length; i++) {
1317
+ if (arguments[i] != null && arguments[i] === arguments[i]) {return arguments[i];}
1318
+ }
1319
+ return arguments[arguments.length - 1];
1320
+ };
1321
+ this.get = function(key) {
1322
+ if (styleCache[key] !== undefined) {return styleCache[key];}
1323
+ let keyInfo = Properties[key] || {}, value, result;
1324
+ for (let i = 0; i < 3; i++) {
1325
+ switch (i) {
1326
+ case 0:
1327
+ if (key !== 'transform') { // the CSS transform behaves strangely
1328
+ value = this.css[keyInfo.css || key];
1329
+ }
1330
+ break;
1331
+ case 1:
1332
+ value = this.style[key];
1333
+ break;
1334
+ case 2:
1335
+ value = this.attr(key);
1336
+ break;
1337
+ }
1338
+ if (value === 'inherit') {
1339
+ result = (this.inherits ? this.inherits.get(key) : keyInfo.initial);
1340
+ if (result != null) {return styleCache[key] = result;}
1341
+ }
1342
+ if (keyInfo.values != null) {
1343
+ result = keyInfo.values[value];
1344
+ if (result != null) {return styleCache[key] = result;}
1345
+ }
1346
+ if (value != null) {
1347
+ let parsed;
1348
+ switch (key) {
1349
+ case 'font-size':
1350
+ result = this.computeLength(value, this.inherits ? this.inherits.get(key) : keyInfo.initial, undefined, true);
1351
+ break;
1352
+ case 'baseline-shift':
1353
+ result = this.computeLength(value, this.get('font-size'));
1354
+ break;
1355
+ case 'font-family':
1356
+ result = value || undefined;
1357
+ break;
1358
+ case 'opacity': case 'stroke-opacity': case 'fill-opacity': case 'stop-opacity':
1359
+ parsed = parseFloat(value);
1360
+ if (!isNaN(parsed)) {
1361
+ result = Math.max(0, Math.min(1, parsed));
1362
+ }
1363
+ break;
1364
+ case 'transform':
1365
+ result = parseTranform(value);
1366
+ break;
1367
+ case 'stroke-dasharray':
1368
+ if (value === 'none') {
1369
+ result = [];
1370
+ } else if (parsed = this.computeLengthList(value, this.getViewport(), true)) {
1371
+ let sum = 0, error = false;
1372
+ for (let j = 0; j < parsed.length; j++) {
1373
+ if (parsed[j] < 0) {error = true;}
1374
+ sum += parsed[j];
1375
+ }
1376
+ if (!error) {
1377
+ if (parsed.length % 2 === 1) {
1378
+ parsed = parsed.concat(parsed);
1379
+ }
1380
+ result = (sum === 0 ? [] : parsed);
1381
+ }
1382
+ }
1383
+ break;
1384
+ case 'color':
1385
+ if (value === 'none' || value === 'transparent') {
1386
+ result = 'none';
1387
+ } else {
1388
+ result = parseColor(value);
1389
+ }
1390
+ break;
1391
+ case 'fill': case 'stroke':
1392
+ if (value === 'none' || value === 'transparent') {
1393
+ result = 'none';
1394
+ } else if (value === 'currentColor') {
1395
+ result = this.get('color');
1396
+ } else if (parsed = parseColor(value)) {
1397
+ return parsed;
1398
+ } else if (parsed = (value || '').split(' ')) {
1399
+ let object = this.resolveUrl(parsed[0]),
1400
+ fallbackColor = parseColor(parsed[1]);
1401
+ if (object == null) {
1402
+ result = fallbackColor;
1403
+ } else if (object.nodeName === 'linearGradient' || object.nodeName === 'radialGradient') {
1404
+ result = new SvgElemGradient(object, null, fallbackColor);
1405
+ } else if (object.nodeName === 'pattern') {
1406
+ result = new SvgElemPattern(object, null, fallbackColor);
1407
+ } else {
1408
+ result = fallbackColor;
1409
+ }
1410
+ }
1411
+ break;
1412
+ case 'stop-color':
1413
+ if (value === 'none' || value === 'transparent') {
1414
+ result = 'none';
1415
+ } else if (value === 'currentColor') {
1416
+ result = this.get('color');
1417
+ } else {
1418
+ result = parseColor(value);
1419
+ }
1420
+ break;
1421
+ case 'marker-start': case 'marker-mid': case 'marker-end': case 'clip-path': case 'mask':
1422
+ if (value === 'none') {
1423
+ result = 'none';
1424
+ } else {
1425
+ result = this.resolveUrl(value);
1426
+ }
1427
+ break;
1428
+ case 'stroke-width':
1429
+ parsed = this.computeLength(value, this.getViewport());
1430
+ if (parsed != null && parsed >= 0) {
1431
+ result = parsed;
1432
+ }
1433
+ break;
1434
+ case 'stroke-miterlimit':
1435
+ parsed = parseFloat(value);
1436
+ if (parsed != null && parsed >= 1) {
1437
+ result = parsed;
1438
+ }
1439
+ break;
1440
+ case 'word-spacing': case 'letter-spacing':
1441
+ result = this.computeLength(value, this.getViewport());
1442
+ break;
1443
+ case 'stroke-dashoffset':
1444
+ result = this.computeLength(value, this.getViewport());
1445
+ break;
1446
+ }
1447
+ if (result != null) {return styleCache[key] = result;}
1448
+ }
1449
+ }
1450
+ return styleCache[key] = (keyInfo.inherit && this.inherits ? this.inherits.get(key) : keyInfo.initial);
1451
+ };
1452
+ this.getChildren = function() {
1453
+ if (childrenCache != null) {return childrenCache;}
1454
+ let children = [];
1455
+ for (let i = 0; i < obj.childNodes.length; i++) {
1456
+ let child = obj.childNodes[i];
1457
+ if (!child.error && this.allowedChildren.indexOf(child.nodeName) !== -1) {
1458
+ children.push(createSVGElement(child, this));
1459
+ }
1460
+ }
1461
+ return childrenCache = children;
1462
+ };
1463
+ this.getParentVWidth = function() {
1464
+ return (this.inherits ? this.inherits.getVWidth(): viewportWidth);
1465
+ };
1466
+ this.getParentVHeight = function() {
1467
+ return (this.inherits ? this.inherits.getVHeight() : viewportHeight);
1468
+ };
1469
+ this.getParentViewport = function() {
1470
+ return Math.sqrt(0.5 * this.getParentVWidth() * this.getParentVWidth() + 0.5 * this.getParentVHeight() * this.getParentVHeight());
1471
+ };
1472
+ this.getVWidth = function() {
1473
+ return this.getParentVWidth();
1474
+ };
1475
+ this.getVHeight = function() {
1476
+ return this.getParentVHeight();
1477
+ };
1478
+ this.getViewport = function() {
1479
+ return Math.sqrt(0.5 * this.getVWidth() * this.getVWidth() + 0.5 * this.getVHeight() * this.getVHeight());
1480
+ };
1481
+ this.getBoundingBox = function() {
1482
+ let shape = this.getBoundingShape();
1483
+ return shape.getBoundingBox();
1484
+ };
1485
+ };
1486
+
1487
+ var SvgElemStylable = function(obj, inherits) {
1488
+ SvgElem.call(this, obj, inherits);
1489
+ this.transform = function() {
1490
+ doc.transform.apply(doc, this.getTransformation());
1491
+ };
1492
+ this.clip = function() {
1493
+ if (this.get('clip-path') !== 'none') {
1494
+ let clipPath = new SvgElemClipPath(this.get('clip-path'), null);
1495
+ clipPath.useMask((clipPath.attr('clipPathUnits') === 'objectBoundingBox') ? this.getBoundingBox() : null);
1496
+ return true;
1497
+ }
1498
+ };
1499
+ this.mask = function() {
1500
+ if (this.get('mask') !== 'none') {
1501
+ let mask = new SvgElemMask(this.get('mask'), null);
1502
+ mask.useMask(this.getBoundingBox());
1503
+ return true;
1504
+ }
1505
+ };
1506
+ this.getFill = function(isClip, isMask) {
1507
+ let opacity = this.get('opacity'),
1508
+ fill = this.get('fill'),
1509
+ fillOpacity = this.get('fill-opacity');
1510
+ if (isClip) {return DefaultColors.white;}
1511
+ if (fill !== 'none' && opacity && fillOpacity) {
1512
+ if (fill instanceof SvgElemGradient || fill instanceof SvgElemPattern) {
1513
+ return fill.getPaint(this.getBoundingBox(), fillOpacity * opacity, isClip, isMask);
1514
+ }
1515
+ return opacityToColor(fill, fillOpacity * opacity, isMask);
1516
+ }
1517
+ };
1518
+ this.getStroke = function(isClip, isMask) {
1519
+ let opacity = this.get('opacity'),
1520
+ stroke = this.get('stroke'),
1521
+ strokeOpacity = this.get('stroke-opacity');
1522
+ if (isClip || isEqual(this.get('stroke-width'), 0)) {return;}
1523
+ if (stroke !== 'none' && opacity && strokeOpacity) {
1524
+ if (stroke instanceof SvgElemGradient || stroke instanceof SvgElemPattern) {
1525
+ return stroke.getPaint(this.getBoundingBox(), strokeOpacity * opacity, isClip, isMask);
1526
+ }
1527
+ return opacityToColor(stroke, strokeOpacity * opacity, isMask);
1528
+ }
1529
+ };
1530
+ };
1531
+
1532
+ var SvgElemHasChildren = function(obj, inherits) {
1533
+ SvgElemStylable.call(this, obj, inherits);
1534
+ this.allowedChildren = ['use', 'g', 'a', 'svg', 'image', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path', 'text'];
1535
+ this.getBoundingShape = function() {
1536
+ let shape = new SvgShape(),
1537
+ children = this.getChildren();
1538
+ for (let i = 0; i < children.length; i++) {
1539
+ if (children[i].get('display') !== 'none') {
1540
+ if (typeof children[i].getBoundingShape === 'function') {
1541
+ let childShape = children[i].getBoundingShape().clone();
1542
+ if (typeof children[i].getTransformation === 'function') {
1543
+ childShape.transform(children[i].getTransformation());
1544
+ }
1545
+ shape.mergeShape(childShape);
1546
+ }
1547
+ }
1548
+ }
1549
+ return shape;
1550
+ };
1551
+ this.drawChildren = function(isClip, isMask) {
1552
+ let children = this.getChildren();
1553
+ for (let i = 0; i < children.length; i++) {
1554
+ if (children[i].get('display') !== 'none') {
1555
+ if (typeof children[i].drawInDocument === 'function') {
1556
+ children[i].drawInDocument(isClip, isMask);
1557
+ }
1558
+ }
1559
+ }
1560
+ };
1561
+ };
1562
+
1563
+ var SvgElemContainer = function(obj, inherits) {
1564
+ SvgElemHasChildren.call(this, obj, inherits);
1565
+ this.drawContent = function(isClip, isMask) {
1566
+ this.transform();
1567
+ let clipped = this.clip(),
1568
+ masked = this.mask(),
1569
+ group;
1570
+ if ((this.get('opacity') < 1 || clipped || masked) && !isClip) {
1571
+ group = docBeginGroup(getPageBBox());
1572
+ }
1573
+ this.drawChildren(isClip, isMask);
1574
+ if (group) {
1575
+ docEndGroup(group);
1576
+ doc.fillOpacity(this.get('opacity'));
1577
+ docInsertGroup(group);
1578
+ }
1579
+ };
1580
+ };
1581
+
1582
+ var SvgElemUse = function(obj, inherits) {
1583
+ SvgElemContainer.call(this, obj, inherits);
1584
+ let x = this.getLength('x', this.getVWidth(), 0),
1585
+ y = this.getLength('y', this.getVHeight(), 0),
1586
+ child = this.getUrl('href') || this.getUrl('xlink:href');
1587
+ if (child) {child = createSVGElement(child, this);}
1588
+ this.getChildren = function() {
1589
+ return child ? [child] : [];
1590
+ };
1591
+ this.drawInDocument = function(isClip, isMask) {
1592
+ doc.save();
1593
+ this.drawContent(isClip, isMask);
1594
+ doc.restore();
1595
+ };
1596
+ this.getTransformation = function() {
1597
+ return multiplyMatrix(this.get('transform'), [1, 0, 0, 1, x, y]);
1598
+ };
1599
+ };
1600
+
1601
+ var SvgElemSymbol = function(obj, inherits) {
1602
+ SvgElemContainer.call(this, obj, inherits);
1603
+ let width = this.getLength('width', this.getParentVWidth(), this.getParentVWidth()),
1604
+ height = this.getLength('height', this.getParentVHeight(), this.getParentVHeight());
1605
+ if (inherits instanceof SvgElemUse) {
1606
+ width = inherits.getLength('width', inherits.getParentVWidth(), width);
1607
+ height = inherits.getLength('height', inherits.getParentVHeight(), height);
1608
+ }
1609
+ let aspectRatio = (this.attr('preserveAspectRatio') || '').trim(),
1610
+ viewBox = this.getViewbox('viewBox', [0, 0, width, height]);
1611
+ this.getVWidth = function() {
1612
+ return viewBox[2];
1613
+ };
1614
+ this.getVHeight = function() {
1615
+ return viewBox[3];
1616
+ };
1617
+ this.drawInDocument = function(isClip, isMask) {
1618
+ doc.save();
1619
+ this.drawContent(isClip, isMask);
1620
+ doc.restore();
1621
+ };
1622
+ this.getTransformation = function() {
1623
+ return multiplyMatrix(parseAspectRatio(aspectRatio, width, height, viewBox[2], viewBox[3]), [1, 0, 0, 1, -viewBox[0], -viewBox[1]]);
1624
+ };
1625
+ };
1626
+
1627
+ var SvgElemGroup = function(obj, inherits) {
1628
+ SvgElemContainer.call(this, obj, inherits);
1629
+ this.drawInDocument = function(isClip, isMask) {
1630
+ doc.save();
1631
+ if (this.link && !isClip && !isMask) {this.addLink();}
1632
+ this.drawContent(isClip, isMask);
1633
+ doc.restore();
1634
+ };
1635
+ this.getTransformation = function() {
1636
+ return this.get('transform');
1637
+ };
1638
+ };
1639
+
1640
+ var SvgElemLink = function(obj, inherits) {
1641
+ if (inherits && inherits.isText) {
1642
+ SvgElemTspan.call(this, obj, inherits);
1643
+ this.allowedChildren = ['textPath', 'tspan', '#text', '#cdata-section', 'a'];
1644
+ } else {
1645
+ SvgElemGroup.call(this, obj, inherits);
1646
+ }
1647
+ this.link = this.attr('href') || this.attr('xlink:href');
1648
+ this.addLink = function() {
1649
+ if (this.link.match(/^(?:[a-z][a-z0-9+.-]*:|\/\/)?/i) && this.getChildren().length) {
1650
+ let bbox = this.getBoundingShape().transform(getGlobalMatrix()).getBoundingBox();
1651
+ docInsertLink(bbox[0], bbox[1], bbox[2], bbox[3], this.link);
1652
+ }
1653
+ }
1654
+ };
1655
+
1656
+ var SvgElemSvg = function(obj, inherits) {
1657
+ SvgElemContainer.call(this, obj, inherits);
1658
+ let width = this.getLength('width', this.getParentVWidth(), this.getParentVWidth()),
1659
+ height = this.getLength('height', this.getParentVHeight(), this.getParentVHeight()),
1660
+ x = this.getLength('x', this.getParentVWidth(), 0),
1661
+ y = this.getLength('y', this.getParentVHeight(), 0);
1662
+ if (inherits instanceof SvgElemUse) {
1663
+ width = inherits.getLength('width', inherits.getParentVWidth(), width);
1664
+ height = inherits.getLength('height', inherits.getParentVHeight(), height);
1665
+ }
1666
+ let aspectRatio = this.attr('preserveAspectRatio'),
1667
+ viewBox = this.getViewbox('viewBox', [0, 0, width, height]);
1668
+ if (this.isOuterElement && preserveAspectRatio) {
1669
+ x = y = 0;
1670
+ width = viewportWidth;
1671
+ height = viewportHeight;
1672
+ aspectRatio = preserveAspectRatio;
1673
+ }
1674
+ this.getVWidth = function() {
1675
+ return viewBox[2];
1676
+ };
1677
+ this.getVHeight = function() {
1678
+ return viewBox[3];
1679
+ };
1680
+ this.drawInDocument = function(isClip, isMask) {
1681
+ doc.save();
1682
+ if (this.get('overflow') === 'hidden') {
1683
+ new SvgShape().M(x, y).L(x + width, y).L(x + width, y + height).L(x, y + height).Z()
1684
+ .transform(this.get('transform'))
1685
+ .insertInDocument();
1686
+ doc.clip();
1687
+ }
1688
+ this.drawContent(isClip, isMask);
1689
+ doc.restore();
1690
+ };
1691
+ this.getTransformation = function() {
1692
+ return multiplyMatrix(
1693
+ this.get('transform'),
1694
+ [1, 0, 0, 1, x, y],
1695
+ parseAspectRatio(aspectRatio, width, height, viewBox[2], viewBox[3]),
1696
+ [1, 0, 0, 1, -viewBox[0], -viewBox[1]]
1697
+ );
1698
+ };
1699
+ };
1700
+
1701
+ var SVGElemImage = function(obj, inherits) {
1702
+ SvgElemStylable.call(this, obj, inherits);
1703
+ let link = imageCallback(this.attr('href') || this.attr('xlink:href') || ''),
1704
+ x = this.getLength('x', this.getVWidth(), 0),
1705
+ y = this.getLength('y', this.getVHeight(), 0),
1706
+ width = this.getLength('width', this.getVWidth(), 'auto'),
1707
+ height = this.getLength('height', this.getVHeight(), 'auto'),
1708
+ image;
1709
+ try {
1710
+ image = doc.openImage(link);
1711
+ } catch(e) {
1712
+ warningCallback('SVGElemImage: failed to open image "' + link + '" in PDFKit');
1713
+ }
1714
+ if (image) {
1715
+ if (width === 'auto' && height !== 'auto') {
1716
+ width = height * image.width / image.height;
1717
+ } else if (height === 'auto' && width !== 'auto') {
1718
+ height = width * image.height / image.width;
1719
+ } else if (width === 'auto' && height === 'auto') {
1720
+ width = image.width;
1721
+ height = image.height;
1722
+ }
1723
+ }
1724
+ if (width === 'auto' || width < 0) {width = 0;}
1725
+ if (height === 'auto' || height < 0) {height = 0;}
1726
+ this.getTransformation = function() {
1727
+ return this.get('transform');
1728
+ };
1729
+ this.getBoundingShape = function() {
1730
+ return new SvgShape().M(x, y).L(x + width, y).M(x + width, y + height).L(x, y + height);
1731
+ };
1732
+ this.drawInDocument = function(isClip, isMask) {
1733
+ if (this.get('visibility') === 'hidden' || !image) {return;}
1734
+ doc.save();
1735
+ this.transform();
1736
+ if (this.get('overflow') === 'hidden') {
1737
+ doc.rect(x, y, width, height).clip();
1738
+ }
1739
+ this.clip();
1740
+ this.mask();
1741
+ doc.translate(x, y);
1742
+ doc.transform.apply(doc, parseAspectRatio(this.attr('preserveAspectRatio'), width, height, image ? image.width : width, image ? image.height : height));
1743
+ if (!isClip) {
1744
+ doc.fillOpacity(this.get('opacity'));
1745
+ doc.image(image, 0, 0);
1746
+ } else {
1747
+ doc.rect(0, 0, image.width, image.height);
1748
+ docFillColor(DefaultColors.white).fill();
1749
+ }
1750
+ doc.restore();
1751
+ };
1752
+ };
1753
+
1754
+ var SvgElemPattern = function(obj, inherits, fallback) {
1755
+ SvgElemHasChildren.call(this, obj, inherits);
1756
+ this.ref = (function() {
1757
+ let ref = this.getUrl('href') || this.getUrl('xlink:href');
1758
+ if (ref && ref.nodeName === obj.nodeName) {
1759
+ return new SvgElemPattern(ref, inherits, fallback);
1760
+ }
1761
+ }).call(this);
1762
+ let _attr = this.attr;
1763
+ this.attr = function(key) {
1764
+ let attr = _attr.call(this, key);
1765
+ if (attr != null || key === 'href' || key === 'xlink:href') {return attr;}
1766
+ return this.ref ? this.ref.attr(key) : null;
1767
+ };
1768
+ let _getChildren = this.getChildren;
1769
+ this.getChildren = function() {
1770
+ let children = _getChildren.call(this);
1771
+ if (children.length > 0) {return children;}
1772
+ return this.ref ? this.ref.getChildren() : [];
1773
+ };
1774
+ this.getPaint = function(bBox, gOpacity, isClip, isMask) {
1775
+ let bBoxUnitsPattern = (this.attr('patternUnits') !== 'userSpaceOnUse'),
1776
+ bBoxUnitsContent = (this.attr('patternContentUnits') === 'objectBoundingBox'),
1777
+ x = this.getLength('x', (bBoxUnitsPattern ? 1 : this.getParentVWidth()), 0),
1778
+ y = this.getLength('y', (bBoxUnitsPattern ? 1 : this.getParentVHeight()), 0),
1779
+ width = this.getLength('width', (bBoxUnitsPattern ? 1 : this.getParentVWidth()), 0),
1780
+ height = this.getLength('height', (bBoxUnitsPattern ? 1 : this.getParentVHeight()), 0);
1781
+ if (bBoxUnitsContent && !bBoxUnitsPattern) { // Use the same units for pattern & pattern content
1782
+ x = (x - bBox[0]) / (bBox[2] - bBox[0]) || 0;
1783
+ y = (y - bBox[1]) / (bBox[3] - bBox[1]) || 0;
1784
+ width = width / (bBox[2] - bBox[0]) || 0;
1785
+ height = height / (bBox[3] - bBox[1]) || 0;
1786
+ } else if (!bBoxUnitsContent && bBoxUnitsPattern) {
1787
+ x = bBox[0] + x * (bBox[2] - bBox[0]);
1788
+ y = bBox[1] + y * (bBox[3] - bBox[1]);
1789
+ width = width * (bBox[2] - bBox[0]);
1790
+ height = height * (bBox[3] - bBox[1]);
1791
+ }
1792
+ let viewBox = this.getViewbox('viewBox', [0, 0, width, height]),
1793
+ aspectRatio = (this.attr('preserveAspectRatio') || '').trim(),
1794
+ aspectRatioMatrix = multiplyMatrix(
1795
+ parseAspectRatio(aspectRatio, width, height, viewBox[2], viewBox[3], 0),
1796
+ [1, 0, 0, 1, -viewBox[0], -viewBox[1]]
1797
+ ),
1798
+ matrix = parseTranform(this.attr('patternTransform'));
1799
+ if (bBoxUnitsContent) {
1800
+ matrix = multiplyMatrix([bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]], matrix);
1801
+ }
1802
+ matrix = multiplyMatrix(matrix, [1, 0, 0, 1, x, y]);
1803
+ if ((matrix = validateMatrix(matrix)) && (aspectRatioMatrix = validateMatrix(aspectRatioMatrix)) && (width = validateNumber(width)) && (height = validateNumber(height))) {
1804
+ let group = docBeginGroup([0, 0, width, height]);
1805
+ doc.transform.apply(doc, aspectRatioMatrix);
1806
+ this.drawChildren(isClip, isMask);
1807
+ docEndGroup(group);
1808
+ return [docCreatePattern(group, width, height, matrix), gOpacity];
1809
+ } else {
1810
+ return fallback ? [fallback[0], fallback[1] * gOpacity] : undefined;
1811
+ }
1812
+ };
1813
+ this.getVWidth = function() {
1814
+ let bBoxUnitsPattern = (this.attr('patternUnits') !== 'userSpaceOnUse'),
1815
+ width = this.getLength('width', (bBoxUnitsPattern ? 1 : this.getParentVWidth()), 0);
1816
+ return this.getViewbox('viewBox', [0, 0, width, 0])[2];
1817
+ };
1818
+ this.getVHeight = function() {
1819
+ let bBoxUnitsPattern = (this.attr('patternUnits') !== 'userSpaceOnUse'),
1820
+ height = this.getLength('height', (bBoxUnitsPattern ? 1 : this.getParentVHeight()), 0);
1821
+ return this.getViewbox('viewBox', [0, 0, 0, height])[3];
1822
+ };
1823
+ };
1824
+
1825
+ var SvgElemGradient = function(obj, inherits, fallback) {
1826
+ SvgElem.call(this, obj, inherits);
1827
+ this.allowedChildren = ['stop'];
1828
+ this.ref = (function() {
1829
+ let ref = this.getUrl('href') || this.getUrl('xlink:href');
1830
+ if (ref && ref.nodeName === obj.nodeName) {
1831
+ return new SvgElemGradient(ref, inherits, fallback);
1832
+ }
1833
+ }).call(this);
1834
+ let _attr = this.attr;
1835
+ this.attr = function(key) {
1836
+ let attr = _attr.call(this, key);
1837
+ if (attr != null || key === 'href' || key === 'xlink:href') {return attr;}
1838
+ return this.ref ? this.ref.attr(key) : null;
1839
+ };
1840
+ let _getChildren = this.getChildren;
1841
+ this.getChildren = function() {
1842
+ let children = _getChildren.call(this);
1843
+ if (children.length > 0) {return children;}
1844
+ return this.ref ? this.ref.getChildren() : [];
1845
+ };
1846
+ this.getPaint = function(bBox, gOpacity, isClip, isMask) {
1847
+ let children = this.getChildren();
1848
+ if (children.length === 0) {return;}
1849
+ if (children.length === 1) {
1850
+ let child = children[0],
1851
+ stopColor = child.get('stop-color');
1852
+ if (stopColor === 'none') {return;}
1853
+ return opacityToColor(stopColor, child.get('stop-opacity') * gOpacity, isMask);
1854
+ }
1855
+ let bBoxUnits = (this.attr('gradientUnits') !== 'userSpaceOnUse'),
1856
+ matrix = parseTranform(this.attr('gradientTransform')),
1857
+ spread = this.attr('spreadMethod'),
1858
+ grad,
1859
+ x1, x2, y1, y2, r2,
1860
+ nAfter = 0,
1861
+ nBefore = 0,
1862
+ nTotal = 1;
1863
+ if (bBoxUnits) {
1864
+ matrix = multiplyMatrix([bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]], matrix);
1865
+ }
1866
+ if (matrix = validateMatrix(matrix)) {
1867
+ if (this.name === 'linearGradient') {
1868
+ x1 = this.getLength('x1', (bBoxUnits ? 1 : this.getVWidth()), 0);
1869
+ x2 = this.getLength('x2', (bBoxUnits ? 1 : this.getVWidth()), (bBoxUnits ? 1 : this.getVWidth()));
1870
+ y1 = this.getLength('y1', (bBoxUnits ? 1 : this.getVHeight()), 0);
1871
+ y2 = this.getLength('y2', (bBoxUnits ? 1 : this.getVHeight()), 0);
1872
+ } else {
1873
+ x2 = this.getLength('cx', (bBoxUnits ? 1 : this.getVWidth()), (bBoxUnits ? 0.5 : 0.5 * this.getVWidth()));
1874
+ y2 = this.getLength('cy', (bBoxUnits ? 1 : this.getVHeight()), (bBoxUnits ? 0.5 : 0.5 * this.getVHeight()));
1875
+ r2 = this.getLength('r', (bBoxUnits ? 1 : this.getViewport()), (bBoxUnits ? 0.5 : 0.5 * this.getViewport()));
1876
+ x1 = this.getLength('fx', (bBoxUnits ? 1 : this.getVWidth()), x2);
1877
+ y1 = this.getLength('fy', (bBoxUnits ? 1 : this.getVHeight()), y2);
1878
+ if (r2 < 0) {
1879
+ warningCallback('SvgElemGradient: negative r value');
1880
+ }
1881
+ let d = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)),
1882
+ multiplier = 1;
1883
+ if (d > r2) { // according to specification
1884
+ multiplier = r2 / d;
1885
+ x1 = x2 + (x1 - x2) * multiplier;
1886
+ y1 = y2 + (y1 - y2) * multiplier;
1887
+ }
1888
+ r2 = Math.max(r2, d * multiplier * (1 + 1e-6)); // fix for edge-case gradients see issue #84
1889
+ }
1890
+ if (spread === 'reflect' || spread === 'repeat') {
1891
+ let inv = inverseMatrix(matrix),
1892
+ corner1 = transformPoint([bBox[0], bBox[1]], inv),
1893
+ corner2 = transformPoint([bBox[2], bBox[1]], inv),
1894
+ corner3 = transformPoint([bBox[2], bBox[3]], inv),
1895
+ corner4 = transformPoint([bBox[0], bBox[3]], inv);
1896
+ if (this.name === 'linearGradient') { // See file 'gradient-repeat-maths.png'
1897
+ nAfter = Math.max((corner1[0] - x2) * (x2 - x1) + (corner1[1] - y2) * (y2 - y1),
1898
+ (corner2[0] - x2) * (x2 - x1) + (corner2[1] - y2) * (y2 - y1),
1899
+ (corner3[0] - x2) * (x2 - x1) + (corner3[1] - y2) * (y2 - y1),
1900
+ (corner4[0] - x2) * (x2 - x1) + (corner4[1] - y2) * (y2 - y1))
1901
+ / (Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
1902
+ nBefore = Math.max((corner1[0] - x1) * (x1 - x2) + (corner1[1] - y1) * (y1 - y2),
1903
+ (corner2[0] - x1) * (x1 - x2) + (corner2[1] - y1) * (y1 - y2),
1904
+ (corner3[0] - x1) * (x1 - x2) + (corner3[1] - y1) * (y1 - y2),
1905
+ (corner4[0] - x1) * (x1 - x2) + (corner4[1] - y1) * (y1 - y2))
1906
+ / (Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
1907
+ } else {
1908
+ nAfter = Math.sqrt(Math.max(Math.pow(corner1[0] - x2, 2) + Math.pow(corner1[1] - y2, 2),
1909
+ Math.pow(corner2[0] - x2, 2) + Math.pow(corner2[1] - y2, 2),
1910
+ Math.pow(corner3[0] - x2, 2) + Math.pow(corner3[1] - y2, 2),
1911
+ Math.pow(corner4[0] - x2, 2) + Math.pow(corner4[1] - y2, 2))) / r2 - 1;
1912
+ }
1913
+ nAfter = Math.ceil(nAfter + 0.5); // Add a little more because the stroke can extend outside of the bounding box
1914
+ nBefore = Math.ceil(nBefore + 0.5);
1915
+ nTotal = nBefore + 1 + nAfter; // How many times the gradient needs to be repeated to fill the object bounding box
1916
+ }
1917
+ if (this.name === 'linearGradient') {
1918
+ grad = doc.linearGradient(x1 - nBefore * (x2 - x1), y1 - nBefore * (y2 - y1), x2 + nAfter * (x2 - x1), y2 + nAfter * (y2 - y1));
1919
+ } else {
1920
+ grad = doc.radialGradient(x1, y1, 0, x2, y2, r2 + nAfter * r2);
1921
+ }
1922
+ for (let n = 0; n < nTotal; n++) {
1923
+ let offset = 0,
1924
+ inOrder = (spread !== 'reflect' || (n - nBefore) % 2 === 0);
1925
+ for (let i = 0; i < children.length; i++) {
1926
+ let child = children[inOrder ? i : children.length - 1 - i],
1927
+ stopColor = child.get('stop-color');
1928
+ if (stopColor === 'none') {stopColor = DefaultColors.transparent;}
1929
+ stopColor = opacityToColor(stopColor, child.get('stop-opacity') * gOpacity, isMask);
1930
+ offset = Math.max(offset, inOrder ? child.getPercent('offset', 0) : 1 - child.getPercent('offset', 0));
1931
+ if (i === 0 && stopColor[0].length === 4) {grad._colorSpace = 'DeviceCMYK';} // Fix until PR #763 is merged into PDFKit
1932
+ if (i === 0 && offset > 0) {
1933
+ grad.stop((n + 0) / nTotal, stopColor[0], stopColor[1]);
1934
+ }
1935
+ grad.stop((n + offset) / (nAfter + nBefore + 1), stopColor[0], stopColor[1]);
1936
+ if (i === children.length - 1 && offset < 1) {
1937
+ grad.stop((n + 1) / nTotal, stopColor[0], stopColor[1]);
1938
+ }
1939
+ }
1940
+ }
1941
+ grad.setTransform.apply(grad, matrix);
1942
+ return [grad, 1];
1943
+ } else {
1944
+ return fallback ? [fallback[0], fallback[1] * gOpacity] : undefined;
1945
+ }
1946
+ }
1947
+ };
1948
+
1949
+ var SvgElemBasicShape = function(obj, inherits) {
1950
+ SvgElemStylable.call(this, obj, inherits);
1951
+ this.dashScale = 1;
1952
+ this.getBoundingShape = function() {
1953
+ return this.shape;
1954
+ };
1955
+ this.getTransformation = function() {
1956
+ return this.get('transform');
1957
+ };
1958
+ this.drawInDocument = function(isClip, isMask) {
1959
+ if (this.get('visibility') === 'hidden' || !this.shape) {return;}
1960
+ doc.save();
1961
+ if (this.get('vector-effect') === 'non-scaling-stroke') {
1962
+ this.shape.transform(this.getTransformation());
1963
+ } else {
1964
+ this.transform();
1965
+ }
1966
+ this.clip();
1967
+ if (!isClip) {
1968
+ let masked = this.mask(),
1969
+ group;
1970
+ if (masked) {
1971
+ group = docBeginGroup(getPageBBox());
1972
+ }
1973
+ let subPaths = this.shape.getSubPaths(),
1974
+ fill = this.getFill(isClip, isMask),
1975
+ stroke = this.getStroke(isClip, isMask),
1976
+ lineWidth = this.get('stroke-width'),
1977
+ lineCap = this.get('stroke-linecap');
1978
+
1979
+ if (this.get('vector-effect') === 'non-scaling-stroke') {
1980
+ lineWidth = lineWidth / getPageScale();
1981
+ }
1982
+
1983
+ if (fill || stroke) {
1984
+ if (fill) {
1985
+ docFillColor(fill);
1986
+ }
1987
+ if (stroke) {
1988
+ for (let j = 0; j < subPaths.length; j++) {
1989
+ if (isEqual(subPaths[j].totalLength, 0)) {
1990
+ if ((lineCap === 'square' || lineCap === 'round') && lineWidth > 0) {
1991
+ if (subPaths[j].startPoint && subPaths[j].startPoint.length > 1) {
1992
+ let x = subPaths[j].startPoint[0],
1993
+ y = subPaths[j].startPoint[1];
1994
+ docFillColor(stroke);
1995
+ if (lineCap === 'square') {
1996
+ doc.rect(x - 0.5 * lineWidth, y - 0.5 * lineWidth, lineWidth, lineWidth);
1997
+ } else if (lineCap === 'round') {
1998
+ doc.circle(x, y, 0.5 * lineWidth);
1999
+ }
2000
+ doc.fill();
2001
+ }
2002
+ }
2003
+ }
2004
+ }
2005
+ let dashArray = this.get('stroke-dasharray'),
2006
+ dashOffset = this.get('stroke-dashoffset');
2007
+ if (isNotEqual(this.dashScale, 1)) {
2008
+ for (let j = 0; j < dashArray.length; j++) {
2009
+ dashArray[j] *= this.dashScale;
2010
+ }
2011
+ dashOffset *= this.dashScale;
2012
+ }
2013
+ docStrokeColor(stroke);
2014
+ doc.lineWidth(lineWidth)
2015
+ .miterLimit(this.get('stroke-miterlimit'))
2016
+ .lineJoin(this.get('stroke-linejoin'))
2017
+ .lineCap(lineCap);
2018
+ docApplyDash(dashArray, dashOffset);
2019
+ }
2020
+ for (let j = 0; j < subPaths.length; j++) {
2021
+ if (subPaths[j].totalLength > 0) {
2022
+ subPaths[j].insertInDocument();
2023
+ }
2024
+ }
2025
+ if (fill && stroke) {
2026
+ doc.fillAndStroke(this.get('fill-rule'));
2027
+ } else if (fill) {
2028
+ doc.fill(this.get('fill-rule'));
2029
+ } else if (stroke) {
2030
+ doc.stroke();
2031
+ }
2032
+ }
2033
+ let markerStart = this.get('marker-start'),
2034
+ markerMid = this.get('marker-mid'),
2035
+ markerEnd = this.get('marker-end');
2036
+ if (markerStart !== 'none' || markerMid !== 'none' || markerEnd !== 'none') {
2037
+ let markersPos = this.shape.getMarkers();
2038
+ if (markerStart !== 'none' && markersPos.length > 0) {
2039
+ let marker = new SvgElemMarker(markerStart, null);
2040
+ marker.drawMarker(false, isMask, markersPos[0], lineWidth);
2041
+ }
2042
+ if (markerMid !== 'none') {
2043
+ for (let i = 1; i < markersPos.length - 1; i++) {
2044
+ let marker = new SvgElemMarker(markerMid, null);
2045
+ marker.drawMarker(false, isMask, markersPos[i], lineWidth);
2046
+ }
2047
+ }
2048
+ if (markerEnd !== 'none' && markersPos.length > 0) {
2049
+ let marker = new SvgElemMarker(markerEnd, null);
2050
+ marker.drawMarker(false, isMask, markersPos[markersPos.length - 1], lineWidth);
2051
+ }
2052
+ }
2053
+ if (group) {
2054
+ docEndGroup(group);
2055
+ docInsertGroup(group);
2056
+ }
2057
+ } else {
2058
+ this.shape.insertInDocument();
2059
+ docFillColor(DefaultColors.white);
2060
+ doc.fill(this.get('clip-rule'));
2061
+ }
2062
+ doc.restore();
2063
+ };
2064
+ };
2065
+
2066
+ var SvgElemRect = function(obj, inherits) {
2067
+ SvgElemBasicShape.call(this, obj, inherits);
2068
+ let x = this.getLength('x', this.getVWidth(), 0),
2069
+ y = this.getLength('y', this.getVHeight(), 0),
2070
+ w = this.getLength('width', this.getVWidth(), 0),
2071
+ h = this.getLength('height', this.getVHeight(), 0),
2072
+ rx = this.getLength('rx', this.getVWidth()),
2073
+ ry = this.getLength('ry', this.getVHeight());
2074
+ if (rx === undefined && ry === undefined) {rx = ry = 0;}
2075
+ else if (rx === undefined && ry !== undefined) {rx = ry;}
2076
+ else if (rx !== undefined && ry === undefined) {ry = rx;}
2077
+ if (w > 0 && h > 0) {
2078
+ if (rx && ry) {
2079
+ rx = Math.min(rx, 0.5 * w);
2080
+ ry = Math.min(ry, 0.5 * h);
2081
+ this.shape = new SvgShape().M(x + rx, y).L(x + w - rx, y).A(rx, ry, 0, 0, 1, x + w, y + ry)
2082
+ .L(x + w, y + h - ry).A(rx, ry, 0, 0, 1, x + w - rx, y + h).L(x + rx, y + h)
2083
+ .A(rx, ry, 0, 0, 1, x, y + h - ry).L(x, y + ry).A(rx, ry, 0, 0, 1, x + rx, y).Z();
2084
+ } else {
2085
+ this.shape = new SvgShape().M(x, y).L(x + w, y).L(x + w, y + h).L(x, y + h).Z();
2086
+ }
2087
+ } else {
2088
+ this.shape = new SvgShape();
2089
+ }
2090
+ };
2091
+
2092
+ var SvgElemCircle = function(obj, inherits) {
2093
+ SvgElemBasicShape.call(this, obj, inherits);
2094
+ let cx = this.getLength('cx', this.getVWidth(), 0),
2095
+ cy = this.getLength('cy', this.getVHeight(), 0),
2096
+ r = this.getLength('r', this.getViewport(), 0);
2097
+ if (r > 0) {
2098
+ this.shape = new SvgShape().M(cx + r, cy).A(r, r, 0, 0, 1, cx - r, cy).A(r, r, 0, 0, 1, cx + r, cy).Z();
2099
+ } else {
2100
+ this.shape = new SvgShape();
2101
+ }
2102
+ };
2103
+
2104
+ var SvgElemEllipse = function(obj, inherits) {
2105
+ SvgElemBasicShape.call(this, obj, inherits);
2106
+ let cx = this.getLength('cx', this.getVWidth(), 0),
2107
+ cy = this.getLength('cy', this.getVHeight(), 0),
2108
+ rx = this.getLength('rx', this.getVWidth(), 0),
2109
+ ry = this.getLength('ry', this.getVHeight(), 0);
2110
+ if (rx > 0 && ry > 0) {
2111
+ this.shape = new SvgShape().M(cx + rx, cy).A(rx, ry, 0, 0, 1, cx - rx, cy).A(rx, ry, 0, 0, 1, cx + rx, cy).Z();
2112
+ } else {
2113
+ this.shape = new SvgShape();
2114
+ }
2115
+ };
2116
+
2117
+ var SvgElemLine = function(obj, inherits) {
2118
+ SvgElemBasicShape.call(this, obj, inherits);
2119
+ let x1 = this.getLength('x1', this.getVWidth(), 0),
2120
+ y1 = this.getLength('y1', this.getVHeight(), 0),
2121
+ x2 = this.getLength('x2', this.getVWidth(), 0),
2122
+ y2 = this.getLength('y2', this.getVHeight(), 0);
2123
+ this.shape = new SvgShape().M(x1, y1).L(x2, y2);
2124
+ };
2125
+
2126
+ var SvgElemPolyline = function(obj, inherits) {
2127
+ SvgElemBasicShape.call(this, obj, inherits);
2128
+ let points = this.getNumberList('points');
2129
+ this.shape = new SvgShape();
2130
+ for (let i = 0; i < points.length - 1; i += 2) {
2131
+ if (i === 0) {
2132
+ this.shape.M(points[i], points[i+1]);
2133
+ } else {
2134
+ this.shape.L(points[i], points[i+1]);
2135
+ }
2136
+ }
2137
+ if (points.error) {warningCallback('SvgElemPolygon: unexpected string ' + points.error);}
2138
+ if (points.length % 2 === 1) {warningCallback('SvgElemPolyline: uneven number of coordinates');}
2139
+ };
2140
+
2141
+ var SvgElemPolygon = function(obj, inherits) {
2142
+ SvgElemBasicShape.call(this, obj, inherits);
2143
+ let points = this.getNumberList('points');
2144
+ this.shape = new SvgShape();
2145
+ for (let i = 0; i < points.length - 1; i += 2) {
2146
+ if (i === 0) {
2147
+ this.shape.M(points[i], points[i+1]);
2148
+ } else {
2149
+ this.shape.L(points[i], points[i+1]);
2150
+ }
2151
+ }
2152
+ this.shape.Z();
2153
+ if (points.error) {warningCallback('SvgElemPolygon: unexpected string ' + points.error);}
2154
+ if (points.length % 2 === 1) {warningCallback('SvgElemPolygon: uneven number of coordinates');}
2155
+ };
2156
+
2157
+ var SvgElemPath = function(obj, inherits) {
2158
+ SvgElemBasicShape.call(this, obj, inherits);
2159
+ this.shape = new SvgShape().path(this.attr('d'));
2160
+ let pathLength = this.getLength('pathLength', this.getViewport());
2161
+ this.pathLength = pathLength > 0 ? pathLength : undefined;
2162
+ this.dashScale = (this.pathLength !== undefined ? this.shape.totalLength / this.pathLength : 1);
2163
+ };
2164
+
2165
+ var SvgElemMarker = function(obj, inherits) {
2166
+ SvgElemHasChildren.call(this, obj, inherits);
2167
+ let width = this.getLength('markerWidth', this.getParentVWidth(), 3),
2168
+ height = this.getLength('markerHeight', this.getParentVHeight(), 3),
2169
+ viewBox = this.getViewbox('viewBox', [0, 0, width, height]);
2170
+ this.getVWidth = function() {
2171
+ return viewBox[2];
2172
+ };
2173
+ this.getVHeight = function() {
2174
+ return viewBox[3];
2175
+ };
2176
+ this.drawMarker = function(isClip, isMask, posArray, strokeWidth) {
2177
+ doc.save();
2178
+ let orient = this.attr('orient'),
2179
+ units = this.attr('markerUnits'),
2180
+ rotate = (orient === 'auto' ? posArray[2] : (parseFloat(orient) || 0) * Math.PI / 180),
2181
+ scale = (units === 'userSpaceOnUse' ? 1 : strokeWidth);
2182
+ doc.transform(Math.cos(rotate) * scale, Math.sin(rotate) * scale, -Math.sin(rotate) * scale, Math.cos(rotate) * scale, posArray[0], posArray[1]);
2183
+ let refX = this.getLength('refX', this.getVWidth(), 0),
2184
+ refY = this.getLength('refY', this.getVHeight(), 0),
2185
+ aspectRatioMatrix = parseAspectRatio(this.attr('preserveAspectRatio'), width, height, viewBox[2], viewBox[3], 0.5);
2186
+ if (this.get('overflow') === 'hidden') {
2187
+ doc.rect(aspectRatioMatrix[0] * (viewBox[0] + viewBox[2] / 2 - refX) - width / 2, aspectRatioMatrix[3] * (viewBox[1] + viewBox[3] / 2 - refY) - height / 2, width, height).clip();
2188
+ }
2189
+ doc.transform.apply(doc, aspectRatioMatrix);
2190
+ doc.translate(-refX, -refY);
2191
+ let group;
2192
+ if (this.get('opacity') < 1 && !isClip) {
2193
+ group = docBeginGroup(getPageBBox());
2194
+ }
2195
+ this.drawChildren(isClip, isMask);
2196
+ if (group) {
2197
+ docEndGroup(group);
2198
+ doc.fillOpacity(this.get('opacity'));
2199
+ docInsertGroup(group);
2200
+ }
2201
+ doc.restore();
2202
+ };
2203
+ };
2204
+
2205
+ var SvgElemClipPath = function(obj, inherits) {
2206
+ SvgElemHasChildren.call(this, obj, inherits);
2207
+ this.useMask = function(bBox) {
2208
+ let group = docBeginGroup(getPageBBox());
2209
+ doc.save();
2210
+ doc.transform.apply(doc, this.get('transform'));
2211
+ if (this.attr('clipPathUnits') === 'objectBoundingBox') {
2212
+ doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
2213
+ }
2214
+ this.clip();
2215
+ this.drawChildren(true, false);
2216
+ doc.restore();
2217
+ docEndGroup(group);
2218
+ docApplyMask(group, true);
2219
+ };
2220
+ };
2221
+
2222
+ var SvgElemMask = function(obj, inherits) {
2223
+ SvgElemHasChildren.call(this, obj, inherits);
2224
+ this.useMask = function(bBox) {
2225
+ let group = docBeginGroup(getPageBBox());
2226
+ doc.save();
2227
+ let x, y, w, h;
2228
+ if (this.attr('maskUnits') === 'userSpaceOnUse') {
2229
+ x = this.getLength('x', this.getVWidth(), -0.1 * (bBox[2] - bBox[0]) + bBox[0]);
2230
+ y = this.getLength('y', this.getVHeight(), -0.1 * (bBox[3] - bBox[1]) + bBox[1]);
2231
+ w = this.getLength('width', this.getVWidth(), 1.2 * (bBox[2] - bBox[0]));
2232
+ h = this.getLength('height', this.getVHeight(), 1.2 * (bBox[3] - bBox[1]));
2233
+ } else {
2234
+ x = this.getLength('x', this.getVWidth(), -0.1) * (bBox[2] - bBox[0]) + bBox[0];
2235
+ y = this.getLength('y', this.getVHeight(), -0.1) * (bBox[3] - bBox[1]) + bBox[1];
2236
+ w = this.getLength('width', this.getVWidth(), 1.2) * (bBox[2] - bBox[0]);
2237
+ h = this.getLength('height', this.getVHeight(), 1.2) * (bBox[3] - bBox[1]);
2238
+ }
2239
+ if (this.attr('maskContentUnits') === 'objectBoundingBox') {
2240
+ doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
2241
+ }
2242
+ this.clip();
2243
+ this.drawChildren(false, true);
2244
+ doc.restore();
2245
+ docEndGroup(group);
2246
+ docApplyMask(group, true);
2247
+ };
2248
+ };
2249
+
2250
+ var SvgElemTextContainer = function(obj, inherits) {
2251
+ SvgElemStylable.call(this, obj, inherits);
2252
+ this.allowedChildren = ['tspan', '#text', '#cdata-section', 'a'];
2253
+ this.isText = true;
2254
+ this.getBoundingShape = function() {
2255
+ let shape = new SvgShape();
2256
+ for (let i = 0; i < this._pos.length; i++) {
2257
+ let pos = this._pos[i];
2258
+ if (!pos.hidden) {
2259
+ let dx0 = pos.ascent * Math.sin(pos.rotate), dy0 = -pos.ascent * Math.cos(pos.rotate),
2260
+ dx1 = pos.descent * Math.sin(pos.rotate), dy1 = -pos.descent * Math.cos(pos.rotate),
2261
+ dx2 = pos.width * Math.cos(pos.rotate), dy2 = pos.width * Math.sin(pos.rotate);
2262
+ shape.M(pos.x + dx0, pos.y + dy0).L(pos.x + dx0 + dx2, pos.y + dy0 + dy2)
2263
+ .M(pos.x + dx1 + dx2, pos.y + dy1 + dy2).L(pos.x + dx1, pos.y + dy1);
2264
+ }
2265
+ }
2266
+ return shape;
2267
+ };
2268
+ this.drawTextInDocument = function(isClip, isMask) {
2269
+ if (this.link && !isClip && !isMask) {this.addLink();}
2270
+ if (this.get('text-decoration') === 'underline') {
2271
+ this.decorate(0.05 * this._font.size, -0.075 * this._font.size, isClip, isMask);
2272
+ }
2273
+ if (this.get('text-decoration') === 'overline') {
2274
+ this.decorate(0.05 * this._font.size, getAscent(this._font.font, this._font.size) + 0.075 * this._font.size, isClip, isMask);
2275
+ }
2276
+ let fill = this.getFill(isClip, isMask),
2277
+ stroke = this.getStroke(isClip, isMask),
2278
+ strokeWidth = this.get('stroke-width');
2279
+ if (this._font.fauxBold) {
2280
+ if (!stroke) {
2281
+ stroke = fill;
2282
+ strokeWidth = this._font.size * 0.03;
2283
+ } else {
2284
+ strokeWidth += this._font.size * 0.03;
2285
+ }
2286
+ }
2287
+ let children = this.getChildren();
2288
+ for (let i = 0; i < children.length; i++) {
2289
+ let childElem = children[i];
2290
+ switch(childElem.name) {
2291
+ case 'tspan': case 'textPath': case 'a':
2292
+ if (childElem.get('display') !== 'none') {
2293
+ childElem.drawTextInDocument(isClip, isMask);
2294
+ }
2295
+ break;
2296
+ case '#text': case '#cdata-section':
2297
+ if (this.get('visibility') === 'hidden') {continue;}
2298
+ if (fill || stroke || isClip) {
2299
+ if (fill) {
2300
+ docFillColor(fill);
2301
+ }
2302
+ if (stroke && strokeWidth) {
2303
+ docStrokeColor(stroke);
2304
+ doc.lineWidth(strokeWidth)
2305
+ .miterLimit(this.get('stroke-miterlimit'))
2306
+ .lineJoin(this.get('stroke-linejoin'))
2307
+ .lineCap(this.get('stroke-linecap'));
2308
+ docApplyDash(this.get('stroke-dasharray'), this.get('stroke-dashoffset'));
2309
+ }
2310
+ docBeginText(this._font.font, this._font.size);
2311
+ docSetTextMode(!!fill, !!stroke);
2312
+ docWriteGlyphs(childElem._pos, this._font);
2313
+ docEndText();
2314
+ }
2315
+ break;
2316
+ }
2317
+ }
2318
+ if (this.get('text-decoration') === 'line-through') {
2319
+ this.decorate(0.05 * this._font.size, 0.5 * (getAscent(this._font.font, this._font.size) + getDescent(this._font.font, this._font.size)), isClip, isMask);
2320
+ }
2321
+ };
2322
+ this.decorate = function(lineWidth, linePosition, isClip, isMask) {
2323
+ let fill = this.getFill(isClip, isMask),
2324
+ stroke = this.getStroke(isClip, isMask);
2325
+ if (fill) {
2326
+ docFillColor(fill);
2327
+ }
2328
+ if (stroke) {
2329
+ docStrokeColor(stroke);
2330
+ doc.lineWidth(this.get('stroke-width'))
2331
+ .miterLimit(this.get('stroke-miterlimit'))
2332
+ .lineJoin(this.get('stroke-linejoin'))
2333
+ .lineCap(this.get('stroke-linecap'));
2334
+ docApplyDash(this.get('stroke-dasharray'), this.get('stroke-dashoffset'));
2335
+ }
2336
+ for (let j = 0, pos = this._pos; j < pos.length; j++) {
2337
+ if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
2338
+ let dx0 = (linePosition + lineWidth / 2) * Math.sin(pos[j].rotate),
2339
+ dy0 = -(linePosition + lineWidth / 2) * Math.cos(pos[j].rotate),
2340
+ dx1 = (linePosition - lineWidth / 2) * Math.sin(pos[j].rotate),
2341
+ dy1 = -(linePosition - lineWidth / 2) * Math.cos(pos[j].rotate),
2342
+ dx2 = pos[j].width * Math.cos(pos[j].rotate),
2343
+ dy2 = pos[j].width * Math.sin(pos[j].rotate);
2344
+ new SvgShape().M(pos[j].x + dx0, pos[j].y + dy0)
2345
+ .L(pos[j].x + dx0 + dx2, pos[j].y + dy0 + dy2)
2346
+ .L(pos[j].x + dx1 + dx2, pos[j].y + dy1 + dy2)
2347
+ .L(pos[j].x + dx1, pos[j].y + dy1).Z()
2348
+ .insertInDocument();
2349
+ if (fill && stroke) {
2350
+ doc.fillAndStroke();
2351
+ } else if (fill) {
2352
+ doc.fill();
2353
+ } else if (stroke) {
2354
+ doc.stroke();
2355
+ }
2356
+ }
2357
+ }
2358
+ };
2359
+ };
2360
+
2361
+ var SvgElemTextNode = function(obj, inherits) {
2362
+ this.name = obj.nodeName;
2363
+ this.textContent = obj.nodeValue;
2364
+ };
2365
+
2366
+ var SvgElemTspan = function(obj, inherits) {
2367
+ SvgElemTextContainer.call(this, obj, inherits);
2368
+ };
2369
+
2370
+ var SvgElemTextPath = function(obj, inherits) {
2371
+ SvgElemTextContainer.call(this, obj, inherits);
2372
+ let pathObject, pathLength, temp;
2373
+ if ((temp = this.attr('path')) && temp.trim() !== '') {
2374
+ let pathLength = this.getLength('pathLength', this.getViewport());
2375
+ this.pathObject = new SvgShape().path(temp);
2376
+ this.pathLength = pathLength > 0 ? pathLength : this.pathObject.totalLength;
2377
+ this.pathScale = this.pathObject.totalLength / this.pathLength;
2378
+ } else if ((temp = this.getUrl('href') || this.getUrl('xlink:href')) && temp.nodeName === 'path') {
2379
+ let pathElem = new SvgElemPath(temp, this);
2380
+ this.pathObject = pathElem.shape.clone().transform(pathElem.get('transform'));
2381
+ this.pathLength = this.chooseValue(pathElem.pathLength, this.pathObject.totalLength);
2382
+ this.pathScale = this.pathObject.totalLength / this.pathLength;
2383
+ }
2384
+ };
2385
+
2386
+ var SvgElemText = function(obj, inherits) {
2387
+ SvgElemTextContainer.call(this, obj, inherits);
2388
+ this.allowedChildren = ['textPath', 'tspan', '#text', '#cdata-section', 'a'];
2389
+ (function (textParentElem) {
2390
+ let processedText = '', remainingText = obj.textContent, textPaths = [], currentChunk = [], currentAnchor, currentDirection, currentX = 0, currentY = 0;
2391
+ function doAnchoring() {
2392
+ if (currentChunk.length) {
2393
+ let last = currentChunk[currentChunk.length - 1];
2394
+ let first = currentChunk[0]
2395
+ let width = last.x + last.width - first.x;
2396
+ let anchordx = {'startltr': 0, 'middleltr': 0.5, 'endltr': 1, 'startrtl': 1, 'middlertl': 0.5, 'endrtl': 0}[currentAnchor + currentDirection] * width || 0;
2397
+ for (let i = 0; i < currentChunk.length; i++) {
2398
+ currentChunk[i].x -= anchordx;
2399
+ }
2400
+ }
2401
+ currentChunk = [];
2402
+ }
2403
+ function adjustLength(pos, length, spacingAndGlyphs) {
2404
+ let firstChar = pos[0], lastChar = pos[pos.length - 1],
2405
+ startX = firstChar.x, endX = lastChar.x + lastChar.width;
2406
+ if (spacingAndGlyphs) {
2407
+ let textScale = length / (endX - startX);
2408
+ if (textScale > 0 && textScale < Infinity) {
2409
+ for (let j = 0; j < pos.length; j++) {
2410
+ pos[j].continuous = false;
2411
+ pos[j].x = startX + textScale * (pos[j].x - startX);
2412
+ pos[j].scale *= textScale;
2413
+ pos[j].width *= textScale;
2414
+ }
2415
+ }
2416
+ } else {
2417
+ if (pos.length >= 2) {
2418
+ let spaceDiff = (length - (endX - startX)) / (pos.length - 1);
2419
+ for (let j = 0; j < pos.length; j++) {
2420
+ pos[j].continuous = false;
2421
+ pos[j].x += j * spaceDiff;
2422
+ }
2423
+ }
2424
+ }
2425
+ currentX += length - (endX - startX);
2426
+ }
2427
+ function recursive(currentElem, parentElem) {
2428
+ currentElem._x = combineArrays(currentElem.getLengthList('x', currentElem.getVWidth()), (parentElem ? parentElem._x.slice(parentElem._pos.length) : []));
2429
+ currentElem._y = combineArrays(currentElem.getLengthList('y', currentElem.getVHeight()), (parentElem ? parentElem._y.slice(parentElem._pos.length) : []));
2430
+ currentElem._dx = combineArrays(currentElem.getLengthList('dx', currentElem.getVWidth()), (parentElem ? parentElem._dx.slice(parentElem._pos.length) : []));
2431
+ currentElem._dy = combineArrays(currentElem.getLengthList('dy', currentElem.getVHeight()), (parentElem ? parentElem._dy.slice(parentElem._pos.length) : []));
2432
+ currentElem._rot = combineArrays(currentElem.getNumberList('rotate'), (parentElem ? parentElem._rot.slice(parentElem._pos.length) : []));
2433
+ currentElem._defRot = currentElem.chooseValue(currentElem._rot[currentElem._rot.length - 1], parentElem && parentElem._defRot, 0);
2434
+ if (currentElem.name === 'textPath') {currentElem._y = [];}
2435
+ let fontOptions = {fauxItalic: false, fauxBold: false},
2436
+ fontNameorLink = fontCallback(currentElem.get('font-family'), currentElem.get('font-weight') === 'bold', currentElem.get('font-style') === 'italic', fontOptions);
2437
+ try {
2438
+ doc.font(fontNameorLink);
2439
+ } catch(e) {
2440
+ warningCallback('SVGElemText: failed to open font "' + fontNameorLink + '" in PDFKit: ' + e.message);
2441
+ }
2442
+ currentElem._pos = [];
2443
+ currentElem._index = 0;
2444
+ currentElem._font = {font: doc._font, size: currentElem.get('font-size'), fauxItalic: fontOptions.fauxItalic, fauxBold: fontOptions.fauxBold};
2445
+ let textLength = currentElem.getLength('textLength', currentElem.getVWidth(), undefined),
2446
+ spacingAndGlyphs = currentElem.attr('lengthAdjust') === 'spacingAndGlyphs',
2447
+ wordSpacing = currentElem.get('word-spacing'),
2448
+ letterSpacing = currentElem.get('letter-spacing'),
2449
+ textAnchor = currentElem.get('text-anchor'),
2450
+ textDirection = currentElem.get('direction'),
2451
+ // `alignment-baseline` and `baseline-shift` have no effect on
2452
+ // `<text>` elements according to the SVG spec. So, detect when
2453
+ // we're styling a `<text>` element and ignore
2454
+ // `alignment-baseline` (only factoring in `dominant-baseline`)
2455
+ // and `baseline-shift` (which can only have the default value of
2456
+ // `baseline`).
2457
+ //
2458
+ // Note that Chrome (as of v99) incorrectly factors in
2459
+ // `alignment-baseline` on `<text>` elements, while Firefox
2460
+ // correctly follows the spec and ignores it. This means that our
2461
+ // output will differ from Chrome's in these cases, but conform to
2462
+ // SVG specification.
2463
+ isTextElem = currentElem.name === 'text',
2464
+ baselineAttr = isTextElem ? currentElem.get('dominant-baseline') : (currentElem.get('alignment-baseline') || currentElem.get('dominant-baseline')),
2465
+ baselineShiftAttr = isTextElem ? 'baseline' : currentElem.get('baseline-shift'),
2466
+ baseline = getBaseline(currentElem._font.font, currentElem._font.size, baselineAttr, baselineShiftAttr);
2467
+ if (currentElem.name === 'textPath') {
2468
+ doAnchoring();
2469
+ currentX = currentY = 0;
2470
+ }
2471
+ let children = currentElem.getChildren();
2472
+ for (let i = 0; i < children.length; i++) {
2473
+ let childElem = children[i];
2474
+ switch(childElem.name) {
2475
+ case 'tspan': case 'textPath': case 'a':
2476
+ recursive(childElem, currentElem);
2477
+ break;
2478
+ case '#text': case '#cdata-section':
2479
+ let rawText = childElem.textContent, renderedText = rawText, words;
2480
+ childElem._font = currentElem._font;
2481
+ childElem._pos = [];
2482
+ remainingText = remainingText.substring(rawText.length);
2483
+ if (currentElem.get('xml:space') === 'preserve') {
2484
+ renderedText = renderedText.replace(/[\s]/g, ' ');
2485
+ } else {
2486
+ renderedText = renderedText.replace(/[\s]+/g, ' ');
2487
+ if (processedText.match(/[\s]$|^$/)) {renderedText = renderedText.replace(/^[\s]/, '');}
2488
+ if (remainingText.match(/^[\s]*$/)) {renderedText = renderedText.replace(/[\s]$/, '');}
2489
+ }
2490
+ processedText += rawText;
2491
+ if (wordSpacing === 0) {
2492
+ words = [renderedText];
2493
+ } else {
2494
+ words = renderedText.split(/(\s)/);
2495
+ }
2496
+ for (let w = 0; w < words.length; w++) {
2497
+ let pos = getTextPos(currentElem._font.font, currentElem._font.size, words[w]);
2498
+ for (let j = 0; j < pos.length; j++) {
2499
+ let index = currentElem._index,
2500
+ xAttr = currentElem._x[index],
2501
+ yAttr = currentElem._y[index],
2502
+ dxAttr = currentElem._dx[index],
2503
+ dyAttr = currentElem._dy[index],
2504
+ rotAttr = currentElem._rot[index],
2505
+ continuous = !(w === 0 && j === 0);
2506
+ if (letterSpacing !== 0) {continuous = false}
2507
+ if (wordSpacing !== 0) {continuous = false}
2508
+ if (xAttr !== undefined) {continuous = false; doAnchoring(); currentX = xAttr;}
2509
+ if (yAttr !== undefined) {continuous = false; doAnchoring(); currentY = yAttr;}
2510
+ if (dxAttr !== undefined) {continuous = false; currentX += dxAttr;}
2511
+ if (dyAttr !== undefined) {continuous = false; currentY += dyAttr;}
2512
+ if (rotAttr !== undefined || currentElem._defRot !== 0) {continuous = false;}
2513
+ let position = {
2514
+ glyph: pos[j].glyph,
2515
+ rotate: (Math.PI / 180) * currentElem.chooseValue(rotAttr, currentElem._defRot),
2516
+ x: currentX + pos[j].xOffset,
2517
+ kern: pos[j].kern,
2518
+ y: currentY + baseline + pos[j].yOffset,
2519
+ width: pos[j].width,
2520
+ ascent: getAscent(currentElem._font.font, currentElem._font.size),
2521
+ descent: getDescent(currentElem._font.font, currentElem._font.size),
2522
+ scale: 1,
2523
+ hidden: false,
2524
+ continuous: continuous
2525
+ };
2526
+ currentChunk.push(position);
2527
+ childElem._pos.push(position);
2528
+ currentElem._pos.push(position);
2529
+ currentElem._index += pos[j].unicode.length;
2530
+ if (currentChunk.length === 1) {
2531
+ currentAnchor = textAnchor;
2532
+ currentDirection = textDirection;
2533
+ }
2534
+ currentX += pos[j].xAdvance + letterSpacing;
2535
+ currentY += pos[j].yAdvance;
2536
+ }
2537
+ if (words[w] === ' ') {
2538
+ currentX += wordSpacing;
2539
+ }
2540
+ }
2541
+ break;
2542
+ default:
2543
+ remainingText = remainingText.substring(childElem.textContent.length);
2544
+ }
2545
+ }
2546
+ if (textLength && currentElem._pos.length) {
2547
+ adjustLength(currentElem._pos, textLength, spacingAndGlyphs);
2548
+ }
2549
+ if (currentElem.name === 'textPath' || currentElem.name === 'text') {
2550
+ doAnchoring();
2551
+ }
2552
+ if (currentElem.name === 'textPath') {
2553
+ textPaths.push(currentElem);
2554
+ let pathObject = currentElem.pathObject;
2555
+ if (pathObject) {
2556
+ currentX = pathObject.endPoint[0]; currentY = pathObject.endPoint[1];
2557
+ }
2558
+ }
2559
+ if (parentElem) {
2560
+ parentElem._pos = parentElem._pos.concat(currentElem._pos);
2561
+ parentElem._index += currentElem._index;
2562
+ }
2563
+ }
2564
+ function textOnPath(currentElem) {
2565
+ let pathObject = currentElem.pathObject,
2566
+ pathLength = currentElem.pathLength,
2567
+ pathScale = currentElem.pathScale;
2568
+ if (pathObject) {
2569
+ let textOffset = currentElem.getLength('startOffset', pathLength, 0);
2570
+ for (let j = 0; j < currentElem._pos.length; j++) {
2571
+ let charMidX = textOffset + currentElem._pos[j].x + 0.5 * currentElem._pos[j].width;
2572
+ if (charMidX > pathLength || charMidX < 0) {
2573
+ currentElem._pos[j].hidden = true;
2574
+ } else {
2575
+ let pointOnPath = pathObject.getPointAtLength(charMidX * pathScale);
2576
+ if (isNotEqual(pathScale, 1)) {
2577
+ currentElem._pos[j].scale *= pathScale;
2578
+ currentElem._pos[j].width *= pathScale;
2579
+ }
2580
+ currentElem._pos[j].x = pointOnPath[0] - 0.5 * currentElem._pos[j].width * Math.cos(pointOnPath[2]) - currentElem._pos[j].y * Math.sin(pointOnPath[2]);
2581
+ currentElem._pos[j].y = pointOnPath[1] - 0.5 * currentElem._pos[j].width * Math.sin(pointOnPath[2]) + currentElem._pos[j].y * Math.cos(pointOnPath[2]);
2582
+ currentElem._pos[j].rotate = pointOnPath[2] + currentElem._pos[j].rotate;
2583
+ currentElem._pos[j].continuous = false;
2584
+ }
2585
+ }
2586
+ } else {
2587
+ for (let j = 0; j < currentElem._pos.length; j++) {
2588
+ currentElem._pos[j].hidden = true;
2589
+ }
2590
+ }
2591
+ }
2592
+ recursive(textParentElem, null);
2593
+ for (let i = 0; i < textPaths.length; i++) {
2594
+ textOnPath(textPaths[i]);
2595
+ }
2596
+ })(this);
2597
+ this.getTransformation = function() {
2598
+ return this.get('transform');
2599
+ };
2600
+ this.drawInDocument = function(isClip, isMask) {
2601
+ doc.save();
2602
+ this.transform();
2603
+ this.clip();
2604
+ let masked = this.mask(), group;
2605
+ if (masked) {
2606
+ group = docBeginGroup(getPageBBox());
2607
+ }
2608
+ this.drawTextInDocument(isClip, isMask);
2609
+ if (group) {
2610
+ docEndGroup(group);
2611
+ docInsertGroup(group);
2612
+ }
2613
+ doc.restore();
2614
+ };
2615
+ };
2616
+
2617
+ options = options || {};
2618
+ var pxToPt = options.assumePt ? 1 : (72/96), // 1px = 72/96pt, but only if assumePt is false
2619
+ viewportWidth = (options.width || doc.page.width) / pxToPt,
2620
+ viewportHeight = (options.height || doc.page.height) / pxToPt,
2621
+ preserveAspectRatio = options.preserveAspectRatio || null, // default to null so that the attr can override if not passed
2622
+ useCSS = options.useCSS && typeof SVGElement !== 'undefined' && svg instanceof SVGElement && typeof getComputedStyle === 'function',
2623
+ warningCallback = options.warningCallback,
2624
+ fontCallback = options.fontCallback,
2625
+ imageCallback = options.imageCallback,
2626
+ colorCallback = options.colorCallback,
2627
+ documentCallback = options.documentCallback,
2628
+ precision = Math.ceil(Math.max(1, options.precision)) || 3,
2629
+ groupStack = [],
2630
+ documentCache = {},
2631
+ links = [],
2632
+ styleRules = [];
2633
+
2634
+ if (typeof warningCallback !== 'function') {
2635
+ warningCallback = function(str) {
2636
+ if (typeof console !== undefined && typeof console.warn === 'function') {console.warn(str);}
2637
+ };
2638
+ }
2639
+ if (typeof fontCallback !== 'function') {
2640
+ fontCallback = function(family, bold, italic, fontOptions) {
2641
+ // Check if the font is already registered in the document
2642
+ if (bold && italic) {
2643
+ if (doc._registeredFonts.hasOwnProperty(family + '-BoldItalic')) {
2644
+ return family + '-BoldItalic';
2645
+ } else if (doc._registeredFonts.hasOwnProperty(family + '-Italic')) {
2646
+ fontOptions.fauxBold = true;
2647
+ return family + '-Italic';
2648
+ } else if (doc._registeredFonts.hasOwnProperty(family + '-Bold')) {
2649
+ fontOptions.fauxItalic = true;
2650
+ return family + '-Bold';
2651
+ } else if (doc._registeredFonts.hasOwnProperty(family)) {
2652
+ fontOptions.fauxBold = true;
2653
+ fontOptions.fauxItalic = true;
2654
+ return family;
2655
+ }
2656
+ }
2657
+ if (bold && !italic) {
2658
+ if (doc._registeredFonts.hasOwnProperty(family + '-Bold')) {
2659
+ return family + '-Bold';
2660
+ } else if (doc._registeredFonts.hasOwnProperty(family)) {
2661
+ fontOptions.fauxBold = true;
2662
+ return family;
2663
+ }
2664
+ }
2665
+ if (!bold && italic) {
2666
+ if (doc._registeredFonts.hasOwnProperty(family + '-Italic')) {
2667
+ return family + '-Italic';
2668
+ } else if (doc._registeredFonts.hasOwnProperty(family)) {
2669
+ fontOptions.fauxItalic = true;
2670
+ return family;
2671
+ }
2672
+ }
2673
+ if (!bold && !italic) {
2674
+ if (doc._registeredFonts.hasOwnProperty(family)) {
2675
+ return family;
2676
+ }
2677
+ }
2678
+ // Use standard fonts as fallback
2679
+ if (family.match(/(?:^|,)\s*serif\s*$/)) {
2680
+ if (bold && italic) {return 'Times-BoldItalic';}
2681
+ if (bold && !italic) {return 'Times-Bold';}
2682
+ if (!bold && italic) {return 'Times-Italic';}
2683
+ if (!bold && !italic) {return 'Times-Roman';}
2684
+ } else if (family.match(/(?:^|,)\s*monospace\s*$/)) {
2685
+ if (bold && italic) {return 'Courier-BoldOblique';}
2686
+ if (bold && !italic) {return 'Courier-Bold';}
2687
+ if (!bold && italic) {return 'Courier-Oblique';}
2688
+ if (!bold && !italic) {return 'Courier';}
2689
+ } else if (family.match(/(?:^|,)\s*sans-serif\s*$/) || true) {
2690
+ if (bold && italic) {return 'Helvetica-BoldOblique';}
2691
+ if (bold && !italic) {return 'Helvetica-Bold';}
2692
+ if (!bold && italic) {return 'Helvetica-Oblique';}
2693
+ if (!bold && !italic) {return 'Helvetica';}
2694
+ }
2695
+ };
2696
+ }
2697
+ if (typeof imageCallback !== 'function') {
2698
+ imageCallback = function(link) {
2699
+ return link.replace(/\s+/g, '');
2700
+ };
2701
+ }
2702
+ if (typeof colorCallback !== 'function') {
2703
+ colorCallback = null;
2704
+ } else {
2705
+ for (let color in DefaultColors) {
2706
+ let newColor = colorCallback(DefaultColors[color]);
2707
+ DefaultColors[color][0] = newColor[0];
2708
+ DefaultColors[color][1] = newColor[1];
2709
+ }
2710
+ }
2711
+ if (typeof documentCallback !== 'function') {
2712
+ documentCallback = null;
2713
+ }
2714
+
2715
+ if (typeof svg === 'string') {svg = parseXml(svg);}
2716
+ if (svg) {
2717
+ let styles = svg.getElementsByTagName('style');
2718
+ for (let i = 0; i < styles.length; i++) {
2719
+ styleRules = styleRules.concat(parseStyleSheet(styles[i].textContent));
2720
+ }
2721
+ let elem = createSVGElement(svg, null);
2722
+ if (typeof elem.drawInDocument === 'function') {
2723
+ if (options.useCSS && !useCSS) {
2724
+ warningCallback('SVGtoPDF: useCSS option can only be used for SVG *elements* in compatible browsers');
2725
+ }
2726
+ let savedFillColor = doc._fillColor;
2727
+ doc.save().translate(x || 0, y || 0).scale(pxToPt);
2728
+ elem.drawInDocument();
2729
+ for (let i = 0; i < links.length; i++) {
2730
+ doc.page.annotations.push(links[i]);
2731
+ }
2732
+ doc.restore();
2733
+ doc._fillColor = savedFillColor;
2734
+ } else {
2735
+ warningCallback('SVGtoPDF: this element can\'t be rendered directly: ' + svg.nodeName);
2736
+ }
2737
+ } else {
2738
+ warningCallback('SVGtoPDF: the input does not look like a valid SVG');
2739
+ }
2740
+
2741
+ };
2742
+
2743
+ if (typeof module !== 'undefined' && module && typeof module.exports !== 'undefined') {
2744
+ module.exports = SVGtoPDF;
2745
+ }