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