fabric 7.1.0 → 7.2.0

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 (253) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/CHANGELOG.md +13 -0
  3. package/dist/extensions/cropping_controls/croppingControls.d.ts +12 -8
  4. package/dist/extensions/cropping_controls/croppingControls.d.ts.map +1 -1
  5. package/dist/extensions/cropping_controls/croppingHandlers.d.ts +19 -1
  6. package/dist/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -1
  7. package/dist/extensions/cropping_controls/enterCropMode.d.ts.map +1 -1
  8. package/dist/index.js +189 -160
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/index.min.mjs +1 -1
  13. package/dist/index.min.mjs.map +1 -1
  14. package/dist/index.mjs +189 -160
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.node.cjs +189 -160
  17. package/dist/index.node.cjs.map +1 -1
  18. package/dist/index.node.mjs +189 -160
  19. package/dist/index.node.mjs.map +1 -1
  20. package/dist/package.json.min.mjs +1 -1
  21. package/dist/package.json.mjs +1 -1
  22. package/dist/src/EventTypeDefs.d.ts +3 -0
  23. package/dist/src/EventTypeDefs.d.ts.map +1 -1
  24. package/dist/src/Pattern/Pattern.d.ts.map +1 -1
  25. package/dist/src/Pattern/Pattern.min.mjs +1 -1
  26. package/dist/src/Pattern/Pattern.min.mjs.map +1 -1
  27. package/dist/src/Pattern/Pattern.mjs +2 -1
  28. package/dist/src/Pattern/Pattern.mjs.map +1 -1
  29. package/dist/src/Shadow.d.ts +1 -1
  30. package/dist/src/Shadow.d.ts.map +1 -1
  31. package/dist/src/Shadow.min.mjs +1 -1
  32. package/dist/src/Shadow.min.mjs.map +1 -1
  33. package/dist/src/Shadow.mjs +5 -4
  34. package/dist/src/Shadow.mjs.map +1 -1
  35. package/dist/src/canvas/CanvasOptions.d.ts.map +1 -1
  36. package/dist/src/canvas/CanvasOptions.min.mjs.map +1 -1
  37. package/dist/src/canvas/CanvasOptions.mjs.map +1 -1
  38. package/dist/src/canvas/SelectableCanvas.d.ts +2 -0
  39. package/dist/src/canvas/SelectableCanvas.d.ts.map +1 -1
  40. package/dist/src/canvas/SelectableCanvas.min.mjs +1 -1
  41. package/dist/src/canvas/SelectableCanvas.min.mjs.map +1 -1
  42. package/dist/src/canvas/SelectableCanvas.mjs +6 -1
  43. package/dist/src/canvas/SelectableCanvas.mjs.map +1 -1
  44. package/dist/src/canvas/StaticCanvas.d.ts.map +1 -1
  45. package/dist/src/canvas/StaticCanvas.min.mjs +1 -1
  46. package/dist/src/canvas/StaticCanvas.min.mjs.map +1 -1
  47. package/dist/src/canvas/StaticCanvas.mjs +3 -1
  48. package/dist/src/canvas/StaticCanvas.mjs.map +1 -1
  49. package/dist/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
  50. package/dist/src/canvas/StaticCanvasOptions.min.mjs.map +1 -1
  51. package/dist/src/canvas/StaticCanvasOptions.mjs.map +1 -1
  52. package/dist/src/controls/Control.d.ts +9 -1
  53. package/dist/src/controls/Control.d.ts.map +1 -1
  54. package/dist/src/controls/Control.min.mjs +1 -1
  55. package/dist/src/controls/Control.min.mjs.map +1 -1
  56. package/dist/src/controls/Control.mjs +8 -0
  57. package/dist/src/controls/Control.mjs.map +1 -1
  58. package/dist/src/gradient/Gradient.d.ts.map +1 -1
  59. package/dist/src/gradient/Gradient.min.mjs +1 -1
  60. package/dist/src/gradient/Gradient.min.mjs.map +1 -1
  61. package/dist/src/gradient/Gradient.mjs +19 -6
  62. package/dist/src/gradient/Gradient.mjs.map +1 -1
  63. package/dist/src/shapes/Circle.d.ts.map +1 -1
  64. package/dist/src/shapes/Circle.min.mjs +1 -1
  65. package/dist/src/shapes/Circle.min.mjs.map +1 -1
  66. package/dist/src/shapes/Circle.mjs +10 -7
  67. package/dist/src/shapes/Circle.mjs.map +1 -1
  68. package/dist/src/shapes/Ellipse.d.ts.map +1 -1
  69. package/dist/src/shapes/Ellipse.min.mjs +1 -1
  70. package/dist/src/shapes/Ellipse.min.mjs.map +1 -1
  71. package/dist/src/shapes/Ellipse.mjs +2 -1
  72. package/dist/src/shapes/Ellipse.mjs.map +1 -1
  73. package/dist/src/shapes/Group.d.ts.map +1 -1
  74. package/dist/src/shapes/Group.min.mjs +1 -1
  75. package/dist/src/shapes/Group.min.mjs.map +1 -1
  76. package/dist/src/shapes/Group.mjs +2 -1
  77. package/dist/src/shapes/Group.mjs.map +1 -1
  78. package/dist/src/shapes/IText/IText.d.ts.map +1 -1
  79. package/dist/src/shapes/IText/IText.min.mjs.map +1 -1
  80. package/dist/src/shapes/IText/IText.mjs.map +1 -1
  81. package/dist/src/shapes/Image.d.ts +1 -1
  82. package/dist/src/shapes/Image.d.ts.map +1 -1
  83. package/dist/src/shapes/Image.min.mjs +1 -1
  84. package/dist/src/shapes/Image.min.mjs.map +1 -1
  85. package/dist/src/shapes/Image.mjs +4 -3
  86. package/dist/src/shapes/Image.mjs.map +1 -1
  87. package/dist/src/shapes/Line.d.ts.map +1 -1
  88. package/dist/src/shapes/Line.min.mjs +1 -1
  89. package/dist/src/shapes/Line.min.mjs.map +1 -1
  90. package/dist/src/shapes/Line.mjs +6 -10
  91. package/dist/src/shapes/Line.mjs.map +1 -1
  92. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
  93. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs +1 -1
  94. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs.map +1 -1
  95. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs +5 -4
  96. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs.map +1 -1
  97. package/dist/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  98. package/dist/src/shapes/Object/InteractiveObject.min.mjs.map +1 -1
  99. package/dist/src/shapes/Object/InteractiveObject.mjs.map +1 -1
  100. package/dist/src/shapes/Object/Object.d.ts.map +1 -1
  101. package/dist/src/shapes/Object/Object.min.mjs +1 -1
  102. package/dist/src/shapes/Object/Object.min.mjs.map +1 -1
  103. package/dist/src/shapes/Object/Object.mjs +3 -0
  104. package/dist/src/shapes/Object/Object.mjs.map +1 -1
  105. package/dist/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
  106. package/dist/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
  107. package/dist/src/shapes/Path.d.ts.map +1 -1
  108. package/dist/src/shapes/Path.min.mjs.map +1 -1
  109. package/dist/src/shapes/Path.mjs +1 -2
  110. package/dist/src/shapes/Path.mjs.map +1 -1
  111. package/dist/src/shapes/Polyline.d.ts.map +1 -1
  112. package/dist/src/shapes/Polyline.min.mjs +1 -1
  113. package/dist/src/shapes/Polyline.min.mjs.map +1 -1
  114. package/dist/src/shapes/Polyline.mjs +10 -6
  115. package/dist/src/shapes/Polyline.mjs.map +1 -1
  116. package/dist/src/shapes/Rect.d.ts.map +1 -1
  117. package/dist/src/shapes/Rect.min.mjs +1 -1
  118. package/dist/src/shapes/Rect.min.mjs.map +1 -1
  119. package/dist/src/shapes/Rect.mjs +2 -1
  120. package/dist/src/shapes/Rect.mjs.map +1 -1
  121. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  122. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  123. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  124. package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs +1 -1
  125. package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs.map +1 -1
  126. package/dist/src/shapes/Text/TextSVGExportMixin.mjs +5 -5
  127. package/dist/src/shapes/Text/TextSVGExportMixin.mjs.map +1 -1
  128. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  129. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  130. package/dist/src/shapes/Textbox.mjs.map +1 -1
  131. package/dist/src/shapes/Triangle.d.ts.map +1 -1
  132. package/dist/src/shapes/Triangle.min.mjs.map +1 -1
  133. package/dist/src/shapes/Triangle.mjs.map +1 -1
  134. package/dist/src/util/lang_string.d.ts +1 -1
  135. package/dist/src/util/lang_string.d.ts.map +1 -1
  136. package/dist/src/util/lang_string.min.mjs +1 -1
  137. package/dist/src/util/lang_string.min.mjs.map +1 -1
  138. package/dist/src/util/lang_string.mjs +1 -1
  139. package/dist/src/util/lang_string.mjs.map +1 -1
  140. package/dist/src/util/misc/svgParsing.d.ts.map +1 -1
  141. package/dist/src/util/misc/svgParsing.min.mjs +1 -1
  142. package/dist/src/util/misc/svgParsing.min.mjs.map +1 -1
  143. package/dist/src/util/misc/svgParsing.mjs +2 -1
  144. package/dist/src/util/misc/svgParsing.mjs.map +1 -1
  145. package/dist-extensions/cropping_controls/croppingControls.mjs +39 -9
  146. package/dist-extensions/cropping_controls/croppingControls.mjs.map +1 -1
  147. package/dist-extensions/cropping_controls/croppingHandlers.mjs +84 -2
  148. package/dist-extensions/cropping_controls/croppingHandlers.mjs.map +1 -1
  149. package/dist-extensions/cropping_controls/enterCropMode.mjs +7 -2
  150. package/dist-extensions/cropping_controls/enterCropMode.mjs.map +1 -1
  151. package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts +12 -8
  152. package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts.map +1 -1
  153. package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts +19 -1
  154. package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -1
  155. package/dist-extensions/extensions/cropping_controls/enterCropMode.d.ts.map +1 -1
  156. package/dist-extensions/fabric-extensions.min.js +1 -1
  157. package/dist-extensions/fabric-extensions.min.js.map +1 -1
  158. package/dist-extensions/src/EventTypeDefs.d.ts +3 -0
  159. package/dist-extensions/src/EventTypeDefs.d.ts.map +1 -1
  160. package/dist-extensions/src/Pattern/Pattern.d.ts.map +1 -1
  161. package/dist-extensions/src/Shadow.d.ts +1 -1
  162. package/dist-extensions/src/Shadow.d.ts.map +1 -1
  163. package/dist-extensions/src/canvas/CanvasOptions.d.ts.map +1 -1
  164. package/dist-extensions/src/canvas/SelectableCanvas.d.ts +2 -0
  165. package/dist-extensions/src/canvas/SelectableCanvas.d.ts.map +1 -1
  166. package/dist-extensions/src/canvas/StaticCanvas.d.ts.map +1 -1
  167. package/dist-extensions/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
  168. package/dist-extensions/src/controls/Control.d.ts +9 -1
  169. package/dist-extensions/src/controls/Control.d.ts.map +1 -1
  170. package/dist-extensions/src/gradient/Gradient.d.ts.map +1 -1
  171. package/dist-extensions/src/shapes/Circle.d.ts.map +1 -1
  172. package/dist-extensions/src/shapes/Ellipse.d.ts.map +1 -1
  173. package/dist-extensions/src/shapes/Group.d.ts.map +1 -1
  174. package/dist-extensions/src/shapes/IText/IText.d.ts.map +1 -1
  175. package/dist-extensions/src/shapes/Image.d.ts.map +1 -1
  176. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  177. package/dist-extensions/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
  178. package/dist-extensions/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  179. package/dist-extensions/src/shapes/Object/Object.d.ts.map +1 -1
  180. package/dist-extensions/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
  181. package/dist-extensions/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
  182. package/dist-extensions/src/shapes/Path.d.ts +1 -1
  183. package/dist-extensions/src/shapes/Path.d.ts.map +1 -1
  184. package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
  185. package/dist-extensions/src/shapes/Rect.d.ts.map +1 -1
  186. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  187. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  188. package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
  189. package/dist-extensions/src/util/lang_string.d.ts +1 -1
  190. package/dist-extensions/src/util/lang_string.d.ts.map +1 -1
  191. package/dist-extensions/src/util/misc/svgParsing.d.ts.map +1 -1
  192. package/eslint.config.mjs +2 -0
  193. package/extensions/cropping_controls/croppingControls.spec.ts +65 -27
  194. package/extensions/cropping_controls/croppingControls.ts +40 -8
  195. package/extensions/cropping_controls/croppingHandlers.spec.ts +355 -46
  196. package/extensions/cropping_controls/croppingHandlers.ts +123 -0
  197. package/extensions/cropping_controls/enterCropMode.ts +6 -2
  198. package/package.json +17 -8
  199. package/src/ClassRegistry.spec.ts +18 -19
  200. package/src/EventTypeDefs.ts +13 -11
  201. package/src/Pattern/Pattern.spec.ts +12 -0
  202. package/src/Pattern/Pattern.ts +3 -2
  203. package/src/Shadow.ts +9 -8
  204. package/src/brushes/PencilBrush.spec.ts +11 -11
  205. package/src/canvas/Canvas-dispose.spec.ts +8 -7
  206. package/src/canvas/Canvas.spec.ts +27 -29
  207. package/src/canvas/CanvasOptions.ts +2 -1
  208. package/src/canvas/SelectableCanvas.ts +11 -4
  209. package/src/canvas/StaticCanvas.spec.ts +20 -0
  210. package/src/canvas/StaticCanvas.ts +7 -4
  211. package/src/canvas/StaticCanvasOptions.ts +1 -3
  212. package/src/controls/Control.ts +24 -1
  213. package/src/gradient/Gradient.spec.ts +101 -46
  214. package/src/gradient/Gradient.ts +27 -14
  215. package/src/shapes/Circle.spec.ts +10 -39
  216. package/src/shapes/Circle.ts +11 -11
  217. package/src/shapes/Ellipse.spec.ts +8 -37
  218. package/src/shapes/Ellipse.ts +7 -7
  219. package/src/shapes/Group.ts +3 -3
  220. package/src/shapes/IText/IText-click-behavior.spec.ts +36 -49
  221. package/src/shapes/IText/IText.ts +5 -6
  222. package/src/shapes/IText/__snapshots__/ITextBehavior.test.ts.snap +6 -6
  223. package/src/shapes/Image.spec.ts +17 -33
  224. package/src/shapes/Image.ts +15 -11
  225. package/src/shapes/Line.spec.ts +4 -30
  226. package/src/shapes/Line.ts +11 -16
  227. package/src/shapes/Object/FabricObjectSVGExportMixin.ts +11 -4
  228. package/src/shapes/Object/InteractiveObject.ts +4 -4
  229. package/src/shapes/Object/Object.ts +6 -5
  230. package/src/shapes/Object/objectSvgExport.spec.ts +112 -0
  231. package/src/shapes/Object/types/FabricObjectProps.ts +1 -4
  232. package/src/shapes/Object/types/ObjectProps.ts +1 -3
  233. package/src/shapes/Path.spec.ts +4 -27
  234. package/src/shapes/Path.ts +2 -4
  235. package/src/shapes/Polygon.spec.ts +4 -31
  236. package/src/shapes/Polyline.spec.ts +4 -31
  237. package/src/shapes/Polyline.ts +11 -12
  238. package/src/shapes/Rect.spec.ts +25 -33
  239. package/src/shapes/Rect.ts +7 -7
  240. package/src/shapes/Text/Text.spec.ts +3 -32
  241. package/src/shapes/Text/Text.ts +5 -6
  242. package/src/shapes/Text/TextSVGExportMixin.ts +14 -14
  243. package/src/shapes/Text/__snapshots__/Text.spec.ts.snap +1 -1
  244. package/src/shapes/Textbox.spec.ts +5 -5
  245. package/src/shapes/Textbox.ts +6 -5
  246. package/src/shapes/Triangle.ts +4 -4
  247. package/src/shapes/__snapshots__/Image.spec.ts.snap +4 -4
  248. package/src/shapes/__snapshots__/Textbox.spec.ts.snap +5 -5
  249. package/src/util/lang_string.ts +3 -2
  250. package/src/util/misc/svgParsing.ts +2 -1
  251. package/tsconfig.spec.json +1 -0
  252. package/vitest.config.ts +12 -2
  253. package/vitest.extend.ts +6 -2
package/dist/index.js CHANGED
@@ -362,7 +362,7 @@
362
362
  }
363
363
  const cache = new Cache();
364
364
 
365
- var version = "7.1.0";
365
+ var version = "7.2.0";
366
366
 
367
367
  // use this syntax so babel plugin see this import here
368
368
  const VERSION = version;
@@ -2197,6 +2197,111 @@
2197
2197
  patternQuality: 'best'
2198
2198
  };
2199
2199
 
2200
+ /**
2201
+ * Capitalizes a string
2202
+ * @param {String} string String to capitalize
2203
+ * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
2204
+ * and other letters stay untouched, if false first letter is capitalized
2205
+ * and other letters are converted to lowercase.
2206
+ * @return {String} Capitalized version of a string
2207
+ */
2208
+ const capitalize = function (string) {
2209
+ let firstLetterOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2210
+ return `${string.charAt(0).toUpperCase()}${firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()}`;
2211
+ };
2212
+
2213
+ /**
2214
+ * Escapes XML in a string
2215
+ * @param {String} string String to escape
2216
+ * @return {String} Escaped version of a string
2217
+ */
2218
+ const escapeXml = stringOrNumber => stringOrNumber.toString().replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2219
+ let segmenter;
2220
+ const getSegmenter = () => {
2221
+ if (!segmenter) {
2222
+ segmenter = 'Intl' in getFabricWindow() && 'Segmenter' in Intl && new Intl.Segmenter(undefined, {
2223
+ granularity: 'grapheme'
2224
+ });
2225
+ }
2226
+ return segmenter;
2227
+ };
2228
+
2229
+ /**
2230
+ * Divide a string in the user perceived single units
2231
+ * @param {String} textstring String to escape
2232
+ * @return {Array} array containing the graphemes
2233
+ */
2234
+ const graphemeSplit = textstring => {
2235
+ segmenter || getSegmenter();
2236
+ if (segmenter) {
2237
+ const segments = segmenter.segment(textstring);
2238
+ return Array.from(segments).map(_ref => {
2239
+ let {
2240
+ segment
2241
+ } = _ref;
2242
+ return segment;
2243
+ });
2244
+ }
2245
+
2246
+ //Fallback
2247
+ return graphemeSplitImpl(textstring);
2248
+ };
2249
+ const graphemeSplitImpl = textstring => {
2250
+ const graphemes = [];
2251
+ for (let i = 0, chr; i < textstring.length; i++) {
2252
+ if ((chr = getWholeChar(textstring, i)) === false) {
2253
+ continue;
2254
+ }
2255
+ graphemes.push(chr);
2256
+ }
2257
+ return graphemes;
2258
+ };
2259
+
2260
+ // taken from mdn in the charAt doc page.
2261
+ const getWholeChar = (str, i) => {
2262
+ const code = str.charCodeAt(i);
2263
+ if (isNaN(code)) {
2264
+ return ''; // Position not found
2265
+ }
2266
+ if (code < 0xd800 || code > 0xdfff) {
2267
+ return str.charAt(i);
2268
+ }
2269
+
2270
+ // High surrogate (could change last hex to 0xDB7F to treat high private
2271
+ // surrogates as single characters)
2272
+ if (0xd800 <= code && code <= 0xdbff) {
2273
+ if (str.length <= i + 1) {
2274
+ throw 'High surrogate without following low surrogate';
2275
+ }
2276
+ const next = str.charCodeAt(i + 1);
2277
+ if (0xdc00 > next || next > 0xdfff) {
2278
+ throw 'High surrogate without following low surrogate';
2279
+ }
2280
+ return str.charAt(i) + str.charAt(i + 1);
2281
+ }
2282
+ // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
2283
+ if (i === 0) {
2284
+ throw 'Low surrogate without preceding high surrogate';
2285
+ }
2286
+ const prev = str.charCodeAt(i - 1);
2287
+
2288
+ // (could change last hex to 0xDB7F to treat high private
2289
+ // surrogates as single characters)
2290
+ if (0xd800 > prev || prev > 0xdbff) {
2291
+ throw 'Low surrogate without preceding high surrogate';
2292
+ }
2293
+ // We can pass over low surrogates now as the second component
2294
+ // in a pair which we have already processed
2295
+ return false;
2296
+ };
2297
+
2298
+ var lang_string = /*#__PURE__*/Object.freeze({
2299
+ __proto__: null,
2300
+ capitalize: capitalize,
2301
+ escapeXml: escapeXml,
2302
+ graphemeSplit: graphemeSplit
2303
+ });
2304
+
2200
2305
  /**
2201
2306
  * Having both options in TCanvasSizeOptions set to true transform the call in a calcOffset
2202
2307
  * Better try to restrict with types to avoid confusion.
@@ -2966,7 +3071,8 @@
2966
3071
  this._setSVGPreamble(markup, options);
2967
3072
  this._setSVGHeader(markup, options);
2968
3073
  if (this.clipPath) {
2969
- markup.push(`<g clip-path="url(#${this.clipPath.clipPathId})" >\n`);
3074
+ var _this$clipPath$clipPa;
3075
+ markup.push(`<g clip-path="url(#${escapeXml((_this$clipPath$clipPa = this.clipPath.clipPathId) !== null && _this$clipPath$clipPa !== void 0 ? _this$clipPath$clipPa : '')})" >\n`);
2970
3076
  }
2971
3077
  this._setSVGBgOverlayColor(markup, 'background');
2972
3078
  this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);
@@ -4593,7 +4699,7 @@
4593
4699
  if (!value) {
4594
4700
  colorValue = 'none';
4595
4701
  } else if (value.toLive) {
4596
- colorValue = `url(#SVGID_${value.id})`;
4702
+ colorValue = `url(#SVGID_${escapeXml(value.id)})`;
4597
4703
  } else {
4598
4704
  const color = new Color(value),
4599
4705
  opacity = color.getAlpha();
@@ -4646,7 +4752,7 @@
4646
4752
  filter = skipShadow ? '' : this.getSvgFilter(),
4647
4753
  fill = colorPropToSVG(FILL, this.fill),
4648
4754
  stroke = colorPropToSVG(STROKE, this.stroke);
4649
- return [stroke, 'stroke-width: ', strokeWidth, '; ', 'stroke-dasharray: ', strokeDashArray, '; ', 'stroke-linecap: ', strokeLineCap, '; ', 'stroke-dashoffset: ', strokeDashOffset, '; ', 'stroke-linejoin: ', strokeLineJoin, '; ', 'stroke-miterlimit: ', strokeMiterLimit, '; ', fill, 'fill-rule: ', fillRule, '; ', 'opacity: ', opacity, ';', filter, visibility].join('');
4755
+ return [stroke, 'stroke-width: ', strokeWidth, '; ', 'stroke-dasharray: ', strokeDashArray, '; ', 'stroke-linecap: ', strokeLineCap, '; ', 'stroke-dashoffset: ', strokeDashOffset, '; ', 'stroke-linejoin: ', strokeLineJoin, '; ', 'stroke-miterlimit: ', strokeMiterLimit, '; ', fill, 'fill-rule: ', fillRule, '; ', 'opacity: ', opacity, ';', filter, visibility].map(v => escapeXml(v)).join('');
4650
4756
  }
4651
4757
 
4652
4758
  /**
@@ -4654,7 +4760,7 @@
4654
4760
  * @return {String}
4655
4761
  */
4656
4762
  getSvgFilter() {
4657
- return this.shadow ? `filter: url(#SVGID_${this.shadow.id});` : '';
4763
+ return this.shadow ? `filter: url(#SVGID_${escapeXml(this.shadow.id)});` : '';
4658
4764
  }
4659
4765
 
4660
4766
  /**
@@ -4662,7 +4768,7 @@
4662
4768
  * @return {String}
4663
4769
  */
4664
4770
  getSvgCommons() {
4665
- return [this.id ? `id="${this.id}" ` : '', this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : ''].join('');
4771
+ return [this.id ? `id="${escapeXml(String(this.id))}" ` : '', this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : ''].join('');
4666
4772
  }
4667
4773
 
4668
4774
  /**
@@ -4775,7 +4881,7 @@
4775
4881
  return reviver ? reviver(markup.join('')) : markup.join('');
4776
4882
  }
4777
4883
  addPaintOrder() {
4778
- return this.paintFirst !== FILL ? ` paint-order="${this.paintFirst}" ` : '';
4884
+ return this.paintFirst !== FILL ? ` paint-order="${escapeXml(this.paintFirst)}" ` : '';
4779
4885
  }
4780
4886
  }
4781
4887
 
@@ -4913,7 +5019,6 @@
4913
5019
 
4914
5020
  (?:$|\s): This captures either the end of the line or a whitespace character. It ensures that the match ends either at the end of the string or with a whitespace character.
4915
5021
  */
4916
- // eslint-disable-next-line max-len
4917
5022
 
4918
5023
  const shadowOffsetRegex = '(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?';
4919
5024
  const reOffsetsAndBlur = new RegExp('(?:\\s|^)' + shadowOffsetRegex + shadowOffsetRegex + '(' + reNum + '?(?:px)?)?(?:\\s?|$)(?:$|\\s)');
@@ -4972,14 +5077,15 @@
4972
5077
  toSVG(object) {
4973
5078
  const offset = rotateVector(new Point(this.offsetX, this.offsetY), degreesToRadians(-object.angle)),
4974
5079
  BLUR_BOX = 20,
5080
+ NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS,
4975
5081
  color = new Color(this.color);
4976
5082
  let fBoxX = 40,
4977
5083
  fBoxY = 40;
4978
5084
  if (object.width && object.height) {
4979
5085
  //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
4980
5086
  // we add some extra space to filter box to contain the blur ( 20 )
4981
- fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, config.NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
4982
- fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, config.NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5087
+ fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5088
+ fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
4983
5089
  }
4984
5090
  if (object.flipX) {
4985
5091
  offset.x *= -1;
@@ -4987,7 +5093,7 @@
4987
5093
  if (object.flipY) {
4988
5094
  offset.y *= -1;
4989
5095
  }
4990
- return `<filter id="SVGID_${this.id}" y="-${fBoxY}%" height="${100 + 2 * fBoxY}%" x="-${fBoxX}%" width="${100 + 2 * fBoxX}%" >\n\t<feGaussianBlur in="SourceAlpha" stdDeviation="${toFixed(this.blur ? this.blur / 2 : 0, config.NUM_FRACTION_DIGITS)}"></feGaussianBlur>\n\t<feOffset dx="${toFixed(offset.x, config.NUM_FRACTION_DIGITS)}" dy="${toFixed(offset.y, config.NUM_FRACTION_DIGITS)}" result="oBlur" ></feOffset>\n\t<feFlood flood-color="${color.toRgb()}" flood-opacity="${color.getAlpha()}"/>\n\t<feComposite in2="oBlur" operator="in" />\n\t<feMerge>\n\t\t<feMergeNode></feMergeNode>\n\t\t<feMergeNode in="SourceGraphic"></feMergeNode>\n\t</feMerge>\n</filter>\n`;
5096
+ return `<filter id="SVGID_${escapeXml(this.id)}" y="-${fBoxY}%" height="${100 + 2 * fBoxY}%" x="-${fBoxX}%" width="${100 + 2 * fBoxX}%" >\n\t<feGaussianBlur in="SourceAlpha" stdDeviation="${toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS)}"></feGaussianBlur>\n\t<feOffset dx="${toFixed(offset.x, NUM_FRACTION_DIGITS)}" dy="${toFixed(offset.y, NUM_FRACTION_DIGITS)}" result="oBlur" ></feOffset>\n\t<feFlood flood-color="${color.toRgb()}" flood-opacity="${color.getAlpha()}"/>\n\t<feComposite in2="oBlur" operator="in" />\n\t<feMerge>\n\t\t<feMergeNode></feMergeNode>\n\t\t<feMergeNode in="SourceGraphic"></feMergeNode>\n\t</feMerge>\n</filter>\n`;
4991
5097
  }
4992
5098
 
4993
5099
  /**
@@ -7138,6 +7244,9 @@
7138
7244
  } else {
7139
7245
  this._renderBackground(ctx);
7140
7246
  }
7247
+ this.fire('before:render', {
7248
+ ctx
7249
+ });
7141
7250
  this._render(ctx);
7142
7251
  this._drawClipPath(ctx, this.clipPath, context);
7143
7252
  this.fill = originalFill;
@@ -8428,6 +8537,14 @@
8428
8537
  _defineProperty(this, "withConnection", false);
8429
8538
  Object.assign(this, options);
8430
8539
  }
8540
+ getTransformAnchorPoint() {
8541
+ var _this$transformAnchor;
8542
+ return (// return the control transformAnchorPoint
8543
+ (_this$transformAnchor = this.transformAnchorPoint) !== null && _this$transformAnchor !== void 0 ? _this$transformAnchor :
8544
+ // otherwise will return the opposite origin of where the control is located.
8545
+ new Point(-this.x + 0.5, -this.y + 0.5)
8546
+ );
8547
+ }
8431
8548
 
8432
8549
  /**
8433
8550
  * The control actionHandler, provide one to handle action ( control being moved )
@@ -10243,111 +10360,6 @@
10243
10360
  return newObj;
10244
10361
  };
10245
10362
 
10246
- /**
10247
- * Capitalizes a string
10248
- * @param {String} string String to capitalize
10249
- * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
10250
- * and other letters stay untouched, if false first letter is capitalized
10251
- * and other letters are converted to lowercase.
10252
- * @return {String} Capitalized version of a string
10253
- */
10254
- const capitalize = function (string) {
10255
- let firstLetterOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
10256
- return `${string.charAt(0).toUpperCase()}${firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()}`;
10257
- };
10258
-
10259
- /**
10260
- * Escapes XML in a string
10261
- * @param {String} string String to escape
10262
- * @return {String} Escaped version of a string
10263
- */
10264
- const escapeXml = string => string.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
10265
- let segmenter;
10266
- const getSegmenter = () => {
10267
- if (!segmenter) {
10268
- segmenter = 'Intl' in getFabricWindow() && 'Segmenter' in Intl && new Intl.Segmenter(undefined, {
10269
- granularity: 'grapheme'
10270
- });
10271
- }
10272
- return segmenter;
10273
- };
10274
-
10275
- /**
10276
- * Divide a string in the user perceived single units
10277
- * @param {String} textstring String to escape
10278
- * @return {Array} array containing the graphemes
10279
- */
10280
- const graphemeSplit = textstring => {
10281
- segmenter || getSegmenter();
10282
- if (segmenter) {
10283
- const segments = segmenter.segment(textstring);
10284
- return Array.from(segments).map(_ref => {
10285
- let {
10286
- segment
10287
- } = _ref;
10288
- return segment;
10289
- });
10290
- }
10291
-
10292
- //Fallback
10293
- return graphemeSplitImpl(textstring);
10294
- };
10295
- const graphemeSplitImpl = textstring => {
10296
- const graphemes = [];
10297
- for (let i = 0, chr; i < textstring.length; i++) {
10298
- if ((chr = getWholeChar(textstring, i)) === false) {
10299
- continue;
10300
- }
10301
- graphemes.push(chr);
10302
- }
10303
- return graphemes;
10304
- };
10305
-
10306
- // taken from mdn in the charAt doc page.
10307
- const getWholeChar = (str, i) => {
10308
- const code = str.charCodeAt(i);
10309
- if (isNaN(code)) {
10310
- return ''; // Position not found
10311
- }
10312
- if (code < 0xd800 || code > 0xdfff) {
10313
- return str.charAt(i);
10314
- }
10315
-
10316
- // High surrogate (could change last hex to 0xDB7F to treat high private
10317
- // surrogates as single characters)
10318
- if (0xd800 <= code && code <= 0xdbff) {
10319
- if (str.length <= i + 1) {
10320
- throw 'High surrogate without following low surrogate';
10321
- }
10322
- const next = str.charCodeAt(i + 1);
10323
- if (0xdc00 > next || next > 0xdfff) {
10324
- throw 'High surrogate without following low surrogate';
10325
- }
10326
- return str.charAt(i) + str.charAt(i + 1);
10327
- }
10328
- // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
10329
- if (i === 0) {
10330
- throw 'Low surrogate without preceding high surrogate';
10331
- }
10332
- const prev = str.charCodeAt(i - 1);
10333
-
10334
- // (could change last hex to 0xDB7F to treat high private
10335
- // surrogates as single characters)
10336
- if (0xd800 > prev || prev > 0xdbff) {
10337
- throw 'Low surrogate without preceding high surrogate';
10338
- }
10339
- // We can pass over low surrogates now as the second component
10340
- // in a pair which we have already processed
10341
- return false;
10342
- };
10343
-
10344
- var lang_string = /*#__PURE__*/Object.freeze({
10345
- __proto__: null,
10346
- capitalize: capitalize,
10347
- escapeXml: escapeXml,
10348
- graphemeSplit: graphemeSplit
10349
- });
10350
-
10351
10363
  /**
10352
10364
  * @param {Object} prevStyle first style to compare
10353
10365
  * @param {Object} thisStyle second style to compare
@@ -10931,7 +10943,7 @@
10931
10943
  rx,
10932
10944
  ry
10933
10945
  } = this;
10934
- return ['<rect ', 'COMMON_PARTS', `x="${-width / 2}" y="${-height / 2}" rx="${rx}" ry="${ry}" width="${width}" height="${height}" />\n`];
10946
+ return ['<rect ', 'COMMON_PARTS', `x="${-width / 2}" y="${-height / 2}" rx="${escapeXml(rx)}" ry="${escapeXml(ry)}" width="${escapeXml(width)}" height="${escapeXml(height)}" />\n`];
10935
10947
  }
10936
10948
 
10937
10949
  /**
@@ -11896,7 +11908,7 @@
11896
11908
  * @return {String}
11897
11909
  */
11898
11910
  getSvgStyles() {
11899
- const opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ? `opacity: ${this.opacity};` : '',
11911
+ const opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ? `opacity: ${escapeXml(this.opacity)};` : '',
11900
11912
  visibility = this.visible ? '' : ' visibility: hidden;';
11901
11913
  return [opacity, this.getSvgFilter(), visibility].join('');
11902
11914
  }
@@ -13850,11 +13862,13 @@
13850
13862
  * Given the control clicked, determine the origin of the transform.
13851
13863
  * This is bad because controls can totally have custom names
13852
13864
  * should disappear before release 4.0
13865
+ * Fabric 7.1, jan 2026 we are still using this.
13866
+ * Needs to go.
13853
13867
  * @private
13854
13868
  * @deprecated
13855
13869
  */
13856
13870
  _getOriginFromCorner(target, controlName) {
13857
- const origin = {
13871
+ const origin = controlName ? target.controls[controlName].getTransformAnchorPoint() : {
13858
13872
  x: target.originX,
13859
13873
  y: target.originY
13860
13874
  };
@@ -13862,6 +13876,9 @@
13862
13876
  return origin;
13863
13877
  }
13864
13878
 
13879
+ // this part down here is deprecated.
13880
+ // It is left to do not change the standard behavior in the middle of a major version
13881
+ // but when possible `getTransformAnchorPoint` will be the only source of truth
13865
13882
  // is a left control ?
13866
13883
  if (['ml', 'tl', 'bl'].includes(controlName)) {
13867
13884
  origin.x = RIGHT;
@@ -16359,7 +16376,8 @@
16359
16376
  }
16360
16377
  transform[4] -= offsetX;
16361
16378
  transform[5] -= offsetY;
16362
- const commonAttributes = [`id="SVGID_${this.id}"`, `gradientUnits="${gradientUnits}"`, `gradientTransform="${preTransform ? preTransform + ' ' : ''}${matrixToSVG(transform)}"`, ''].join(' ');
16379
+ const commonAttributes = [`id="SVGID_${escapeXml(String(this.id))}"`, `gradientUnits="${gradientUnits}"`, `gradientTransform="${preTransform ? preTransform + ' ' : ''}${matrixToSVG(transform)}"`, ''].join(' ');
16380
+ const sanitizeCoord = value => parseFloat(String(value));
16363
16381
  if (this.type === 'linear') {
16364
16382
  const {
16365
16383
  x1,
@@ -16367,7 +16385,11 @@
16367
16385
  x2,
16368
16386
  y2
16369
16387
  } = this.coords;
16370
- markup.push('<linearGradient ', commonAttributes, ' x1="', x1, '" y1="', y1, '" x2="', x2, '" y2="', y2, '">\n');
16388
+ const sx1 = sanitizeCoord(x1);
16389
+ const sy1 = sanitizeCoord(y1);
16390
+ const sx2 = sanitizeCoord(x2);
16391
+ const sy2 = sanitizeCoord(y2);
16392
+ markup.push('<linearGradient ', commonAttributes, ' x1="', sx1, '" y1="', sy1, '" x2="', sx2, '" y2="', sy2, '">\n');
16371
16393
  } else if (this.type === 'radial') {
16372
16394
  const {
16373
16395
  x1,
@@ -16377,9 +16399,15 @@
16377
16399
  r1,
16378
16400
  r2
16379
16401
  } = this.coords;
16380
- const needsSwap = r1 > r2;
16402
+ const sx1 = sanitizeCoord(x1);
16403
+ const sy1 = sanitizeCoord(y1);
16404
+ const sx2 = sanitizeCoord(x2);
16405
+ const sy2 = sanitizeCoord(y2);
16406
+ const sr1 = sanitizeCoord(r1);
16407
+ const sr2 = sanitizeCoord(r2);
16408
+ const needsSwap = sr1 > sr2;
16381
16409
  // svg radial gradient has just 1 radius. the biggest.
16382
- markup.push('<radialGradient ', commonAttributes, ' cx="', needsSwap ? x1 : x2, '" cy="', needsSwap ? y1 : y2, '" r="', needsSwap ? r1 : r2, '" fx="', needsSwap ? x2 : x1, '" fy="', needsSwap ? y2 : y1, '">\n');
16410
+ markup.push('<radialGradient ', commonAttributes, ' cx="', needsSwap ? sx1 : sx2, '" cy="', needsSwap ? sy1 : sy2, '" r="', needsSwap ? sr1 : sr2, '" fx="', needsSwap ? sx2 : sx1, '" fy="', needsSwap ? sy2 : sy1, '">\n');
16383
16411
  if (needsSwap) {
16384
16412
  // svg goes from internal to external radius. if radius are inverted, swap color stops.
16385
16413
  colorStops.reverse(); // mutates array
@@ -16387,16 +16415,17 @@
16387
16415
  colorStop.offset = 1 - colorStop.offset;
16388
16416
  });
16389
16417
  }
16390
- const minRadius = Math.min(r1, r2);
16418
+ const minRadius = Math.min(sr1, sr2);
16391
16419
  if (minRadius > 0) {
16392
16420
  // i have to shift all colorStops and add new one in 0.
16393
- const maxRadius = Math.max(r1, r2),
16421
+ const maxRadius = Math.max(sr1, sr2),
16394
16422
  percentageShift = minRadius / maxRadius;
16395
16423
  colorStops.forEach(colorStop => {
16396
16424
  colorStop.offset += percentageShift * (1 - colorStop.offset);
16397
16425
  });
16398
16426
  }
16399
16427
  }
16428
+ // todo make a malicious script tag injection test with color and also apply a fix with escapeXml
16400
16429
  colorStops.forEach(_ref => {
16401
16430
  let {
16402
16431
  color,
@@ -16712,7 +16741,7 @@
16712
16741
  patternOffsetY = ifNaN(this.offsetY / height, 0),
16713
16742
  patternWidth = repeat === 'repeat-y' || repeat === 'no-repeat' ? 1 + Math.abs(patternOffsetX || 0) : ifNaN(patternSource.width / width, 0),
16714
16743
  patternHeight = repeat === 'repeat-x' || repeat === 'no-repeat' ? 1 + Math.abs(patternOffsetY || 0) : ifNaN(patternSource.height / height, 0);
16715
- return [`<pattern id="SVGID_${id}" x="${patternOffsetX}" y="${patternOffsetY}" width="${patternWidth}" height="${patternHeight}">`, `<image x="0" y="0" width="${patternSource.width}" height="${patternSource.height}" xlink:href="${this.sourceToString()}"></image>`, `</pattern>`, ''].join('\n');
16744
+ return [`<pattern id="SVGID_${escapeXml(id)}" x="${patternOffsetX}" y="${patternOffsetY}" width="${patternWidth}" height="${patternHeight}">`, `<image x="0" y="0" width="${patternSource.width}" height="${patternSource.height}" xlink:href="${escapeXml(this.sourceToString())}"></image>`, `</pattern>`, ''].join('\n');
16716
16745
  }
16717
16746
  /* _TO_SVG_END_ */
16718
16747
 
@@ -16994,8 +17023,7 @@
16994
17023
  * of the instance
16995
17024
  */
16996
17025
  _toSVG() {
16997
- const path = joinPath(this.path, config.NUM_FRACTION_DIGITS);
16998
- return ['<path ', 'COMMON_PARTS', `d="${path}" stroke-linecap="round" />\n`];
17026
+ return ['<path ', 'COMMON_PARTS', `d="${joinPath(this.path, config.NUM_FRACTION_DIGITS)}" stroke-linecap="round" />\n`];
16999
17027
  }
17000
17028
 
17001
17029
  /**
@@ -17546,15 +17574,17 @@
17546
17574
  * of the instance
17547
17575
  */
17548
17576
  _toSVG() {
17549
- const angle = (this.endAngle - this.startAngle) % 360;
17577
+ const {
17578
+ radius,
17579
+ startAngle,
17580
+ endAngle
17581
+ } = this;
17582
+ const angle = (endAngle - startAngle) % 360;
17550
17583
  if (angle === 0) {
17551
- return ['<circle ', 'COMMON_PARTS', 'cx="0" cy="0" ', 'r="', `${this.radius}`, '" />\n'];
17584
+ return ['<circle ', 'COMMON_PARTS', 'cx="0" cy="0" ', 'r="', `${escapeXml(radius)}`, '" />\n'];
17552
17585
  } else {
17553
- const {
17554
- radius
17555
- } = this;
17556
- const start = degreesToRadians(this.startAngle),
17557
- end = degreesToRadians(this.endAngle),
17586
+ const start = degreesToRadians(startAngle),
17587
+ end = degreesToRadians(endAngle),
17558
17588
  startX = cos(start) * radius,
17559
17589
  startY = sin(start) * radius,
17560
17590
  endX = cos(end) * radius,
@@ -18126,17 +18156,13 @@
18126
18156
  width,
18127
18157
  height
18128
18158
  } = this;
18129
- const xMult = _x1 <= _x2 ? -1 : 1,
18130
- yMult = _y1 <= _y2 ? -1 : 1,
18131
- x1 = xMult * width / 2,
18132
- y1 = yMult * height / 2,
18133
- x2 = xMult * -width / 2,
18134
- y2 = yMult * -height / 2;
18159
+ const xMult = _x1 <= _x2 ? -0.5 : 0.5,
18160
+ yMult = _y1 <= _y2 ? -0.5 : 0.5;
18135
18161
  return {
18136
- x1,
18137
- x2,
18138
- y1,
18139
- y2
18162
+ x1: xMult * width,
18163
+ x2: xMult * -width,
18164
+ y1: yMult * height,
18165
+ y2: yMult * -height
18140
18166
  };
18141
18167
  }
18142
18168
 
@@ -18354,7 +18380,7 @@
18354
18380
  * of the instance
18355
18381
  */
18356
18382
  _toSVG() {
18357
- return ['<ellipse ', 'COMMON_PARTS', `cx="0" cy="0" rx="${this.rx}" ry="${this.ry}" />\n`];
18383
+ return ['<ellipse ', 'COMMON_PARTS', `cx="0" cy="0" rx="${escapeXml(this.rx)}" ry="${escapeXml(this.ry)}" />\n`];
18358
18384
  }
18359
18385
 
18360
18386
  /**
@@ -18672,14 +18698,17 @@
18672
18698
  * of the instance
18673
18699
  */
18674
18700
  _toSVG() {
18675
- const points = [],
18676
- diffX = this.pathOffset.x,
18701
+ const diffX = this.pathOffset.x,
18677
18702
  diffY = this.pathOffset.y,
18678
18703
  NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS;
18679
- for (let i = 0, len = this.points.length; i < len; i++) {
18680
- points.push(toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',', toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' ');
18681
- }
18682
- return [`<${this.constructor.type.toLowerCase()} `, 'COMMON_PARTS', `points="${points.join('')}" />\n`];
18704
+ const points = this.points.map(_ref2 => {
18705
+ let {
18706
+ x,
18707
+ y
18708
+ } = _ref2;
18709
+ return `${toFixed(x - diffX, NUM_FRACTION_DIGITS)},${toFixed(y - diffY, NUM_FRACTION_DIGITS)}`;
18710
+ }).join(' ');
18711
+ return [`<${escapeXml(this.constructor.type).toLowerCase()} `, 'COMMON_PARTS', `points="${points}" />\n`];
18683
18712
  }
18684
18713
 
18685
18714
  /**
@@ -19103,7 +19132,7 @@
19103
19132
  } = _ref;
19104
19133
  const noShadow = true,
19105
19134
  textDecoration = this.getSvgTextDecoration(this);
19106
- return [textBgRects.join(''), '\t\t<text xml:space="preserve" ', `font-family="${this.fontFamily.replace(dblQuoteRegex, "'")}" `, `font-size="${this.fontSize}" `, this.fontStyle ? `font-style="${this.fontStyle}" ` : '', this.fontWeight ? `font-weight="${this.fontWeight}" ` : '', textDecoration ? `text-decoration="${textDecoration}" ` : '', this.direction === 'rtl' ? `direction="${this.direction}" ` : '', 'style="', this.getSvgStyles(noShadow), '"', this.addPaintOrder(), ' >', textSpans.join(''), '</text>\n'];
19135
+ return [textBgRects.join(''), '\t\t<text xml:space="preserve" ', `font-family="${escapeXml(this.fontFamily.replace(dblQuoteRegex, "'"))}" `, `font-size="${escapeXml(this.fontSize)}" `, this.fontStyle ? `font-style="${escapeXml(this.fontStyle)}" ` : '', this.fontWeight ? `font-weight="${escapeXml(this.fontWeight)}" ` : '', textDecoration ? `text-decoration="${textDecoration}" ` : '', this.direction === 'rtl' ? `direction="rtl" ` : '', 'style="', this.getSvgStyles(noShadow), '"', this.addPaintOrder(), ' >', textSpans.join(''), '</text>\n'];
19107
19136
  }
19108
19137
 
19109
19138
  /**
@@ -19119,7 +19148,7 @@
19119
19148
  lineOffset;
19120
19149
 
19121
19150
  // bounding-box background
19122
- this.backgroundColor && textBgRects.push(...createSVGInlineRect(this.backgroundColor, -this.width / 2, -this.height / 2, this.width, this.height));
19151
+ this.backgroundColor && textBgRects.push(createSVGInlineRect(this.backgroundColor, -this.width / 2, -this.height / 2, this.width, this.height));
19123
19152
 
19124
19153
  // text and text-background
19125
19154
  for (let i = 0, len = this._textLines.length; i < len; i++) {
@@ -19227,7 +19256,7 @@
19227
19256
  } = this.__charBounds[i][j];
19228
19257
  currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');
19229
19258
  if (currentColor !== lastColor) {
19230
- lastColor && textBgRects.push(...createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19259
+ lastColor && textBgRects.push(createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19231
19260
  boxStart = left;
19232
19261
  boxWidth = width;
19233
19262
  lastColor = currentColor;
@@ -19235,7 +19264,7 @@
19235
19264
  boxWidth += kernedWidth;
19236
19265
  }
19237
19266
  }
19238
- currentColor && textBgRects.push(...createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19267
+ currentColor && textBgRects.push(createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19239
19268
  }
19240
19269
 
19241
19270
  /**
@@ -19273,7 +19302,7 @@
19273
19302
  linethrough: linethrough !== null && linethrough !== void 0 ? linethrough : this.linethrough
19274
19303
  });
19275
19304
  const thickness = textDecorationThickness || this.textDecorationThickness;
19276
- return [stroke ? colorPropToSVG(STROKE, stroke) : '', strokeWidth ? `stroke-width: ${strokeWidth}; ` : '', fontFamily ? `font-family: ${!fontFamily.includes("'") && !fontFamily.includes('"') ? `'${fontFamily}'` : fontFamily}; ` : '', fontSize ? `font-size: ${fontSize}px; ` : '', fontStyle ? `font-style: ${fontStyle}; ` : '', fontWeight ? `font-weight: ${fontWeight}; ` : '', textDecoration ? `text-decoration: ${textDecoration}; text-decoration-thickness: ${toFixed(thickness * this.getObjectScaling().y / 10, config.NUM_FRACTION_DIGITS)}%; ` : '', fill ? colorPropToSVG(FILL, fill) : '', useWhiteSpace ? 'white-space: pre; ' : ''].join('');
19305
+ return [stroke ? colorPropToSVG(STROKE, stroke) : '', strokeWidth ? `stroke-width: ${escapeXml(strokeWidth)}; ` : '', fontFamily ? `font-family: ${!fontFamily.includes("'") && !fontFamily.includes('"') ? `'${escapeXml(fontFamily)}'` : escapeXml(fontFamily)}; ` : '', fontSize ? `font-size: ${escapeXml(fontSize)}px; ` : '', fontStyle ? `font-style: ${escapeXml(fontStyle)}; ` : '', fontWeight ? `font-weight: ${escapeXml(fontWeight)}; ` : '', textDecoration ? `text-decoration: ${textDecoration}; text-decoration-thickness: ${toFixed(thickness * this.getObjectScaling().y / 10, config.NUM_FRACTION_DIGITS)}%; ` : '', fill ? colorPropToSVG(FILL, fill) : '', useWhiteSpace ? 'white-space: pre; ' : ''].join('');
19277
19306
  }
19278
19307
 
19279
19308
  /**
@@ -24837,13 +24866,13 @@
24837
24866
  }
24838
24867
  if (this.hasCrop()) {
24839
24868
  const clipPathId = uid();
24840
- svgString.push('<clipPath id="imageCrop_' + clipPathId + '">\n', '\t<rect x="' + x + '" y="' + y + '" width="' + this.width + '" height="' + this.height + '" />\n', '</clipPath>\n');
24869
+ svgString.push('<clipPath id="imageCrop_' + clipPathId + '">\n', '\t<rect x="' + x + '" y="' + y + '" width="' + escapeXml(this.width) + '" height="' + escapeXml(this.height) + '" />\n', '</clipPath>\n');
24841
24870
  clipPath = ' clip-path="url(#imageCrop_' + clipPathId + ')" ';
24842
24871
  }
24843
24872
  if (!this.imageSmoothing) {
24844
24873
  imageRendering = ' image-rendering="optimizeSpeed"';
24845
24874
  }
24846
- imageMarkup.push('\t<image ', 'COMMON_PARTS', `xlink:href="${this.getSvgSrc(true)}" x="${x - this.cropX}" y="${y - this.cropY
24875
+ imageMarkup.push('\t<image ', 'COMMON_PARTS', `xlink:href="${escapeXml(this.getSrc(true))}" x="${x - this.cropX}" y="${y - this.cropY
24847
24876
  // we're essentially moving origin of transformation from top/left corner to the center of the shape
24848
24877
  // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
24849
24878
  // so that object's center aligns with container's left/top
@@ -24851,7 +24880,7 @@
24851
24880
  if (this.stroke || this.strokeDashArray) {
24852
24881
  const origFill = this.fill;
24853
24882
  this.fill = null;
24854
- strokeSvg = [`\t<rect x="${x}" y="${y}" width="${this.width}" height="${this.height}" style="${this.getSvgStyles()}" />\n`];
24883
+ strokeSvg = [`\t<rect x="${x}" y="${y}" width="${escapeXml(this.width)}" height="${escapeXml(this.height)}" style="${this.getSvgStyles()}" />\n`];
24855
24884
  this.fill = origFill;
24856
24885
  }
24857
24886
  if (this.paintFirst !== FILL) {