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
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { Circle } from '../Circle';
|
|
3
|
+
import { Ellipse } from '../Ellipse';
|
|
4
|
+
import { Rect } from '../Rect';
|
|
5
|
+
import { FabricText } from '../Text/Text';
|
|
6
|
+
import { FabricImage } from '../Image';
|
|
7
|
+
import { Shadow } from '../../Shadow';
|
|
8
|
+
|
|
9
|
+
const MALICIOUS = 'x" /><script>alert(1)</script>';
|
|
10
|
+
const MALICIOUS2 = `x" onclick="alert('svg animatetransform onbegin')"`;
|
|
11
|
+
const ONCLICK_PAYLOAD = `onclick="alert('svg animatetransform onbegin')"`;
|
|
12
|
+
|
|
13
|
+
describe.each([MALICIOUS, MALICIOUS2])(
|
|
14
|
+
'Object SVG export sanitization (%s)',
|
|
15
|
+
(payload) => {
|
|
16
|
+
it('sanitizes object id attributes', () => {
|
|
17
|
+
const rect = new Rect({
|
|
18
|
+
id: payload,
|
|
19
|
+
width: 10,
|
|
20
|
+
height: 10,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const svg = rect.toSVG();
|
|
24
|
+
expect(svg).not.toContain('<script>');
|
|
25
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('sanitizes object style attributes', () => {
|
|
29
|
+
const rect = new Rect({
|
|
30
|
+
width: 10,
|
|
31
|
+
height: 10,
|
|
32
|
+
fillRule: payload as unknown as 'nonzero',
|
|
33
|
+
strokeLineCap: payload as unknown as 'round',
|
|
34
|
+
strokeLineJoin: payload as unknown as 'round',
|
|
35
|
+
strokeDashArray: [payload as unknown as number],
|
|
36
|
+
paintFirst: payload as unknown as 'stroke',
|
|
37
|
+
shadow: new Shadow({
|
|
38
|
+
color: 'rgba(0, 0, 0, 0.5)',
|
|
39
|
+
blur: 0,
|
|
40
|
+
offsetX: 0,
|
|
41
|
+
offsetY: 0,
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
rect.shadow.id = payload as unknown as number;
|
|
45
|
+
|
|
46
|
+
const svg = rect.toSVG();
|
|
47
|
+
expect(svg).not.toContain('<script>');
|
|
48
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('sanitizes circle radius output', () => {
|
|
52
|
+
const circle = new Circle({
|
|
53
|
+
radius: payload as unknown as number,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const svg = circle.toSVG();
|
|
57
|
+
expect(svg).not.toContain('<script>');
|
|
58
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('sanitizes ellipse radii output', () => {
|
|
62
|
+
const ellipse = new Ellipse({
|
|
63
|
+
rx: payload as unknown as number,
|
|
64
|
+
ry: payload as unknown as number,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const svg = ellipse.toSVG();
|
|
68
|
+
expect(svg).not.toContain('<script>');
|
|
69
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('sanitizes text content and font attributes', () => {
|
|
73
|
+
const text = new FabricText('<script>alert(1)</script>', {
|
|
74
|
+
fontFamily: `Times New Roman ${payload}`,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const svg = text.toSVG();
|
|
78
|
+
expect(svg).not.toContain('<script>');
|
|
79
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('sanitizes text style overrides', () => {
|
|
83
|
+
const text = new FabricText('x', {
|
|
84
|
+
styles: {
|
|
85
|
+
0: {
|
|
86
|
+
0: {
|
|
87
|
+
fill: `red ${payload}`,
|
|
88
|
+
fontFamily: `Times ${payload}`,
|
|
89
|
+
fontWeight: `bold ${payload}`,
|
|
90
|
+
fontStyle: `italic ${payload}`,
|
|
91
|
+
fontSize: payload as unknown as number,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const svg = text.toSVG();
|
|
98
|
+
expect(svg).not.toContain('<script>');
|
|
99
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('sanitizes image src output', () => {
|
|
103
|
+
const element = new Image(10, 10);
|
|
104
|
+
element.src = `data:image/svg+xml,<svg>${payload}</svg>`;
|
|
105
|
+
const image = new FabricImage(element, { width: 10, height: 10 });
|
|
106
|
+
|
|
107
|
+
const svg = image.toSVG();
|
|
108
|
+
expect(svg).not.toContain('<script>');
|
|
109
|
+
expect(svg).not.toContain(ONCLICK_PAYLOAD);
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
);
|
|
@@ -4,10 +4,7 @@ import type { LockInteractionProps } from './LockInteractionProps';
|
|
|
4
4
|
import type { ObjectProps } from './ObjectProps';
|
|
5
5
|
|
|
6
6
|
export interface FabricObjectProps
|
|
7
|
-
extends ObjectProps,
|
|
8
|
-
ControlProps,
|
|
9
|
-
BorderProps,
|
|
10
|
-
LockInteractionProps {
|
|
7
|
+
extends ObjectProps, ControlProps, BorderProps, LockInteractionProps {
|
|
11
8
|
/**
|
|
12
9
|
* When `true`, cache does not get updated during scaling. The picture will get blocky if scaled
|
|
13
10
|
* too much and will be redrawn with correct details at the end of scaling.
|
|
@@ -10,9 +10,7 @@ import type {
|
|
|
10
10
|
} from './SerializedObjectProps';
|
|
11
11
|
|
|
12
12
|
export interface ObjectProps
|
|
13
|
-
extends SerializedObjectProps,
|
|
14
|
-
ClipPathProps,
|
|
15
|
-
ObjectTransformActionProps {
|
|
13
|
+
extends SerializedObjectProps, ClipPathProps, ObjectTransformActionProps {
|
|
16
14
|
clipPath?: FabricObject;
|
|
17
15
|
fill: TFiller | string | null;
|
|
18
16
|
stroke: TFiller | string | null;
|
package/src/shapes/Path.spec.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
2
|
import { Path } from './Path';
|
|
3
3
|
import type { TSimpleParsedCommand } from '../util';
|
|
4
|
-
import { FabricObject, getFabricDocument
|
|
4
|
+
import { FabricObject, getFabricDocument } from '../../fabric';
|
|
5
|
+
import { createReferenceObject } from '../../test/utils';
|
|
5
6
|
|
|
6
|
-
const REFERENCE_PATH_OBJECT = {
|
|
7
|
-
version: version,
|
|
8
|
-
type: 'Path',
|
|
9
|
-
originX: 'center' as const,
|
|
10
|
-
originY: 'center' as const,
|
|
7
|
+
const REFERENCE_PATH_OBJECT = createReferenceObject('Path', {
|
|
11
8
|
left: 200,
|
|
12
9
|
top: 200,
|
|
13
10
|
width: 200,
|
|
@@ -15,33 +12,13 @@ const REFERENCE_PATH_OBJECT = {
|
|
|
15
12
|
fill: 'red',
|
|
16
13
|
stroke: 'blue',
|
|
17
14
|
strokeWidth: 0,
|
|
18
|
-
strokeDashArray: null,
|
|
19
|
-
strokeLineCap: 'butt' as const,
|
|
20
|
-
strokeDashOffset: 0,
|
|
21
|
-
strokeLineJoin: 'miter' as const,
|
|
22
|
-
strokeMiterLimit: 4,
|
|
23
|
-
scaleX: 1,
|
|
24
|
-
scaleY: 1,
|
|
25
|
-
angle: 0,
|
|
26
|
-
flipX: false,
|
|
27
|
-
flipY: false,
|
|
28
|
-
opacity: 1,
|
|
29
15
|
path: [
|
|
30
16
|
['M', 100, 100],
|
|
31
17
|
['L', 300, 100],
|
|
32
18
|
['L', 200, 300],
|
|
33
19
|
['Z'],
|
|
34
20
|
] as TSimpleParsedCommand[],
|
|
35
|
-
|
|
36
|
-
visible: true,
|
|
37
|
-
backgroundColor: '',
|
|
38
|
-
fillRule: 'nonzero' as const,
|
|
39
|
-
paintFirst: 'fill' as const,
|
|
40
|
-
globalCompositeOperation: 'source-over' as const,
|
|
41
|
-
skewX: 0,
|
|
42
|
-
skewY: 0,
|
|
43
|
-
strokeUniform: false,
|
|
44
|
-
};
|
|
21
|
+
});
|
|
45
22
|
|
|
46
23
|
function getPathElement(path: string) {
|
|
47
24
|
const namespace = 'http://www.w3.org/2000/svg';
|
package/src/shapes/Path.ts
CHANGED
|
@@ -35,8 +35,7 @@ interface UniquePathProps {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export interface SerializedPathProps
|
|
38
|
-
extends SerializedObjectProps,
|
|
39
|
-
UniquePathProps {}
|
|
38
|
+
extends SerializedObjectProps, UniquePathProps {}
|
|
40
39
|
|
|
41
40
|
export interface PathProps extends FabricObjectProps, UniquePathProps {}
|
|
42
41
|
|
|
@@ -214,11 +213,10 @@ export class Path<
|
|
|
214
213
|
* of the instance
|
|
215
214
|
*/
|
|
216
215
|
_toSVG() {
|
|
217
|
-
const path = joinPath(this.path, config.NUM_FRACTION_DIGITS);
|
|
218
216
|
return [
|
|
219
217
|
'<path ',
|
|
220
218
|
'COMMON_PARTS',
|
|
221
|
-
`d="${path}" stroke-linecap="round" />\n`,
|
|
219
|
+
`d="${joinPath(this.path, config.NUM_FRACTION_DIGITS)}" stroke-linecap="round" />\n`,
|
|
222
220
|
];
|
|
223
221
|
}
|
|
224
222
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { Point } from '../Point';
|
|
3
3
|
import { getFabricDocument } from '../env';
|
|
4
|
-
import { VERSION as version } from '../constants';
|
|
5
4
|
import { Polygon } from './Polygon';
|
|
6
5
|
import { Polyline } from './Polyline';
|
|
7
6
|
import { FabricObject } from './Object/FabricObject';
|
|
7
|
+
import { createReferenceObject } from '../../test/utils';
|
|
8
8
|
|
|
9
9
|
function getPoints() {
|
|
10
10
|
return [
|
|
@@ -13,40 +13,13 @@ function getPoints() {
|
|
|
13
13
|
];
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const REFERENCE_OBJECT = {
|
|
17
|
-
version: version,
|
|
18
|
-
type: 'Polygon',
|
|
19
|
-
originX: 'center',
|
|
20
|
-
originY: 'center',
|
|
16
|
+
const REFERENCE_OBJECT = createReferenceObject('Polygon', {
|
|
21
17
|
left: 15,
|
|
22
18
|
top: 17,
|
|
23
19
|
width: 10,
|
|
24
20
|
height: 10,
|
|
25
|
-
fill: 'rgb(0,0,0)',
|
|
26
|
-
stroke: null,
|
|
27
|
-
strokeWidth: 1,
|
|
28
|
-
strokeDashArray: null,
|
|
29
|
-
strokeLineCap: 'butt',
|
|
30
|
-
strokeDashOffset: 0,
|
|
31
|
-
strokeLineJoin: 'miter',
|
|
32
|
-
strokeMiterLimit: 4,
|
|
33
|
-
scaleX: 1,
|
|
34
|
-
scaleY: 1,
|
|
35
|
-
angle: 0,
|
|
36
|
-
flipX: false,
|
|
37
|
-
flipY: false,
|
|
38
|
-
opacity: 1,
|
|
39
21
|
points: getPoints(),
|
|
40
|
-
|
|
41
|
-
visible: true,
|
|
42
|
-
backgroundColor: '',
|
|
43
|
-
fillRule: 'nonzero',
|
|
44
|
-
paintFirst: 'fill',
|
|
45
|
-
globalCompositeOperation: 'source-over',
|
|
46
|
-
skewX: 0,
|
|
47
|
-
skewY: 0,
|
|
48
|
-
strokeUniform: false,
|
|
49
|
-
} as const;
|
|
22
|
+
});
|
|
50
23
|
|
|
51
24
|
const REFERENCE_EMPTY_OBJECT = {
|
|
52
25
|
points: [],
|
|
@@ -273,7 +246,7 @@ describe('Polygon', () => {
|
|
|
273
246
|
expect(polygon.toSVG, 'toSVG should be a function').toBeTypeOf('function');
|
|
274
247
|
|
|
275
248
|
const EXPECTED_SVG =
|
|
276
|
-
'<g transform="matrix(1 0 0 1 15 17)" >\n<polygon style="stroke: rgb(0,0,255); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" points="-5,-5 5,5
|
|
249
|
+
'<g transform="matrix(1 0 0 1 15 17)" >\n<polygon style="stroke: rgb(0,0,255); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" points="-5,-5 5,5" />\n</g>\n';
|
|
277
250
|
|
|
278
251
|
expect(polygon.toSVG(), 'SVG output should match expected').toBe(
|
|
279
252
|
EXPECTED_SVG,
|
|
@@ -3,9 +3,9 @@ import { Point } from '../Point';
|
|
|
3
3
|
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
5
5
|
import { getFabricDocument } from '../env';
|
|
6
|
-
import { version } from '../../package.json';
|
|
7
6
|
import { Polygon } from './Polygon';
|
|
8
7
|
import { FabricObject } from './Object/FabricObject';
|
|
8
|
+
import { createReferenceObject } from '../../test/utils';
|
|
9
9
|
|
|
10
10
|
const points = [
|
|
11
11
|
{ x: 2, y: 2 },
|
|
@@ -13,40 +13,13 @@ const points = [
|
|
|
13
13
|
{ x: 12, y: 7 },
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
-
const REFERENCE_OBJECT = {
|
|
17
|
-
version: version,
|
|
18
|
-
type: 'Polyline',
|
|
19
|
-
originX: 'center',
|
|
20
|
-
originY: 'center',
|
|
16
|
+
const REFERENCE_OBJECT = createReferenceObject('Polyline', {
|
|
21
17
|
left: 15,
|
|
22
18
|
top: 17,
|
|
23
19
|
width: 10,
|
|
24
20
|
height: 10,
|
|
25
|
-
fill: 'rgb(0,0,0)',
|
|
26
|
-
stroke: null,
|
|
27
|
-
strokeWidth: 1,
|
|
28
|
-
strokeDashArray: null,
|
|
29
|
-
strokeLineCap: 'butt',
|
|
30
|
-
strokeDashOffset: 0,
|
|
31
|
-
strokeLineJoin: 'miter',
|
|
32
|
-
strokeMiterLimit: 4,
|
|
33
|
-
scaleX: 1,
|
|
34
|
-
scaleY: 1,
|
|
35
|
-
angle: 0,
|
|
36
|
-
flipX: false,
|
|
37
|
-
flipY: false,
|
|
38
|
-
opacity: 1,
|
|
39
21
|
points: getPoints(),
|
|
40
|
-
|
|
41
|
-
visible: true,
|
|
42
|
-
backgroundColor: '',
|
|
43
|
-
fillRule: 'nonzero',
|
|
44
|
-
paintFirst: 'fill',
|
|
45
|
-
globalCompositeOperation: 'source-over',
|
|
46
|
-
skewX: 0,
|
|
47
|
-
skewY: 0,
|
|
48
|
-
strokeUniform: false,
|
|
49
|
-
} as const;
|
|
22
|
+
});
|
|
50
23
|
|
|
51
24
|
describe('Polyline', () => {
|
|
52
25
|
describe('_calcDimensions and pathOffset', () => {
|
|
@@ -229,7 +202,7 @@ describe('Polyline', () => {
|
|
|
229
202
|
const polyline = new Polygon(getPoints(), { fill: 'red', stroke: 'blue' });
|
|
230
203
|
expect(polyline.toSVG).toBeTypeOf('function');
|
|
231
204
|
const EXPECTED_SVG =
|
|
232
|
-
'<g transform="matrix(1 0 0 1 15 17)" >\n<polygon style="stroke: rgb(0,0,255); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" points="-5,-5 5,5
|
|
205
|
+
'<g transform="matrix(1 0 0 1 15 17)" >\n<polygon style="stroke: rgb(0,0,255); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" points="-5,-5 5,5" />\n</g>\n';
|
|
233
206
|
expect(polyline.toSVG()).toEqual(EXPECTED_SVG);
|
|
234
207
|
});
|
|
235
208
|
|
package/src/shapes/Polyline.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
TOP,
|
|
26
26
|
} from '../constants';
|
|
27
27
|
import type { CSSRules } from '../parser/typedefs';
|
|
28
|
+
import { escapeXml } from '../util/lang_string';
|
|
28
29
|
|
|
29
30
|
export const polylineDefaultValues: Partial<TClassProperties<Polyline>> = {
|
|
30
31
|
/**
|
|
@@ -323,27 +324,25 @@ export class Polyline<
|
|
|
323
324
|
* of the instance
|
|
324
325
|
*/
|
|
325
326
|
_toSVG() {
|
|
326
|
-
const
|
|
327
|
-
diffX = this.pathOffset.x,
|
|
327
|
+
const diffX = this.pathOffset.x,
|
|
328
328
|
diffY = this.pathOffset.y,
|
|
329
329
|
NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS;
|
|
330
330
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
331
|
+
const points = this.points
|
|
332
|
+
.map(
|
|
333
|
+
({ x, y }) =>
|
|
334
|
+
`${toFixed(x - diffX, NUM_FRACTION_DIGITS)},${toFixed(y - diffY, NUM_FRACTION_DIGITS)}`,
|
|
335
|
+
)
|
|
336
|
+
.join(' ');
|
|
337
|
+
|
|
339
338
|
return [
|
|
340
339
|
`<${
|
|
341
|
-
(this.constructor as typeof Polyline).type.toLowerCase() as
|
|
340
|
+
escapeXml((this.constructor as typeof Polyline).type).toLowerCase() as
|
|
342
341
|
| 'polyline'
|
|
343
342
|
| 'polygon'
|
|
344
343
|
} `,
|
|
345
344
|
'COMMON_PARTS',
|
|
346
|
-
`points="${points
|
|
345
|
+
`points="${points}" />\n`,
|
|
347
346
|
];
|
|
348
347
|
}
|
|
349
348
|
|
package/src/shapes/Rect.spec.ts
CHANGED
|
@@ -7,42 +7,12 @@ import { Pattern } from '../Pattern';
|
|
|
7
7
|
// will require some kind of handling here
|
|
8
8
|
import { getEnv } from '../env';
|
|
9
9
|
import { loadSVGFromString } from '../parser/loadSVGFromString';
|
|
10
|
+
import { createReferenceObject } from '../../test/utils';
|
|
10
11
|
|
|
11
|
-
const REFERENCE_RECT = {
|
|
12
|
-
version,
|
|
13
|
-
type: 'Rect',
|
|
14
|
-
originX: 'center',
|
|
15
|
-
originY: 'center',
|
|
16
|
-
left: 0,
|
|
17
|
-
top: 0,
|
|
18
|
-
width: 0,
|
|
19
|
-
height: 0,
|
|
20
|
-
fill: 'rgb(0,0,0)',
|
|
21
|
-
stroke: null,
|
|
22
|
-
strokeWidth: 1,
|
|
23
|
-
strokeDashArray: null,
|
|
24
|
-
strokeLineCap: 'butt',
|
|
25
|
-
strokeDashOffset: 0,
|
|
26
|
-
strokeLineJoin: 'miter',
|
|
27
|
-
strokeMiterLimit: 4,
|
|
28
|
-
scaleX: 1,
|
|
29
|
-
scaleY: 1,
|
|
30
|
-
angle: 0,
|
|
31
|
-
flipX: false,
|
|
32
|
-
flipY: false,
|
|
33
|
-
opacity: 1,
|
|
34
|
-
shadow: null,
|
|
35
|
-
visible: true,
|
|
36
|
-
backgroundColor: '',
|
|
37
|
-
fillRule: 'nonzero',
|
|
38
|
-
paintFirst: 'fill',
|
|
39
|
-
globalCompositeOperation: 'source-over',
|
|
12
|
+
const REFERENCE_RECT = createReferenceObject('Rect', {
|
|
40
13
|
rx: 0,
|
|
41
14
|
ry: 0,
|
|
42
|
-
|
|
43
|
-
skewY: 0,
|
|
44
|
-
strokeUniform: false,
|
|
45
|
-
};
|
|
15
|
+
});
|
|
46
16
|
|
|
47
17
|
describe('Rect', () => {
|
|
48
18
|
it('constructor', function () {
|
|
@@ -273,4 +243,26 @@ describe('Rect', () => {
|
|
|
273
243
|
expect(rectObject.paintFirst).toBe('stroke');
|
|
274
244
|
expect(rectSvg).toContain('paint-order="stroke"');
|
|
275
245
|
});
|
|
246
|
+
|
|
247
|
+
describe('svg attribute injection', () => {
|
|
248
|
+
it('properties are properly escaped', () => {
|
|
249
|
+
const rect = new Rect({
|
|
250
|
+
id: 'asd"><script>alert(1)</script>',
|
|
251
|
+
width: 100,
|
|
252
|
+
height: 100,
|
|
253
|
+
});
|
|
254
|
+
const svg = rect.toSVG();
|
|
255
|
+
expect(svg).toContain(
|
|
256
|
+
`id="asd"><script>alert(1)</script>"`,
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
it('polyglot test', () => {
|
|
260
|
+
const polyglotPayload =
|
|
261
|
+
'jaVasCript:/*-/*`/*\\`/*\'/*"/**/(/* */oNcliCk=alert() )';
|
|
262
|
+
const rect = new Rect({ id: polyglotPayload, width: 100, height: 100 });
|
|
263
|
+
const svg = rect.toSVG();
|
|
264
|
+
// Should escape all special characters
|
|
265
|
+
expect(svg).not.toContain(polyglotPayload);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
276
268
|
});
|
package/src/shapes/Rect.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { FabricObject, cacheProperties } from './Object/FabricObject';
|
|
|
7
7
|
import type { FabricObjectProps, SerializedObjectProps } from './Object/types';
|
|
8
8
|
import type { ObjectEvents } from '../EventTypeDefs';
|
|
9
9
|
import type { CSSRules } from '../parser/typedefs';
|
|
10
|
+
import { escapeXml } from '../util/lang_string';
|
|
10
11
|
|
|
11
12
|
export const rectDefaultValues: Partial<TClassProperties<Rect>> = {
|
|
12
13
|
rx: 0,
|
|
@@ -19,18 +20,17 @@ interface UniqueRectProps {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export interface SerializedRectProps
|
|
22
|
-
extends SerializedObjectProps,
|
|
23
|
-
UniqueRectProps {}
|
|
23
|
+
extends SerializedObjectProps, UniqueRectProps {}
|
|
24
24
|
|
|
25
25
|
export interface RectProps extends FabricObjectProps, UniqueRectProps {}
|
|
26
26
|
|
|
27
27
|
const RECT_PROPS = ['rx', 'ry'] as const;
|
|
28
28
|
|
|
29
29
|
export class Rect<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
Props extends TOptions<RectProps> = Partial<RectProps>,
|
|
31
|
+
SProps extends SerializedRectProps = SerializedRectProps,
|
|
32
|
+
EventSpec extends ObjectEvents = ObjectEvents,
|
|
33
|
+
>
|
|
34
34
|
extends FabricObject<Props, SProps, EventSpec>
|
|
35
35
|
implements RectProps
|
|
36
36
|
{
|
|
@@ -164,7 +164,7 @@ export class Rect<
|
|
|
164
164
|
'COMMON_PARTS',
|
|
165
165
|
`x="${-width / 2}" y="${
|
|
166
166
|
-height / 2
|
|
167
|
-
}" rx="${rx}" ry="${ry}" width="${width}" height="${height}" />\n`,
|
|
167
|
+
}" rx="${escapeXml(rx)}" ry="${escapeXml(ry)}" width="${escapeXml(width)}" height="${escapeXml(height)}" />\n`,
|
|
168
168
|
];
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -10,38 +10,15 @@ import {
|
|
|
10
10
|
getFabricDocument,
|
|
11
11
|
IText,
|
|
12
12
|
Textbox,
|
|
13
|
-
version,
|
|
14
13
|
} from '../../../fabric';
|
|
15
14
|
import { toFixed } from '../../util';
|
|
15
|
+
import { createReferenceObject } from '../../../test/utils';
|
|
16
16
|
|
|
17
17
|
const CHAR_WIDTH = 20;
|
|
18
18
|
|
|
19
|
-
const REFERENCE_TEXT_OBJECT = {
|
|
20
|
-
version: version,
|
|
21
|
-
type: 'Text',
|
|
22
|
-
originX: 'center',
|
|
23
|
-
originY: 'center',
|
|
24
|
-
left: 0,
|
|
25
|
-
top: 0,
|
|
19
|
+
const REFERENCE_TEXT_OBJECT = createReferenceObject('Text', {
|
|
26
20
|
width: CHAR_WIDTH,
|
|
27
21
|
height: 45.2,
|
|
28
|
-
fill: 'rgb(0,0,0)',
|
|
29
|
-
stroke: null,
|
|
30
|
-
strokeWidth: 1,
|
|
31
|
-
strokeDashArray: null,
|
|
32
|
-
strokeLineCap: 'butt',
|
|
33
|
-
strokeDashOffset: 0,
|
|
34
|
-
strokeLineJoin: 'miter',
|
|
35
|
-
strokeMiterLimit: 4,
|
|
36
|
-
scaleX: 1,
|
|
37
|
-
scaleY: 1,
|
|
38
|
-
angle: 0,
|
|
39
|
-
flipX: false,
|
|
40
|
-
flipY: false,
|
|
41
|
-
opacity: 1,
|
|
42
|
-
shadow: null,
|
|
43
|
-
visible: true,
|
|
44
|
-
backgroundColor: '',
|
|
45
22
|
text: 'x',
|
|
46
23
|
fontSize: 40,
|
|
47
24
|
fontWeight: 'normal',
|
|
@@ -53,21 +30,15 @@ const REFERENCE_TEXT_OBJECT = {
|
|
|
53
30
|
linethrough: false,
|
|
54
31
|
textAlign: 'left',
|
|
55
32
|
textBackgroundColor: '',
|
|
56
|
-
fillRule: 'nonzero',
|
|
57
|
-
paintFirst: 'fill',
|
|
58
|
-
globalCompositeOperation: 'source-over',
|
|
59
|
-
skewX: 0,
|
|
60
|
-
skewY: 0,
|
|
61
33
|
charSpacing: 0,
|
|
62
34
|
styles: [],
|
|
63
35
|
path: undefined,
|
|
64
|
-
strokeUniform: false,
|
|
65
36
|
direction: 'ltr',
|
|
66
37
|
pathStartOffset: 0,
|
|
67
38
|
pathSide: 'left',
|
|
68
39
|
pathAlign: 'baseline',
|
|
69
40
|
textDecorationThickness: 66.667,
|
|
70
|
-
};
|
|
41
|
+
});
|
|
71
42
|
|
|
72
43
|
function createTextObject() {
|
|
73
44
|
return new FabricText('x');
|
package/src/shapes/Text/Text.ts
CHANGED
|
@@ -125,8 +125,7 @@ interface UniqueTextProps {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export interface SerializedTextProps
|
|
128
|
-
extends SerializedObjectProps,
|
|
129
|
-
UniqueTextProps {
|
|
128
|
+
extends SerializedObjectProps, UniqueTextProps {
|
|
130
129
|
styles: TextStyleArray | TextStyle;
|
|
131
130
|
}
|
|
132
131
|
|
|
@@ -139,10 +138,10 @@ export interface TextProps extends FabricObjectProps, UniqueTextProps {
|
|
|
139
138
|
* @see {@link http://fabric5.fabricjs.com/fabric-intro-part-2#text}
|
|
140
139
|
*/
|
|
141
140
|
export class FabricText<
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
Props extends TOptions<TextProps> = Partial<TextProps>,
|
|
142
|
+
SProps extends SerializedTextProps = SerializedTextProps,
|
|
143
|
+
EventSpec extends ObjectEvents = ObjectEvents,
|
|
144
|
+
>
|
|
146
145
|
extends StyledText<Props, SProps, EventSpec>
|
|
147
146
|
implements UniqueTextProps
|
|
148
147
|
{
|
|
@@ -77,12 +77,12 @@ export class TextSVGExportMixin extends FabricObjectSVGExportMixin {
|
|
|
77
77
|
return [
|
|
78
78
|
textBgRects.join(''),
|
|
79
79
|
'\t\t<text xml:space="preserve" ',
|
|
80
|
-
`font-family="${this.fontFamily.replace(dblQuoteRegex, "'")}" `,
|
|
81
|
-
`font-size="${this.fontSize}" `,
|
|
82
|
-
this.fontStyle ? `font-style="${this.fontStyle}" ` : '',
|
|
83
|
-
this.fontWeight ? `font-weight="${this.fontWeight}" ` : '',
|
|
80
|
+
`font-family="${escapeXml(this.fontFamily.replace(dblQuoteRegex, "'"))}" `,
|
|
81
|
+
`font-size="${escapeXml(this.fontSize)}" `,
|
|
82
|
+
this.fontStyle ? `font-style="${escapeXml(this.fontStyle)}" ` : '',
|
|
83
|
+
this.fontWeight ? `font-weight="${escapeXml(this.fontWeight)}" ` : '',
|
|
84
84
|
textDecoration ? `text-decoration="${textDecoration}" ` : '',
|
|
85
|
-
this.direction === 'rtl' ? `direction="
|
|
85
|
+
this.direction === 'rtl' ? `direction="rtl" ` : '',
|
|
86
86
|
'style="',
|
|
87
87
|
this.getSvgStyles(noShadow),
|
|
88
88
|
'"',
|
|
@@ -112,7 +112,7 @@ export class TextSVGExportMixin extends FabricObjectSVGExportMixin {
|
|
|
112
112
|
// bounding-box background
|
|
113
113
|
this.backgroundColor &&
|
|
114
114
|
textBgRects.push(
|
|
115
|
-
|
|
115
|
+
createSVGInlineRect(
|
|
116
116
|
this.backgroundColor,
|
|
117
117
|
-this.width / 2,
|
|
118
118
|
-this.height / 2,
|
|
@@ -270,7 +270,7 @@ export class TextSVGExportMixin extends FabricObjectSVGExportMixin {
|
|
|
270
270
|
if (currentColor !== lastColor) {
|
|
271
271
|
lastColor &&
|
|
272
272
|
textBgRects.push(
|
|
273
|
-
|
|
273
|
+
createSVGInlineRect(
|
|
274
274
|
lastColor,
|
|
275
275
|
leftOffset + boxStart,
|
|
276
276
|
textTopOffset,
|
|
@@ -287,7 +287,7 @@ export class TextSVGExportMixin extends FabricObjectSVGExportMixin {
|
|
|
287
287
|
}
|
|
288
288
|
currentColor &&
|
|
289
289
|
textBgRects.push(
|
|
290
|
-
|
|
290
|
+
createSVGInlineRect(
|
|
291
291
|
lastColor,
|
|
292
292
|
leftOffset + boxStart,
|
|
293
293
|
textTopOffset,
|
|
@@ -339,17 +339,17 @@ export class TextSVGExportMixin extends FabricObjectSVGExportMixin {
|
|
|
339
339
|
const thickness = textDecorationThickness || this.textDecorationThickness;
|
|
340
340
|
return [
|
|
341
341
|
stroke ? colorPropToSVG(STROKE, stroke) : '',
|
|
342
|
-
strokeWidth ? `stroke-width: ${strokeWidth}; ` : '',
|
|
342
|
+
strokeWidth ? `stroke-width: ${escapeXml(strokeWidth)}; ` : '',
|
|
343
343
|
fontFamily
|
|
344
344
|
? `font-family: ${
|
|
345
345
|
!fontFamily.includes("'") && !fontFamily.includes('"')
|
|
346
|
-
? `'${fontFamily}'`
|
|
347
|
-
: fontFamily
|
|
346
|
+
? `'${escapeXml(fontFamily)}'`
|
|
347
|
+
: escapeXml(fontFamily)
|
|
348
348
|
}; `
|
|
349
349
|
: '',
|
|
350
|
-
fontSize ? `font-size: ${fontSize}px; ` : '',
|
|
351
|
-
fontStyle ? `font-style: ${fontStyle}; ` : '',
|
|
352
|
-
fontWeight ? `font-weight: ${fontWeight}; ` : '',
|
|
350
|
+
fontSize ? `font-size: ${escapeXml(fontSize)}px; ` : '',
|
|
351
|
+
fontStyle ? `font-style: ${escapeXml(fontStyle)}; ` : '',
|
|
352
|
+
fontWeight ? `font-weight: ${escapeXml(fontWeight)}; ` : '',
|
|
353
353
|
textDecoration
|
|
354
354
|
? `text-decoration: ${textDecoration}; text-decoration-thickness: ${toFixed((thickness * this.getObjectScaling().y) / 10, config.NUM_FRACTION_DIGITS)}%; `
|
|
355
355
|
: '',
|