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