pdfmake 0.2.1 → 0.3.0-beta.1

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 (130) hide show
  1. package/CHANGELOG.md +8 -14
  2. package/README.md +8 -6
  3. package/build/pdfmake.js +31416 -28217
  4. package/build/pdfmake.js.map +1 -1
  5. package/build/pdfmake.min.js +2 -2
  6. package/build/pdfmake.min.js.map +1 -1
  7. package/build/standard-fonts/Courier.js +27 -0
  8. package/build/standard-fonts/Helvetica.js +27 -0
  9. package/build/standard-fonts/Symbol.js +21 -0
  10. package/build/standard-fonts/Times.js +27 -0
  11. package/build/standard-fonts/ZapfDingbats.js +21 -0
  12. package/build/vfs_fonts.js +2 -2
  13. package/build-vfs.js +3 -3
  14. package/fonts/Roboto/Roboto-Italic.ttf +0 -0
  15. package/fonts/Roboto/Roboto-Medium.ttf +0 -0
  16. package/fonts/Roboto/Roboto-MediumItalic.ttf +0 -0
  17. package/fonts/Roboto/Roboto-Regular.ttf +0 -0
  18. package/fonts/Roboto.js +8 -0
  19. package/js/3rd-party/svg-to-pdfkit/source.js +4301 -0
  20. package/js/3rd-party/svg-to-pdfkit.js +11 -0
  21. package/js/DocMeasure.js +750 -0
  22. package/js/DocPreprocessor.js +285 -0
  23. package/js/DocumentContext.js +306 -0
  24. package/js/ElementWriter.js +377 -0
  25. package/js/LayoutBuilder.js +833 -0
  26. package/js/Line.js +125 -0
  27. package/js/OutputDocument.js +86 -0
  28. package/js/OutputDocumentServer.js +34 -0
  29. package/js/PDFDocument.js +163 -0
  30. package/js/PageElementWriter.js +161 -0
  31. package/js/PageSize.js +88 -0
  32. package/js/Printer.js +238 -0
  33. package/js/Renderer.js +433 -0
  34. package/js/SVGMeasure.js +89 -0
  35. package/js/StyleContextStack.js +206 -0
  36. package/js/TableProcessor.js +590 -0
  37. package/js/TextBreaker.js +182 -0
  38. package/js/TextDecorator.js +181 -0
  39. package/js/TextInlines.js +248 -0
  40. package/js/URLResolver.js +79 -0
  41. package/js/base.js +69 -0
  42. package/js/browser-extensions/OutputDocumentBrowser.js +131 -0
  43. package/js/browser-extensions/URLBrowserResolver.js +89 -0
  44. package/js/browser-extensions/fonts/Roboto.js +42 -0
  45. package/js/browser-extensions/index.js +70 -0
  46. package/js/browser-extensions/pdfMake.js +17 -0
  47. package/js/browser-extensions/standard-fonts/Courier.js +42 -0
  48. package/js/browser-extensions/standard-fonts/Helvetica.js +42 -0
  49. package/js/browser-extensions/standard-fonts/Symbol.js +27 -0
  50. package/js/browser-extensions/standard-fonts/Times.js +42 -0
  51. package/js/browser-extensions/standard-fonts/ZapfDingbats.js +27 -0
  52. package/js/browser-extensions/virtual-fs-cjs.js +3 -0
  53. package/js/columnCalculator.js +142 -0
  54. package/js/helpers/node.js +122 -0
  55. package/js/helpers/tools.js +48 -0
  56. package/js/helpers/variableType.js +52 -0
  57. package/js/index.js +21 -0
  58. package/js/qrEnc.js +810 -0
  59. package/js/standardPageSizes.js +57 -0
  60. package/js/tableLayouts.js +127 -0
  61. package/js/virtual-fs.js +77 -0
  62. package/package.json +31 -25
  63. package/src/3rd-party/svg-to-pdfkit/LICENSE +9 -0
  64. package/src/3rd-party/svg-to-pdfkit/source.js +2552 -0
  65. package/src/3rd-party/svg-to-pdfkit.js +3 -0
  66. package/src/DocMeasure.js +694 -0
  67. package/src/DocPreprocessor.js +258 -0
  68. package/src/DocumentContext.js +309 -0
  69. package/src/ElementWriter.js +368 -0
  70. package/src/LayoutBuilder.js +814 -0
  71. package/src/Line.js +114 -0
  72. package/src/OutputDocument.js +78 -0
  73. package/src/OutputDocumentServer.js +26 -0
  74. package/src/PDFDocument.js +148 -0
  75. package/src/PageElementWriter.js +156 -0
  76. package/src/PageSize.js +53 -0
  77. package/src/Printer.js +220 -0
  78. package/src/Renderer.js +370 -0
  79. package/src/SVGMeasure.js +79 -0
  80. package/src/StyleContextStack.js +216 -0
  81. package/src/TableProcessor.js +558 -0
  82. package/src/TextBreaker.js +149 -0
  83. package/src/TextDecorator.js +161 -0
  84. package/src/TextInlines.js +223 -0
  85. package/src/URLResolver.js +69 -0
  86. package/src/base.js +61 -0
  87. package/src/browser-extensions/OutputDocumentBrowser.js +117 -0
  88. package/src/browser-extensions/URLBrowserResolver.js +46 -53
  89. package/src/browser-extensions/fonts/Roboto.js +27 -0
  90. package/src/browser-extensions/index.js +55 -0
  91. package/src/browser-extensions/pdfMake.js +10 -287
  92. package/src/browser-extensions/standard-fonts/Courier.js +27 -0
  93. package/src/browser-extensions/standard-fonts/Helvetica.js +27 -0
  94. package/src/browser-extensions/standard-fonts/Symbol.js +21 -0
  95. package/src/browser-extensions/standard-fonts/Times.js +27 -0
  96. package/src/browser-extensions/standard-fonts/ZapfDingbats.js +21 -0
  97. package/src/browser-extensions/virtual-fs-cjs.js +1 -0
  98. package/src/columnCalculator.js +29 -32
  99. package/src/helpers/node.js +110 -0
  100. package/src/helpers/tools.js +39 -0
  101. package/src/helpers/variableType.js +39 -0
  102. package/src/index.js +16 -0
  103. package/src/qrEnc.js +15 -10
  104. package/src/standardPageSizes.js +1 -3
  105. package/src/tableLayouts.js +100 -0
  106. package/src/virtual-fs.js +66 -0
  107. package/standard-fonts/Courier.js +8 -0
  108. package/standard-fonts/Helvetica.js +9 -0
  109. package/standard-fonts/Symbol.js +5 -0
  110. package/standard-fonts/Times.js +8 -0
  111. package/standard-fonts/ZapfDingbats.js +5 -0
  112. package/src/browser-extensions/virtual-fs.js +0 -55
  113. package/src/docMeasure.js +0 -807
  114. package/src/docPreprocessor.js +0 -255
  115. package/src/documentContext.js +0 -314
  116. package/src/elementWriter.js +0 -322
  117. package/src/fontProvider.js +0 -68
  118. package/src/helpers.js +0 -113
  119. package/src/imageMeasure.js +0 -51
  120. package/src/layoutBuilder.js +0 -807
  121. package/src/line.js +0 -91
  122. package/src/pageElementWriter.js +0 -174
  123. package/src/pdfKitEngine.js +0 -21
  124. package/src/printer.js +0 -685
  125. package/src/styleContextStack.js +0 -179
  126. package/src/svgMeasure.js +0 -70
  127. package/src/tableProcessor.js +0 -542
  128. package/src/textDecorator.js +0 -151
  129. package/src/textTools.js +0 -373
  130. package/src/traversalTracker.js +0 -47
@@ -0,0 +1,2552 @@
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
+ };
65
+
66
+ function docBeginGroup(bbox) {
67
+ let group = new (function PDFGroup() {})();
68
+ group.name = 'G' + (doc._groupCount = (doc._groupCount || 0) + 1);
69
+ group.resources = doc.ref();
70
+ group.xobj = doc.ref({
71
+ Type: 'XObject',
72
+ Subtype: 'Form',
73
+ FormType: 1,
74
+ BBox: bbox,
75
+ Group: {S: 'Transparency', CS: 'DeviceRGB', I: true, K: false},
76
+ Resources: group.resources
77
+ });
78
+ group.xobj.write('');
79
+ group.savedMatrix = doc._ctm;
80
+ group.savedPage = doc.page;
81
+ groupStack.push(group);
82
+ doc._ctm = [1, 0, 0, 1, 0, 0];
83
+ doc.page = {
84
+ width: doc.page.width, height: doc.page.height,
85
+ write: function(data) {group.xobj.write(data);},
86
+ fonts: {}, xobjects: {}, ext_gstates: {}, patterns: {}
87
+ };
88
+ return group;
89
+ }
90
+ function docEndGroup(group) {
91
+ if (group !== groupStack.pop()) {throw('Group not matching');}
92
+ if (Object.keys(doc.page.fonts).length) {group.resources.data.Font = doc.page.fonts;}
93
+ if (Object.keys(doc.page.xobjects).length) {group.resources.data.XObject = doc.page.xobjects;}
94
+ if (Object.keys(doc.page.ext_gstates).length) {group.resources.data.ExtGState = doc.page.ext_gstates;}
95
+ if (Object.keys(doc.page.patterns).length) {group.resources.data.Pattern = doc.page.patterns;}
96
+ group.resources.end();
97
+ group.xobj.end();
98
+ doc._ctm = group.savedMatrix;
99
+ doc.page = group.savedPage;
100
+ }
101
+ function docInsertGroup(group) {
102
+ doc.page.xobjects[group.name] = group.xobj;
103
+ doc.addContent('/' + group.name + ' Do');
104
+ }
105
+ function docApplyMask(group, clip) {
106
+ let name = 'M' + (doc._maskCount = (doc._maskCount || 0) + 1);
107
+ let gstate = doc.ref({
108
+ Type: 'ExtGState', CA: 1, ca: 1, BM: 'Normal',
109
+ SMask: {S: 'Luminosity', G: group.xobj, BC: (clip ? [0, 0, 0] : [1, 1, 1])}
110
+ });
111
+ gstate.end();
112
+ doc.page.ext_gstates[name] = gstate;
113
+ doc.addContent('/' + name + ' gs');
114
+ }
115
+ function docCreatePattern(group, dx, dy, matrix) {
116
+ let pattern = new (function PDFPattern() {})();
117
+ pattern.group = group;
118
+ pattern.dx = dx;
119
+ pattern.dy = dy;
120
+ pattern.matrix = matrix || [1, 0, 0, 1, 0, 0];
121
+ return pattern;
122
+ }
123
+ function docUsePattern(pattern, stroke) {
124
+ let name = 'P' + (doc._patternCount = (doc._patternCount || 0) + 1);
125
+ let ref = doc.ref({
126
+ Type: 'Pattern', PatternType: 1, PaintType: 1, TilingType: 2,
127
+ BBox: [0, 0, pattern.dx, pattern.dy], XStep: pattern.dx, YStep: pattern.dy,
128
+ Matrix: multiplyMatrix(doc._ctm, pattern.matrix),
129
+ Resources: {
130
+ ProcSet: ['PDF', 'Text', 'ImageB', 'ImageC', 'ImageI'],
131
+ XObject: (function() {let temp = {}; temp[pattern.group.name] = pattern.group.xobj; return temp;})()
132
+ }
133
+ });
134
+ ref.write('/' + pattern.group.name + ' Do');
135
+ ref.end();
136
+ doc.page.patterns[name] = ref;
137
+ if (stroke) {
138
+ doc.addContent('/Pattern CS');
139
+ doc.addContent('/' + name + ' SCN');
140
+ } else {
141
+ doc.addContent('/Pattern cs');
142
+ doc.addContent('/' + name + ' scn');
143
+ }
144
+ }
145
+ function docBeginText(font, size) {
146
+ if (!doc.page.fonts[font.id]) {doc.page.fonts[font.id] = font.ref();}
147
+ doc.addContent('BT').addContent('/' + font.id + ' ' + size + ' Tf');
148
+ }
149
+ function docSetTextMatrix(a, b, c, d, e, f) {
150
+ doc.addContent(validateNumber(a) + ' ' + validateNumber(b) + ' ' + validateNumber(-c) + ' ' + validateNumber(-d) + ' ' + validateNumber(e) + ' ' + validateNumber(f) + ' Tm');
151
+ }
152
+ function docSetTextMode(fill, stroke) {
153
+ let mode = fill && stroke ? 2 : stroke ? 1 : fill ? 0 : 3;
154
+ doc.addContent(mode + ' Tr');
155
+ }
156
+ function docWriteGlyph(glyph) {
157
+ doc.addContent('<' + glyph + '> Tj');
158
+ }
159
+ function docEndText() {
160
+ doc.addContent('ET');
161
+ }
162
+ function docFillColor(color) {
163
+ if (color[0].constructor.name === 'PDFPattern') {
164
+ doc.fillOpacity(color[1]);
165
+ docUsePattern(color[0], false);
166
+ } else {
167
+ doc.fillColor(color[0], color[1]);
168
+ }
169
+ }
170
+ function docStrokeColor(color) {
171
+ if (color[0].constructor.name === 'PDFPattern') {
172
+ doc.strokeOpacity(color[1]);
173
+ docUsePattern(color[0], true);
174
+ } else {
175
+ doc.strokeColor(color[0], color[1]);
176
+ }
177
+ }
178
+ function docInsertLink(x, y, w, h, url) {
179
+ let ref = doc.ref({
180
+ Type: 'Annot',
181
+ Subtype: 'Link',
182
+ Rect: [x, y, w, h],
183
+ Border: [0, 0, 0],
184
+ A: {
185
+ S: 'URI',
186
+ URI: new String(url)
187
+ }
188
+ });
189
+ ref.end();
190
+ links.push(ref);
191
+ }
192
+ function parseXml(xml) {
193
+ let SvgNode = function(tag, type, value, error) {
194
+ this.error = error;
195
+ this.nodeName = tag;
196
+ this.nodeValue = value;
197
+ this.nodeType = type;
198
+ this.attributes = Object.create(null);
199
+ this.childNodes = [];
200
+ this.parentNode = null;
201
+ this.id = '';
202
+ this.textContent = '';
203
+ this.classList = [];
204
+ };
205
+ SvgNode.prototype.getAttribute = function(attr) {
206
+ return this.attributes[attr] != null ? this.attributes[attr] : null;
207
+ };
208
+ SvgNode.prototype.getElementById = function(id) {
209
+ let result = null;
210
+ (function recursive(node) {
211
+ if (result) {return;}
212
+ if (node.nodeType === 1) {
213
+ if (node.id === id) {result = node;}
214
+ for (let i = 0; i < node.childNodes.length; i++) {
215
+ recursive(node.childNodes[i]);
216
+ }
217
+ }
218
+ })(this);
219
+ return result;
220
+ };
221
+ SvgNode.prototype.getElementsByTagName = function(tag) {
222
+ let result = [];
223
+ (function recursive(node) {
224
+ if (node.nodeType === 1) {
225
+ if (node.nodeName === tag) {result.push(node);}
226
+ for (let i = 0; i < node.childNodes.length; i++) {
227
+ recursive(node.childNodes[i]);
228
+ }
229
+ }
230
+ })(this);
231
+ return result;
232
+ };
233
+ let parser = new StringParser(xml.trim()), result, child, error = false;
234
+ let recursive = function() {
235
+ let temp, child;
236
+ if (temp = parser.match(/^<([\w:.-]+)\s*/, true)) { // Opening tag
237
+ let node = new SvgNode(temp[1], 1, null, error);
238
+ while (temp = parser.match(/^([\w:.-]+)(?:\s*=\s*"([^"]*)"|\s*=\s*'([^']*)')?\s*/, true)) { // Attribute
239
+ let attr = temp[1], value = decodeEntities(temp[2] || temp[3] || '');
240
+ if (!node.attributes[attr]) {
241
+ node.attributes[attr] = value;
242
+ if (attr === 'id') {node.id = value;}
243
+ if (attr === 'class') {node.classList = value.split(' ');}
244
+ } else {
245
+ warningCallback('parseXml: duplicate attribute "' + attr + '"');
246
+ error = true;
247
+ }
248
+ }
249
+ if (parser.match(/^>/)) { // End of opening tag
250
+ while (child = recursive()) {
251
+ node.childNodes.push(child);
252
+ child.parentNode = node;
253
+ node.textContent += (child.nodeType === 3 || child.nodeType === 4 ? child.nodeValue : child.textContent);
254
+ }
255
+ if (temp = parser.match(/^<\/([\w:.-]+)\s*>/, true)) { // Closing tag
256
+ if (temp[1] === node.nodeName) {
257
+ return node;
258
+ } else {
259
+ warningCallback('parseXml: tag not matching, opening "' + node.nodeName + '" & closing "' + temp[1] + '"');
260
+ error = true;
261
+ return node;
262
+ }
263
+ } else {
264
+ warningCallback('parseXml: tag not matching, opening "' + node.nodeName + '" & not closing');
265
+ error = true;
266
+ return node;
267
+ }
268
+ } else if (parser.match(/^\/>/)) { // Self-closing tag
269
+ return node;
270
+ } else {
271
+ warningCallback('parseXml: tag could not be parsed "' + node.nodeName + '"');
272
+ error = true;
273
+ }
274
+ } else if (temp = parser.match(/^<!--[\s\S]*?-->/)) { // Comment
275
+ return new SvgNode(null, 8, temp, error);
276
+ } else if (temp = parser.match(/^<\?[\s\S]*?\?>/)) { // Processing instructions
277
+ return new SvgNode(null, 7, temp, error);
278
+ } else if (temp = parser.match(/^<!DOCTYPE\s*([\s\S]*?)>/)) { // Doctype
279
+ return new SvgNode(null, 10, temp, error);
280
+ } else if (temp = parser.match(/^<!\[CDATA\[([\s\S]*?)\]\]>/, true)) { // Cdata node
281
+ return new SvgNode('#cdata-section', 4, temp[1], error);
282
+ } else if (temp = parser.match(/^([^<]+)/, true)) { // Text node
283
+ return new SvgNode('#text', 3, decodeEntities(temp[1]), error);
284
+ }
285
+ };
286
+ while (child = recursive()) {
287
+ if (child.nodeType === 1 && !result) {
288
+ result = child;
289
+ } else if (child.nodeType === 1 || (child.nodeType === 3 && child.nodeValue.trim() !== '')) {
290
+ warningCallback('parseXml: data after document end has been discarded');
291
+ }
292
+ }
293
+ if (parser.matchAll()) {
294
+ warningCallback('parseXml: parsing error');
295
+ }
296
+ return result;
297
+ };
298
+ function decodeEntities(str) {
299
+ return(str.replace(/&(?:#([0-9]+)|#[xX]([0-9A-Fa-f]+)|([0-9A-Za-z]+));/g, function(mt, m0, m1, m2) {
300
+ if (m0) {return String.fromCharCode(parseInt(m0, 10));}
301
+ else if (m1) {return String.fromCharCode(parseInt(m1, 16));}
302
+ else if (m2 && Entities[m2]) {return String.fromCharCode(Entities[m2]);}
303
+ else {return mt;}
304
+ }));
305
+ }
306
+ function parseColor(raw) {
307
+ let temp, result;
308
+ raw = (raw || '').trim();
309
+ if (temp = NamedColors[raw]) {
310
+ result = [temp.slice(), 1];
311
+ } else if (temp = raw.match(/^rgba\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9.]+)\s*\)$/i)) {
312
+ temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]); temp[4] = parseFloat(temp[4]);
313
+ if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256 && temp[4] <= 1) {
314
+ result = [temp.slice(1, 4), temp[4]];
315
+ }
316
+ } else if (temp = raw.match(/^rgb\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)$/i)) {
317
+ temp[1] = parseInt(temp[1]); temp[2] = parseInt(temp[2]); temp[3] = parseInt(temp[3]);
318
+ if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256) {
319
+ result = [temp.slice(1, 4), 1];
320
+ }
321
+ } else if (temp = raw.match(/^rgb\(\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*,\s*([0-9.]+)%\s*\)$/i)) {
322
+ temp[1] = 2.55 * parseFloat(temp[1]); temp[2] = 2.55 * parseFloat(temp[2]); temp[3] = 2.55 * parseFloat(temp[3]);
323
+ if (temp[1] < 256 && temp[2] < 256 && temp[3] < 256) {
324
+ result = [temp.slice(1, 4), 1];
325
+ }
326
+ } else if (temp = raw.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i)) {
327
+ result = [[parseInt(temp[1], 16), parseInt(temp[2], 16), parseInt(temp[3], 16)], 1];
328
+ } else if (temp = raw.match(/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i)) {
329
+ result = [[0x11 * parseInt(temp[1], 16), 0x11 * parseInt(temp[2], 16), 0x11 * parseInt(temp[3], 16)], 1];
330
+ }
331
+ return colorCallback ? colorCallback(result, raw) : result;
332
+ }
333
+ function opacityToColor(color, opacity, isMask) {
334
+ let newColor = color[0].slice(),
335
+ newOpacity = color[1] * opacity;
336
+ if (isMask) {
337
+ for (let i = 0; i < color.length; i++) {
338
+ newColor[i] *= newOpacity;
339
+ }
340
+ return [newColor, 1];
341
+ } else {
342
+ return [newColor, newOpacity];
343
+ }
344
+ }
345
+ function multiplyMatrix() {
346
+ function multiply(a, b) {
347
+ 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],
348
+ 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] ];
349
+ }
350
+ let result = arguments[0];
351
+ for (let i = 1; i < arguments.length; i++) {
352
+ result = multiply(result, arguments[i]);
353
+ }
354
+ return result;
355
+ }
356
+ function transformPoint(p, m) {
357
+ return [m[0] * p[0] + m[2] * p[1] + m[4], m[1] * p[0] + m[3] * p[1] + m[5]];
358
+ }
359
+ function getGlobalMatrix() {
360
+ let ctm = doc._ctm;
361
+ for (let i = groupStack.length - 1; i >= 0; i--) {
362
+ ctm = multiplyMatrix(groupStack[i].savedMatrix, ctm);
363
+ }
364
+ return ctm;
365
+ }
366
+ function getPageBBox() {
367
+ return new SvgShape().M(0, 0).L(doc.page.width, 0).L(doc.page.width, doc.page.height).L(0, doc.page.height)
368
+ .transform(inverseMatrix(getGlobalMatrix())).getBoundingBox();
369
+ }
370
+ function inverseMatrix(m) {
371
+ let dt = m[0] * m[3] - m[1] * m[2];
372
+ 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];
373
+ }
374
+ function validateMatrix(m) {
375
+ let m0 = validateNumber(m[0]), m1 = validateNumber(m[1]), m2 = validateNumber(m[2]),
376
+ m3 = validateNumber(m[3]), m4 = validateNumber(m[4]), m5 = validateNumber(m[5]);
377
+ if (isNotEqual(m0 * m3 - m1 * m2, 0)) {
378
+ return [m0, m1, m2, m3, m4, m5];
379
+ }
380
+ }
381
+ function solveEquation(curve) {
382
+ let a = curve[2] || 0, b = curve[1] || 0, c = curve[0] || 0;
383
+ if (isEqual(a, 0) && isEqual(b, 0)) {
384
+ return [];
385
+ } else if (isEqual(a, 0)) {
386
+ return [(-c) / b];
387
+ } else {
388
+ let d = b * b - 4 * a * c;
389
+ if (isNotEqual(d, 0) && d > 0) {
390
+ return [(-b + Math.sqrt(d)) / (2 * a), (-b - Math.sqrt(d)) / (2 * a)];
391
+ } else if (isEqual(d, 0)) {
392
+ return [(-b) / (2 * a)];
393
+ } else {
394
+ return [];
395
+ }
396
+ }
397
+ }
398
+ function getCurveValue(t, curve) {
399
+ return (curve[0] || 0) + (curve[1] || 0) * t + (curve[2] || 0) * t * t + (curve[3] || 0) * t * t * t;
400
+ }
401
+ function isEqual(number, ref) {
402
+ return Math.abs(number - ref) < 1e-10;
403
+ }
404
+ function isNotEqual(number, ref) {
405
+ return Math.abs(number - ref) >= 1e-10;
406
+ }
407
+ function validateNumber(n) {
408
+ return n > -1e21 && n < 1e21 ? Math.round(n * 1e6) / 1e6 : 0;
409
+ }
410
+ function isArrayLike(v) {
411
+ return typeof v === 'object' && v !== null && typeof v.length === 'number';
412
+ }
413
+ function parseTranform(v) {
414
+ let parser = new StringParser((v || '').trim()), result = [1, 0, 0, 1, 0, 0], temp;
415
+ while (temp = parser.match(/^([A-Za-z]+)\s*[(]([^(]+)[)]/, true)) {
416
+ let func = temp[1], nums = [], parser2 = new StringParser(temp[2].trim()), temp2;
417
+ while (temp2 = parser2.matchNumber()) {
418
+ nums.push(Number(temp2));
419
+ parser2.matchSeparator();
420
+ }
421
+ if (func === 'matrix' && nums.length === 6) {
422
+ result = multiplyMatrix(result, [nums[0], nums[1], nums[2], nums[3], nums[4], nums[5]]);
423
+ } else if (func === 'translate' && nums.length === 2) {
424
+ result = multiplyMatrix(result, [1, 0, 0, 1, nums[0], nums[1]]);
425
+ } else if (func === 'translate' && nums.length === 1) {
426
+ result = multiplyMatrix(result, [1, 0, 0, 1, nums[0], 0]);
427
+ } else if (func === 'scale' && nums.length === 2) {
428
+ result = multiplyMatrix(result, [nums[0], 0, 0, nums[1], 0, 0]);
429
+ } else if (func === 'scale' && nums.length === 1) {
430
+ result = multiplyMatrix(result, [nums[0], 0, 0, nums[0], 0, 0]);
431
+ } else if (func === 'rotate' && nums.length === 3) {
432
+ let a = nums[0] * Math.PI / 180;
433
+ 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]]);
434
+ } else if (func === 'rotate' && nums.length === 1) {
435
+ let a = nums[0] * Math.PI / 180;
436
+ result = multiplyMatrix(result, [Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]);
437
+ } else if (func === 'skewX' && nums.length === 1) {
438
+ let a = nums[0] * Math.PI / 180;
439
+ result = multiplyMatrix(result, [1, 0, Math.tan(a), 1, 0, 0]);
440
+ } else if (func === 'skewY' && nums.length === 1) {
441
+ let a = nums[0] * Math.PI / 180;
442
+ result = multiplyMatrix(result, [1, Math.tan(a), 0, 1, 0, 0]);
443
+ } else {return;}
444
+ parser.matchSeparator();
445
+ }
446
+ if (parser.matchAll()) {return;}
447
+ return result;
448
+ }
449
+ function parseAspectRatio(aspectRatio, availWidth, availHeight, elemWidth, elemHeight, initAlign) {
450
+ let temp = (aspectRatio || '').trim().match(/^(none)$|^x(Min|Mid|Max)Y(Min|Mid|Max)(?:\s+(meet|slice))?$/) || [],
451
+ ratioType = temp[1] || temp[4] || 'meet',
452
+ xAlign = temp[2] || 'Mid',
453
+ yAlign = temp[3] || 'Mid',
454
+ scaleX = availWidth / elemWidth,
455
+ scaleY = availHeight / elemHeight,
456
+ dx = {'Min':0, 'Mid':0.5, 'Max':1}[xAlign] - (initAlign || 0),
457
+ dy = {'Min':0, 'Mid':0.5, 'Max':1}[yAlign] - (initAlign || 0);
458
+ if (ratioType === 'slice') {
459
+ scaleY = scaleX = Math.max(scaleX, scaleY);
460
+ } else if (ratioType === 'meet') {
461
+ scaleY = scaleX = Math.min(scaleX, scaleY);
462
+ }
463
+ return [scaleX, 0, 0, scaleY, dx * (availWidth - elemWidth * scaleX), dy * (availHeight - elemHeight * scaleY)];
464
+ }
465
+ function parseStyleAttr(v) {
466
+ let result = Object.create(null);
467
+ v = (v || '').trim().split(/;/);
468
+ for (let i = 0; i < v.length; i++) {
469
+ let key = (v[i].split(':')[0] || '').trim(),
470
+ value = (v[i].split(':')[1] || '').trim();
471
+ if (key) {
472
+ result[key] = value;
473
+ }
474
+ }
475
+ if (result['marker']) {
476
+ if (!result['marker-start']) {result['marker-start'] = result['marker'];}
477
+ if (!result['marker-mid']) {result['marker-mid'] = result['marker'];}
478
+ if (!result['marker-end']) {result['marker-end'] = result['marker'];}
479
+ }
480
+ if (result['font']) {
481
+ let fontFamily = null, fontSize = null, fontStyle = "normal", fontWeight = "normal", fontVariant = "normal";
482
+ let parts = result['font'].split(/\s+/);
483
+ for (let i = 0; i < parts.length; i++) {
484
+ switch (parts[i]) {
485
+ case "normal":
486
+ break;
487
+ case "italic": case "oblique":
488
+ fontStyle = parts[i];
489
+ break;
490
+ case "small-caps":
491
+ fontVariant = parts[i];
492
+ break;
493
+ case "bold": case "bolder": case "lighter": case "100": case "200": case "300":
494
+ case "400": case "500": case "600": case "700": case "800": case "900":
495
+ fontWeight = parts[i];
496
+ break;
497
+ default:
498
+ if (!fontSize) {
499
+ fontSize = parts[i].split('/')[0];
500
+ } else {
501
+ if (!fontFamily) {
502
+ fontFamily = parts[i];
503
+ } else {
504
+ fontFamily += ' ' + parts[i];
505
+ }
506
+ }
507
+ break;
508
+ }
509
+ }
510
+ if (!result['font-style']) {result['font-style'] = fontStyle;}
511
+ if (!result['font-variant']) {result['font-variant'] = fontVariant;}
512
+ if (!result['font-weight']) {result['font-weight'] = fontWeight;}
513
+ if (!result['font-size']) {result['font-size'] = fontSize;}
514
+ if (!result['font-family']) {result['font-family'] = fontFamily;}
515
+ }
516
+ return result;
517
+ }
518
+ function parseSelector(v) {
519
+ let parts = v.split(/(?=[.#])/g), ids = [], classes = [], tags = [], temp;
520
+ for (let i = 0; i < parts.length; i++) {
521
+ if (temp = parts[i].match(/^[#]([_A-Za-z0-9-]+)$/)) {
522
+ ids.push(temp[1]);
523
+ } else if (temp = parts[i].match(/^[.]([_A-Za-z0-9-]+)$/)) {
524
+ classes.push(temp[1]);
525
+ } else if (temp = parts[i].match(/^([_A-Za-z0-9-]+)$/)) {
526
+ tags.push(temp[1]);
527
+ } else if (parts[i] !== '*') {
528
+ return;
529
+ }
530
+ }
531
+ return {
532
+ tags: tags, ids: ids, classes: classes,
533
+ specificity: ids.length * 10000 + classes.length * 100 + tags.length
534
+ };
535
+ }
536
+ function parseStyleSheet(v) {
537
+ let parser = new StringParser(v.trim()), rules = [], rule;
538
+ while (rule = parser.match(/^\s*([^\{\}]*?)\s*\{([^\{\}]*?)\}/, true)) {
539
+ let selectors = rule[1].split(/\s*,\s*/g),
540
+ css = parseStyleAttr(rule[2]);
541
+ for (let i = 0; i < selectors.length; i++) {
542
+ let selector = parseSelector(selectors[i]);
543
+ if (selector) {
544
+ rules.push({selector: selector, css:css});
545
+ }
546
+ }
547
+ }
548
+ return rules;
549
+ }
550
+ function matchesSelector(elem, selector) {
551
+ if (elem.nodeType !== 1) {return false;}
552
+ for (let i = 0; i < selector.tags.length; i++) {
553
+ if (selector.tags[i] !== elem.nodeName) {return false;}
554
+ }
555
+ for (let i = 0; i < selector.ids.length; i++) {
556
+ if (selector.ids[i] !== elem.id) {return false;}
557
+ }
558
+ for (let i = 0; i < selector.classes.length; i++) {
559
+ if (elem.classList.indexOf(selector.classes[i]) === -1) {return false;}
560
+ }
561
+ return true;
562
+ }
563
+ function getStyle(elem) {
564
+ let result = Object.create(null);
565
+ let specificities = Object.create(null);
566
+ for (let i = 0; i < styleRules.length; i++) {
567
+ let rule = styleRules[i];
568
+ if (matchesSelector(elem, rule.selector)) {
569
+ for (let key in rule.css) {
570
+ if (!(specificities[key] > rule.selector.specificity)) {
571
+ result[key] = rule.css[key];
572
+ specificities[key] = rule.selector.specificity;
573
+ }
574
+ }
575
+ }
576
+ }
577
+ return result;
578
+ }
579
+ function combineArrays(array1, array2) {
580
+ return array1.concat(array2.slice(array1.length));
581
+ }
582
+ function getAscent(font, size) {
583
+ return Math.max(font.ascender, (font.bbox[3] || font.bbox.maxY) * (font.scale || 1)) * size / 1000;
584
+ }
585
+ function getDescent(font, size) {
586
+ return Math.min(font.descender, (font.bbox[1] || font.bbox.minY) * (font.scale || 1)) * size / 1000;
587
+ }
588
+ function getXHeight(font, size) {
589
+ return (font.xHeight || 0.5 * (font.ascender - font.descender)) * size / 1000;
590
+ }
591
+ function getBaseline(font, size, baseline, shift) {
592
+ let dy1, dy2;
593
+ switch (baseline) {
594
+ case 'middle': dy1 = 0.5 * getXHeight(font, size); break;
595
+ case 'central': dy1 = 0.5 * (getDescent(font, size) + getAscent(font, size)); break;
596
+ case 'after-edge': case 'text-after-edge': dy1 = getDescent(font, size); break;
597
+ case 'alphabetic': case 'auto': case 'baseline': dy1 = 0; break;
598
+ case 'mathematical': dy1 = 0.5 * getAscent(font, size); break;
599
+ case 'hanging': dy1 = 0.8 * getAscent(font, size); break;
600
+ case 'before-edge': case 'text-before-edge': dy1 = getAscent(font, size); break;
601
+ default: dy1 = 0; break;
602
+ }
603
+ switch (shift) {
604
+ case 'baseline': dy2 = 0; break;
605
+ case 'super': dy2 = 0.6 * size; break;
606
+ case 'sub': dy2 = -0.6 * size; break;
607
+ default: dy2 = shift; break;
608
+ }
609
+ return dy1 - dy2;
610
+ }
611
+ function getTextPos(font, size, text) {
612
+ let encoded = font.encode('' + text), hex = encoded[0], pos = encoded[1], data = [];
613
+ for (let i = 0; i < hex.length; i++) {
614
+ let unicode = font.unicode ? font.unicode[parseInt(hex[i], 16)] : [text.charCodeAt(i)];
615
+ data.push({
616
+ glyph: hex[i],
617
+ unicode: unicode,
618
+ width: pos[i].advanceWidth * size / 1000,
619
+ xOffset: pos[i].xOffset * size / 1000,
620
+ yOffset: pos[i].yOffset * size / 1000,
621
+ xAdvance: pos[i].xAdvance * size / 1000,
622
+ yAdvance: pos[i].yAdvance * size / 1000
623
+ });
624
+ }
625
+ return data;
626
+ }
627
+ function createSVGElement(obj, inherits) {
628
+ switch (obj.nodeName) {
629
+ case 'use': return new SvgElemUse(obj, inherits);
630
+ case 'symbol': return new SvgElemSymbol(obj, inherits);
631
+ case 'g': return new SvgElemGroup(obj, inherits);
632
+ case 'a': return new SvgElemLink(obj, inherits);
633
+ case 'svg': return new SvgElemSvg(obj, inherits);
634
+ case 'image': return new SVGElemImage(obj, inherits);
635
+ case 'rect': return new SvgElemRect(obj, inherits);
636
+ case 'circle': return new SvgElemCircle(obj, inherits);
637
+ case 'ellipse': return new SvgElemEllipse(obj, inherits);
638
+ case 'line': return new SvgElemLine(obj, inherits);
639
+ case 'polyline': return new SvgElemPolyline(obj, inherits);
640
+ case 'polygon': return new SvgElemPolygon(obj, inherits);
641
+ case 'path': return new SvgElemPath(obj, inherits);
642
+ case 'text': return new SvgElemText(obj, inherits);
643
+ case 'tspan': return new SvgElemTspan(obj, inherits);
644
+ case 'textPath': return new SvgElemTextPath(obj, inherits);
645
+ case '#text': case '#cdata-section': return new SvgElemTextNode(obj, inherits);
646
+ default: return new SvgElem(obj, inherits);
647
+ }
648
+ }
649
+
650
+ var StringParser = function(str) {
651
+ this.match = function(exp, all) {
652
+ let temp = str.match(exp);
653
+ if (!temp || temp.index !== 0) {return;}
654
+ str = str.substring(temp[0].length);
655
+ return (all ? temp : temp[0]);
656
+ };
657
+ this.matchSeparator = function() {
658
+ return this.match(/^(?:\s*,\s*|\s*|)/);
659
+ };
660
+ this.matchSpace = function() {
661
+ return this.match(/^(?:\s*)/);
662
+ };
663
+ this.matchLengthUnit = function() {
664
+ return this.match(/^(?:px|pt|cm|mm|in|pc|em|ex|%|)/);
665
+ };
666
+ this.matchNumber = function() {
667
+ return this.match(/^(?:[-+]?(?:[0-9]+[.][0-9]+|[0-9]+[.]|[.][0-9]+|[0-9]+)(?:[eE][-+]?[0-9]+)?)/);
668
+ };
669
+ this.matchAll = function() {
670
+ return this.match(/^[\s\S]+/);
671
+ };
672
+ };
673
+
674
+ var BezierSegment = function(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
675
+ let divisions = 6 * precision;
676
+ let equationX = [p1x, -3 * p1x + 3 * c1x, 3 * p1x - 6 * c1x + 3 * c2x, -p1x + 3 * c1x - 3 * c2x + p2x];
677
+ let equationY = [p1y, -3 * p1y + 3 * c1y, 3 * p1y - 6 * c1y + 3 * c2y, -p1y + 3 * c1y - 3 * c2y + p2y];
678
+ let derivativeX = [-3 * p1x + 3 * c1x, 6 * p1x - 12 * c1x + 6 * c2x, -3 * p1x + 9 * c1x - 9 * c2x + 3 * p2x];
679
+ let derivativeY = [-3 * p1y + 3 * c1y, 6 * p1y - 12 * c1y + 6 * c2y, -3 * p1y + 9 * c1y - 9 * c2y + 3 * p2y];
680
+ let lengthMap = [0];
681
+ for (let i = 1; i <= divisions; i++) {
682
+ let t = (i - 0.5) / divisions;
683
+ let dx = getCurveValue(t, derivativeX) / divisions,
684
+ dy = getCurveValue(t, derivativeY) / divisions,
685
+ l = Math.sqrt(dx * dx + dy * dy);
686
+ lengthMap[i] = lengthMap[i - 1] + l;
687
+ }
688
+ this.totalLength = lengthMap[divisions];
689
+ this.startPoint = [p1x, p1y, isEqual(p1x, c1x) && isEqual(p1y, c1y) ? Math.atan2(c2y - c1y, c2x - c1x) : Math.atan2(c1y - p1y, c1x - p1x)];
690
+ this.endPoint = [p2x, p2y, isEqual(c2x, p2x) && isEqual(c2y, p2y) ? Math.atan2(c2y - c1y, c2x - c1x) : Math.atan2(p2y - c2y, p2x - c2x)];
691
+ this.getBoundingBox = function() {
692
+ let temp;
693
+ let minX = getCurveValue(0, equationX), minY = getCurveValue(0, equationY),
694
+ maxX = getCurveValue(1, equationX), maxY = getCurveValue(1, equationY);
695
+ if (minX > maxX) {temp = maxX; maxX = minX; minX = temp;}
696
+ if (minY > maxY) {temp = maxY; maxY = minY; minY = temp;}
697
+ let rootsX = solveEquation(derivativeX);
698
+ for (let i = 0; i < rootsX.length; i++) {
699
+ if (rootsX[i] >= 0 && rootsX[i] <= 1) {
700
+ let x = getCurveValue(rootsX[i], equationX);
701
+ if (x < minX) {minX = x;}
702
+ if (x > maxX) {maxX = x;}
703
+ }
704
+ }
705
+ let rootsY = solveEquation(derivativeY);
706
+ for (let i = 0; i < rootsY.length; i++) {
707
+ if (rootsY[i] >= 0 && rootsY[i] <= 1) {
708
+ let y = getCurveValue(rootsY[i], equationY);
709
+ if (y < minY) {minY = y;}
710
+ if (y > maxY) {maxY = y;}
711
+ }
712
+ }
713
+ return [minX, minY, maxX, maxY];
714
+ };
715
+ this.getPointAtLength = function(l) {
716
+ if (isEqual(l, 0)) {return this.startPoint;}
717
+ if (isEqual(l, this.totalLength)) {return this.endPoint;}
718
+ if (l < 0 || l > this.totalLength) {return;}
719
+ for (let i = 1; i <= divisions; i++) {
720
+ let l1 = lengthMap[i-1], l2 = lengthMap[i];
721
+ if (l1 <= l && l <= l2) {
722
+ let t = (i - (l2 - l) / (l2 - l1)) / divisions,
723
+ x = getCurveValue(t, equationX), y = getCurveValue(t, equationY),
724
+ dx = getCurveValue(t, derivativeX), dy = getCurveValue(t, derivativeY);
725
+ return [x, y, Math.atan2(dy, dx)];
726
+ }
727
+ }
728
+ };
729
+ };
730
+
731
+ var LineSegment = function(p1x, p1y, p2x, p2y) {
732
+ this.totalLength = Math.sqrt((p2x - p1x) * (p2x - p1x) + (p2y - p1y) * (p2y - p1y));
733
+ this.startPoint = [p1x, p1y, Math.atan2(p2y - p1y, p2x - p1x)];
734
+ this.endPoint = [p2x, p2y, Math.atan2(p2y - p1y, p2x - p1x)];
735
+ this.getBoundingBox = function() {
736
+ return [Math.min(this.startPoint[0], this.endPoint[0]), Math.min(this.startPoint[1], this.endPoint[1]),
737
+ Math.max(this.startPoint[0], this.endPoint[0]), Math.max(this.startPoint[1], this.endPoint[1])];
738
+ };
739
+ this.getPointAtLength = function(l) {
740
+ if (l >= 0 && l <= this.totalLength) {
741
+ let r = l / this.totalLength || 0,
742
+ x = this.startPoint[0] + r * (this.endPoint[0] - this.startPoint[0]),
743
+ y = this.startPoint[1] + r * (this.endPoint[1] - this.startPoint[1]);
744
+ return [x, y, this.startPoint[2]];
745
+ }
746
+ };
747
+ };
748
+
749
+ var SvgShape = function() {
750
+ this.pathCommands = [];
751
+ this.pathSegments = [];
752
+ this.startPoint = null;
753
+ this.endPoint = null;
754
+ this.totalLength = 0;
755
+ let startX = 0, startY = 0, currX = 0, currY = 0, lastCom, lastCtrlX, lastCtrlY;
756
+ this.move = function(x, y) {
757
+ startX = currX = x; startY = currY = y;
758
+ return null;
759
+ };
760
+ this.line = function(x, y) {
761
+ let segment = new LineSegment(currX, currY, x, y);
762
+ currX = x; currY = y;
763
+ return segment;
764
+ };
765
+ this.curve = function(c1x, c1y, c2x, c2y, x, y) {
766
+ let segment = new BezierSegment(currX, currY, c1x, c1y, c2x, c2y, x, y);
767
+ currX = x; currY = y;
768
+ return segment;
769
+ };
770
+ this.close = function() {
771
+ let segment = new LineSegment(currX, currY, startX, startY);
772
+ currX = startX; currY = startY;
773
+ return segment;
774
+ };
775
+ this.addCommand = function(data) {
776
+ this.pathCommands.push(data);
777
+ let segment = this[data[0]].apply(this, data.slice(3));
778
+ if (segment) {
779
+ segment.hasStart = data[1];
780
+ segment.hasEnd = data[2];
781
+ this.startPoint = this.startPoint || segment.startPoint;
782
+ this.endPoint = segment.endPoint;
783
+ this.pathSegments.push(segment);
784
+ this.totalLength += segment.totalLength;
785
+ }
786
+ };
787
+ this.M = function(x, y) {
788
+ this.addCommand(['move', true, true, x, y]);
789
+ lastCom = 'M';
790
+ return this;
791
+ };
792
+ this.m = function(x, y) {
793
+ return this.M(currX + x, currY + y);
794
+ };
795
+ this.Z = this.z = function() {
796
+ this.addCommand(['close', true, true]);
797
+ lastCom = 'Z';
798
+ return this;
799
+ };
800
+ this.L = function(x, y) {
801
+ this.addCommand(['line', true, true, x, y]);
802
+ lastCom = 'L';
803
+ return this;
804
+ };
805
+ this.l = function(x, y) {
806
+ return this.L(currX + x, currY + y);
807
+ };
808
+ this.H = function(x) {
809
+ return this.L(x, currY);
810
+ };
811
+ this.h = function(x) {
812
+ return this.L(currX + x, currY);
813
+ };
814
+ this.V = function(y) {
815
+ return this.L(currX, y);
816
+ };
817
+ this.v = function(y) {
818
+ return this.L(currX, currY + y);
819
+ };
820
+ this.C = function(c1x, c1y, c2x, c2y, x, y) {
821
+ this.addCommand(['curve', true, true, c1x, c1y, c2x, c2y, x, y]);
822
+ lastCom = 'C'; lastCtrlX = c2x; lastCtrlY = c2y;
823
+ return this;
824
+ };
825
+ this.c = function(c1x, c1y, c2x, c2y, x, y) {
826
+ return this.C(currX + c1x, currY + c1y, currX + c2x, currY + c2y, currX + x, currY + y);
827
+ };
828
+ this.S = function(c1x, c1y, x, y) {
829
+ return this.C(currX + (lastCom === 'C' ? currX - lastCtrlX : 0), currY + (lastCom === 'C' ? currY - lastCtrlY : 0), c1x, c1y, x, y);
830
+ };
831
+ this.s = function(c1x, c1y, x, y) {
832
+ return this.C(currX + (lastCom === 'C' ? currX - lastCtrlX : 0), currY + (lastCom === 'C' ? currY - lastCtrlY : 0), currX + c1x, currY + c1y, currX + x, currY + y);
833
+ };
834
+ this.Q = function(cx, cy, x, y) {
835
+ let c1x = currX + 2 / 3 * (cx - currX), c1y = currY + 2 / 3 * (cy - currY),
836
+ c2x = x + 2 / 3 * (cx - x), c2y = y + 2 / 3 * (cy - y);
837
+ this.addCommand(['curve', true, true, c1x, c1y, c2x, c2y, x, y]);
838
+ lastCom = 'Q'; lastCtrlX = cx; lastCtrlY = cy;
839
+ return this;
840
+ };
841
+ this.q = function(c1x, c1y, x, y) {
842
+ return this.Q(currX + c1x, currY + c1y, currX + x, currY + y);
843
+ };
844
+ this.T = function(x, y) {
845
+ return this.Q(currX + (lastCom === 'Q' ? currX - lastCtrlX : 0), currY + (lastCom === 'Q' ? currY - lastCtrlY : 0), x, y);
846
+ };
847
+ this.t = function(x, y) {
848
+ return this.Q(currX + (lastCom === 'Q' ? currX - lastCtrlX : 0), currY + (lastCom === 'Q' ? currY - lastCtrlY : 0), currX + x, currY + y);
849
+ };
850
+ this.A = function(rx, ry, fi, fa, fs, x, y) {
851
+ if (isEqual(rx, 0) || isEqual(ry, 0)) {
852
+ this.addCommand(['line', true, true, x, y]);
853
+ } else {
854
+ fi = fi * (Math.PI / 180);
855
+ rx = Math.abs(rx);
856
+ ry = Math.abs(ry);
857
+ fa = 1 * !!fa;
858
+ fs = 1 * !!fs;
859
+ let x1 = Math.cos(fi) * (currX - x) / 2 + Math.sin(fi) * (currY - y) / 2,
860
+ y1 = Math.cos(fi) * (currY - y) / 2 - Math.sin(fi) * (currX - x) / 2,
861
+ lambda = (x1 * x1) / (rx * rx) + (y1 * y1) / (ry * ry);
862
+ if (lambda > 1) {
863
+ rx *= Math.sqrt(lambda);
864
+ ry *= Math.sqrt(lambda);
865
+ }
866
+ 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)),
867
+ x2 = (fa === fs ? -1 : 1) * r * rx * y1 / ry,
868
+ y2 = (fa === fs ? 1 : -1) * r * ry * x1 / rx;
869
+ let cx = Math.cos(fi) * x2 - Math.sin(fi) * y2 + (currX + x) / 2,
870
+ cy = Math.sin(fi) * x2 + Math.cos(fi) * y2 + (currY + y) / 2,
871
+ th1 = Math.atan2((y1 - y2) / ry, (x1 - x2) / rx),
872
+ th2 = Math.atan2((-y1 - y2) / ry, (-x1 - x2) / rx);
873
+ if (fs === 0 && th2 - th1 > 0) {
874
+ th2 -= 2 * Math.PI;
875
+ } else if (fs === 1 && th2 - th1 < 0) {
876
+ th2 += 2 * Math.PI;
877
+ }
878
+ let segms = Math.ceil(Math.abs(th2 - th1) / (Math.PI / precision));
879
+ for (let i = 0; i < segms; i++) {
880
+ let th3 = th1 + i * (th2 - th1) / segms,
881
+ th4 = th1 + (i + 1) * (th2 - th1) / segms,
882
+ t = 4/3 * Math.tan((th4 - th3) / 4);
883
+ 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)),
884
+ c1y = cy + Math.sin(fi) * rx * (Math.cos(th3) - t * Math.sin(th3)) + Math.cos(fi) * ry * (Math.sin(th3) + t * Math.cos(th3)),
885
+ c2x = cx + Math.cos(fi) * rx * (Math.cos(th4) + t * Math.sin(th4)) - Math.sin(fi) * ry * (Math.sin(th4) - t * Math.cos(th4)),
886
+ c2y = cy + Math.sin(fi) * rx * (Math.cos(th4) + t * Math.sin(th4)) + Math.cos(fi) * ry * (Math.sin(th4) - t * Math.cos(th4)),
887
+ endX = cx + Math.cos(fi) * rx * Math.cos(th4) - Math.sin(fi) * ry * Math.sin(th4),
888
+ endY = cy + Math.sin(fi) * rx * Math.cos(th4) + Math.cos(fi) * ry * Math.sin(th4);
889
+ this.addCommand(['curve', (i === 0), (i === segms - 1), c1x, c1y, c2x, c2y, endX, endY]);
890
+ }
891
+ }
892
+ lastCom = 'A';
893
+ return this;
894
+ };
895
+ this.a = function(rx, ry, fi, fa, fs, x, y) {
896
+ return this.A(rx, ry, fi, fa, fs, currX + x, currY + y);
897
+ };
898
+ this.path = function(d) {
899
+ let command, value, temp,
900
+ parser = new StringParser((d || '').trim());
901
+ while (command = parser.match(/^[astvzqmhlcASTVZQMHLC]/)) {
902
+ parser.matchSeparator();
903
+ let values = [];
904
+ while (value = (PathFlags[command + values.length] ? parser.match(/^[01]/) : parser.matchNumber())) {
905
+ parser.matchSeparator();
906
+ if (values.length === PathArguments[command]) {
907
+ this[command].apply(this, values);
908
+ values = [];
909
+ if (command === 'M') {command = 'L';}
910
+ else if (command === 'm') {command = 'l';}
911
+ }
912
+ values.push(Number(value));
913
+ }
914
+ if (values.length === PathArguments[command]) {
915
+ this[command].apply(this, values);
916
+ } else {
917
+ warningCallback('SvgPath: command ' + command + ' with ' + values.length + ' numbers'); return;
918
+ }
919
+ }
920
+ if (temp = parser.matchAll()) {
921
+ warningCallback('SvgPath: unexpected string ' + temp);
922
+ }
923
+ return this;
924
+ };
925
+ this.getBoundingBox = function() {
926
+ let bbox = [Infinity, Infinity, -Infinity, -Infinity];
927
+ function addBounds(bbox1) {
928
+ if (bbox1[0] < bbox[0]) {bbox[0] = bbox1[0];}
929
+ if (bbox1[2] > bbox[2]) {bbox[2] = bbox1[2];}
930
+ if (bbox1[1] < bbox[1]) {bbox[1] = bbox1[1];}
931
+ if (bbox1[3] > bbox[3]) {bbox[3] = bbox1[3];}
932
+ }
933
+ for (let i = 0; i < this.pathSegments.length; i++) {
934
+ addBounds(this.pathSegments[i].getBoundingBox());
935
+ }
936
+ if (bbox[0] === Infinity) {bbox[0] = 0;}
937
+ if (bbox[1] === Infinity) {bbox[1] = 0;}
938
+ if (bbox[2] === -Infinity) {bbox[2] = 0;}
939
+ if (bbox[3] === -Infinity) {bbox[3] = 0;}
940
+ return bbox;
941
+ };
942
+ this.getPointAtLength = function(l) {
943
+ if (l >= 0 && l <= this.totalLength) {
944
+ let temp;
945
+ for (let i = 0; i < this.pathSegments.length; i++) {
946
+ if (temp = this.pathSegments[i].getPointAtLength(l)) {
947
+ return temp;
948
+ }
949
+ l -= this.pathSegments[i].totalLength;
950
+ }
951
+ return this.endPoint;
952
+ }
953
+ };
954
+ this.transform = function(m) {
955
+ this.pathSegments = [];
956
+ this.startPoint = null;
957
+ this.endPoint = null;
958
+ this.totalLength = 0;
959
+ for (let i = 0; i < this.pathCommands.length; i++) {
960
+ let data = this.pathCommands.shift();
961
+ for (let j = 3; j < data.length; j+=2) {
962
+ let p = transformPoint([data[j], data[j + 1]], m)
963
+ data[j] = p[0];
964
+ data[j + 1] = p[1];
965
+ }
966
+ this.addCommand(data);
967
+ }
968
+ return this;
969
+ };
970
+ this.mergeShape = function(shape) {
971
+ for (let i = 0; i < shape.pathCommands.length; i++) {
972
+ this.addCommand(shape.pathCommands[i].slice());
973
+ }
974
+ return this;
975
+ };
976
+ this.clone = function() {
977
+ return new SvgShape().mergeShape(this);
978
+ };
979
+ this.insertInDocument = function() {
980
+ for (let i = 0; i < this.pathCommands.length; i++) {
981
+ let command = this.pathCommands[i][0], values = this.pathCommands[i].slice(3);
982
+ switch(command) {
983
+ case 'move': doc.moveTo(values[0], values[1]); break;
984
+ case 'line': doc.lineTo(values[0], values[1]); break;
985
+ case 'curve': doc.bezierCurveTo(values[0], values[1], values[2], values[3], values[4], values[5]); break;
986
+ case 'close': doc.closePath(); break;
987
+ }
988
+ }
989
+ };
990
+ this.getSubPaths = function() {
991
+ let subPaths = [], shape = new SvgShape();
992
+ for (let i = 0; i < this.pathCommands.length; i++) {
993
+ let data = this.pathCommands[i], command = this.pathCommands[i][0];
994
+ if (command === 'move' && i !== 0) {
995
+ subPaths.push(shape);
996
+ shape = new SvgShape();
997
+ }
998
+ shape.addCommand(data);
999
+ }
1000
+ subPaths.push(shape);
1001
+ return subPaths;
1002
+ };
1003
+ this.getMarkers = function() {
1004
+ let markers = [], subPaths = this.getSubPaths();
1005
+ for (let i = 0; i < subPaths.length; i++) {
1006
+ let subPath = subPaths[i], subPathMarkers = [];
1007
+ for (let j = 0; j < subPath.pathSegments.length; j++) {
1008
+ let segment = subPath.pathSegments[j];
1009
+ if (isNotEqual(segment.totalLength, 0) || j === 0 || j === subPath.pathSegments.length - 1) {
1010
+ if (segment.hasStart) {
1011
+ let startMarker = segment.getPointAtLength(0), prevEndMarker = subPathMarkers.pop();
1012
+ if (prevEndMarker) {startMarker[2] = 0.5 * (prevEndMarker[2] + startMarker[2]);}
1013
+ subPathMarkers.push(startMarker);
1014
+ }
1015
+ if (segment.hasEnd) {
1016
+ let endMarker = segment.getPointAtLength(segment.totalLength);
1017
+ subPathMarkers.push(endMarker);
1018
+ }
1019
+ }
1020
+ }
1021
+ markers = markers.concat(subPathMarkers);
1022
+ }
1023
+ return markers;
1024
+ };
1025
+ };
1026
+
1027
+ var SvgElem = function(obj, inherits) {
1028
+ let styleCache = Object.create(null);
1029
+ let childrenCache = null;
1030
+ this.name = obj.nodeName;
1031
+ this.isOuterElement = obj === svg || !obj.parentNode;
1032
+ this.inherits = inherits || (!this.isOuterElement ? createSVGElement(obj.parentNode, null) : null);
1033
+ this.stack = (this.inherits ? this.inherits.stack.concat(obj) : [obj]);
1034
+ this.style = parseStyleAttr(typeof obj.getAttribute === 'function' && obj.getAttribute('style'));
1035
+ this.css = useCSS ? getComputedStyle(obj) : getStyle(obj);
1036
+ this.allowedChildren = [];
1037
+ this.attr = function(key) {
1038
+ if (typeof obj.getAttribute === 'function') {
1039
+ return obj.getAttribute(key);
1040
+ }
1041
+ };
1042
+ this.resolveUrl = function(value) {
1043
+ let temp = (value || '').match(/^\s*(?:url\("(.*)#(.*)"\)|url\('(.*)#(.*)'\)|url\((.*)#(.*)\)|(.*)#(.*))\s*$/) || [];
1044
+ let file = temp[1] || temp[3] || temp[5] || temp[7],
1045
+ id = temp[2] || temp[4] || temp[6] || temp[8];
1046
+ if (id) {
1047
+ if (!file) {
1048
+ let svgObj = svg.getElementById(id);
1049
+ if (svgObj) {
1050
+ if (this.stack.indexOf(svgObj) === -1) {
1051
+ return svgObj;
1052
+ } else {
1053
+ warningCallback('SVGtoPDF: loop of circular references for id "' + id + '"');
1054
+ return;
1055
+ }
1056
+ }
1057
+ }
1058
+ if (documentCallback) {
1059
+ let svgs = documentCache[file];
1060
+ if (!svgs) {
1061
+ svgs = documentCallback(file);
1062
+ if (!isArrayLike(svgs)) {svgs = [svgs];}
1063
+ for (let i = 0; i < svgs.length; i++) {
1064
+ if (typeof svgs[i] === 'string') {svgs[i] = parseXml(svgs[i]);}
1065
+ }
1066
+ documentCache[file] = svgs;
1067
+ }
1068
+ for (let i = 0; i < svgs.length; i++) {
1069
+ let svgObj = svgs[i].getElementById(id);
1070
+ if (svgObj) {
1071
+ if (this.stack.indexOf(svgObj) === -1) {
1072
+ return svgObj;
1073
+ } else {
1074
+ warningCallback('SVGtoPDF: loop of circular references for id "' + file + '#' + id + '"');
1075
+ return;
1076
+ }
1077
+ }
1078
+ }
1079
+ }
1080
+ }
1081
+ };
1082
+ this.computeUnits = function(value, unit, percent, isFontSize) {
1083
+ if (unit === '%') {
1084
+ return parseFloat(value) / 100 * (isFontSize || percent != null ? percent : this.getViewport());
1085
+ } else if (unit === 'ex' || unit === 'em') {
1086
+ return value * {'em':1, 'ex':0.5}[unit] * (isFontSize ? percent : this.get('font-size'));
1087
+ } else {
1088
+ return value * {'':1, 'px':1, 'pt':96/72, 'cm':96/2.54, 'mm':96/25.4, 'in':96, 'pc':96/6}[unit];
1089
+ }
1090
+ };
1091
+ this.computeLength = function(value, percent, initial, isFontSize) {
1092
+ let parser = new StringParser((value || '').trim()), temp1, temp2;
1093
+ if (typeof (temp1 = parser.matchNumber()) === 'string' && typeof (temp2 = parser.matchLengthUnit()) === 'string' && !parser.matchAll()) {
1094
+ return this.computeUnits(temp1, temp2, percent, isFontSize);
1095
+ }
1096
+ return initial;
1097
+ };
1098
+ this.computeLengthList = function(value, percent, strict) {
1099
+ let parser = new StringParser((value || '').trim()), result = [], temp1, temp2;
1100
+ while (typeof (temp1 = parser.matchNumber()) === 'string' && typeof (temp2 = parser.matchLengthUnit()) === 'string') {
1101
+ result.push(this.computeUnits(temp1, temp2, percent));
1102
+ parser.matchSeparator();
1103
+ }
1104
+ if (strict && parser.matchAll()) {return;}
1105
+ return result;
1106
+ };
1107
+ this.getLength = function(key, percent, initial) {
1108
+ return this.computeLength(this.attr(key), percent, initial);
1109
+ };
1110
+ this.getLengthList = function(key, percent) {
1111
+ return this.computeLengthList(this.attr(key), percent);
1112
+ };
1113
+ this.getUrl = function(key) {
1114
+ return this.resolveUrl(this.attr(key))
1115
+ };
1116
+ this.getNumberList = function(key) {
1117
+ let parser = new StringParser((this.attr(key) || '').trim()), result = [], temp;
1118
+ while (temp = parser.matchNumber()) {
1119
+ result.push(Number(temp));
1120
+ parser.matchSeparator();
1121
+ }
1122
+ result.error = parser.matchAll();
1123
+ return result;
1124
+ }
1125
+ this.getViewbox = function(key, initial) {
1126
+ let viewBox = this.getNumberList(key);
1127
+ if (viewBox.length === 4 && viewBox[2] >= 0 && viewBox[3] >= 0) {return viewBox;}
1128
+ return initial;
1129
+ };
1130
+ this.getPercent = function(key, initial) {
1131
+ let value = this.attr(key);
1132
+ let parser = new StringParser((value || '').trim()), temp1, temp2;
1133
+ let number = parser.matchNumber();
1134
+ if (!number) {return initial;}
1135
+ if (parser.match('%')) {number *= 0.01;}
1136
+ if (parser.matchAll()) {return initial;}
1137
+ return Math.max(0, Math.min(1, number));
1138
+ };
1139
+ this.chooseValue = function(args) {
1140
+ for (let i = 0; i < arguments.length; i++) {
1141
+ if (arguments[i] != null && arguments[i] === arguments[i]) {return arguments[i];}
1142
+ }
1143
+ return arguments[arguments.length - 1];
1144
+ };
1145
+ this.get = function(key) {
1146
+ if (styleCache[key] !== undefined) {return styleCache[key];}
1147
+ let keyInfo = Properties[key] || {}, value, result;
1148
+ for (let i = 0; i < 3; i++) {
1149
+ switch (i) {
1150
+ case 0:
1151
+ if (key !== 'transform') { // the CSS transform behaves strangely
1152
+ value = this.css[keyInfo.css || key];
1153
+ }
1154
+ break;
1155
+ case 1:
1156
+ value = this.style[key];
1157
+ break;
1158
+ case 2:
1159
+ value = this.attr(key);
1160
+ break;
1161
+ }
1162
+ if (value === 'inherit') {
1163
+ result = (this.inherits ? this.inherits.get(key) : keyInfo.initial);
1164
+ if (result != null) {return styleCache[key] = result;}
1165
+ }
1166
+ if (keyInfo.values != null) {
1167
+ result = keyInfo.values[value];
1168
+ if (result != null) {return styleCache[key] = result;}
1169
+ }
1170
+ if (value != null) {
1171
+ let parsed;
1172
+ switch (key) {
1173
+ case 'font-size':
1174
+ result = this.computeLength(value, this.inherits ? this.inherits.get(key) : keyInfo.initial, undefined, true);
1175
+ break;
1176
+ case 'baseline-shift':
1177
+ result = this.computeLength(value, this.get('font-size'));
1178
+ break;
1179
+ case 'font-family':
1180
+ result = value || undefined;
1181
+ break;
1182
+ case 'opacity': case 'stroke-opacity': case 'fill-opacity': case 'stop-opacity':
1183
+ parsed = parseFloat(value);
1184
+ if (!isNaN(parsed)) {
1185
+ result = Math.max(0, Math.min(1, parsed));
1186
+ }
1187
+ break;
1188
+ case 'transform':
1189
+ result = parseTranform(value);
1190
+ break;
1191
+ case 'stroke-dasharray':
1192
+ if (value === 'none') {
1193
+ result = [];
1194
+ } else if (parsed = this.computeLengthList(value, this.getViewport(), true)) {
1195
+ let sum = 0, error = false;
1196
+ for (let j = 0; j < parsed.length; j++) {
1197
+ if (parsed[j] < 0) {error = true;}
1198
+ sum += parsed[j];
1199
+ }
1200
+ if (!error) {
1201
+ if (parsed.length % 2 === 1) {
1202
+ parsed = parsed.concat(parsed);
1203
+ }
1204
+ result = (sum === 0 ? [] : parsed);
1205
+ }
1206
+ }
1207
+ break;
1208
+ case 'color':
1209
+ if (value === 'none' || value === 'transparent') {
1210
+ result = 'none';
1211
+ } else {
1212
+ result = parseColor(value);
1213
+ }
1214
+ break;
1215
+ case 'fill': case 'stroke':
1216
+ if (value === 'none' || value === 'transparent') {
1217
+ result = 'none';
1218
+ } else if (value === 'currentColor') {
1219
+ result = this.get('color');
1220
+ } else if (parsed = parseColor(value)) {
1221
+ return parsed;
1222
+ } else if (parsed = (value || '').split(' ')) {
1223
+ let object = this.resolveUrl(parsed[0]),
1224
+ fallbackColor = parseColor(parsed[1]);
1225
+ if (object == null) {
1226
+ result = fallbackColor;
1227
+ } else if (object.nodeName === 'linearGradient' || object.nodeName === 'radialGradient') {
1228
+ result = new SvgElemGradient(object, null, fallbackColor);
1229
+ } else if (object.nodeName === 'pattern') {
1230
+ result = new SvgElemPattern(object, null, fallbackColor);
1231
+ } else {
1232
+ result = fallbackColor;
1233
+ }
1234
+ }
1235
+ break;
1236
+ case 'stop-color':
1237
+ if (value === 'none' || value === 'transparent') {
1238
+ result = 'none';
1239
+ } else if (value === 'currentColor') {
1240
+ result = this.get('color');
1241
+ } else {
1242
+ result = parseColor(value);
1243
+ }
1244
+ break;
1245
+ case 'marker-start': case 'marker-mid': case 'marker-end': case 'clip-path': case 'mask':
1246
+ if (value === 'none') {
1247
+ result = 'none';
1248
+ } else {
1249
+ result = this.resolveUrl(value);
1250
+ }
1251
+ break;
1252
+ case 'stroke-width':
1253
+ parsed = this.computeLength(value, this.getViewport());
1254
+ if (parsed != null && parsed >= 0) {
1255
+ result = parsed;
1256
+ }
1257
+ break;
1258
+ case 'stroke-miterlimit':
1259
+ parsed = parseFloat(value);
1260
+ if (parsed != null && parsed >= 1) {
1261
+ result = parsed;
1262
+ }
1263
+ break;
1264
+ case 'word-spacing': case 'letter-spacing':
1265
+ result = this.computeLength(value, this.getViewport());
1266
+ break;
1267
+ case 'stroke-dashoffset':
1268
+ result = this.computeLength(value, this.getViewport());
1269
+ if (result != null) {
1270
+ if (result < 0) { // fix for crbug.com/660850
1271
+ let dasharray = this.get('stroke-dasharray');
1272
+ for (let j = 0; j < dasharray.length; j++) {result += dasharray[j];}
1273
+ }
1274
+ }
1275
+ break;
1276
+ }
1277
+ if (result != null) {return styleCache[key] = result;}
1278
+ }
1279
+ }
1280
+ return styleCache[key] = (keyInfo.inherit && this.inherits ? this.inherits.get(key) : keyInfo.initial);
1281
+ };
1282
+ this.getChildren = function() {
1283
+ if (childrenCache != null) {return childrenCache;}
1284
+ let children = [];
1285
+ for (let i = 0; i < obj.childNodes.length; i++) {
1286
+ let child = obj.childNodes[i];
1287
+ if (!child.error && this.allowedChildren.indexOf(child.nodeName) !== -1) {
1288
+ children.push(createSVGElement(child, this));
1289
+ }
1290
+ }
1291
+ return childrenCache = children;
1292
+ };
1293
+ this.getParentVWidth = function() {
1294
+ return (this.inherits ? this.inherits.getVWidth(): viewportWidth);
1295
+ };
1296
+ this.getParentVHeight = function() {
1297
+ return (this.inherits ? this.inherits.getVHeight() : viewportHeight);
1298
+ };
1299
+ this.getParentViewport = function() {
1300
+ return Math.sqrt(0.5 * this.getParentVWidth() * this.getParentVWidth() + 0.5 * this.getParentVHeight() * this.getParentVHeight());
1301
+ };
1302
+ this.getVWidth = function() {
1303
+ return this.getParentVWidth();
1304
+ };
1305
+ this.getVHeight = function() {
1306
+ return this.getParentVHeight();
1307
+ };
1308
+ this.getViewport = function() {
1309
+ return Math.sqrt(0.5 * this.getVWidth() * this.getVWidth() + 0.5 * this.getVHeight() * this.getVHeight());
1310
+ };
1311
+ this.getBoundingBox = function() {
1312
+ let shape = this.getBoundingShape();
1313
+ return shape.getBoundingBox();
1314
+ };
1315
+ };
1316
+
1317
+ var SvgElemStylable = function(obj, inherits) {
1318
+ SvgElem.call(this, obj, inherits);
1319
+ this.transform = function() {
1320
+ doc.transform.apply(doc, this.getTransformation());
1321
+ };
1322
+ this.clip = function() {
1323
+ if (this.get('clip-path') !== 'none') {
1324
+ let clipPath = new SvgElemClipPath(this.get('clip-path'), null);
1325
+ clipPath.useMask(this.getBoundingBox());
1326
+ return true;
1327
+ }
1328
+ };
1329
+ this.mask = function() {
1330
+ if (this.get('mask') !== 'none') {
1331
+ let mask = new SvgElemMask(this.get('mask'), null);
1332
+ mask.useMask(this.getBoundingBox());
1333
+ return true;
1334
+ }
1335
+ };
1336
+ this.getFill = function(isClip, isMask) {
1337
+ let opacity = this.get('opacity'),
1338
+ fill = this.get('fill'),
1339
+ fillOpacity = this.get('fill-opacity');
1340
+ if (isClip) {return DefaultColors.white;}
1341
+ if (fill !== 'none' && opacity && fillOpacity) {
1342
+ if (fill instanceof SvgElemGradient || fill instanceof SvgElemPattern) {
1343
+ return fill.getPaint(this.getBoundingBox(), fillOpacity * opacity, isClip, isMask);
1344
+ }
1345
+ return opacityToColor(fill, fillOpacity * opacity, isMask);
1346
+ }
1347
+ };
1348
+ this.getStroke = function(isClip, isMask) {
1349
+ let opacity = this.get('opacity'),
1350
+ stroke = this.get('stroke'),
1351
+ strokeOpacity = this.get('stroke-opacity');
1352
+ if (isClip || isEqual(this.get('stroke-width'), 0)) {return;}
1353
+ if (stroke !== 'none' && opacity && strokeOpacity) {
1354
+ if (stroke instanceof SvgElemGradient || stroke instanceof SvgElemPattern) {
1355
+ return stroke.getPaint(this.getBoundingBox(), strokeOpacity * opacity, isClip, isMask);
1356
+ }
1357
+ return opacityToColor(stroke, strokeOpacity * opacity, isMask);
1358
+ }
1359
+ };
1360
+ };
1361
+
1362
+ var SvgElemHasChildren = function(obj, inherits) {
1363
+ SvgElemStylable.call(this, obj, inherits);
1364
+ this.allowedChildren = ['use', 'g', 'a', 'svg', 'image', 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path', 'text'];
1365
+ this.getBoundingShape = function() {
1366
+ let shape = new SvgShape(),
1367
+ children = this.getChildren();
1368
+ for (let i = 0; i < children.length; i++) {
1369
+ if (children[i].get('display') !== 'none') {
1370
+ if (typeof children[i].getBoundingShape === 'function') {
1371
+ let childShape = children[i].getBoundingShape().clone();
1372
+ if (typeof children[i].getTransformation === 'function') {
1373
+ childShape.transform(children[i].getTransformation());
1374
+ }
1375
+ shape.mergeShape(childShape);
1376
+ }
1377
+ }
1378
+ }
1379
+ return shape;
1380
+ };
1381
+ this.drawChildren = function(isClip, isMask) {
1382
+ let children = this.getChildren();
1383
+ for (let i = 0; i < children.length; i++) {
1384
+ if (children[i].get('display') !== 'none') {
1385
+ if (typeof children[i].drawInDocument === 'function') {
1386
+ children[i].drawInDocument(isClip, isMask);
1387
+ }
1388
+ }
1389
+ }
1390
+ };
1391
+ };
1392
+
1393
+ var SvgElemContainer = function(obj, inherits) {
1394
+ SvgElemHasChildren.call(this, obj, inherits);
1395
+ this.drawContent = function(isClip, isMask) {
1396
+ this.transform();
1397
+ let clipped = this.clip(),
1398
+ masked = this.mask(),
1399
+ group;
1400
+ if ((this.get('opacity') < 1 || clipped || masked) && !isClip) {
1401
+ group = docBeginGroup(getPageBBox());
1402
+ }
1403
+ this.drawChildren(isClip, isMask);
1404
+ if (group) {
1405
+ docEndGroup(group);
1406
+ doc.fillOpacity(this.get('opacity'));
1407
+ docInsertGroup(group);
1408
+ }
1409
+ };
1410
+ };
1411
+
1412
+ var SvgElemUse = function(obj, inherits) {
1413
+ SvgElemContainer.call(this, obj, inherits);
1414
+ let x = this.getLength('x', this.getVWidth(), 0),
1415
+ y = this.getLength('y', this.getVHeight(), 0),
1416
+ child = this.getUrl('href') || this.getUrl('xlink:href');
1417
+ if (child) {child = createSVGElement(child, this);}
1418
+ this.getChildren = function() {
1419
+ return child ? [child] : [];
1420
+ };
1421
+ this.drawInDocument = function(isClip, isMask) {
1422
+ doc.save();
1423
+ this.drawContent(isClip, isMask);
1424
+ doc.restore();
1425
+ };
1426
+ this.getTransformation = function() {
1427
+ return multiplyMatrix(this.get('transform'), [1, 0, 0, 1, x, y]);
1428
+ };
1429
+ };
1430
+
1431
+ var SvgElemSymbol = function(obj, inherits) {
1432
+ SvgElemContainer.call(this, obj, inherits);
1433
+ let width = this.getLength('width', this.getParentVWidth(), this.getParentVWidth()),
1434
+ height = this.getLength('height', this.getParentVHeight(), this.getParentVHeight());
1435
+ if (inherits instanceof SvgElemUse) {
1436
+ width = inherits.getLength('width', inherits.getParentVWidth(), width);
1437
+ height = inherits.getLength('height', inherits.getParentVHeight(), height);
1438
+ }
1439
+ let aspectRatio = (this.attr('preserveAspectRatio') || '').trim(),
1440
+ viewBox = this.getViewbox('viewBox', [0, 0, width, height]);
1441
+ this.getVWidth = function() {
1442
+ return viewBox[2];
1443
+ };
1444
+ this.getVHeight = function() {
1445
+ return viewBox[3];
1446
+ };
1447
+ this.drawInDocument = function(isClip, isMask) {
1448
+ doc.save();
1449
+ this.drawContent(isClip, isMask);
1450
+ doc.restore();
1451
+ };
1452
+ this.getTransformation = function() {
1453
+ return multiplyMatrix(parseAspectRatio(aspectRatio, width, height, viewBox[2], viewBox[3]), [1, 0, 0, 1, -viewBox[0], -viewBox[1]]);
1454
+ };
1455
+ };
1456
+
1457
+ var SvgElemGroup = function(obj, inherits) {
1458
+ SvgElemContainer.call(this, obj, inherits);
1459
+ this.drawInDocument = function(isClip, isMask) {
1460
+ doc.save();
1461
+ if (this.link && !isClip && !isMask) {this.addLink();}
1462
+ this.drawContent(isClip, isMask);
1463
+ doc.restore();
1464
+ };
1465
+ this.getTransformation = function() {
1466
+ return this.get('transform');
1467
+ };
1468
+ };
1469
+
1470
+ var SvgElemLink = function(obj, inherits) {
1471
+ if (inherits && inherits.isText) {
1472
+ SvgElemTspan.call(this, obj, inherits);
1473
+ this.allowedChildren = ['textPath', 'tspan', '#text', '#cdata-section', 'a'];
1474
+ } else {
1475
+ SvgElemGroup.call(this, obj, inherits);
1476
+ }
1477
+ this.link = this.attr('href') || this.attr('xlink:href');
1478
+ this.addLink = function() {
1479
+ if (this.link.match(/^(?:[a-z][a-z0-9+.-]*:|\/\/)?/i) && this.getChildren().length) {
1480
+ let bbox = this.getBoundingShape().transform(getGlobalMatrix()).getBoundingBox();
1481
+ docInsertLink(bbox[0], bbox[1], bbox[2], bbox[3], this.link);
1482
+ }
1483
+ }
1484
+ };
1485
+
1486
+ var SvgElemSvg = function(obj, inherits) {
1487
+ SvgElemContainer.call(this, obj, inherits);
1488
+ let width = this.getLength('width', this.getParentVWidth(), this.getParentVWidth()),
1489
+ height = this.getLength('height', this.getParentVHeight(), this.getParentVHeight()),
1490
+ x = this.getLength('x', this.getParentVWidth(), 0),
1491
+ y = this.getLength('y', this.getParentVHeight(), 0);
1492
+ if (inherits instanceof SvgElemUse) {
1493
+ width = inherits.getLength('width', inherits.getParentVWidth(), width);
1494
+ height = inherits.getLength('height', inherits.getParentVHeight(), height);
1495
+ }
1496
+ let aspectRatio = this.attr('preserveAspectRatio'),
1497
+ viewBox = this.getViewbox('viewBox', [0, 0, width, height]);
1498
+ if (this.isOuterElement && preserveAspectRatio) {
1499
+ x = y = 0;
1500
+ width = viewportWidth;
1501
+ height = viewportHeight;
1502
+ aspectRatio = preserveAspectRatio;
1503
+ }
1504
+ this.getVWidth = function() {
1505
+ return viewBox[2];
1506
+ };
1507
+ this.getVHeight = function() {
1508
+ return viewBox[3];
1509
+ };
1510
+ this.drawInDocument = function(isClip, isMask) {
1511
+ doc.save();
1512
+ if (this.get('overflow') === 'hidden') {
1513
+ new SvgShape().M(x, y).L(x + width, y).L(x + width, y + height).L(x, y + height).Z()
1514
+ .transform(this.get('transform'))
1515
+ .insertInDocument();
1516
+ doc.clip();
1517
+ }
1518
+ this.drawContent(isClip, isMask);
1519
+ doc.restore();
1520
+ };
1521
+ this.getTransformation = function() {
1522
+ return multiplyMatrix(
1523
+ this.get('transform'),
1524
+ [1, 0, 0, 1, x, y],
1525
+ parseAspectRatio(aspectRatio, width, height, viewBox[2], viewBox[3]),
1526
+ [1, 0, 0, 1, -viewBox[0], -viewBox[1]]
1527
+ );
1528
+ };
1529
+ };
1530
+
1531
+ var SVGElemImage = function(obj, inherits) {
1532
+ SvgElemStylable.call(this, obj, inherits);
1533
+ let link = imageCallback(this.attr('href') || this.attr('xlink:href') || ''),
1534
+ x = this.getLength('x', this.getVWidth(), 0),
1535
+ y = this.getLength('y', this.getVHeight(), 0),
1536
+ width = this.getLength('width', this.getVWidth(), 'auto'),
1537
+ height = this.getLength('height', this.getVHeight(), 'auto'),
1538
+ image;
1539
+ try {
1540
+ image = doc.openImage(link);
1541
+ } catch(e) {
1542
+ warningCallback('SVGElemImage: failed to open image "' + link + '" in PDFKit');
1543
+ }
1544
+ if (image) {
1545
+ if (width === 'auto' && height !== 'auto') {
1546
+ width = height * image.width / image.height;
1547
+ } else if (height === 'auto' && width !== 'auto') {
1548
+ height = width * image.height / image.width;
1549
+ } else if (width === 'auto' && height === 'auto') {
1550
+ width = image.width;
1551
+ height = image.height;
1552
+ }
1553
+ }
1554
+ if (width === 'auto' || width < 0) {width = 0;}
1555
+ if (height === 'auto' || height < 0) {height = 0;}
1556
+ this.getTransformation = function() {
1557
+ return this.get('transform');
1558
+ };
1559
+ this.getBoundingShape = function() {
1560
+ return new SvgShape().M(x, y).L(x + width, y).M(x + width, y + height).L(x, y + height);
1561
+ };
1562
+ this.drawInDocument = function(isClip, isMask) {
1563
+ if (this.get('visibility') === 'hidden' || !image) {return;}
1564
+ doc.save();
1565
+ this.transform();
1566
+ if (this.get('overflow') === 'hidden') {
1567
+ doc.rect(x, y, width, height).clip();
1568
+ }
1569
+ this.clip();
1570
+ this.mask();
1571
+ doc.translate(x, y);
1572
+ doc.transform.apply(doc, parseAspectRatio(this.attr('preserveAspectRatio'), width, height, image ? image.width : width, image ? image.height : height));
1573
+ if (!isClip) {
1574
+ doc.fillOpacity(this.get('opacity'));
1575
+ doc.image(image, 0, 0);
1576
+ } else {
1577
+ doc.rect(0, 0, image.width, image.height);
1578
+ docFillColor(DefaultColors.white).fill();
1579
+ }
1580
+ doc.restore();
1581
+ };
1582
+ };
1583
+
1584
+ var SvgElemPattern = function(obj, inherits, fallback) {
1585
+ SvgElemHasChildren.call(this, obj, inherits);
1586
+ this.ref = (function() {
1587
+ let ref = this.getUrl('href') || this.getUrl('xlink:href');
1588
+ if (ref && ref.nodeName === obj.nodeName) {
1589
+ return new SvgElemPattern(ref, inherits, fallback);
1590
+ }
1591
+ }).call(this);
1592
+ let _attr = this.attr;
1593
+ this.attr = function(key) {
1594
+ let attr = _attr.call(this, key);
1595
+ if (attr != null || key === 'href' || key === 'xlink:href') {return attr;}
1596
+ return this.ref ? this.ref.attr(key) : null;
1597
+ };
1598
+ let _getChildren = this.getChildren;
1599
+ this.getChildren = function() {
1600
+ let children = _getChildren.call(this);
1601
+ if (children.length > 0) {return children;}
1602
+ return this.ref ? this.ref.getChildren() : [];
1603
+ };
1604
+ this.getPaint = function(bBox, gOpacity, isClip, isMask) {
1605
+ let bBoxUnitsPattern = (this.attr('patternUnits') !== 'userSpaceOnUse'),
1606
+ bBoxUnitsContent = (this.attr('patternContentUnits') === 'objectBoundingBox'),
1607
+ x = this.getLength('x', (bBoxUnitsPattern ? 1 : this.getParentVWidth()), 0),
1608
+ y = this.getLength('y', (bBoxUnitsPattern ? 1 : this.getParentVHeight()), 0),
1609
+ width = this.getLength('width', (bBoxUnitsPattern ? 1 : this.getParentVWidth()), 0),
1610
+ height = this.getLength('height', (bBoxUnitsPattern ? 1 : this.getParentVHeight()), 0);
1611
+ if (bBoxUnitsContent && !bBoxUnitsPattern) { // Use the same units for pattern & pattern content
1612
+ x = (x - bBox[0]) / (bBox[2] - bBox[0]) || 0;
1613
+ y = (y - bBox[1]) / (bBox[3] - bBox[1]) || 0;
1614
+ width = width / (bBox[2] - bBox[0]) || 0;
1615
+ height = height / (bBox[3] - bBox[1]) || 0;
1616
+ } else if (!bBoxUnitsContent && bBoxUnitsPattern) {
1617
+ x = bBox[0] + x * (bBox[2] - bBox[0]);
1618
+ y = bBox[1] + y * (bBox[3] - bBox[1]);
1619
+ width = width * (bBox[2] - bBox[0]);
1620
+ height = height * (bBox[3] - bBox[1]);
1621
+ }
1622
+ let viewBox = this.getViewbox('viewBox', [0, 0, width, height]),
1623
+ aspectRatio = (this.attr('preserveAspectRatio') || '').trim(),
1624
+ aspectRatioMatrix = multiplyMatrix(
1625
+ parseAspectRatio(aspectRatio, width, height, viewBox[2], viewBox[3], 0),
1626
+ [1, 0, 0, 1, -viewBox[0], -viewBox[1]]
1627
+ ),
1628
+ matrix = parseTranform(this.attr('patternTransform'));
1629
+ if (bBoxUnitsContent) {
1630
+ matrix = multiplyMatrix([bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]], matrix);
1631
+ }
1632
+ matrix = multiplyMatrix(matrix, [1, 0, 0, 1, x, y]);
1633
+ if ((matrix = validateMatrix(matrix)) && (aspectRatioMatrix = validateMatrix(aspectRatioMatrix)) && (width = validateNumber(width)) && (height = validateNumber(height))) {
1634
+ let group = docBeginGroup([0, 0, width, height]);
1635
+ doc.transform.apply(doc, aspectRatioMatrix);
1636
+ this.drawChildren(isClip, isMask);
1637
+ docEndGroup(group);
1638
+ return [docCreatePattern(group, width, height, matrix), gOpacity];
1639
+ } else {
1640
+ return fallback ? [fallback[0], fallback[1] * gOpacity] : undefined;
1641
+ }
1642
+ };
1643
+ this.getVWidth = function() {
1644
+ let bBoxUnitsPattern = (this.attr('patternUnits') !== 'userSpaceOnUse'),
1645
+ width = this.getLength('width', (bBoxUnitsPattern ? 1 : this.getParentVWidth()), 0);
1646
+ return this.getViewbox('viewBox', [0, 0, width, 0])[2];
1647
+ };
1648
+ this.getVHeight = function() {
1649
+ let bBoxUnitsPattern = (this.attr('patternUnits') !== 'userSpaceOnUse'),
1650
+ height = this.getLength('height', (bBoxUnitsPattern ? 1 : this.getParentVHeight()), 0);
1651
+ return this.getViewbox('viewBox', [0, 0, 0, height])[3];
1652
+ };
1653
+ };
1654
+
1655
+ var SvgElemGradient = function(obj, inherits, fallback) {
1656
+ SvgElem.call(this, obj, inherits);
1657
+ this.allowedChildren = ['stop'];
1658
+ this.ref = (function() {
1659
+ let ref = this.getUrl('href') || this.getUrl('xlink:href');
1660
+ if (ref && ref.nodeName === obj.nodeName) {
1661
+ return new SvgElemGradient(ref, inherits, fallback);
1662
+ }
1663
+ }).call(this);
1664
+ let _attr = this.attr;
1665
+ this.attr = function(key) {
1666
+ let attr = _attr.call(this, key);
1667
+ if (attr != null || key === 'href' || key === 'xlink:href') {return attr;}
1668
+ return this.ref ? this.ref.attr(key) : null;
1669
+ };
1670
+ let _getChildren = this.getChildren;
1671
+ this.getChildren = function() {
1672
+ let children = _getChildren.call(this);
1673
+ if (children.length > 0) {return children;}
1674
+ return this.ref ? this.ref.getChildren() : [];
1675
+ };
1676
+ this.getPaint = function(bBox, gOpacity, isClip, isMask) {
1677
+ let children = this.getChildren();
1678
+ if (children.length === 0) {return;}
1679
+ if (children.length === 1) {
1680
+ let child = children[0],
1681
+ stopColor = child.get('stop-color');
1682
+ if (stopColor === 'none') {return;}
1683
+ return opacityToColor(stopColor, child.get('stop-opacity') * gOpacity, isMask);
1684
+ }
1685
+ let bBoxUnits = (this.attr('gradientUnits') !== 'userSpaceOnUse'),
1686
+ matrix = parseTranform(this.attr('gradientTransform')),
1687
+ spread = this.attr('spreadMethod'),
1688
+ grad,
1689
+ x1, x2, y1, y2, r2,
1690
+ nAfter = 0,
1691
+ nBefore = 0,
1692
+ nTotal = 1;
1693
+ if (bBoxUnits) {
1694
+ matrix = multiplyMatrix([bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]], matrix);
1695
+ }
1696
+ if (matrix = validateMatrix(matrix)) {
1697
+ if (this.name === 'linearGradient') {
1698
+ x1 = this.getLength('x1', (bBoxUnits ? 1 : this.getVWidth()), 0);
1699
+ x2 = this.getLength('x2', (bBoxUnits ? 1 : this.getVWidth()), (bBoxUnits ? 1 : this.getVWidth()));
1700
+ y1 = this.getLength('y1', (bBoxUnits ? 1 : this.getVHeight()), 0);
1701
+ y2 = this.getLength('y2', (bBoxUnits ? 1 : this.getVHeight()), 0);
1702
+ } else {
1703
+ x2 = this.getLength('cx', (bBoxUnits ? 1 : this.getVWidth()), (bBoxUnits ? 0.5 : 0.5 * this.getVWidth()));
1704
+ y2 = this.getLength('cy', (bBoxUnits ? 1 : this.getVHeight()), (bBoxUnits ? 0.5 : 0.5 * this.getVHeight()));
1705
+ r2 = this.getLength('r', (bBoxUnits ? 1 : this.getViewport()), (bBoxUnits ? 0.5 : 0.5 * this.getViewport()));
1706
+ x1 = this.getLength('fx', (bBoxUnits ? 1 : this.getVWidth()), x2);
1707
+ y1 = this.getLength('fy', (bBoxUnits ? 1 : this.getVHeight()), y2);
1708
+ if (r2 < 0) {
1709
+ warningCallback('SvgElemGradient: negative r value');
1710
+ }
1711
+ let d = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)),
1712
+ multiplier = 1;
1713
+ if (d > r2) { // according to specification
1714
+ multiplier = r2 / d;
1715
+ x1 = x2 + (x1 - x2) * multiplier;
1716
+ y1 = y2 + (y1 - y2) * multiplier;
1717
+ }
1718
+ r2 = Math.max(r2, d * multiplier * (1 + 1e-6)); // fix for edge-case gradients see issue #84
1719
+ }
1720
+ if (spread === 'reflect' || spread === 'repeat') {
1721
+ let inv = inverseMatrix(matrix),
1722
+ corner1 = transformPoint([bBox[0], bBox[1]], inv),
1723
+ corner2 = transformPoint([bBox[2], bBox[1]], inv),
1724
+ corner3 = transformPoint([bBox[2], bBox[3]], inv),
1725
+ corner4 = transformPoint([bBox[0], bBox[3]], inv);
1726
+ if (this.name === 'linearGradient') { // See file 'gradient-repeat-maths.png'
1727
+ nAfter = Math.max((corner1[0] - x2) * (x2 - x1) + (corner1[1] - y2) * (y2 - y1),
1728
+ (corner2[0] - x2) * (x2 - x1) + (corner2[1] - y2) * (y2 - y1),
1729
+ (corner3[0] - x2) * (x2 - x1) + (corner3[1] - y2) * (y2 - y1),
1730
+ (corner4[0] - x2) * (x2 - x1) + (corner4[1] - y2) * (y2 - y1))
1731
+ / (Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
1732
+ nBefore = Math.max((corner1[0] - x1) * (x1 - x2) + (corner1[1] - y1) * (y1 - y2),
1733
+ (corner2[0] - x1) * (x1 - x2) + (corner2[1] - y1) * (y1 - y2),
1734
+ (corner3[0] - x1) * (x1 - x2) + (corner3[1] - y1) * (y1 - y2),
1735
+ (corner4[0] - x1) * (x1 - x2) + (corner4[1] - y1) * (y1 - y2))
1736
+ / (Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
1737
+ } else {
1738
+ nAfter = Math.sqrt(Math.max(Math.pow(corner1[0] - x2, 2) + Math.pow(corner1[1] - y2, 2),
1739
+ Math.pow(corner2[0] - x2, 2) + Math.pow(corner2[1] - y2, 2),
1740
+ Math.pow(corner3[0] - x2, 2) + Math.pow(corner3[1] - y2, 2),
1741
+ Math.pow(corner4[0] - x2, 2) + Math.pow(corner4[1] - y2, 2))) / r2 - 1;
1742
+ }
1743
+ nAfter = Math.ceil(nAfter + 0.5); // Add a little more because the stroke can extend outside of the bounding box
1744
+ nBefore = Math.ceil(nBefore + 0.5);
1745
+ nTotal = nBefore + 1 + nAfter; // How many times the gradient needs to be repeated to fill the object bounding box
1746
+ }
1747
+ if (this.name === 'linearGradient') {
1748
+ grad = doc.linearGradient(x1 - nBefore * (x2 - x1), y1 - nBefore * (y2 - y1), x2 + nAfter * (x2 - x1), y2 + nAfter * (y2 - y1));
1749
+ } else {
1750
+ grad = doc.radialGradient(x1, y1, 0, x2, y2, r2 + nAfter * r2);
1751
+ }
1752
+ for (let n = 0; n < nTotal; n++) {
1753
+ let offset = 0,
1754
+ inOrder = (spread !== 'reflect' || (n - nBefore) % 2 === 0);
1755
+ for (let i = 0; i < children.length; i++) {
1756
+ let child = children[inOrder ? i : children.length - 1 - i],
1757
+ stopColor = child.get('stop-color');
1758
+ if (stopColor === 'none') {stopColor = DefaultColors.transparent;}
1759
+ stopColor = opacityToColor(stopColor, child.get('stop-opacity') * gOpacity, isMask);
1760
+ offset = Math.max(offset, inOrder ? child.getPercent('offset', 0) : 1 - child.getPercent('offset', 0));
1761
+ if (i === 0 && stopColor[0].length === 4) {grad._colorSpace = 'DeviceCMYK';} // Fix until PR #763 is merged into PDFKit
1762
+ if (i === 0 && offset > 0) {
1763
+ grad.stop((n + 0) / nTotal, stopColor[0], stopColor[1]);
1764
+ }
1765
+ grad.stop((n + offset) / (nAfter + nBefore + 1), stopColor[0], stopColor[1]);
1766
+ if (i === children.length - 1 && offset < 1) {
1767
+ grad.stop((n + 1) / nTotal, stopColor[0], stopColor[1]);
1768
+ }
1769
+ }
1770
+ }
1771
+ grad.setTransform.apply(grad, matrix);
1772
+ return [grad, 1];
1773
+ } else {
1774
+ return fallback ? [fallback[0], fallback[1] * gOpacity] : undefined;
1775
+ }
1776
+ }
1777
+ };
1778
+
1779
+ var SvgElemBasicShape = function(obj, inherits) {
1780
+ SvgElemStylable.call(this, obj, inherits);
1781
+ this.dashScale = 1;
1782
+ this.getBoundingShape = function() {
1783
+ return this.shape;
1784
+ };
1785
+ this.getTransformation = function() {
1786
+ return this.get('transform');
1787
+ };
1788
+ this.drawInDocument = function(isClip, isMask) {
1789
+ if (this.get('visibility') === 'hidden' || !this.shape) {return;}
1790
+ doc.save();
1791
+ this.transform();
1792
+ this.clip();
1793
+ if (!isClip) {
1794
+ let masked = this.mask(),
1795
+ group;
1796
+ if (masked) {
1797
+ group = docBeginGroup(getPageBBox());
1798
+ }
1799
+ let subPaths = this.shape.getSubPaths(),
1800
+ fill = this.getFill(isClip, isMask),
1801
+ stroke = this.getStroke(isClip, isMask),
1802
+ lineWidth = this.get('stroke-width'),
1803
+ lineCap = this.get('stroke-linecap');
1804
+ if (fill || stroke) {
1805
+ if (fill) {
1806
+ docFillColor(fill);
1807
+ }
1808
+ if (stroke) {
1809
+ for (let j = 0; j < subPaths.length; j++) {
1810
+ if (isEqual(subPaths[j].totalLength, 0)) {
1811
+ if ((lineCap === 'square' || lineCap === 'round') && lineWidth > 0) {
1812
+ if (subPaths[j].startPoint && subPaths[j].startPoint.length > 1) {
1813
+ let x = subPaths[j].startPoint[0],
1814
+ y = subPaths[j].startPoint[1];
1815
+ docFillColor(stroke);
1816
+ if (lineCap === 'square') {
1817
+ doc.rect(x - 0.5 * lineWidth, y - 0.5 * lineWidth, lineWidth, lineWidth);
1818
+ } else if (lineCap === 'round') {
1819
+ doc.circle(x, y, 0.5 * lineWidth);
1820
+ }
1821
+ doc.fill();
1822
+ }
1823
+ }
1824
+ }
1825
+ }
1826
+ let dashArray = this.get('stroke-dasharray'),
1827
+ dashOffset = this.get('stroke-dashoffset');
1828
+ if (isNotEqual(this.dashScale, 1)) {
1829
+ for (let j = 0; j < dashArray.length; j++) {
1830
+ dashArray[j] *= this.dashScale;
1831
+ }
1832
+ dashOffset *= this.dashScale;
1833
+ }
1834
+ docStrokeColor(stroke);
1835
+ doc.lineWidth(lineWidth)
1836
+ .miterLimit(this.get('stroke-miterlimit'))
1837
+ .lineJoin(this.get('stroke-linejoin'))
1838
+ .lineCap(lineCap)
1839
+ .dash(dashArray, {phase: dashOffset});
1840
+ }
1841
+ for (let j = 0; j < subPaths.length; j++) {
1842
+ if (subPaths[j].totalLength > 0) {
1843
+ subPaths[j].insertInDocument();
1844
+ }
1845
+ }
1846
+ if (fill && stroke) {
1847
+ doc.fillAndStroke(this.get('fill-rule'));
1848
+ } else if (fill) {
1849
+ doc.fill(this.get('fill-rule'));
1850
+ } else if (stroke) {
1851
+ doc.stroke();
1852
+ }
1853
+ }
1854
+ let markerStart = this.get('marker-start'),
1855
+ markerMid = this.get('marker-mid'),
1856
+ markerEnd = this.get('marker-end');
1857
+ if (markerStart !== 'none' || markerMid !== 'none' || markerEnd !== 'none') {
1858
+ let markersPos = this.shape.getMarkers();
1859
+ if (markerStart !== 'none') {
1860
+ let marker = new SvgElemMarker(markerStart, null);
1861
+ marker.drawMarker(false, isMask, markersPos[0], lineWidth);
1862
+ }
1863
+ if (markerMid !== 'none') {
1864
+ for (let i = 1; i < markersPos.length - 1; i++) {
1865
+ let marker = new SvgElemMarker(markerMid, null);
1866
+ marker.drawMarker(false, isMask, markersPos[i], lineWidth);
1867
+ }
1868
+ }
1869
+ if (markerEnd !== 'none') {
1870
+ let marker = new SvgElemMarker(markerEnd, null);
1871
+ marker.drawMarker(false, isMask, markersPos[markersPos.length - 1], lineWidth);
1872
+ }
1873
+ }
1874
+ if (group) {
1875
+ docEndGroup(group);
1876
+ docInsertGroup(group);
1877
+ }
1878
+ } else {
1879
+ this.shape.insertInDocument();
1880
+ docFillColor(DefaultColors.white);
1881
+ doc.fill(this.get('clip-rule'));
1882
+ }
1883
+ doc.restore();
1884
+ };
1885
+ };
1886
+
1887
+ var SvgElemRect = function(obj, inherits) {
1888
+ SvgElemBasicShape.call(this, obj, inherits);
1889
+ let x = this.getLength('x', this.getVWidth(), 0),
1890
+ y = this.getLength('y', this.getVHeight(), 0),
1891
+ w = this.getLength('width', this.getVWidth(), 0),
1892
+ h = this.getLength('height', this.getVHeight(), 0),
1893
+ rx = this.getLength('rx', this.getVWidth()),
1894
+ ry = this.getLength('ry', this.getVHeight());
1895
+ if (rx === undefined && ry === undefined) {rx = ry = 0;}
1896
+ else if (rx === undefined && ry !== undefined) {rx = ry;}
1897
+ else if (rx !== undefined && ry === undefined) {ry = rx;}
1898
+ if (w > 0 && h > 0) {
1899
+ if (rx && ry) {
1900
+ rx = Math.min(rx, 0.5 * w);
1901
+ ry = Math.min(ry, 0.5 * h);
1902
+ this.shape = new SvgShape().M(x + rx, y).L(x + w - rx, y).A(rx, ry, 0, 0, 1, x + w, y + ry)
1903
+ .L(x + w, y + h - ry).A(rx, ry, 0, 0, 1, x + w - rx, y + h).L(x + rx, y + h)
1904
+ .A(rx, ry, 0, 0, 1, x, y + h - ry).L(x, y + ry).A(rx, ry, 0, 0, 1, x + rx, y).Z();
1905
+ } else {
1906
+ this.shape = new SvgShape().M(x, y).L(x + w, y).L(x + w, y + h).L(x, y + h).Z();
1907
+ }
1908
+ } else {
1909
+ this.shape = new SvgShape();
1910
+ }
1911
+ };
1912
+
1913
+ var SvgElemCircle = function(obj, inherits) {
1914
+ SvgElemBasicShape.call(this, obj, inherits);
1915
+ let cx = this.getLength('cx', this.getVWidth(), 0),
1916
+ cy = this.getLength('cy', this.getVHeight(), 0),
1917
+ r = this.getLength('r', this.getViewport(), 0);
1918
+ if (r > 0) {
1919
+ 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();
1920
+ } else {
1921
+ this.shape = new SvgShape();
1922
+ }
1923
+ };
1924
+
1925
+ var SvgElemEllipse = function(obj, inherits) {
1926
+ SvgElemBasicShape.call(this, obj, inherits);
1927
+ let cx = this.getLength('cx', this.getVWidth(), 0),
1928
+ cy = this.getLength('cy', this.getVHeight(), 0),
1929
+ rx = this.getLength('rx', this.getVWidth(), 0),
1930
+ ry = this.getLength('ry', this.getVHeight(), 0);
1931
+ if (rx > 0 && ry > 0) {
1932
+ 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();
1933
+ } else {
1934
+ this.shape = new SvgShape();
1935
+ }
1936
+ };
1937
+
1938
+ var SvgElemLine = function(obj, inherits) {
1939
+ SvgElemBasicShape.call(this, obj, inherits);
1940
+ let x1 = this.getLength('x1', this.getVWidth(), 0),
1941
+ y1 = this.getLength('y1', this.getVHeight(), 0),
1942
+ x2 = this.getLength('x2', this.getVWidth(), 0),
1943
+ y2 = this.getLength('y2', this.getVHeight(), 0);
1944
+ this.shape = new SvgShape().M(x1, y1).L(x2, y2);
1945
+ };
1946
+
1947
+ var SvgElemPolyline = function(obj, inherits) {
1948
+ SvgElemBasicShape.call(this, obj, inherits);
1949
+ let points = this.getNumberList('points');
1950
+ this.shape = new SvgShape();
1951
+ for (let i = 0; i < points.length - 1; i += 2) {
1952
+ if (i === 0) {
1953
+ this.shape.M(points[i], points[i+1]);
1954
+ } else {
1955
+ this.shape.L(points[i], points[i+1]);
1956
+ }
1957
+ }
1958
+ if (points.error) {warningCallback('SvgElemPolygon: unexpected string ' + points.error);}
1959
+ if (points.length % 2 === 1) {warningCallback('SvgElemPolyline: uneven number of coordinates');}
1960
+ };
1961
+
1962
+ var SvgElemPolygon = function(obj, inherits) {
1963
+ SvgElemBasicShape.call(this, obj, inherits);
1964
+ let points = this.getNumberList('points');
1965
+ this.shape = new SvgShape();
1966
+ for (let i = 0; i < points.length - 1; i += 2) {
1967
+ if (i === 0) {
1968
+ this.shape.M(points[i], points[i+1]);
1969
+ } else {
1970
+ this.shape.L(points[i], points[i+1]);
1971
+ }
1972
+ }
1973
+ this.shape.Z();
1974
+ if (points.error) {warningCallback('SvgElemPolygon: unexpected string ' + points.error);}
1975
+ if (points.length % 2 === 1) {warningCallback('SvgElemPolygon: uneven number of coordinates');}
1976
+ };
1977
+
1978
+ var SvgElemPath = function(obj, inherits) {
1979
+ SvgElemBasicShape.call(this, obj, inherits);
1980
+ this.shape = new SvgShape().path(this.attr('d'));
1981
+ let pathLength = this.getLength('pathLength', this.getViewport());
1982
+ this.pathLength = pathLength > 0 ? pathLength : undefined;
1983
+ this.dashScale = (this.pathLength !== undefined ? this.shape.totalLength / this.pathLength : 1);
1984
+ };
1985
+
1986
+ var SvgElemMarker = function(obj, inherits) {
1987
+ SvgElemHasChildren.call(this, obj, inherits);
1988
+ let width = this.getLength('markerWidth', this.getParentVWidth(), 3),
1989
+ height = this.getLength('markerHeight', this.getParentVHeight(), 3),
1990
+ viewBox = this.getViewbox('viewBox', [0, 0, width, height]);
1991
+ this.getVWidth = function() {
1992
+ return viewBox[2];
1993
+ };
1994
+ this.getVHeight = function() {
1995
+ return viewBox[3];
1996
+ };
1997
+ this.drawMarker = function(isClip, isMask, posArray, strokeWidth) {
1998
+ doc.save();
1999
+ let orient = this.attr('orient'),
2000
+ units = this.attr('markerUnits'),
2001
+ rotate = (orient === 'auto' ? posArray[2] : (parseFloat(orient) || 0) * Math.PI / 180),
2002
+ scale = (units === 'userSpaceOnUse' ? 1 : strokeWidth);
2003
+ doc.transform(Math.cos(rotate) * scale, Math.sin(rotate) * scale, -Math.sin(rotate) * scale, Math.cos(rotate) * scale, posArray[0], posArray[1]);
2004
+ let refX = this.getLength('refX', this.getVWidth(), 0),
2005
+ refY = this.getLength('refY', this.getVHeight(), 0),
2006
+ aspectRatioMatrix = parseAspectRatio(this.attr('preserveAspectRatio'), width, height, viewBox[2], viewBox[3], 0.5);
2007
+ if (this.get('overflow') === 'hidden') {
2008
+ 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();
2009
+ }
2010
+ doc.transform.apply(doc, aspectRatioMatrix);
2011
+ doc.translate(-refX, -refY);
2012
+ let group;
2013
+ if (this.get('opacity') < 1 && !isClip) {
2014
+ group = docBeginGroup(getPageBBox());
2015
+ }
2016
+ this.drawChildren(isClip, isMask);
2017
+ if (group) {
2018
+ docEndGroup(group);
2019
+ doc.fillOpacity(this.get('opacity'));
2020
+ docInsertGroup(group);
2021
+ }
2022
+ doc.restore();
2023
+ };
2024
+ };
2025
+
2026
+ var SvgElemClipPath = function(obj, inherits) {
2027
+ SvgElemHasChildren.call(this, obj, inherits);
2028
+ this.useMask = function(bBox) {
2029
+ let group = docBeginGroup(getPageBBox());
2030
+ doc.save();
2031
+ if (this.attr('clipPathUnits') === 'objectBoundingBox') {
2032
+ doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
2033
+ }
2034
+ this.clip();
2035
+ this.drawChildren(true, false);
2036
+ doc.restore();
2037
+ docEndGroup(group);
2038
+ docApplyMask(group, true);
2039
+ };
2040
+ };
2041
+
2042
+ var SvgElemMask = function(obj, inherits) {
2043
+ SvgElemHasChildren.call(this, obj, inherits);
2044
+ this.useMask = function(bBox) {
2045
+ let group = docBeginGroup(getPageBBox());
2046
+ doc.save();
2047
+ let x, y, w, h;
2048
+ if (this.attr('maskUnits') === 'userSpaceOnUse') {
2049
+ x = this.getLength('x', this.getVWidth(), -0.1 * (bBox[2] - bBox[0]) + bBox[0]);
2050
+ y = this.getLength('y', this.getVHeight(), -0.1 * (bBox[3] - bBox[1]) + bBox[1]);
2051
+ w = this.getLength('width', this.getVWidth(), 1.2 * (bBox[2] - bBox[0]));
2052
+ h = this.getLength('height', this.getVHeight(), 1.2 * (bBox[3] - bBox[1]));
2053
+ } else {
2054
+ x = this.getLength('x', this.getVWidth(), -0.1) * (bBox[2] - bBox[0]) + bBox[0];
2055
+ y = this.getLength('y', this.getVHeight(), -0.1) * (bBox[3] - bBox[1]) + bBox[1];
2056
+ w = this.getLength('width', this.getVWidth(), 1.2) * (bBox[2] - bBox[0]);
2057
+ h = this.getLength('height', this.getVHeight(), 1.2) * (bBox[3] - bBox[1]);
2058
+ }
2059
+ doc.rect(x, y, w, h).clip();
2060
+ if (this.attr('maskContentUnits') === 'objectBoundingBox') {
2061
+ doc.transform(bBox[2] - bBox[0], 0, 0, bBox[3] - bBox[1], bBox[0], bBox[1]);
2062
+ }
2063
+ this.clip();
2064
+ this.drawChildren(false, true);
2065
+ doc.restore();
2066
+ docEndGroup(group);
2067
+ docApplyMask(group, true);
2068
+ };
2069
+ };
2070
+
2071
+ var SvgElemTextContainer = function(obj, inherits) {
2072
+ SvgElemStylable.call(this, obj, inherits);
2073
+ this.allowedChildren = ['tspan', '#text', '#cdata-section', 'a'];
2074
+ this.isText = true;
2075
+ this.getBoundingShape = function() {
2076
+ let shape = new SvgShape();
2077
+ for (let i = 0; i < this._pos.length; i++) {
2078
+ let pos = this._pos[i];
2079
+ if (!pos.hidden) {
2080
+ let dx0 = pos.ascent * Math.sin(pos.rotate), dy0 = -pos.ascent * Math.cos(pos.rotate),
2081
+ dx1 = pos.descent * Math.sin(pos.rotate), dy1 = -pos.descent * Math.cos(pos.rotate),
2082
+ dx2 = pos.width * Math.cos(pos.rotate), dy2 = pos.width * Math.sin(pos.rotate);
2083
+ shape.M(pos.x + dx0, pos.y + dy0).L(pos.x + dx0 + dx2, pos.y + dy0 + dy2)
2084
+ .M(pos.x + dx1 + dx2, pos.y + dy1 + dy2).L(pos.x + dx1, pos.y + dy1);
2085
+ }
2086
+ }
2087
+ return shape;
2088
+ };
2089
+ this.drawTextInDocument = function(isClip, isMask) {
2090
+ if (this.link && !isClip && !isMask) {this.addLink();}
2091
+ if (this.get('text-decoration') === 'underline') {
2092
+ this.decorate(0.05 * this._font.size, -0.075 * this._font.size, isClip, isMask);
2093
+ }
2094
+ if (this.get('text-decoration') === 'overline') {
2095
+ this.decorate(0.05 * this._font.size, getAscent(this._font.font, this._font.size) + 0.075 * this._font.size, isClip, isMask);
2096
+ }
2097
+ let fill = this.getFill(isClip, isMask),
2098
+ stroke = this.getStroke(isClip, isMask),
2099
+ strokeWidth = this.get('stroke-width');
2100
+ if (this._font.fauxBold) {
2101
+ if (!stroke) {
2102
+ stroke = fill;
2103
+ strokeWidth = this._font.size * 0.03;
2104
+ } else {
2105
+ strokeWidth += this._font.size * 0.03;
2106
+ }
2107
+ }
2108
+ let children = this.getChildren();
2109
+ for (let i = 0; i < children.length; i++) {
2110
+ let childElem = children[i];
2111
+ switch(childElem.name) {
2112
+ case 'tspan': case 'textPath': case 'a':
2113
+ if (childElem.get('display') !== 'none') {
2114
+ childElem.drawTextInDocument(isClip, isMask);
2115
+ }
2116
+ break;
2117
+ case '#text': case '#cdata-section':
2118
+ if (this.get('visibility') === 'hidden') {continue;}
2119
+ if (fill || stroke || isClip) {
2120
+ if (fill) {
2121
+ docFillColor(fill);
2122
+ }
2123
+ if (stroke && strokeWidth) {
2124
+ docStrokeColor(stroke);
2125
+ doc.lineWidth(strokeWidth)
2126
+ .miterLimit(this.get('stroke-miterlimit'))
2127
+ .lineJoin(this.get('stroke-linejoin'))
2128
+ .lineCap(this.get('stroke-linecap'))
2129
+ .dash(this.get('stroke-dasharray'), {phase:this.get('stroke-dashoffset')});
2130
+ }
2131
+ docBeginText(this._font.font, this._font.size);
2132
+ docSetTextMode(!!fill, !!stroke);
2133
+ for (let j = 0, pos = childElem._pos; j < pos.length; j++) {
2134
+ if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
2135
+ let cos = Math.cos(pos[j].rotate), sin = Math.sin(pos[j].rotate), skew = (this._font.fauxItalic ? -0.25 : 0);
2136
+ docSetTextMatrix(cos * pos[j].scale, sin * pos[j].scale, cos * skew - sin, sin * skew + cos, pos[j].x, pos[j].y);
2137
+ docWriteGlyph(pos[j].glyph);
2138
+ }
2139
+ }
2140
+ docEndText();
2141
+ }
2142
+ break;
2143
+ }
2144
+ }
2145
+ if (this.get('text-decoration') === 'line-through') {
2146
+ 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);
2147
+ }
2148
+ };
2149
+ this.decorate = function(lineWidth, linePosition, isClip, isMask) {
2150
+ let fill = this.getFill(isClip, isMask),
2151
+ stroke = this.getStroke(isClip, isMask);
2152
+ if (fill) {
2153
+ docFillColor(fill);
2154
+ }
2155
+ if (stroke) {
2156
+ docStrokeColor(stroke);
2157
+ doc.lineWidth(this.get('stroke-width'))
2158
+ .miterLimit(this.get('stroke-miterlimit'))
2159
+ .lineJoin(this.get('stroke-linejoin'))
2160
+ .lineCap(this.get('stroke-linecap'))
2161
+ .dash(this.get('stroke-dasharray'), {phase:this.get('stroke-dashoffset')});
2162
+ }
2163
+ for (let j = 0, pos = this._pos; j < pos.length; j++) {
2164
+ if (!pos[j].hidden && isNotEqual(pos[j].width, 0)) {
2165
+ let dx0 = (linePosition + lineWidth / 2) * Math.sin(pos[j].rotate),
2166
+ dy0 = -(linePosition + lineWidth / 2) * Math.cos(pos[j].rotate),
2167
+ dx1 = (linePosition - lineWidth / 2) * Math.sin(pos[j].rotate),
2168
+ dy1 = -(linePosition - lineWidth / 2) * Math.cos(pos[j].rotate),
2169
+ dx2 = pos[j].width * Math.cos(pos[j].rotate),
2170
+ dy2 = pos[j].width * Math.sin(pos[j].rotate);
2171
+ new SvgShape().M(pos[j].x + dx0, pos[j].y + dy0)
2172
+ .L(pos[j].x + dx0 + dx2, pos[j].y + dy0 + dy2)
2173
+ .L(pos[j].x + dx1 + dx2, pos[j].y + dy1 + dy2)
2174
+ .L(pos[j].x + dx1, pos[j].y + dy1).Z()
2175
+ .insertInDocument();
2176
+ if (fill && stroke) {
2177
+ doc.fillAndStroke();
2178
+ } else if (fill) {
2179
+ doc.fill();
2180
+ } else if (stroke) {
2181
+ doc.stroke();
2182
+ }
2183
+ }
2184
+ }
2185
+ };
2186
+ };
2187
+
2188
+ var SvgElemTextNode = function(obj, inherits) {
2189
+ this.name = obj.nodeName;
2190
+ this.textContent = obj.nodeValue;
2191
+ };
2192
+
2193
+ var SvgElemTspan = function(obj, inherits) {
2194
+ SvgElemTextContainer.call(this, obj, inherits);
2195
+ };
2196
+
2197
+ var SvgElemTextPath = function(obj, inherits) {
2198
+ SvgElemTextContainer.call(this, obj, inherits);
2199
+ let pathObject, pathLength, temp;
2200
+ if ((temp = this.attr('path')) && temp.trim() !== '') {
2201
+ let pathLength = this.getLength('pathLength', this.getViewport());
2202
+ this.pathObject = new SvgShape().path(temp);
2203
+ this.pathLength = pathLength > 0 ? pathLength : this.pathObject.totalLength;
2204
+ this.pathScale = this.pathObject.totalLength / this.pathLength;
2205
+ } else if ((temp = this.getUrl('href') || this.getUrl('xlink:href')) && temp.nodeName === 'path') {
2206
+ let pathElem = new SvgElemPath(temp, this);
2207
+ this.pathObject = pathElem.shape.clone().transform(pathElem.get('transform'));
2208
+ this.pathLength = this.chooseValue(pathElem.pathLength, this.pathObject.totalLength);
2209
+ this.pathScale = this.pathObject.totalLength / this.pathLength;
2210
+ }
2211
+ };
2212
+
2213
+ var SvgElemText = function(obj, inherits) {
2214
+ SvgElemTextContainer.call(this, obj, inherits);
2215
+ this.allowedChildren = ['textPath', 'tspan', '#text', '#cdata-section', 'a'];
2216
+ (function (textParentElem) {
2217
+ let processedText = '', remainingText = obj.textContent, textPaths = [], currentChunk = [], currentAnchor, currentDirection, currentX = 0, currentY = 0;
2218
+ function doAnchoring() {
2219
+ if (currentChunk.length) {
2220
+ let last = currentChunk[currentChunk.length - 1];
2221
+ let first = currentChunk[0]
2222
+ let width = last.x + last.width - first.x;
2223
+ let anchordx = {'startltr': 0, 'middleltr': 0.5, 'endltr': 1, 'startrtl': 1, 'middlertl': 0.5, 'endrtl': 0}[currentAnchor + currentDirection] * width || 0;
2224
+ for (let i = 0; i < currentChunk.length; i++) {
2225
+ currentChunk[i].x -= anchordx;
2226
+ }
2227
+ }
2228
+ currentChunk = [];
2229
+ }
2230
+ function adjustLength(pos, length, spacingAndGlyphs) {
2231
+ let firstChar = pos[0], lastChar = pos[pos.length - 1],
2232
+ startX = firstChar.x, endX = lastChar.x + lastChar.width;
2233
+ if (spacingAndGlyphs) {
2234
+ let textScale = length / (endX - startX);
2235
+ if (textScale > 0 && textScale < Infinity) {
2236
+ for (let j = 0; j < pos.length; j++) {
2237
+ pos[j].x = startX + textScale * (pos[j].x - startX);
2238
+ pos[j].scale *= textScale;
2239
+ pos[j].width *= textScale;
2240
+ }
2241
+ }
2242
+ } else {
2243
+ if (pos.length >= 2) {
2244
+ let spaceDiff = (length - (endX - startX)) / (pos.length - 1);
2245
+ for (let j = 0; j < pos.length; j++) {
2246
+ pos[j].x += j * spaceDiff;
2247
+ }
2248
+ }
2249
+ }
2250
+ currentX += length - (endX - startX);
2251
+ }
2252
+ function recursive(currentElem, parentElem) {
2253
+ currentElem._x = combineArrays(currentElem.getLengthList('x', currentElem.getVWidth()), (parentElem ? parentElem._x.slice(parentElem._pos.length) : []));
2254
+ currentElem._y = combineArrays(currentElem.getLengthList('y', currentElem.getVHeight()), (parentElem ? parentElem._y.slice(parentElem._pos.length) : []));
2255
+ currentElem._dx = combineArrays(currentElem.getLengthList('dx', currentElem.getVWidth()), (parentElem ? parentElem._dx.slice(parentElem._pos.length) : []));
2256
+ currentElem._dy = combineArrays(currentElem.getLengthList('dy', currentElem.getVHeight()), (parentElem ? parentElem._dy.slice(parentElem._pos.length) : []));
2257
+ currentElem._rot = combineArrays(currentElem.getNumberList('rotate'), (parentElem ? parentElem._rot.slice(parentElem._pos.length) : []));
2258
+ currentElem._defRot = currentElem.chooseValue(currentElem._rot[currentElem._rot.length - 1], parentElem && parentElem._defRot, 0);
2259
+ if (currentElem.name === 'textPath') {currentElem._y = [];}
2260
+ let fontOptions = {fauxItalic: false, fauxBold: false},
2261
+ fontNameorLink = fontCallback(currentElem.get('font-family'), currentElem.get('font-weight') === 'bold', currentElem.get('font-style') === 'italic', fontOptions);
2262
+ try {
2263
+ doc.font(fontNameorLink);
2264
+ } catch(e) {
2265
+ warningCallback('SVGElemText: failed to open font "' + fontNameorLink + '" in PDFKit');
2266
+ }
2267
+ currentElem._pos = [];
2268
+ currentElem._index = 0;
2269
+ currentElem._font = {font: doc._font, size: currentElem.get('font-size'), fauxItalic: fontOptions.fauxItalic, fauxBold: fontOptions.fauxBold};
2270
+ let textLength = currentElem.getLength('textLength', currentElem.getVWidth(), undefined),
2271
+ spacingAndGlyphs = currentElem.attr('lengthAdjust') === 'spacingAndGlyphs',
2272
+ wordSpacing = currentElem.get('word-spacing'),
2273
+ letterSpacing = currentElem.get('letter-spacing'),
2274
+ textAnchor = currentElem.get('text-anchor'),
2275
+ textDirection = currentElem.get('direction'),
2276
+ baseline = getBaseline(currentElem._font.font, currentElem._font.size, currentElem.get('alignment-baseline') || currentElem.get('dominant-baseline'), currentElem.get('baseline-shift'));
2277
+ if (currentElem.name === 'textPath') {
2278
+ doAnchoring();
2279
+ currentX = currentY = 0;
2280
+ }
2281
+ let children = currentElem.getChildren();
2282
+ for (let i = 0; i < children.length; i++) {
2283
+ let childElem = children[i];
2284
+ switch(childElem.name) {
2285
+ case 'tspan': case 'textPath': case 'a':
2286
+ recursive(childElem, currentElem);
2287
+ break;
2288
+ case '#text': case '#cdata-section':
2289
+ let rawText = childElem.textContent, renderedText = rawText, words;
2290
+ childElem._font = currentElem._font;
2291
+ childElem._pos = [];
2292
+ remainingText = remainingText.substring(rawText.length);
2293
+ if (currentElem.get('xml:space') === 'preserve') {
2294
+ renderedText = renderedText.replace(/[\s]/g, ' ');
2295
+ } else {
2296
+ renderedText = renderedText.replace(/[\s]+/g, ' ');
2297
+ if (processedText.match(/[\s]$|^$/)) {renderedText = renderedText.replace(/^[\s]/, '');}
2298
+ if (remainingText.match(/^[\s]*$/)) {renderedText = renderedText.replace(/[\s]$/, '');}
2299
+ }
2300
+ processedText += rawText;
2301
+ if (wordSpacing === 0) {
2302
+ words = [renderedText];
2303
+ } else {
2304
+ words = renderedText.split(/(\s)/);
2305
+ }
2306
+ for (let w = 0; w < words.length; w++) {
2307
+ let pos = getTextPos(currentElem._font.font, currentElem._font.size, words[w]);
2308
+ for (let j = 0; j < pos.length; j++) {
2309
+ let index = currentElem._index,
2310
+ xAttr = currentElem._x[index],
2311
+ yAttr = currentElem._y[index],
2312
+ dxAttr = currentElem._dx[index],
2313
+ dyAttr = currentElem._dy[index],
2314
+ rotAttr = currentElem._rot[index],
2315
+ continuous = !(w === 0 && j === 0);
2316
+ if (xAttr !== undefined) {continuous = false; doAnchoring(); currentX = xAttr;}
2317
+ if (yAttr !== undefined) {continuous = false; doAnchoring(); currentY = yAttr;}
2318
+ if (dxAttr !== undefined) {continuous = false; currentX += dxAttr;}
2319
+ if (dyAttr !== undefined) {continuous = false; currentY += dyAttr;}
2320
+ if (rotAttr !== undefined || currentElem._defRot !== 0) {continuous = false;}
2321
+ let position = {
2322
+ glyph: pos[j].glyph,
2323
+ rotate: (Math.PI / 180) * currentElem.chooseValue(rotAttr, currentElem._defRot),
2324
+ x: currentX + pos[j].xOffset,
2325
+ y: currentY + baseline + pos[j].yOffset,
2326
+ width: pos[j].width,
2327
+ ascent: getAscent(currentElem._font.font, currentElem._font.size),
2328
+ descent: getDescent(currentElem._font.font, currentElem._font.size),
2329
+ scale: 1,
2330
+ hidden: false,
2331
+ continuous: continuous
2332
+ };
2333
+ currentChunk.push(position);
2334
+ childElem._pos.push(position);
2335
+ currentElem._pos.push(position);
2336
+ currentElem._index += pos[j].unicode.length;
2337
+ if (currentChunk.length === 1) {
2338
+ currentAnchor = textAnchor;
2339
+ currentDirection = textDirection;
2340
+ }
2341
+ currentX += pos[j].xAdvance + letterSpacing;
2342
+ currentY += pos[j].yAdvance;
2343
+ }
2344
+ if (words[w] === ' ') {
2345
+ currentX += wordSpacing;
2346
+ }
2347
+ }
2348
+ break;
2349
+ default:
2350
+ remainingText = remainingText.substring(childElem.textContent.length);
2351
+ }
2352
+ }
2353
+ if (textLength && currentElem._pos.length) {
2354
+ adjustLength(currentElem._pos, textLength, spacingAndGlyphs);
2355
+ }
2356
+ if (currentElem.name === 'textPath' || currentElem.name === 'text') {
2357
+ doAnchoring();
2358
+ }
2359
+ if (currentElem.name === 'textPath') {
2360
+ textPaths.push(currentElem);
2361
+ let pathObject = currentElem.pathObject;
2362
+ if (pathObject) {
2363
+ currentX = pathObject.endPoint[0]; currentY = pathObject.endPoint[1];
2364
+ }
2365
+ }
2366
+ if (parentElem) {
2367
+ parentElem._pos = parentElem._pos.concat(currentElem._pos);
2368
+ parentElem._index += currentElem._index;
2369
+ }
2370
+ }
2371
+ function textOnPath(currentElem) {
2372
+ let pathObject = currentElem.pathObject,
2373
+ pathLength = currentElem.pathLength,
2374
+ pathScale = currentElem.pathScale;
2375
+ if (pathObject) {
2376
+ let textOffset = currentElem.getLength('startOffset', pathLength, 0);
2377
+ for (let j = 0; j < currentElem._pos.length; j++) {
2378
+ let charMidX = textOffset + currentElem._pos[j].x + 0.5 * currentElem._pos[j].width;
2379
+ if (charMidX > pathLength || charMidX < 0) {
2380
+ currentElem._pos[j].hidden = true;
2381
+ } else {
2382
+ let pointOnPath = pathObject.getPointAtLength(charMidX * pathScale);
2383
+ if (isNotEqual(pathScale, 1)) {
2384
+ currentElem._pos[j].scale *= pathScale;
2385
+ currentElem._pos[j].width *= pathScale;
2386
+ }
2387
+ currentElem._pos[j].x = pointOnPath[0] - 0.5 * currentElem._pos[j].width * Math.cos(pointOnPath[2]) - currentElem._pos[j].y * Math.sin(pointOnPath[2]);
2388
+ currentElem._pos[j].y = pointOnPath[1] - 0.5 * currentElem._pos[j].width * Math.sin(pointOnPath[2]) + currentElem._pos[j].y * Math.cos(pointOnPath[2]);
2389
+ currentElem._pos[j].rotate = pointOnPath[2] + currentElem._pos[j].rotate;
2390
+ currentElem._pos[j].continuous = false;
2391
+ }
2392
+ }
2393
+ } else {
2394
+ for (let j = 0; j < currentElem._pos.length; j++) {
2395
+ currentElem._pos[j].hidden = true;
2396
+ }
2397
+ }
2398
+ }
2399
+ recursive(textParentElem, null);
2400
+ for (let i = 0; i < textPaths.length; i++) {
2401
+ textOnPath(textPaths[i]);
2402
+ }
2403
+ })(this);
2404
+ this.getTransformation = function() {
2405
+ return this.get('transform');
2406
+ };
2407
+ this.drawInDocument = function(isClip, isMask) {
2408
+ doc.save();
2409
+ this.transform();
2410
+ this.clip();
2411
+ let masked = this.mask(), group;
2412
+ if (masked) {
2413
+ group = docBeginGroup(getPageBBox());
2414
+ }
2415
+ this.drawTextInDocument(isClip, isMask);
2416
+ if (group) {
2417
+ docEndGroup(group);
2418
+ docInsertGroup(group);
2419
+ }
2420
+ doc.restore();
2421
+ };
2422
+ };
2423
+
2424
+ options = options || {};
2425
+ var pxToPt = options.assumePt ? 1 : (72/96), // 1px = 72/96pt, but only if assumePt is false
2426
+ viewportWidth = (options.width || doc.page.width) / pxToPt,
2427
+ viewportHeight = (options.height || doc.page.height) / pxToPt,
2428
+ preserveAspectRatio = options.preserveAspectRatio || null, // default to null so that the attr can override if not passed
2429
+ useCSS = options.useCSS && typeof SVGElement !== 'undefined' && svg instanceof SVGElement && typeof getComputedStyle === 'function',
2430
+ warningCallback = options.warningCallback,
2431
+ fontCallback = options.fontCallback,
2432
+ imageCallback = options.imageCallback,
2433
+ colorCallback = options.colorCallback,
2434
+ documentCallback = options.documentCallback,
2435
+ precision = Math.ceil(Math.max(1, options.precision)) || 3,
2436
+ groupStack = [],
2437
+ documentCache = {},
2438
+ links = [],
2439
+ styleRules = [];
2440
+
2441
+ if (typeof warningCallback !== 'function') {
2442
+ warningCallback = function(str) {
2443
+ if (typeof console !== undefined && typeof console.warn === 'function') {console.warn(str);}
2444
+ };
2445
+ }
2446
+ if (typeof fontCallback !== 'function') {
2447
+ fontCallback = function(family, bold, italic, fontOptions) {
2448
+ // Check if the font is already registered in the document
2449
+ if (bold && italic) {
2450
+ if (doc._registeredFonts.hasOwnProperty(family + '-BoldItalic')) {
2451
+ return family + '-BoldItalic';
2452
+ } else if (doc._registeredFonts.hasOwnProperty(family + '-Italic')) {
2453
+ fontOptions.fauxBold = true;
2454
+ return family + '-Italic';
2455
+ } else if (doc._registeredFonts.hasOwnProperty(family + '-Bold')) {
2456
+ fontOptions.fauxItalic = true;
2457
+ return family + '-Bold';
2458
+ } else if (doc._registeredFonts.hasOwnProperty(family)) {
2459
+ fontOptions.fauxBold = true;
2460
+ fontOptions.fauxItalic = true;
2461
+ return family;
2462
+ }
2463
+ }
2464
+ if (bold && !italic) {
2465
+ if (doc._registeredFonts.hasOwnProperty(family + '-Bold')) {
2466
+ return family + '-Bold';
2467
+ } else if (doc._registeredFonts.hasOwnProperty(family)) {
2468
+ fontOptions.fauxBold = true;
2469
+ return family;
2470
+ }
2471
+ }
2472
+ if (!bold && italic) {
2473
+ if (doc._registeredFonts.hasOwnProperty(family + '-Italic')) {
2474
+ return family + '-Italic';
2475
+ } else if (doc._registeredFonts.hasOwnProperty(family)) {
2476
+ fontOptions.fauxItalic = true;
2477
+ return family;
2478
+ }
2479
+ }
2480
+ if (!bold && !italic) {
2481
+ if (doc._registeredFonts.hasOwnProperty(family)) {
2482
+ return family;
2483
+ }
2484
+ }
2485
+ // Use standard fonts as fallback
2486
+ if (family.match(/(?:^|,)\s*serif\s*$/)) {
2487
+ if (bold && italic) {return 'Times-BoldItalic';}
2488
+ if (bold && !italic) {return 'Times-Bold';}
2489
+ if (!bold && italic) {return 'Times-Italic';}
2490
+ if (!bold && !italic) {return 'Times-Roman';}
2491
+ } else if (family.match(/(?:^|,)\s*monospace\s*$/)) {
2492
+ if (bold && italic) {return 'Courier-BoldOblique';}
2493
+ if (bold && !italic) {return 'Courier-Bold';}
2494
+ if (!bold && italic) {return 'Courier-Oblique';}
2495
+ if (!bold && !italic) {return 'Courier';}
2496
+ } else if (family.match(/(?:^|,)\s*sans-serif\s*$/) || true) {
2497
+ if (bold && italic) {return 'Helvetica-BoldOblique';}
2498
+ if (bold && !italic) {return 'Helvetica-Bold';}
2499
+ if (!bold && italic) {return 'Helvetica-Oblique';}
2500
+ if (!bold && !italic) {return 'Helvetica';}
2501
+ }
2502
+ };
2503
+ }
2504
+ if (typeof imageCallback !== 'function') {
2505
+ imageCallback = function(link) {
2506
+ return link.replace(/\s+/g, '');
2507
+ };
2508
+ }
2509
+ if (typeof colorCallback !== 'function') {
2510
+ colorCallback = null;
2511
+ } else {
2512
+ for (let color in DefaultColors) {
2513
+ let newColor = colorCallback(DefaultColors[color]);
2514
+ DefaultColors[color][0] = newColor[0];
2515
+ DefaultColors[color][1] = newColor[1];
2516
+ }
2517
+ }
2518
+ if (typeof documentCallback !== 'function') {
2519
+ documentCallback = null;
2520
+ }
2521
+
2522
+ if (typeof svg === 'string') {svg = parseXml(svg);}
2523
+ if (svg) {
2524
+ let styles = svg.getElementsByTagName('style');
2525
+ for (let i = 0; i < styles.length; i++) {
2526
+ styleRules = styleRules.concat(parseStyleSheet(styles[i].textContent));
2527
+ }
2528
+ let elem = createSVGElement(svg, null);
2529
+ if (typeof elem.drawInDocument === 'function') {
2530
+ if (options.useCSS && !useCSS) {
2531
+ warningCallback('SVGtoPDF: useCSS option can only be used for SVG *elements* in compatible browsers');
2532
+ }
2533
+ let savedFillColor = doc._fillColor;
2534
+ doc.save().translate(x || 0, y || 0).scale(pxToPt);
2535
+ elem.drawInDocument();
2536
+ for (let i = 0; i < links.length; i++) {
2537
+ doc.page.annotations.push(links[i]);
2538
+ }
2539
+ doc.restore();
2540
+ doc._fillColor = savedFillColor;
2541
+ } else {
2542
+ warningCallback('SVGtoPDF: this element can\'t be rendered directly: ' + svg.nodeName);
2543
+ }
2544
+ } else {
2545
+ warningCallback('SVGtoPDF: the input does not look like a valid SVG');
2546
+ }
2547
+
2548
+ };
2549
+
2550
+ if (typeof module !== 'undefined' && module && typeof module.exports !== 'undefined') {
2551
+ module.exports = SVGtoPDF;
2552
+ }