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
@@ -412,7 +412,7 @@ class Cache {
412
412
  }
413
413
  const cache = new Cache();
414
414
 
415
- var version = "7.1.0";
415
+ var version = "7.2.0";
416
416
 
417
417
  // use this syntax so babel plugin see this import here
418
418
  const VERSION = version;
@@ -2247,6 +2247,111 @@ const staticCanvasDefaults = {
2247
2247
  patternQuality: 'best'
2248
2248
  };
2249
2249
 
2250
+ /**
2251
+ * Capitalizes a string
2252
+ * @param {String} string String to capitalize
2253
+ * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
2254
+ * and other letters stay untouched, if false first letter is capitalized
2255
+ * and other letters are converted to lowercase.
2256
+ * @return {String} Capitalized version of a string
2257
+ */
2258
+ const capitalize = function (string) {
2259
+ let firstLetterOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2260
+ return `${string.charAt(0).toUpperCase()}${firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()}`;
2261
+ };
2262
+
2263
+ /**
2264
+ * Escapes XML in a string
2265
+ * @param {String} string String to escape
2266
+ * @return {String} Escaped version of a string
2267
+ */
2268
+ const escapeXml = stringOrNumber => stringOrNumber.toString().replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2269
+ let segmenter;
2270
+ const getSegmenter = () => {
2271
+ if (!segmenter) {
2272
+ segmenter = 'Intl' in getFabricWindow() && 'Segmenter' in Intl && new Intl.Segmenter(undefined, {
2273
+ granularity: 'grapheme'
2274
+ });
2275
+ }
2276
+ return segmenter;
2277
+ };
2278
+
2279
+ /**
2280
+ * Divide a string in the user perceived single units
2281
+ * @param {String} textstring String to escape
2282
+ * @return {Array} array containing the graphemes
2283
+ */
2284
+ const graphemeSplit = textstring => {
2285
+ segmenter || getSegmenter();
2286
+ if (segmenter) {
2287
+ const segments = segmenter.segment(textstring);
2288
+ return Array.from(segments).map(_ref => {
2289
+ let {
2290
+ segment
2291
+ } = _ref;
2292
+ return segment;
2293
+ });
2294
+ }
2295
+
2296
+ //Fallback
2297
+ return graphemeSplitImpl(textstring);
2298
+ };
2299
+ const graphemeSplitImpl = textstring => {
2300
+ const graphemes = [];
2301
+ for (let i = 0, chr; i < textstring.length; i++) {
2302
+ if ((chr = getWholeChar(textstring, i)) === false) {
2303
+ continue;
2304
+ }
2305
+ graphemes.push(chr);
2306
+ }
2307
+ return graphemes;
2308
+ };
2309
+
2310
+ // taken from mdn in the charAt doc page.
2311
+ const getWholeChar = (str, i) => {
2312
+ const code = str.charCodeAt(i);
2313
+ if (isNaN(code)) {
2314
+ return ''; // Position not found
2315
+ }
2316
+ if (code < 0xd800 || code > 0xdfff) {
2317
+ return str.charAt(i);
2318
+ }
2319
+
2320
+ // High surrogate (could change last hex to 0xDB7F to treat high private
2321
+ // surrogates as single characters)
2322
+ if (0xd800 <= code && code <= 0xdbff) {
2323
+ if (str.length <= i + 1) {
2324
+ throw 'High surrogate without following low surrogate';
2325
+ }
2326
+ const next = str.charCodeAt(i + 1);
2327
+ if (0xdc00 > next || next > 0xdfff) {
2328
+ throw 'High surrogate without following low surrogate';
2329
+ }
2330
+ return str.charAt(i) + str.charAt(i + 1);
2331
+ }
2332
+ // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
2333
+ if (i === 0) {
2334
+ throw 'Low surrogate without preceding high surrogate';
2335
+ }
2336
+ const prev = str.charCodeAt(i - 1);
2337
+
2338
+ // (could change last hex to 0xDB7F to treat high private
2339
+ // surrogates as single characters)
2340
+ if (0xd800 > prev || prev > 0xdbff) {
2341
+ throw 'Low surrogate without preceding high surrogate';
2342
+ }
2343
+ // We can pass over low surrogates now as the second component
2344
+ // in a pair which we have already processed
2345
+ return false;
2346
+ };
2347
+
2348
+ var lang_string = /*#__PURE__*/Object.freeze({
2349
+ __proto__: null,
2350
+ capitalize: capitalize,
2351
+ escapeXml: escapeXml,
2352
+ graphemeSplit: graphemeSplit
2353
+ });
2354
+
2250
2355
  /**
2251
2356
  * Having both options in TCanvasSizeOptions set to true transform the call in a calcOffset
2252
2357
  * Better try to restrict with types to avoid confusion.
@@ -3016,7 +3121,8 @@ let StaticCanvas$1 = class StaticCanvas extends createCollectionMixin(CommonMeth
3016
3121
  this._setSVGPreamble(markup, options);
3017
3122
  this._setSVGHeader(markup, options);
3018
3123
  if (this.clipPath) {
3019
- markup.push(`<g clip-path="url(#${this.clipPath.clipPathId})" >\n`);
3124
+ var _this$clipPath$clipPa;
3125
+ markup.push(`<g clip-path="url(#${escapeXml((_this$clipPath$clipPa = this.clipPath.clipPathId) !== null && _this$clipPath$clipPa !== void 0 ? _this$clipPath$clipPa : '')})" >\n`);
3020
3126
  }
3021
3127
  this._setSVGBgOverlayColor(markup, 'background');
3022
3128
  this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);
@@ -4643,7 +4749,7 @@ const colorPropToSVG = function (prop, value) {
4643
4749
  if (!value) {
4644
4750
  colorValue = 'none';
4645
4751
  } else if (value.toLive) {
4646
- colorValue = `url(#SVGID_${value.id})`;
4752
+ colorValue = `url(#SVGID_${escapeXml(value.id)})`;
4647
4753
  } else {
4648
4754
  const color = new Color(value),
4649
4755
  opacity = color.getAlpha();
@@ -4696,7 +4802,7 @@ class FabricObjectSVGExportMixin {
4696
4802
  filter = skipShadow ? '' : this.getSvgFilter(),
4697
4803
  fill = colorPropToSVG(FILL, this.fill),
4698
4804
  stroke = colorPropToSVG(STROKE, this.stroke);
4699
- 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('');
4805
+ 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('');
4700
4806
  }
4701
4807
 
4702
4808
  /**
@@ -4704,7 +4810,7 @@ class FabricObjectSVGExportMixin {
4704
4810
  * @return {String}
4705
4811
  */
4706
4812
  getSvgFilter() {
4707
- return this.shadow ? `filter: url(#SVGID_${this.shadow.id});` : '';
4813
+ return this.shadow ? `filter: url(#SVGID_${escapeXml(this.shadow.id)});` : '';
4708
4814
  }
4709
4815
 
4710
4816
  /**
@@ -4712,7 +4818,7 @@ class FabricObjectSVGExportMixin {
4712
4818
  * @return {String}
4713
4819
  */
4714
4820
  getSvgCommons() {
4715
- return [this.id ? `id="${this.id}" ` : '', this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : ''].join('');
4821
+ return [this.id ? `id="${escapeXml(String(this.id))}" ` : '', this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : ''].join('');
4716
4822
  }
4717
4823
 
4718
4824
  /**
@@ -4825,7 +4931,7 @@ class FabricObjectSVGExportMixin {
4825
4931
  return reviver ? reviver(markup.join('')) : markup.join('');
4826
4932
  }
4827
4933
  addPaintOrder() {
4828
- return this.paintFirst !== FILL ? ` paint-order="${this.paintFirst}" ` : '';
4934
+ return this.paintFirst !== FILL ? ` paint-order="${escapeXml(this.paintFirst)}" ` : '';
4829
4935
  }
4830
4936
  }
4831
4937
 
@@ -4963,7 +5069,6 @@ const reViewBoxAttrValue = new RegExp(String.raw`^\s*(${reNum})${viewportSeparat
4963
5069
 
4964
5070
  (?:$|\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.
4965
5071
  */
4966
- // eslint-disable-next-line max-len
4967
5072
 
4968
5073
  const shadowOffsetRegex = '(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?';
4969
5074
  const reOffsetsAndBlur = new RegExp('(?:\\s|^)' + shadowOffsetRegex + shadowOffsetRegex + '(' + reNum + '?(?:px)?)?(?:\\s?|$)(?:$|\\s)');
@@ -5022,14 +5127,15 @@ class Shadow {
5022
5127
  toSVG(object) {
5023
5128
  const offset = rotateVector(new Point(this.offsetX, this.offsetY), degreesToRadians(-object.angle)),
5024
5129
  BLUR_BOX = 20,
5130
+ NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS,
5025
5131
  color = new Color(this.color);
5026
5132
  let fBoxX = 40,
5027
5133
  fBoxY = 40;
5028
5134
  if (object.width && object.height) {
5029
5135
  //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
5030
5136
  // we add some extra space to filter box to contain the blur ( 20 )
5031
- fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, config.NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5032
- fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, config.NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5137
+ fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5138
+ fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5033
5139
  }
5034
5140
  if (object.flipX) {
5035
5141
  offset.x *= -1;
@@ -5037,7 +5143,7 @@ class Shadow {
5037
5143
  if (object.flipY) {
5038
5144
  offset.y *= -1;
5039
5145
  }
5040
- 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`;
5146
+ 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`;
5041
5147
  }
5042
5148
 
5043
5149
  /**
@@ -7188,6 +7294,9 @@ let FabricObject$1 = class FabricObject extends ObjectGeometry {
7188
7294
  } else {
7189
7295
  this._renderBackground(ctx);
7190
7296
  }
7297
+ this.fire('before:render', {
7298
+ ctx
7299
+ });
7191
7300
  this._render(ctx);
7192
7301
  this._drawClipPath(ctx, this.clipPath, context);
7193
7302
  this.fill = originalFill;
@@ -8478,6 +8587,14 @@ class Control {
8478
8587
  _defineProperty(this, "withConnection", false);
8479
8588
  Object.assign(this, options);
8480
8589
  }
8590
+ getTransformAnchorPoint() {
8591
+ var _this$transformAnchor;
8592
+ return (// return the control transformAnchorPoint
8593
+ (_this$transformAnchor = this.transformAnchorPoint) !== null && _this$transformAnchor !== void 0 ? _this$transformAnchor :
8594
+ // otherwise will return the opposite origin of where the control is located.
8595
+ new Point(-this.x + 0.5, -this.y + 0.5)
8596
+ );
8597
+ }
8481
8598
 
8482
8599
  /**
8483
8600
  * The control actionHandler, provide one to handle action ( control being moved )
@@ -10293,111 +10410,6 @@ const cloneStyles = style => {
10293
10410
  return newObj;
10294
10411
  };
10295
10412
 
10296
- /**
10297
- * Capitalizes a string
10298
- * @param {String} string String to capitalize
10299
- * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
10300
- * and other letters stay untouched, if false first letter is capitalized
10301
- * and other letters are converted to lowercase.
10302
- * @return {String} Capitalized version of a string
10303
- */
10304
- const capitalize = function (string) {
10305
- let firstLetterOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
10306
- return `${string.charAt(0).toUpperCase()}${firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()}`;
10307
- };
10308
-
10309
- /**
10310
- * Escapes XML in a string
10311
- * @param {String} string String to escape
10312
- * @return {String} Escaped version of a string
10313
- */
10314
- const escapeXml = string => string.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
10315
- let segmenter;
10316
- const getSegmenter = () => {
10317
- if (!segmenter) {
10318
- segmenter = 'Intl' in getFabricWindow() && 'Segmenter' in Intl && new Intl.Segmenter(undefined, {
10319
- granularity: 'grapheme'
10320
- });
10321
- }
10322
- return segmenter;
10323
- };
10324
-
10325
- /**
10326
- * Divide a string in the user perceived single units
10327
- * @param {String} textstring String to escape
10328
- * @return {Array} array containing the graphemes
10329
- */
10330
- const graphemeSplit = textstring => {
10331
- segmenter || getSegmenter();
10332
- if (segmenter) {
10333
- const segments = segmenter.segment(textstring);
10334
- return Array.from(segments).map(_ref => {
10335
- let {
10336
- segment
10337
- } = _ref;
10338
- return segment;
10339
- });
10340
- }
10341
-
10342
- //Fallback
10343
- return graphemeSplitImpl(textstring);
10344
- };
10345
- const graphemeSplitImpl = textstring => {
10346
- const graphemes = [];
10347
- for (let i = 0, chr; i < textstring.length; i++) {
10348
- if ((chr = getWholeChar(textstring, i)) === false) {
10349
- continue;
10350
- }
10351
- graphemes.push(chr);
10352
- }
10353
- return graphemes;
10354
- };
10355
-
10356
- // taken from mdn in the charAt doc page.
10357
- const getWholeChar = (str, i) => {
10358
- const code = str.charCodeAt(i);
10359
- if (isNaN(code)) {
10360
- return ''; // Position not found
10361
- }
10362
- if (code < 0xd800 || code > 0xdfff) {
10363
- return str.charAt(i);
10364
- }
10365
-
10366
- // High surrogate (could change last hex to 0xDB7F to treat high private
10367
- // surrogates as single characters)
10368
- if (0xd800 <= code && code <= 0xdbff) {
10369
- if (str.length <= i + 1) {
10370
- throw 'High surrogate without following low surrogate';
10371
- }
10372
- const next = str.charCodeAt(i + 1);
10373
- if (0xdc00 > next || next > 0xdfff) {
10374
- throw 'High surrogate without following low surrogate';
10375
- }
10376
- return str.charAt(i) + str.charAt(i + 1);
10377
- }
10378
- // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
10379
- if (i === 0) {
10380
- throw 'Low surrogate without preceding high surrogate';
10381
- }
10382
- const prev = str.charCodeAt(i - 1);
10383
-
10384
- // (could change last hex to 0xDB7F to treat high private
10385
- // surrogates as single characters)
10386
- if (0xd800 > prev || prev > 0xdbff) {
10387
- throw 'Low surrogate without preceding high surrogate';
10388
- }
10389
- // We can pass over low surrogates now as the second component
10390
- // in a pair which we have already processed
10391
- return false;
10392
- };
10393
-
10394
- var lang_string = /*#__PURE__*/Object.freeze({
10395
- __proto__: null,
10396
- capitalize: capitalize,
10397
- escapeXml: escapeXml,
10398
- graphemeSplit: graphemeSplit
10399
- });
10400
-
10401
10413
  /**
10402
10414
  * @param {Object} prevStyle first style to compare
10403
10415
  * @param {Object} thisStyle second style to compare
@@ -10981,7 +10993,7 @@ class Rect extends FabricObject {
10981
10993
  rx,
10982
10994
  ry
10983
10995
  } = this;
10984
- return ['<rect ', 'COMMON_PARTS', `x="${-width / 2}" y="${-height / 2}" rx="${rx}" ry="${ry}" width="${width}" height="${height}" />\n`];
10996
+ return ['<rect ', 'COMMON_PARTS', `x="${-width / 2}" y="${-height / 2}" rx="${escapeXml(rx)}" ry="${escapeXml(ry)}" width="${escapeXml(width)}" height="${escapeXml(height)}" />\n`];
10985
10997
  }
10986
10998
 
10987
10999
  /**
@@ -11946,7 +11958,7 @@ class Group extends createCollectionMixin(FabricObject) {
11946
11958
  * @return {String}
11947
11959
  */
11948
11960
  getSvgStyles() {
11949
- const opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ? `opacity: ${this.opacity};` : '',
11961
+ const opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ? `opacity: ${escapeXml(this.opacity)};` : '',
11950
11962
  visibility = this.visible ? '' : ' visibility: hidden;';
11951
11963
  return [opacity, this.getSvgFilter(), visibility].join('');
11952
11964
  }
@@ -13900,11 +13912,13 @@ class SelectableCanvas extends StaticCanvas$1 {
13900
13912
  * Given the control clicked, determine the origin of the transform.
13901
13913
  * This is bad because controls can totally have custom names
13902
13914
  * should disappear before release 4.0
13915
+ * Fabric 7.1, jan 2026 we are still using this.
13916
+ * Needs to go.
13903
13917
  * @private
13904
13918
  * @deprecated
13905
13919
  */
13906
13920
  _getOriginFromCorner(target, controlName) {
13907
- const origin = {
13921
+ const origin = controlName ? target.controls[controlName].getTransformAnchorPoint() : {
13908
13922
  x: target.originX,
13909
13923
  y: target.originY
13910
13924
  };
@@ -13912,6 +13926,9 @@ class SelectableCanvas extends StaticCanvas$1 {
13912
13926
  return origin;
13913
13927
  }
13914
13928
 
13929
+ // this part down here is deprecated.
13930
+ // It is left to do not change the standard behavior in the middle of a major version
13931
+ // but when possible `getTransformAnchorPoint` will be the only source of truth
13915
13932
  // is a left control ?
13916
13933
  if (['ml', 'tl', 'bl'].includes(controlName)) {
13917
13934
  origin.x = RIGHT;
@@ -16409,7 +16426,8 @@ class Gradient {
16409
16426
  }
16410
16427
  transform[4] -= offsetX;
16411
16428
  transform[5] -= offsetY;
16412
- const commonAttributes = [`id="SVGID_${this.id}"`, `gradientUnits="${gradientUnits}"`, `gradientTransform="${preTransform ? preTransform + ' ' : ''}${matrixToSVG(transform)}"`, ''].join(' ');
16429
+ const commonAttributes = [`id="SVGID_${escapeXml(String(this.id))}"`, `gradientUnits="${gradientUnits}"`, `gradientTransform="${preTransform ? preTransform + ' ' : ''}${matrixToSVG(transform)}"`, ''].join(' ');
16430
+ const sanitizeCoord = value => parseFloat(String(value));
16413
16431
  if (this.type === 'linear') {
16414
16432
  const {
16415
16433
  x1,
@@ -16417,7 +16435,11 @@ class Gradient {
16417
16435
  x2,
16418
16436
  y2
16419
16437
  } = this.coords;
16420
- markup.push('<linearGradient ', commonAttributes, ' x1="', x1, '" y1="', y1, '" x2="', x2, '" y2="', y2, '">\n');
16438
+ const sx1 = sanitizeCoord(x1);
16439
+ const sy1 = sanitizeCoord(y1);
16440
+ const sx2 = sanitizeCoord(x2);
16441
+ const sy2 = sanitizeCoord(y2);
16442
+ markup.push('<linearGradient ', commonAttributes, ' x1="', sx1, '" y1="', sy1, '" x2="', sx2, '" y2="', sy2, '">\n');
16421
16443
  } else if (this.type === 'radial') {
16422
16444
  const {
16423
16445
  x1,
@@ -16427,9 +16449,15 @@ class Gradient {
16427
16449
  r1,
16428
16450
  r2
16429
16451
  } = this.coords;
16430
- const needsSwap = r1 > r2;
16452
+ const sx1 = sanitizeCoord(x1);
16453
+ const sy1 = sanitizeCoord(y1);
16454
+ const sx2 = sanitizeCoord(x2);
16455
+ const sy2 = sanitizeCoord(y2);
16456
+ const sr1 = sanitizeCoord(r1);
16457
+ const sr2 = sanitizeCoord(r2);
16458
+ const needsSwap = sr1 > sr2;
16431
16459
  // svg radial gradient has just 1 radius. the biggest.
16432
- 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');
16460
+ 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');
16433
16461
  if (needsSwap) {
16434
16462
  // svg goes from internal to external radius. if radius are inverted, swap color stops.
16435
16463
  colorStops.reverse(); // mutates array
@@ -16437,16 +16465,17 @@ class Gradient {
16437
16465
  colorStop.offset = 1 - colorStop.offset;
16438
16466
  });
16439
16467
  }
16440
- const minRadius = Math.min(r1, r2);
16468
+ const minRadius = Math.min(sr1, sr2);
16441
16469
  if (minRadius > 0) {
16442
16470
  // i have to shift all colorStops and add new one in 0.
16443
- const maxRadius = Math.max(r1, r2),
16471
+ const maxRadius = Math.max(sr1, sr2),
16444
16472
  percentageShift = minRadius / maxRadius;
16445
16473
  colorStops.forEach(colorStop => {
16446
16474
  colorStop.offset += percentageShift * (1 - colorStop.offset);
16447
16475
  });
16448
16476
  }
16449
16477
  }
16478
+ // todo make a malicious script tag injection test with color and also apply a fix with escapeXml
16450
16479
  colorStops.forEach(_ref => {
16451
16480
  let {
16452
16481
  color,
@@ -16762,7 +16791,7 @@ class Pattern {
16762
16791
  patternOffsetY = ifNaN(this.offsetY / height, 0),
16763
16792
  patternWidth = repeat === 'repeat-y' || repeat === 'no-repeat' ? 1 + Math.abs(patternOffsetX || 0) : ifNaN(patternSource.width / width, 0),
16764
16793
  patternHeight = repeat === 'repeat-x' || repeat === 'no-repeat' ? 1 + Math.abs(patternOffsetY || 0) : ifNaN(patternSource.height / height, 0);
16765
- 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');
16794
+ 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');
16766
16795
  }
16767
16796
  /* _TO_SVG_END_ */
16768
16797
 
@@ -17044,8 +17073,7 @@ class Path extends FabricObject {
17044
17073
  * of the instance
17045
17074
  */
17046
17075
  _toSVG() {
17047
- const path = joinPath(this.path, config.NUM_FRACTION_DIGITS);
17048
- return ['<path ', 'COMMON_PARTS', `d="${path}" stroke-linecap="round" />\n`];
17076
+ return ['<path ', 'COMMON_PARTS', `d="${joinPath(this.path, config.NUM_FRACTION_DIGITS)}" stroke-linecap="round" />\n`];
17049
17077
  }
17050
17078
 
17051
17079
  /**
@@ -17596,15 +17624,17 @@ class Circle extends FabricObject {
17596
17624
  * of the instance
17597
17625
  */
17598
17626
  _toSVG() {
17599
- const angle = (this.endAngle - this.startAngle) % 360;
17627
+ const {
17628
+ radius,
17629
+ startAngle,
17630
+ endAngle
17631
+ } = this;
17632
+ const angle = (endAngle - startAngle) % 360;
17600
17633
  if (angle === 0) {
17601
- return ['<circle ', 'COMMON_PARTS', 'cx="0" cy="0" ', 'r="', `${this.radius}`, '" />\n'];
17634
+ return ['<circle ', 'COMMON_PARTS', 'cx="0" cy="0" ', 'r="', `${escapeXml(radius)}`, '" />\n'];
17602
17635
  } else {
17603
- const {
17604
- radius
17605
- } = this;
17606
- const start = degreesToRadians(this.startAngle),
17607
- end = degreesToRadians(this.endAngle),
17636
+ const start = degreesToRadians(startAngle),
17637
+ end = degreesToRadians(endAngle),
17608
17638
  startX = cos(start) * radius,
17609
17639
  startY = sin(start) * radius,
17610
17640
  endX = cos(end) * radius,
@@ -18176,17 +18206,13 @@ class Line extends FabricObject {
18176
18206
  width,
18177
18207
  height
18178
18208
  } = this;
18179
- const xMult = _x1 <= _x2 ? -1 : 1,
18180
- yMult = _y1 <= _y2 ? -1 : 1,
18181
- x1 = xMult * width / 2,
18182
- y1 = yMult * height / 2,
18183
- x2 = xMult * -width / 2,
18184
- y2 = yMult * -height / 2;
18209
+ const xMult = _x1 <= _x2 ? -0.5 : 0.5,
18210
+ yMult = _y1 <= _y2 ? -0.5 : 0.5;
18185
18211
  return {
18186
- x1,
18187
- x2,
18188
- y1,
18189
- y2
18212
+ x1: xMult * width,
18213
+ x2: xMult * -width,
18214
+ y1: yMult * height,
18215
+ y2: yMult * -height
18190
18216
  };
18191
18217
  }
18192
18218
 
@@ -18404,7 +18430,7 @@ class Ellipse extends FabricObject {
18404
18430
  * of the instance
18405
18431
  */
18406
18432
  _toSVG() {
18407
- return ['<ellipse ', 'COMMON_PARTS', `cx="0" cy="0" rx="${this.rx}" ry="${this.ry}" />\n`];
18433
+ return ['<ellipse ', 'COMMON_PARTS', `cx="0" cy="0" rx="${escapeXml(this.rx)}" ry="${escapeXml(this.ry)}" />\n`];
18408
18434
  }
18409
18435
 
18410
18436
  /**
@@ -18722,14 +18748,17 @@ class Polyline extends FabricObject {
18722
18748
  * of the instance
18723
18749
  */
18724
18750
  _toSVG() {
18725
- const points = [],
18726
- diffX = this.pathOffset.x,
18751
+ const diffX = this.pathOffset.x,
18727
18752
  diffY = this.pathOffset.y,
18728
18753
  NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS;
18729
- for (let i = 0, len = this.points.length; i < len; i++) {
18730
- points.push(toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',', toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' ');
18731
- }
18732
- return [`<${this.constructor.type.toLowerCase()} `, 'COMMON_PARTS', `points="${points.join('')}" />\n`];
18754
+ const points = this.points.map(_ref2 => {
18755
+ let {
18756
+ x,
18757
+ y
18758
+ } = _ref2;
18759
+ return `${toFixed(x - diffX, NUM_FRACTION_DIGITS)},${toFixed(y - diffY, NUM_FRACTION_DIGITS)}`;
18760
+ }).join(' ');
18761
+ return [`<${escapeXml(this.constructor.type).toLowerCase()} `, 'COMMON_PARTS', `points="${points}" />\n`];
18733
18762
  }
18734
18763
 
18735
18764
  /**
@@ -19153,7 +19182,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19153
19182
  } = _ref;
19154
19183
  const noShadow = true,
19155
19184
  textDecoration = this.getSvgTextDecoration(this);
19156
- 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'];
19185
+ 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'];
19157
19186
  }
19158
19187
 
19159
19188
  /**
@@ -19169,7 +19198,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19169
19198
  lineOffset;
19170
19199
 
19171
19200
  // bounding-box background
19172
- this.backgroundColor && textBgRects.push(...createSVGInlineRect(this.backgroundColor, -this.width / 2, -this.height / 2, this.width, this.height));
19201
+ this.backgroundColor && textBgRects.push(createSVGInlineRect(this.backgroundColor, -this.width / 2, -this.height / 2, this.width, this.height));
19173
19202
 
19174
19203
  // text and text-background
19175
19204
  for (let i = 0, len = this._textLines.length; i < len; i++) {
@@ -19277,7 +19306,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19277
19306
  } = this.__charBounds[i][j];
19278
19307
  currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');
19279
19308
  if (currentColor !== lastColor) {
19280
- lastColor && textBgRects.push(...createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19309
+ lastColor && textBgRects.push(createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19281
19310
  boxStart = left;
19282
19311
  boxWidth = width;
19283
19312
  lastColor = currentColor;
@@ -19285,7 +19314,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19285
19314
  boxWidth += kernedWidth;
19286
19315
  }
19287
19316
  }
19288
- currentColor && textBgRects.push(...createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19317
+ currentColor && textBgRects.push(createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19289
19318
  }
19290
19319
 
19291
19320
  /**
@@ -19323,7 +19352,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19323
19352
  linethrough: linethrough !== null && linethrough !== void 0 ? linethrough : this.linethrough
19324
19353
  });
19325
19354
  const thickness = textDecorationThickness || this.textDecorationThickness;
19326
- 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('');
19355
+ 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('');
19327
19356
  }
19328
19357
 
19329
19358
  /**
@@ -24887,13 +24916,13 @@ class FabricImage extends FabricObject {
24887
24916
  }
24888
24917
  if (this.hasCrop()) {
24889
24918
  const clipPathId = uid();
24890
- svgString.push('<clipPath id="imageCrop_' + clipPathId + '">\n', '\t<rect x="' + x + '" y="' + y + '" width="' + this.width + '" height="' + this.height + '" />\n', '</clipPath>\n');
24919
+ svgString.push('<clipPath id="imageCrop_' + clipPathId + '">\n', '\t<rect x="' + x + '" y="' + y + '" width="' + escapeXml(this.width) + '" height="' + escapeXml(this.height) + '" />\n', '</clipPath>\n');
24891
24920
  clipPath = ' clip-path="url(#imageCrop_' + clipPathId + ')" ';
24892
24921
  }
24893
24922
  if (!this.imageSmoothing) {
24894
24923
  imageRendering = ' image-rendering="optimizeSpeed"';
24895
24924
  }
24896
- imageMarkup.push('\t<image ', 'COMMON_PARTS', `xlink:href="${this.getSvgSrc(true)}" x="${x - this.cropX}" y="${y - this.cropY
24925
+ imageMarkup.push('\t<image ', 'COMMON_PARTS', `xlink:href="${escapeXml(this.getSrc(true))}" x="${x - this.cropX}" y="${y - this.cropY
24897
24926
  // we're essentially moving origin of transformation from top/left corner to the center of the shape
24898
24927
  // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
24899
24928
  // so that object's center aligns with container's left/top
@@ -24901,7 +24930,7 @@ class FabricImage extends FabricObject {
24901
24930
  if (this.stroke || this.strokeDashArray) {
24902
24931
  const origFill = this.fill;
24903
24932
  this.fill = null;
24904
- strokeSvg = [`\t<rect x="${x}" y="${y}" width="${this.width}" height="${this.height}" style="${this.getSvgStyles()}" />\n`];
24933
+ strokeSvg = [`\t<rect x="${x}" y="${y}" width="${escapeXml(this.width)}" height="${escapeXml(this.height)}" style="${this.getSvgStyles()}" />\n`];
24905
24934
  this.fill = origFill;
24906
24935
  }
24907
24936
  if (this.paintFirst !== FILL) {