fabric 7.1.0 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/CHANGELOG.md +13 -0
  3. package/dist/extensions/cropping_controls/croppingControls.d.ts +12 -8
  4. package/dist/extensions/cropping_controls/croppingControls.d.ts.map +1 -1
  5. package/dist/extensions/cropping_controls/croppingHandlers.d.ts +19 -1
  6. package/dist/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -1
  7. package/dist/extensions/cropping_controls/enterCropMode.d.ts.map +1 -1
  8. package/dist/index.js +189 -160
  9. package/dist/index.js.map +1 -1
  10. package/dist/index.min.js +1 -1
  11. package/dist/index.min.js.map +1 -1
  12. package/dist/index.min.mjs +1 -1
  13. package/dist/index.min.mjs.map +1 -1
  14. package/dist/index.mjs +189 -160
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.node.cjs +189 -160
  17. package/dist/index.node.cjs.map +1 -1
  18. package/dist/index.node.mjs +189 -160
  19. package/dist/index.node.mjs.map +1 -1
  20. package/dist/package.json.min.mjs +1 -1
  21. package/dist/package.json.mjs +1 -1
  22. package/dist/src/EventTypeDefs.d.ts +3 -0
  23. package/dist/src/EventTypeDefs.d.ts.map +1 -1
  24. package/dist/src/Pattern/Pattern.d.ts.map +1 -1
  25. package/dist/src/Pattern/Pattern.min.mjs +1 -1
  26. package/dist/src/Pattern/Pattern.min.mjs.map +1 -1
  27. package/dist/src/Pattern/Pattern.mjs +2 -1
  28. package/dist/src/Pattern/Pattern.mjs.map +1 -1
  29. package/dist/src/Shadow.d.ts +1 -1
  30. package/dist/src/Shadow.d.ts.map +1 -1
  31. package/dist/src/Shadow.min.mjs +1 -1
  32. package/dist/src/Shadow.min.mjs.map +1 -1
  33. package/dist/src/Shadow.mjs +5 -4
  34. package/dist/src/Shadow.mjs.map +1 -1
  35. package/dist/src/canvas/CanvasOptions.d.ts.map +1 -1
  36. package/dist/src/canvas/CanvasOptions.min.mjs.map +1 -1
  37. package/dist/src/canvas/CanvasOptions.mjs.map +1 -1
  38. package/dist/src/canvas/SelectableCanvas.d.ts +2 -0
  39. package/dist/src/canvas/SelectableCanvas.d.ts.map +1 -1
  40. package/dist/src/canvas/SelectableCanvas.min.mjs +1 -1
  41. package/dist/src/canvas/SelectableCanvas.min.mjs.map +1 -1
  42. package/dist/src/canvas/SelectableCanvas.mjs +6 -1
  43. package/dist/src/canvas/SelectableCanvas.mjs.map +1 -1
  44. package/dist/src/canvas/StaticCanvas.d.ts.map +1 -1
  45. package/dist/src/canvas/StaticCanvas.min.mjs +1 -1
  46. package/dist/src/canvas/StaticCanvas.min.mjs.map +1 -1
  47. package/dist/src/canvas/StaticCanvas.mjs +3 -1
  48. package/dist/src/canvas/StaticCanvas.mjs.map +1 -1
  49. package/dist/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
  50. package/dist/src/canvas/StaticCanvasOptions.min.mjs.map +1 -1
  51. package/dist/src/canvas/StaticCanvasOptions.mjs.map +1 -1
  52. package/dist/src/controls/Control.d.ts +9 -1
  53. package/dist/src/controls/Control.d.ts.map +1 -1
  54. package/dist/src/controls/Control.min.mjs +1 -1
  55. package/dist/src/controls/Control.min.mjs.map +1 -1
  56. package/dist/src/controls/Control.mjs +8 -0
  57. package/dist/src/controls/Control.mjs.map +1 -1
  58. package/dist/src/gradient/Gradient.d.ts.map +1 -1
  59. package/dist/src/gradient/Gradient.min.mjs +1 -1
  60. package/dist/src/gradient/Gradient.min.mjs.map +1 -1
  61. package/dist/src/gradient/Gradient.mjs +19 -6
  62. package/dist/src/gradient/Gradient.mjs.map +1 -1
  63. package/dist/src/shapes/Circle.d.ts.map +1 -1
  64. package/dist/src/shapes/Circle.min.mjs +1 -1
  65. package/dist/src/shapes/Circle.min.mjs.map +1 -1
  66. package/dist/src/shapes/Circle.mjs +10 -7
  67. package/dist/src/shapes/Circle.mjs.map +1 -1
  68. package/dist/src/shapes/Ellipse.d.ts.map +1 -1
  69. package/dist/src/shapes/Ellipse.min.mjs +1 -1
  70. package/dist/src/shapes/Ellipse.min.mjs.map +1 -1
  71. package/dist/src/shapes/Ellipse.mjs +2 -1
  72. package/dist/src/shapes/Ellipse.mjs.map +1 -1
  73. package/dist/src/shapes/Group.d.ts.map +1 -1
  74. package/dist/src/shapes/Group.min.mjs +1 -1
  75. package/dist/src/shapes/Group.min.mjs.map +1 -1
  76. package/dist/src/shapes/Group.mjs +2 -1
  77. package/dist/src/shapes/Group.mjs.map +1 -1
  78. package/dist/src/shapes/IText/IText.d.ts.map +1 -1
  79. package/dist/src/shapes/IText/IText.min.mjs.map +1 -1
  80. package/dist/src/shapes/IText/IText.mjs.map +1 -1
  81. package/dist/src/shapes/Image.d.ts +1 -1
  82. package/dist/src/shapes/Image.d.ts.map +1 -1
  83. package/dist/src/shapes/Image.min.mjs +1 -1
  84. package/dist/src/shapes/Image.min.mjs.map +1 -1
  85. package/dist/src/shapes/Image.mjs +4 -3
  86. package/dist/src/shapes/Image.mjs.map +1 -1
  87. package/dist/src/shapes/Line.d.ts.map +1 -1
  88. package/dist/src/shapes/Line.min.mjs +1 -1
  89. package/dist/src/shapes/Line.min.mjs.map +1 -1
  90. package/dist/src/shapes/Line.mjs +6 -10
  91. package/dist/src/shapes/Line.mjs.map +1 -1
  92. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
  93. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs +1 -1
  94. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs.map +1 -1
  95. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs +5 -4
  96. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs.map +1 -1
  97. package/dist/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  98. package/dist/src/shapes/Object/InteractiveObject.min.mjs.map +1 -1
  99. package/dist/src/shapes/Object/InteractiveObject.mjs.map +1 -1
  100. package/dist/src/shapes/Object/Object.d.ts.map +1 -1
  101. package/dist/src/shapes/Object/Object.min.mjs +1 -1
  102. package/dist/src/shapes/Object/Object.min.mjs.map +1 -1
  103. package/dist/src/shapes/Object/Object.mjs +3 -0
  104. package/dist/src/shapes/Object/Object.mjs.map +1 -1
  105. package/dist/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
  106. package/dist/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
  107. package/dist/src/shapes/Path.d.ts.map +1 -1
  108. package/dist/src/shapes/Path.min.mjs.map +1 -1
  109. package/dist/src/shapes/Path.mjs +1 -2
  110. package/dist/src/shapes/Path.mjs.map +1 -1
  111. package/dist/src/shapes/Polyline.d.ts.map +1 -1
  112. package/dist/src/shapes/Polyline.min.mjs +1 -1
  113. package/dist/src/shapes/Polyline.min.mjs.map +1 -1
  114. package/dist/src/shapes/Polyline.mjs +10 -6
  115. package/dist/src/shapes/Polyline.mjs.map +1 -1
  116. package/dist/src/shapes/Rect.d.ts.map +1 -1
  117. package/dist/src/shapes/Rect.min.mjs +1 -1
  118. package/dist/src/shapes/Rect.min.mjs.map +1 -1
  119. package/dist/src/shapes/Rect.mjs +2 -1
  120. package/dist/src/shapes/Rect.mjs.map +1 -1
  121. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  122. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  123. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  124. package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs +1 -1
  125. package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs.map +1 -1
  126. package/dist/src/shapes/Text/TextSVGExportMixin.mjs +5 -5
  127. package/dist/src/shapes/Text/TextSVGExportMixin.mjs.map +1 -1
  128. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  129. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  130. package/dist/src/shapes/Textbox.mjs.map +1 -1
  131. package/dist/src/shapes/Triangle.d.ts.map +1 -1
  132. package/dist/src/shapes/Triangle.min.mjs.map +1 -1
  133. package/dist/src/shapes/Triangle.mjs.map +1 -1
  134. package/dist/src/util/lang_string.d.ts +1 -1
  135. package/dist/src/util/lang_string.d.ts.map +1 -1
  136. package/dist/src/util/lang_string.min.mjs +1 -1
  137. package/dist/src/util/lang_string.min.mjs.map +1 -1
  138. package/dist/src/util/lang_string.mjs +1 -1
  139. package/dist/src/util/lang_string.mjs.map +1 -1
  140. package/dist/src/util/misc/svgParsing.d.ts.map +1 -1
  141. package/dist/src/util/misc/svgParsing.min.mjs +1 -1
  142. package/dist/src/util/misc/svgParsing.min.mjs.map +1 -1
  143. package/dist/src/util/misc/svgParsing.mjs +2 -1
  144. package/dist/src/util/misc/svgParsing.mjs.map +1 -1
  145. package/dist-extensions/cropping_controls/croppingControls.mjs +39 -9
  146. package/dist-extensions/cropping_controls/croppingControls.mjs.map +1 -1
  147. package/dist-extensions/cropping_controls/croppingHandlers.mjs +84 -2
  148. package/dist-extensions/cropping_controls/croppingHandlers.mjs.map +1 -1
  149. package/dist-extensions/cropping_controls/enterCropMode.mjs +7 -2
  150. package/dist-extensions/cropping_controls/enterCropMode.mjs.map +1 -1
  151. package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts +12 -8
  152. package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts.map +1 -1
  153. package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts +19 -1
  154. package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -1
  155. package/dist-extensions/extensions/cropping_controls/enterCropMode.d.ts.map +1 -1
  156. package/dist-extensions/fabric-extensions.min.js +1 -1
  157. package/dist-extensions/fabric-extensions.min.js.map +1 -1
  158. package/dist-extensions/src/EventTypeDefs.d.ts +3 -0
  159. package/dist-extensions/src/EventTypeDefs.d.ts.map +1 -1
  160. package/dist-extensions/src/Pattern/Pattern.d.ts.map +1 -1
  161. package/dist-extensions/src/Shadow.d.ts +1 -1
  162. package/dist-extensions/src/Shadow.d.ts.map +1 -1
  163. package/dist-extensions/src/canvas/CanvasOptions.d.ts.map +1 -1
  164. package/dist-extensions/src/canvas/SelectableCanvas.d.ts +2 -0
  165. package/dist-extensions/src/canvas/SelectableCanvas.d.ts.map +1 -1
  166. package/dist-extensions/src/canvas/StaticCanvas.d.ts.map +1 -1
  167. package/dist-extensions/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
  168. package/dist-extensions/src/controls/Control.d.ts +9 -1
  169. package/dist-extensions/src/controls/Control.d.ts.map +1 -1
  170. package/dist-extensions/src/gradient/Gradient.d.ts.map +1 -1
  171. package/dist-extensions/src/shapes/Circle.d.ts.map +1 -1
  172. package/dist-extensions/src/shapes/Ellipse.d.ts.map +1 -1
  173. package/dist-extensions/src/shapes/Group.d.ts.map +1 -1
  174. package/dist-extensions/src/shapes/IText/IText.d.ts.map +1 -1
  175. package/dist-extensions/src/shapes/Image.d.ts.map +1 -1
  176. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  177. package/dist-extensions/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
  178. package/dist-extensions/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  179. package/dist-extensions/src/shapes/Object/Object.d.ts.map +1 -1
  180. package/dist-extensions/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
  181. package/dist-extensions/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
  182. package/dist-extensions/src/shapes/Path.d.ts +1 -1
  183. package/dist-extensions/src/shapes/Path.d.ts.map +1 -1
  184. package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
  185. package/dist-extensions/src/shapes/Rect.d.ts.map +1 -1
  186. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  187. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  188. package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
  189. package/dist-extensions/src/util/lang_string.d.ts +1 -1
  190. package/dist-extensions/src/util/lang_string.d.ts.map +1 -1
  191. package/dist-extensions/src/util/misc/svgParsing.d.ts.map +1 -1
  192. package/eslint.config.mjs +2 -0
  193. package/extensions/cropping_controls/croppingControls.spec.ts +65 -27
  194. package/extensions/cropping_controls/croppingControls.ts +40 -8
  195. package/extensions/cropping_controls/croppingHandlers.spec.ts +355 -46
  196. package/extensions/cropping_controls/croppingHandlers.ts +123 -0
  197. package/extensions/cropping_controls/enterCropMode.ts +6 -2
  198. package/package.json +17 -8
  199. package/src/ClassRegistry.spec.ts +18 -19
  200. package/src/EventTypeDefs.ts +13 -11
  201. package/src/Pattern/Pattern.spec.ts +12 -0
  202. package/src/Pattern/Pattern.ts +3 -2
  203. package/src/Shadow.ts +9 -8
  204. package/src/brushes/PencilBrush.spec.ts +11 -11
  205. package/src/canvas/Canvas-dispose.spec.ts +8 -7
  206. package/src/canvas/Canvas.spec.ts +27 -29
  207. package/src/canvas/CanvasOptions.ts +2 -1
  208. package/src/canvas/SelectableCanvas.ts +11 -4
  209. package/src/canvas/StaticCanvas.spec.ts +20 -0
  210. package/src/canvas/StaticCanvas.ts +7 -4
  211. package/src/canvas/StaticCanvasOptions.ts +1 -3
  212. package/src/controls/Control.ts +24 -1
  213. package/src/gradient/Gradient.spec.ts +101 -46
  214. package/src/gradient/Gradient.ts +27 -14
  215. package/src/shapes/Circle.spec.ts +10 -39
  216. package/src/shapes/Circle.ts +11 -11
  217. package/src/shapes/Ellipse.spec.ts +8 -37
  218. package/src/shapes/Ellipse.ts +7 -7
  219. package/src/shapes/Group.ts +3 -3
  220. package/src/shapes/IText/IText-click-behavior.spec.ts +36 -49
  221. package/src/shapes/IText/IText.ts +5 -6
  222. package/src/shapes/IText/__snapshots__/ITextBehavior.test.ts.snap +6 -6
  223. package/src/shapes/Image.spec.ts +17 -33
  224. package/src/shapes/Image.ts +15 -11
  225. package/src/shapes/Line.spec.ts +4 -30
  226. package/src/shapes/Line.ts +11 -16
  227. package/src/shapes/Object/FabricObjectSVGExportMixin.ts +11 -4
  228. package/src/shapes/Object/InteractiveObject.ts +4 -4
  229. package/src/shapes/Object/Object.ts +6 -5
  230. package/src/shapes/Object/objectSvgExport.spec.ts +112 -0
  231. package/src/shapes/Object/types/FabricObjectProps.ts +1 -4
  232. package/src/shapes/Object/types/ObjectProps.ts +1 -3
  233. package/src/shapes/Path.spec.ts +4 -27
  234. package/src/shapes/Path.ts +2 -4
  235. package/src/shapes/Polygon.spec.ts +4 -31
  236. package/src/shapes/Polyline.spec.ts +4 -31
  237. package/src/shapes/Polyline.ts +11 -12
  238. package/src/shapes/Rect.spec.ts +25 -33
  239. package/src/shapes/Rect.ts +7 -7
  240. package/src/shapes/Text/Text.spec.ts +3 -32
  241. package/src/shapes/Text/Text.ts +5 -6
  242. package/src/shapes/Text/TextSVGExportMixin.ts +14 -14
  243. package/src/shapes/Text/__snapshots__/Text.spec.ts.snap +1 -1
  244. package/src/shapes/Textbox.spec.ts +5 -5
  245. package/src/shapes/Textbox.ts +6 -5
  246. package/src/shapes/Triangle.ts +4 -4
  247. package/src/shapes/__snapshots__/Image.spec.ts.snap +4 -4
  248. package/src/shapes/__snapshots__/Textbox.spec.ts.snap +5 -5
  249. package/src/util/lang_string.ts +3 -2
  250. package/src/util/misc/svgParsing.ts +2 -1
  251. package/tsconfig.spec.json +1 -0
  252. package/vitest.config.ts +12 -2
  253. package/vitest.extend.ts +6 -2
package/dist/index.mjs CHANGED
@@ -356,7 +356,7 @@ class Cache {
356
356
  }
357
357
  const cache = new Cache();
358
358
 
359
- var version = "7.1.0";
359
+ var version = "7.2.0";
360
360
 
361
361
  // use this syntax so babel plugin see this import here
362
362
  const VERSION = version;
@@ -2191,6 +2191,111 @@ const staticCanvasDefaults = {
2191
2191
  patternQuality: 'best'
2192
2192
  };
2193
2193
 
2194
+ /**
2195
+ * Capitalizes a string
2196
+ * @param {String} string String to capitalize
2197
+ * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
2198
+ * and other letters stay untouched, if false first letter is capitalized
2199
+ * and other letters are converted to lowercase.
2200
+ * @return {String} Capitalized version of a string
2201
+ */
2202
+ const capitalize = function (string) {
2203
+ let firstLetterOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2204
+ return `${string.charAt(0).toUpperCase()}${firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()}`;
2205
+ };
2206
+
2207
+ /**
2208
+ * Escapes XML in a string
2209
+ * @param {String} string String to escape
2210
+ * @return {String} Escaped version of a string
2211
+ */
2212
+ const escapeXml = stringOrNumber => stringOrNumber.toString().replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
2213
+ let segmenter;
2214
+ const getSegmenter = () => {
2215
+ if (!segmenter) {
2216
+ segmenter = 'Intl' in getFabricWindow() && 'Segmenter' in Intl && new Intl.Segmenter(undefined, {
2217
+ granularity: 'grapheme'
2218
+ });
2219
+ }
2220
+ return segmenter;
2221
+ };
2222
+
2223
+ /**
2224
+ * Divide a string in the user perceived single units
2225
+ * @param {String} textstring String to escape
2226
+ * @return {Array} array containing the graphemes
2227
+ */
2228
+ const graphemeSplit = textstring => {
2229
+ segmenter || getSegmenter();
2230
+ if (segmenter) {
2231
+ const segments = segmenter.segment(textstring);
2232
+ return Array.from(segments).map(_ref => {
2233
+ let {
2234
+ segment
2235
+ } = _ref;
2236
+ return segment;
2237
+ });
2238
+ }
2239
+
2240
+ //Fallback
2241
+ return graphemeSplitImpl(textstring);
2242
+ };
2243
+ const graphemeSplitImpl = textstring => {
2244
+ const graphemes = [];
2245
+ for (let i = 0, chr; i < textstring.length; i++) {
2246
+ if ((chr = getWholeChar(textstring, i)) === false) {
2247
+ continue;
2248
+ }
2249
+ graphemes.push(chr);
2250
+ }
2251
+ return graphemes;
2252
+ };
2253
+
2254
+ // taken from mdn in the charAt doc page.
2255
+ const getWholeChar = (str, i) => {
2256
+ const code = str.charCodeAt(i);
2257
+ if (isNaN(code)) {
2258
+ return ''; // Position not found
2259
+ }
2260
+ if (code < 0xd800 || code > 0xdfff) {
2261
+ return str.charAt(i);
2262
+ }
2263
+
2264
+ // High surrogate (could change last hex to 0xDB7F to treat high private
2265
+ // surrogates as single characters)
2266
+ if (0xd800 <= code && code <= 0xdbff) {
2267
+ if (str.length <= i + 1) {
2268
+ throw 'High surrogate without following low surrogate';
2269
+ }
2270
+ const next = str.charCodeAt(i + 1);
2271
+ if (0xdc00 > next || next > 0xdfff) {
2272
+ throw 'High surrogate without following low surrogate';
2273
+ }
2274
+ return str.charAt(i) + str.charAt(i + 1);
2275
+ }
2276
+ // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
2277
+ if (i === 0) {
2278
+ throw 'Low surrogate without preceding high surrogate';
2279
+ }
2280
+ const prev = str.charCodeAt(i - 1);
2281
+
2282
+ // (could change last hex to 0xDB7F to treat high private
2283
+ // surrogates as single characters)
2284
+ if (0xd800 > prev || prev > 0xdbff) {
2285
+ throw 'Low surrogate without preceding high surrogate';
2286
+ }
2287
+ // We can pass over low surrogates now as the second component
2288
+ // in a pair which we have already processed
2289
+ return false;
2290
+ };
2291
+
2292
+ var lang_string = /*#__PURE__*/Object.freeze({
2293
+ __proto__: null,
2294
+ capitalize: capitalize,
2295
+ escapeXml: escapeXml,
2296
+ graphemeSplit: graphemeSplit
2297
+ });
2298
+
2194
2299
  /**
2195
2300
  * Having both options in TCanvasSizeOptions set to true transform the call in a calcOffset
2196
2301
  * Better try to restrict with types to avoid confusion.
@@ -2960,7 +3065,8 @@ class StaticCanvas extends createCollectionMixin(CommonMethods) {
2960
3065
  this._setSVGPreamble(markup, options);
2961
3066
  this._setSVGHeader(markup, options);
2962
3067
  if (this.clipPath) {
2963
- markup.push(`<g clip-path="url(#${this.clipPath.clipPathId})" >\n`);
3068
+ var _this$clipPath$clipPa;
3069
+ markup.push(`<g clip-path="url(#${escapeXml((_this$clipPath$clipPa = this.clipPath.clipPathId) !== null && _this$clipPath$clipPa !== void 0 ? _this$clipPath$clipPa : '')})" >\n`);
2964
3070
  }
2965
3071
  this._setSVGBgOverlayColor(markup, 'background');
2966
3072
  this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);
@@ -4587,7 +4693,7 @@ const colorPropToSVG = function (prop, value) {
4587
4693
  if (!value) {
4588
4694
  colorValue = 'none';
4589
4695
  } else if (value.toLive) {
4590
- colorValue = `url(#SVGID_${value.id})`;
4696
+ colorValue = `url(#SVGID_${escapeXml(value.id)})`;
4591
4697
  } else {
4592
4698
  const color = new Color(value),
4593
4699
  opacity = color.getAlpha();
@@ -4640,7 +4746,7 @@ class FabricObjectSVGExportMixin {
4640
4746
  filter = skipShadow ? '' : this.getSvgFilter(),
4641
4747
  fill = colorPropToSVG(FILL, this.fill),
4642
4748
  stroke = colorPropToSVG(STROKE, this.stroke);
4643
- 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('');
4749
+ 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('');
4644
4750
  }
4645
4751
 
4646
4752
  /**
@@ -4648,7 +4754,7 @@ class FabricObjectSVGExportMixin {
4648
4754
  * @return {String}
4649
4755
  */
4650
4756
  getSvgFilter() {
4651
- return this.shadow ? `filter: url(#SVGID_${this.shadow.id});` : '';
4757
+ return this.shadow ? `filter: url(#SVGID_${escapeXml(this.shadow.id)});` : '';
4652
4758
  }
4653
4759
 
4654
4760
  /**
@@ -4656,7 +4762,7 @@ class FabricObjectSVGExportMixin {
4656
4762
  * @return {String}
4657
4763
  */
4658
4764
  getSvgCommons() {
4659
- return [this.id ? `id="${this.id}" ` : '', this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : ''].join('');
4765
+ return [this.id ? `id="${escapeXml(String(this.id))}" ` : '', this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : ''].join('');
4660
4766
  }
4661
4767
 
4662
4768
  /**
@@ -4769,7 +4875,7 @@ class FabricObjectSVGExportMixin {
4769
4875
  return reviver ? reviver(markup.join('')) : markup.join('');
4770
4876
  }
4771
4877
  addPaintOrder() {
4772
- return this.paintFirst !== FILL ? ` paint-order="${this.paintFirst}" ` : '';
4878
+ return this.paintFirst !== FILL ? ` paint-order="${escapeXml(this.paintFirst)}" ` : '';
4773
4879
  }
4774
4880
  }
4775
4881
 
@@ -4907,7 +5013,6 @@ const reViewBoxAttrValue = new RegExp(String.raw`^\s*(${reNum})${viewportSeparat
4907
5013
 
4908
5014
  (?:$|\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.
4909
5015
  */
4910
- // eslint-disable-next-line max-len
4911
5016
 
4912
5017
  const shadowOffsetRegex = '(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?';
4913
5018
  const reOffsetsAndBlur = new RegExp('(?:\\s|^)' + shadowOffsetRegex + shadowOffsetRegex + '(' + reNum + '?(?:px)?)?(?:\\s?|$)(?:$|\\s)');
@@ -4966,14 +5071,15 @@ class Shadow {
4966
5071
  toSVG(object) {
4967
5072
  const offset = rotateVector(new Point(this.offsetX, this.offsetY), degreesToRadians(-object.angle)),
4968
5073
  BLUR_BOX = 20,
5074
+ NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS,
4969
5075
  color = new Color(this.color);
4970
5076
  let fBoxX = 40,
4971
5077
  fBoxY = 40;
4972
5078
  if (object.width && object.height) {
4973
5079
  //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion
4974
5080
  // we add some extra space to filter box to contain the blur ( 20 )
4975
- fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, config.NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
4976
- fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, config.NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5081
+ fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
5082
+ fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;
4977
5083
  }
4978
5084
  if (object.flipX) {
4979
5085
  offset.x *= -1;
@@ -4981,7 +5087,7 @@ class Shadow {
4981
5087
  if (object.flipY) {
4982
5088
  offset.y *= -1;
4983
5089
  }
4984
- 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`;
5090
+ 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`;
4985
5091
  }
4986
5092
 
4987
5093
  /**
@@ -7132,6 +7238,9 @@ let FabricObject$1 = class FabricObject extends ObjectGeometry {
7132
7238
  } else {
7133
7239
  this._renderBackground(ctx);
7134
7240
  }
7241
+ this.fire('before:render', {
7242
+ ctx
7243
+ });
7135
7244
  this._render(ctx);
7136
7245
  this._drawClipPath(ctx, this.clipPath, context);
7137
7246
  this.fill = originalFill;
@@ -8422,6 +8531,14 @@ class Control {
8422
8531
  _defineProperty(this, "withConnection", false);
8423
8532
  Object.assign(this, options);
8424
8533
  }
8534
+ getTransformAnchorPoint() {
8535
+ var _this$transformAnchor;
8536
+ return (// return the control transformAnchorPoint
8537
+ (_this$transformAnchor = this.transformAnchorPoint) !== null && _this$transformAnchor !== void 0 ? _this$transformAnchor :
8538
+ // otherwise will return the opposite origin of where the control is located.
8539
+ new Point(-this.x + 0.5, -this.y + 0.5)
8540
+ );
8541
+ }
8425
8542
 
8426
8543
  /**
8427
8544
  * The control actionHandler, provide one to handle action ( control being moved )
@@ -10237,111 +10354,6 @@ const cloneStyles = style => {
10237
10354
  return newObj;
10238
10355
  };
10239
10356
 
10240
- /**
10241
- * Capitalizes a string
10242
- * @param {String} string String to capitalize
10243
- * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized
10244
- * and other letters stay untouched, if false first letter is capitalized
10245
- * and other letters are converted to lowercase.
10246
- * @return {String} Capitalized version of a string
10247
- */
10248
- const capitalize = function (string) {
10249
- let firstLetterOnly = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
10250
- return `${string.charAt(0).toUpperCase()}${firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()}`;
10251
- };
10252
-
10253
- /**
10254
- * Escapes XML in a string
10255
- * @param {String} string String to escape
10256
- * @return {String} Escaped version of a string
10257
- */
10258
- const escapeXml = string => string.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&apos;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
10259
- let segmenter;
10260
- const getSegmenter = () => {
10261
- if (!segmenter) {
10262
- segmenter = 'Intl' in getFabricWindow() && 'Segmenter' in Intl && new Intl.Segmenter(undefined, {
10263
- granularity: 'grapheme'
10264
- });
10265
- }
10266
- return segmenter;
10267
- };
10268
-
10269
- /**
10270
- * Divide a string in the user perceived single units
10271
- * @param {String} textstring String to escape
10272
- * @return {Array} array containing the graphemes
10273
- */
10274
- const graphemeSplit = textstring => {
10275
- segmenter || getSegmenter();
10276
- if (segmenter) {
10277
- const segments = segmenter.segment(textstring);
10278
- return Array.from(segments).map(_ref => {
10279
- let {
10280
- segment
10281
- } = _ref;
10282
- return segment;
10283
- });
10284
- }
10285
-
10286
- //Fallback
10287
- return graphemeSplitImpl(textstring);
10288
- };
10289
- const graphemeSplitImpl = textstring => {
10290
- const graphemes = [];
10291
- for (let i = 0, chr; i < textstring.length; i++) {
10292
- if ((chr = getWholeChar(textstring, i)) === false) {
10293
- continue;
10294
- }
10295
- graphemes.push(chr);
10296
- }
10297
- return graphemes;
10298
- };
10299
-
10300
- // taken from mdn in the charAt doc page.
10301
- const getWholeChar = (str, i) => {
10302
- const code = str.charCodeAt(i);
10303
- if (isNaN(code)) {
10304
- return ''; // Position not found
10305
- }
10306
- if (code < 0xd800 || code > 0xdfff) {
10307
- return str.charAt(i);
10308
- }
10309
-
10310
- // High surrogate (could change last hex to 0xDB7F to treat high private
10311
- // surrogates as single characters)
10312
- if (0xd800 <= code && code <= 0xdbff) {
10313
- if (str.length <= i + 1) {
10314
- throw 'High surrogate without following low surrogate';
10315
- }
10316
- const next = str.charCodeAt(i + 1);
10317
- if (0xdc00 > next || next > 0xdfff) {
10318
- throw 'High surrogate without following low surrogate';
10319
- }
10320
- return str.charAt(i) + str.charAt(i + 1);
10321
- }
10322
- // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
10323
- if (i === 0) {
10324
- throw 'Low surrogate without preceding high surrogate';
10325
- }
10326
- const prev = str.charCodeAt(i - 1);
10327
-
10328
- // (could change last hex to 0xDB7F to treat high private
10329
- // surrogates as single characters)
10330
- if (0xd800 > prev || prev > 0xdbff) {
10331
- throw 'Low surrogate without preceding high surrogate';
10332
- }
10333
- // We can pass over low surrogates now as the second component
10334
- // in a pair which we have already processed
10335
- return false;
10336
- };
10337
-
10338
- var lang_string = /*#__PURE__*/Object.freeze({
10339
- __proto__: null,
10340
- capitalize: capitalize,
10341
- escapeXml: escapeXml,
10342
- graphemeSplit: graphemeSplit
10343
- });
10344
-
10345
10357
  /**
10346
10358
  * @param {Object} prevStyle first style to compare
10347
10359
  * @param {Object} thisStyle second style to compare
@@ -10925,7 +10937,7 @@ class Rect extends FabricObject {
10925
10937
  rx,
10926
10938
  ry
10927
10939
  } = this;
10928
- return ['<rect ', 'COMMON_PARTS', `x="${-width / 2}" y="${-height / 2}" rx="${rx}" ry="${ry}" width="${width}" height="${height}" />\n`];
10940
+ return ['<rect ', 'COMMON_PARTS', `x="${-width / 2}" y="${-height / 2}" rx="${escapeXml(rx)}" ry="${escapeXml(ry)}" width="${escapeXml(width)}" height="${escapeXml(height)}" />\n`];
10929
10941
  }
10930
10942
 
10931
10943
  /**
@@ -11890,7 +11902,7 @@ class Group extends createCollectionMixin(FabricObject) {
11890
11902
  * @return {String}
11891
11903
  */
11892
11904
  getSvgStyles() {
11893
- const opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ? `opacity: ${this.opacity};` : '',
11905
+ const opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ? `opacity: ${escapeXml(this.opacity)};` : '',
11894
11906
  visibility = this.visible ? '' : ' visibility: hidden;';
11895
11907
  return [opacity, this.getSvgFilter(), visibility].join('');
11896
11908
  }
@@ -13844,11 +13856,13 @@ class SelectableCanvas extends StaticCanvas {
13844
13856
  * Given the control clicked, determine the origin of the transform.
13845
13857
  * This is bad because controls can totally have custom names
13846
13858
  * should disappear before release 4.0
13859
+ * Fabric 7.1, jan 2026 we are still using this.
13860
+ * Needs to go.
13847
13861
  * @private
13848
13862
  * @deprecated
13849
13863
  */
13850
13864
  _getOriginFromCorner(target, controlName) {
13851
- const origin = {
13865
+ const origin = controlName ? target.controls[controlName].getTransformAnchorPoint() : {
13852
13866
  x: target.originX,
13853
13867
  y: target.originY
13854
13868
  };
@@ -13856,6 +13870,9 @@ class SelectableCanvas extends StaticCanvas {
13856
13870
  return origin;
13857
13871
  }
13858
13872
 
13873
+ // this part down here is deprecated.
13874
+ // It is left to do not change the standard behavior in the middle of a major version
13875
+ // but when possible `getTransformAnchorPoint` will be the only source of truth
13859
13876
  // is a left control ?
13860
13877
  if (['ml', 'tl', 'bl'].includes(controlName)) {
13861
13878
  origin.x = RIGHT;
@@ -16353,7 +16370,8 @@ class Gradient {
16353
16370
  }
16354
16371
  transform[4] -= offsetX;
16355
16372
  transform[5] -= offsetY;
16356
- const commonAttributes = [`id="SVGID_${this.id}"`, `gradientUnits="${gradientUnits}"`, `gradientTransform="${preTransform ? preTransform + ' ' : ''}${matrixToSVG(transform)}"`, ''].join(' ');
16373
+ const commonAttributes = [`id="SVGID_${escapeXml(String(this.id))}"`, `gradientUnits="${gradientUnits}"`, `gradientTransform="${preTransform ? preTransform + ' ' : ''}${matrixToSVG(transform)}"`, ''].join(' ');
16374
+ const sanitizeCoord = value => parseFloat(String(value));
16357
16375
  if (this.type === 'linear') {
16358
16376
  const {
16359
16377
  x1,
@@ -16361,7 +16379,11 @@ class Gradient {
16361
16379
  x2,
16362
16380
  y2
16363
16381
  } = this.coords;
16364
- markup.push('<linearGradient ', commonAttributes, ' x1="', x1, '" y1="', y1, '" x2="', x2, '" y2="', y2, '">\n');
16382
+ const sx1 = sanitizeCoord(x1);
16383
+ const sy1 = sanitizeCoord(y1);
16384
+ const sx2 = sanitizeCoord(x2);
16385
+ const sy2 = sanitizeCoord(y2);
16386
+ markup.push('<linearGradient ', commonAttributes, ' x1="', sx1, '" y1="', sy1, '" x2="', sx2, '" y2="', sy2, '">\n');
16365
16387
  } else if (this.type === 'radial') {
16366
16388
  const {
16367
16389
  x1,
@@ -16371,9 +16393,15 @@ class Gradient {
16371
16393
  r1,
16372
16394
  r2
16373
16395
  } = this.coords;
16374
- const needsSwap = r1 > r2;
16396
+ const sx1 = sanitizeCoord(x1);
16397
+ const sy1 = sanitizeCoord(y1);
16398
+ const sx2 = sanitizeCoord(x2);
16399
+ const sy2 = sanitizeCoord(y2);
16400
+ const sr1 = sanitizeCoord(r1);
16401
+ const sr2 = sanitizeCoord(r2);
16402
+ const needsSwap = sr1 > sr2;
16375
16403
  // svg radial gradient has just 1 radius. the biggest.
16376
- 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');
16404
+ 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');
16377
16405
  if (needsSwap) {
16378
16406
  // svg goes from internal to external radius. if radius are inverted, swap color stops.
16379
16407
  colorStops.reverse(); // mutates array
@@ -16381,16 +16409,17 @@ class Gradient {
16381
16409
  colorStop.offset = 1 - colorStop.offset;
16382
16410
  });
16383
16411
  }
16384
- const minRadius = Math.min(r1, r2);
16412
+ const minRadius = Math.min(sr1, sr2);
16385
16413
  if (minRadius > 0) {
16386
16414
  // i have to shift all colorStops and add new one in 0.
16387
- const maxRadius = Math.max(r1, r2),
16415
+ const maxRadius = Math.max(sr1, sr2),
16388
16416
  percentageShift = minRadius / maxRadius;
16389
16417
  colorStops.forEach(colorStop => {
16390
16418
  colorStop.offset += percentageShift * (1 - colorStop.offset);
16391
16419
  });
16392
16420
  }
16393
16421
  }
16422
+ // todo make a malicious script tag injection test with color and also apply a fix with escapeXml
16394
16423
  colorStops.forEach(_ref => {
16395
16424
  let {
16396
16425
  color,
@@ -16706,7 +16735,7 @@ class Pattern {
16706
16735
  patternOffsetY = ifNaN(this.offsetY / height, 0),
16707
16736
  patternWidth = repeat === 'repeat-y' || repeat === 'no-repeat' ? 1 + Math.abs(patternOffsetX || 0) : ifNaN(patternSource.width / width, 0),
16708
16737
  patternHeight = repeat === 'repeat-x' || repeat === 'no-repeat' ? 1 + Math.abs(patternOffsetY || 0) : ifNaN(patternSource.height / height, 0);
16709
- 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');
16738
+ 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');
16710
16739
  }
16711
16740
  /* _TO_SVG_END_ */
16712
16741
 
@@ -16988,8 +17017,7 @@ class Path extends FabricObject {
16988
17017
  * of the instance
16989
17018
  */
16990
17019
  _toSVG() {
16991
- const path = joinPath(this.path, config.NUM_FRACTION_DIGITS);
16992
- return ['<path ', 'COMMON_PARTS', `d="${path}" stroke-linecap="round" />\n`];
17020
+ return ['<path ', 'COMMON_PARTS', `d="${joinPath(this.path, config.NUM_FRACTION_DIGITS)}" stroke-linecap="round" />\n`];
16993
17021
  }
16994
17022
 
16995
17023
  /**
@@ -17540,15 +17568,17 @@ class Circle extends FabricObject {
17540
17568
  * of the instance
17541
17569
  */
17542
17570
  _toSVG() {
17543
- const angle = (this.endAngle - this.startAngle) % 360;
17571
+ const {
17572
+ radius,
17573
+ startAngle,
17574
+ endAngle
17575
+ } = this;
17576
+ const angle = (endAngle - startAngle) % 360;
17544
17577
  if (angle === 0) {
17545
- return ['<circle ', 'COMMON_PARTS', 'cx="0" cy="0" ', 'r="', `${this.radius}`, '" />\n'];
17578
+ return ['<circle ', 'COMMON_PARTS', 'cx="0" cy="0" ', 'r="', `${escapeXml(radius)}`, '" />\n'];
17546
17579
  } else {
17547
- const {
17548
- radius
17549
- } = this;
17550
- const start = degreesToRadians(this.startAngle),
17551
- end = degreesToRadians(this.endAngle),
17580
+ const start = degreesToRadians(startAngle),
17581
+ end = degreesToRadians(endAngle),
17552
17582
  startX = cos(start) * radius,
17553
17583
  startY = sin(start) * radius,
17554
17584
  endX = cos(end) * radius,
@@ -18120,17 +18150,13 @@ class Line extends FabricObject {
18120
18150
  width,
18121
18151
  height
18122
18152
  } = this;
18123
- const xMult = _x1 <= _x2 ? -1 : 1,
18124
- yMult = _y1 <= _y2 ? -1 : 1,
18125
- x1 = xMult * width / 2,
18126
- y1 = yMult * height / 2,
18127
- x2 = xMult * -width / 2,
18128
- y2 = yMult * -height / 2;
18153
+ const xMult = _x1 <= _x2 ? -0.5 : 0.5,
18154
+ yMult = _y1 <= _y2 ? -0.5 : 0.5;
18129
18155
  return {
18130
- x1,
18131
- x2,
18132
- y1,
18133
- y2
18156
+ x1: xMult * width,
18157
+ x2: xMult * -width,
18158
+ y1: yMult * height,
18159
+ y2: yMult * -height
18134
18160
  };
18135
18161
  }
18136
18162
 
@@ -18348,7 +18374,7 @@ class Ellipse extends FabricObject {
18348
18374
  * of the instance
18349
18375
  */
18350
18376
  _toSVG() {
18351
- return ['<ellipse ', 'COMMON_PARTS', `cx="0" cy="0" rx="${this.rx}" ry="${this.ry}" />\n`];
18377
+ return ['<ellipse ', 'COMMON_PARTS', `cx="0" cy="0" rx="${escapeXml(this.rx)}" ry="${escapeXml(this.ry)}" />\n`];
18352
18378
  }
18353
18379
 
18354
18380
  /**
@@ -18666,14 +18692,17 @@ class Polyline extends FabricObject {
18666
18692
  * of the instance
18667
18693
  */
18668
18694
  _toSVG() {
18669
- const points = [],
18670
- diffX = this.pathOffset.x,
18695
+ const diffX = this.pathOffset.x,
18671
18696
  diffY = this.pathOffset.y,
18672
18697
  NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS;
18673
- for (let i = 0, len = this.points.length; i < len; i++) {
18674
- points.push(toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',', toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' ');
18675
- }
18676
- return [`<${this.constructor.type.toLowerCase()} `, 'COMMON_PARTS', `points="${points.join('')}" />\n`];
18698
+ const points = this.points.map(_ref2 => {
18699
+ let {
18700
+ x,
18701
+ y
18702
+ } = _ref2;
18703
+ return `${toFixed(x - diffX, NUM_FRACTION_DIGITS)},${toFixed(y - diffY, NUM_FRACTION_DIGITS)}`;
18704
+ }).join(' ');
18705
+ return [`<${escapeXml(this.constructor.type).toLowerCase()} `, 'COMMON_PARTS', `points="${points}" />\n`];
18677
18706
  }
18678
18707
 
18679
18708
  /**
@@ -19097,7 +19126,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19097
19126
  } = _ref;
19098
19127
  const noShadow = true,
19099
19128
  textDecoration = this.getSvgTextDecoration(this);
19100
- 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'];
19129
+ 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'];
19101
19130
  }
19102
19131
 
19103
19132
  /**
@@ -19113,7 +19142,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19113
19142
  lineOffset;
19114
19143
 
19115
19144
  // bounding-box background
19116
- this.backgroundColor && textBgRects.push(...createSVGInlineRect(this.backgroundColor, -this.width / 2, -this.height / 2, this.width, this.height));
19145
+ this.backgroundColor && textBgRects.push(createSVGInlineRect(this.backgroundColor, -this.width / 2, -this.height / 2, this.width, this.height));
19117
19146
 
19118
19147
  // text and text-background
19119
19148
  for (let i = 0, len = this._textLines.length; i < len; i++) {
@@ -19221,7 +19250,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19221
19250
  } = this.__charBounds[i][j];
19222
19251
  currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');
19223
19252
  if (currentColor !== lastColor) {
19224
- lastColor && textBgRects.push(...createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19253
+ lastColor && textBgRects.push(createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19225
19254
  boxStart = left;
19226
19255
  boxWidth = width;
19227
19256
  lastColor = currentColor;
@@ -19229,7 +19258,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19229
19258
  boxWidth += kernedWidth;
19230
19259
  }
19231
19260
  }
19232
- currentColor && textBgRects.push(...createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19261
+ currentColor && textBgRects.push(createSVGInlineRect(lastColor, leftOffset + boxStart, textTopOffset, boxWidth, heightOfLine));
19233
19262
  }
19234
19263
 
19235
19264
  /**
@@ -19267,7 +19296,7 @@ class TextSVGExportMixin extends FabricObjectSVGExportMixin {
19267
19296
  linethrough: linethrough !== null && linethrough !== void 0 ? linethrough : this.linethrough
19268
19297
  });
19269
19298
  const thickness = textDecorationThickness || this.textDecorationThickness;
19270
- 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('');
19299
+ 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('');
19271
19300
  }
19272
19301
 
19273
19302
  /**
@@ -24831,13 +24860,13 @@ class FabricImage extends FabricObject {
24831
24860
  }
24832
24861
  if (this.hasCrop()) {
24833
24862
  const clipPathId = uid();
24834
- svgString.push('<clipPath id="imageCrop_' + clipPathId + '">\n', '\t<rect x="' + x + '" y="' + y + '" width="' + this.width + '" height="' + this.height + '" />\n', '</clipPath>\n');
24863
+ svgString.push('<clipPath id="imageCrop_' + clipPathId + '">\n', '\t<rect x="' + x + '" y="' + y + '" width="' + escapeXml(this.width) + '" height="' + escapeXml(this.height) + '" />\n', '</clipPath>\n');
24835
24864
  clipPath = ' clip-path="url(#imageCrop_' + clipPathId + ')" ';
24836
24865
  }
24837
24866
  if (!this.imageSmoothing) {
24838
24867
  imageRendering = ' image-rendering="optimizeSpeed"';
24839
24868
  }
24840
- imageMarkup.push('\t<image ', 'COMMON_PARTS', `xlink:href="${this.getSvgSrc(true)}" x="${x - this.cropX}" y="${y - this.cropY
24869
+ imageMarkup.push('\t<image ', 'COMMON_PARTS', `xlink:href="${escapeXml(this.getSrc(true))}" x="${x - this.cropX}" y="${y - this.cropY
24841
24870
  // we're essentially moving origin of transformation from top/left corner to the center of the shape
24842
24871
  // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
24843
24872
  // so that object's center aligns with container's left/top
@@ -24845,7 +24874,7 @@ class FabricImage extends FabricObject {
24845
24874
  if (this.stroke || this.strokeDashArray) {
24846
24875
  const origFill = this.fill;
24847
24876
  this.fill = null;
24848
- strokeSvg = [`\t<rect x="${x}" y="${y}" width="${this.width}" height="${this.height}" style="${this.getSvgStyles()}" />\n`];
24877
+ strokeSvg = [`\t<rect x="${x}" y="${y}" width="${escapeXml(this.width)}" height="${escapeXml(this.height)}" style="${this.getSvgStyles()}" />\n`];
24849
24878
  this.fill = origFill;
24850
24879
  }
24851
24880
  if (this.paintFirst !== FILL) {