fabric 7.0.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 (323) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/CHANGELOG.md +21 -0
  3. package/dist/extensions/cropping_controls/croppingControls.d.ts +16 -0
  4. package/dist/extensions/cropping_controls/croppingControls.d.ts.map +1 -0
  5. package/dist/extensions/cropping_controls/croppingHandlers.d.ts +39 -0
  6. package/dist/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -0
  7. package/dist/extensions/cropping_controls/enterCropMode.d.ts +7 -0
  8. package/dist/extensions/cropping_controls/enterCropMode.d.ts.map +1 -0
  9. package/dist/extensions/cropping_controls/renderCornerControl.d.ts +14 -0
  10. package/dist/extensions/cropping_controls/renderCornerControl.d.ts.map +1 -0
  11. package/dist/extensions/index.d.ts +3 -0
  12. package/dist/extensions/index.d.ts.map +1 -1
  13. package/dist/fabric.d.ts +1 -0
  14. package/dist/fabric.d.ts.map +1 -1
  15. package/dist/index.js +628 -537
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.min.js +1 -1
  18. package/dist/index.min.js.map +1 -1
  19. package/dist/index.min.mjs +1 -1
  20. package/dist/index.min.mjs.map +1 -1
  21. package/dist/index.mjs +628 -537
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/index.node.cjs +628 -537
  24. package/dist/index.node.cjs.map +1 -1
  25. package/dist/index.node.mjs +628 -537
  26. package/dist/index.node.mjs.map +1 -1
  27. package/dist/package.json.min.mjs +1 -1
  28. package/dist/package.json.mjs +1 -1
  29. package/dist/src/EventTypeDefs.d.ts +5 -0
  30. package/dist/src/EventTypeDefs.d.ts.map +1 -1
  31. package/dist/src/Pattern/Pattern.d.ts.map +1 -1
  32. package/dist/src/Pattern/Pattern.min.mjs +1 -1
  33. package/dist/src/Pattern/Pattern.min.mjs.map +1 -1
  34. package/dist/src/Pattern/Pattern.mjs +2 -1
  35. package/dist/src/Pattern/Pattern.mjs.map +1 -1
  36. package/dist/src/Shadow.d.ts +1 -1
  37. package/dist/src/Shadow.d.ts.map +1 -1
  38. package/dist/src/Shadow.min.mjs +1 -1
  39. package/dist/src/Shadow.min.mjs.map +1 -1
  40. package/dist/src/Shadow.mjs +5 -4
  41. package/dist/src/Shadow.mjs.map +1 -1
  42. package/dist/src/canvas/CanvasOptions.d.ts.map +1 -1
  43. package/dist/src/canvas/CanvasOptions.min.mjs.map +1 -1
  44. package/dist/src/canvas/CanvasOptions.mjs.map +1 -1
  45. package/dist/src/canvas/SelectableCanvas.d.ts +2 -0
  46. package/dist/src/canvas/SelectableCanvas.d.ts.map +1 -1
  47. package/dist/src/canvas/SelectableCanvas.min.mjs +1 -1
  48. package/dist/src/canvas/SelectableCanvas.min.mjs.map +1 -1
  49. package/dist/src/canvas/SelectableCanvas.mjs +33 -13
  50. package/dist/src/canvas/SelectableCanvas.mjs.map +1 -1
  51. package/dist/src/canvas/StaticCanvas.d.ts.map +1 -1
  52. package/dist/src/canvas/StaticCanvas.min.mjs +1 -1
  53. package/dist/src/canvas/StaticCanvas.min.mjs.map +1 -1
  54. package/dist/src/canvas/StaticCanvas.mjs +3 -1
  55. package/dist/src/canvas/StaticCanvas.mjs.map +1 -1
  56. package/dist/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
  57. package/dist/src/canvas/StaticCanvasOptions.min.mjs.map +1 -1
  58. package/dist/src/canvas/StaticCanvasOptions.mjs.map +1 -1
  59. package/dist/src/constants.d.ts +1 -0
  60. package/dist/src/constants.d.ts.map +1 -1
  61. package/dist/src/constants.min.mjs.map +1 -1
  62. package/dist/src/constants.mjs.map +1 -1
  63. package/dist/src/controls/Control.d.ts +22 -1
  64. package/dist/src/controls/Control.d.ts.map +1 -1
  65. package/dist/src/controls/Control.min.mjs +1 -1
  66. package/dist/src/controls/Control.min.mjs.map +1 -1
  67. package/dist/src/controls/Control.mjs +45 -1
  68. package/dist/src/controls/Control.mjs.map +1 -1
  69. package/dist/src/controls/changeWidth.d.ts +22 -0
  70. package/dist/src/controls/changeWidth.d.ts.map +1 -1
  71. package/dist/src/controls/changeWidth.min.mjs +1 -1
  72. package/dist/src/controls/changeWidth.min.mjs.map +1 -1
  73. package/dist/src/controls/changeWidth.mjs +46 -18
  74. package/dist/src/controls/changeWidth.mjs.map +1 -1
  75. package/dist/src/controls/controlRendering.d.ts.map +1 -1
  76. package/dist/src/controls/controlRendering.min.mjs +1 -1
  77. package/dist/src/controls/controlRendering.min.mjs.map +1 -1
  78. package/dist/src/controls/controlRendering.mjs +18 -34
  79. package/dist/src/controls/controlRendering.mjs.map +1 -1
  80. package/dist/src/controls/index.d.ts +2 -1
  81. package/dist/src/controls/index.d.ts.map +1 -1
  82. package/dist/src/controls/index.min.mjs +1 -1
  83. package/dist/src/controls/index.mjs +1 -1
  84. package/dist/src/gradient/Gradient.d.ts.map +1 -1
  85. package/dist/src/gradient/Gradient.min.mjs +1 -1
  86. package/dist/src/gradient/Gradient.min.mjs.map +1 -1
  87. package/dist/src/gradient/Gradient.mjs +19 -6
  88. package/dist/src/gradient/Gradient.mjs.map +1 -1
  89. package/dist/src/shapes/Circle.d.ts.map +1 -1
  90. package/dist/src/shapes/Circle.min.mjs +1 -1
  91. package/dist/src/shapes/Circle.min.mjs.map +1 -1
  92. package/dist/src/shapes/Circle.mjs +10 -7
  93. package/dist/src/shapes/Circle.mjs.map +1 -1
  94. package/dist/src/shapes/Ellipse.d.ts.map +1 -1
  95. package/dist/src/shapes/Ellipse.min.mjs +1 -1
  96. package/dist/src/shapes/Ellipse.min.mjs.map +1 -1
  97. package/dist/src/shapes/Ellipse.mjs +2 -1
  98. package/dist/src/shapes/Ellipse.mjs.map +1 -1
  99. package/dist/src/shapes/Group.d.ts.map +1 -1
  100. package/dist/src/shapes/Group.min.mjs +1 -1
  101. package/dist/src/shapes/Group.min.mjs.map +1 -1
  102. package/dist/src/shapes/Group.mjs +2 -1
  103. package/dist/src/shapes/Group.mjs.map +1 -1
  104. package/dist/src/shapes/IText/IText.d.ts.map +1 -1
  105. package/dist/src/shapes/IText/IText.min.mjs.map +1 -1
  106. package/dist/src/shapes/IText/IText.mjs.map +1 -1
  107. package/dist/src/shapes/Image.d.ts +1 -1
  108. package/dist/src/shapes/Image.d.ts.map +1 -1
  109. package/dist/src/shapes/Image.min.mjs +1 -1
  110. package/dist/src/shapes/Image.min.mjs.map +1 -1
  111. package/dist/src/shapes/Image.mjs +4 -3
  112. package/dist/src/shapes/Image.mjs.map +1 -1
  113. package/dist/src/shapes/Line.d.ts.map +1 -1
  114. package/dist/src/shapes/Line.min.mjs +1 -1
  115. package/dist/src/shapes/Line.min.mjs.map +1 -1
  116. package/dist/src/shapes/Line.mjs +6 -10
  117. package/dist/src/shapes/Line.mjs.map +1 -1
  118. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
  119. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs +1 -1
  120. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs.map +1 -1
  121. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs +5 -4
  122. package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs.map +1 -1
  123. package/dist/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  124. package/dist/src/shapes/Object/InteractiveObject.min.mjs.map +1 -1
  125. package/dist/src/shapes/Object/InteractiveObject.mjs.map +1 -1
  126. package/dist/src/shapes/Object/Object.d.ts.map +1 -1
  127. package/dist/src/shapes/Object/Object.min.mjs +1 -1
  128. package/dist/src/shapes/Object/Object.min.mjs.map +1 -1
  129. package/dist/src/shapes/Object/Object.mjs +3 -0
  130. package/dist/src/shapes/Object/Object.mjs.map +1 -1
  131. package/dist/src/shapes/Object/ObjectGeometry.min.mjs +1 -1
  132. package/dist/src/shapes/Object/ObjectGeometry.min.mjs.map +1 -1
  133. package/dist/src/shapes/Object/ObjectGeometry.mjs +1 -1
  134. package/dist/src/shapes/Object/ObjectGeometry.mjs.map +1 -1
  135. package/dist/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
  136. package/dist/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
  137. package/dist/src/shapes/Path.d.ts.map +1 -1
  138. package/dist/src/shapes/Path.min.mjs.map +1 -1
  139. package/dist/src/shapes/Path.mjs +1 -2
  140. package/dist/src/shapes/Path.mjs.map +1 -1
  141. package/dist/src/shapes/Polyline.d.ts.map +1 -1
  142. package/dist/src/shapes/Polyline.min.mjs +1 -1
  143. package/dist/src/shapes/Polyline.min.mjs.map +1 -1
  144. package/dist/src/shapes/Polyline.mjs +10 -6
  145. package/dist/src/shapes/Polyline.mjs.map +1 -1
  146. package/dist/src/shapes/Rect.d.ts.map +1 -1
  147. package/dist/src/shapes/Rect.min.mjs +1 -1
  148. package/dist/src/shapes/Rect.min.mjs.map +1 -1
  149. package/dist/src/shapes/Rect.mjs +2 -1
  150. package/dist/src/shapes/Rect.mjs.map +1 -1
  151. package/dist/src/shapes/Text/StyledText.d.ts.map +1 -1
  152. package/dist/src/shapes/Text/StyledText.min.mjs.map +1 -1
  153. package/dist/src/shapes/Text/StyledText.mjs +0 -3
  154. package/dist/src/shapes/Text/StyledText.mjs.map +1 -1
  155. package/dist/src/shapes/Text/Text.d.ts.map +1 -1
  156. package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
  157. package/dist/src/shapes/Text/Text.mjs.map +1 -1
  158. package/dist/src/shapes/Text/TextSVGExportMixin.d.ts.map +1 -1
  159. package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs +1 -1
  160. package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs.map +1 -1
  161. package/dist/src/shapes/Text/TextSVGExportMixin.mjs +5 -6
  162. package/dist/src/shapes/Text/TextSVGExportMixin.mjs.map +1 -1
  163. package/dist/src/shapes/Textbox.d.ts.map +1 -1
  164. package/dist/src/shapes/Textbox.min.mjs.map +1 -1
  165. package/dist/src/shapes/Textbox.mjs.map +1 -1
  166. package/dist/src/shapes/Triangle.d.ts.map +1 -1
  167. package/dist/src/shapes/Triangle.min.mjs.map +1 -1
  168. package/dist/src/shapes/Triangle.mjs.map +1 -1
  169. package/dist/src/util/lang_string.d.ts +1 -1
  170. package/dist/src/util/lang_string.d.ts.map +1 -1
  171. package/dist/src/util/lang_string.min.mjs +1 -1
  172. package/dist/src/util/lang_string.min.mjs.map +1 -1
  173. package/dist/src/util/lang_string.mjs +1 -1
  174. package/dist/src/util/lang_string.mjs.map +1 -1
  175. package/dist/src/util/misc/svgParsing.d.ts.map +1 -1
  176. package/dist/src/util/misc/svgParsing.min.mjs +1 -1
  177. package/dist/src/util/misc/svgParsing.min.mjs.map +1 -1
  178. package/dist/src/util/misc/svgParsing.mjs +2 -1
  179. package/dist/src/util/misc/svgParsing.mjs.map +1 -1
  180. package/dist-extensions/cropping_controls/croppingControls.mjs +140 -0
  181. package/dist-extensions/cropping_controls/croppingControls.mjs.map +1 -0
  182. package/dist-extensions/cropping_controls/croppingHandlers.mjs +228 -0
  183. package/dist-extensions/cropping_controls/croppingHandlers.mjs.map +1 -0
  184. package/dist-extensions/cropping_controls/enterCropMode.mjs +38 -0
  185. package/dist-extensions/cropping_controls/enterCropMode.mjs.map +1 -0
  186. package/dist-extensions/cropping_controls/renderCornerControl.mjs +45 -0
  187. package/dist-extensions/cropping_controls/renderCornerControl.mjs.map +1 -0
  188. package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts +16 -0
  189. package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts.map +1 -0
  190. package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts +39 -0
  191. package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -0
  192. package/dist-extensions/extensions/cropping_controls/enterCropMode.d.ts +7 -0
  193. package/dist-extensions/extensions/cropping_controls/enterCropMode.d.ts.map +1 -0
  194. package/dist-extensions/extensions/cropping_controls/renderCornerControl.d.ts +14 -0
  195. package/dist-extensions/extensions/cropping_controls/renderCornerControl.d.ts.map +1 -0
  196. package/dist-extensions/extensions/index.d.ts +3 -0
  197. package/dist-extensions/extensions/index.d.ts.map +1 -1
  198. package/dist-extensions/fabric-extensions.min.js +1 -1
  199. package/dist-extensions/fabric-extensions.min.js.map +1 -1
  200. package/dist-extensions/fabric.d.ts +1 -0
  201. package/dist-extensions/fabric.d.ts.map +1 -1
  202. package/dist-extensions/index.mjs +3 -0
  203. package/dist-extensions/index.mjs.map +1 -1
  204. package/dist-extensions/src/EventTypeDefs.d.ts +5 -0
  205. package/dist-extensions/src/EventTypeDefs.d.ts.map +1 -1
  206. package/dist-extensions/src/Pattern/Pattern.d.ts.map +1 -1
  207. package/dist-extensions/src/Shadow.d.ts +1 -1
  208. package/dist-extensions/src/Shadow.d.ts.map +1 -1
  209. package/dist-extensions/src/canvas/CanvasOptions.d.ts.map +1 -1
  210. package/dist-extensions/src/canvas/SelectableCanvas.d.ts +2 -0
  211. package/dist-extensions/src/canvas/SelectableCanvas.d.ts.map +1 -1
  212. package/dist-extensions/src/canvas/StaticCanvas.d.ts.map +1 -1
  213. package/dist-extensions/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
  214. package/dist-extensions/src/constants.d.ts +1 -0
  215. package/dist-extensions/src/constants.d.ts.map +1 -1
  216. package/dist-extensions/src/controls/Control.d.ts +22 -1
  217. package/dist-extensions/src/controls/Control.d.ts.map +1 -1
  218. package/dist-extensions/src/controls/changeWidth.d.ts +22 -0
  219. package/dist-extensions/src/controls/changeWidth.d.ts.map +1 -1
  220. package/dist-extensions/src/controls/controlRendering.d.ts.map +1 -1
  221. package/dist-extensions/src/controls/index.d.ts +2 -1
  222. package/dist-extensions/src/controls/index.d.ts.map +1 -1
  223. package/dist-extensions/src/gradient/Gradient.d.ts.map +1 -1
  224. package/dist-extensions/src/shapes/Circle.d.ts.map +1 -1
  225. package/dist-extensions/src/shapes/Ellipse.d.ts.map +1 -1
  226. package/dist-extensions/src/shapes/Group.d.ts.map +1 -1
  227. package/dist-extensions/src/shapes/IText/IText.d.ts.map +1 -1
  228. package/dist-extensions/src/shapes/Image.d.ts.map +1 -1
  229. package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
  230. package/dist-extensions/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
  231. package/dist-extensions/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
  232. package/dist-extensions/src/shapes/Object/Object.d.ts.map +1 -1
  233. package/dist-extensions/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
  234. package/dist-extensions/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
  235. package/dist-extensions/src/shapes/Path.d.ts +1 -1
  236. package/dist-extensions/src/shapes/Path.d.ts.map +1 -1
  237. package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
  238. package/dist-extensions/src/shapes/Rect.d.ts.map +1 -1
  239. package/dist-extensions/src/shapes/Text/StyledText.d.ts.map +1 -1
  240. package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
  241. package/dist-extensions/src/shapes/Text/TextSVGExportMixin.d.ts.map +1 -1
  242. package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
  243. package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
  244. package/dist-extensions/src/util/lang_string.d.ts +1 -1
  245. package/dist-extensions/src/util/lang_string.d.ts.map +1 -1
  246. package/dist-extensions/src/util/misc/svgParsing.d.ts.map +1 -1
  247. package/eslint.config.mjs +2 -0
  248. package/extensions/cropping_controls/croppingControls.spec.ts +115 -0
  249. package/extensions/cropping_controls/croppingControls.ts +150 -0
  250. package/extensions/cropping_controls/croppingHandlers.spec.ts +579 -0
  251. package/extensions/cropping_controls/croppingHandlers.ts +285 -0
  252. package/extensions/cropping_controls/enterCropMode.ts +30 -0
  253. package/extensions/cropping_controls/renderCornerControl.ts +53 -0
  254. package/extensions/index.ts +9 -0
  255. package/fabric.ts +1 -0
  256. package/package.json +17 -8
  257. package/src/ClassRegistry.spec.ts +18 -19
  258. package/src/EventTypeDefs.ts +15 -11
  259. package/src/Pattern/Pattern.spec.ts +12 -0
  260. package/src/Pattern/Pattern.ts +3 -2
  261. package/src/Shadow.ts +9 -8
  262. package/src/brushes/PencilBrush.spec.ts +11 -11
  263. package/src/canvas/Canvas-dispose.spec.ts +8 -7
  264. package/src/canvas/Canvas.spec.ts +27 -29
  265. package/src/canvas/CanvasOptions.ts +2 -1
  266. package/src/canvas/SelectableCanvas.ts +38 -15
  267. package/src/canvas/StaticCanvas.spec.ts +20 -0
  268. package/src/canvas/StaticCanvas.ts +7 -4
  269. package/src/canvas/StaticCanvasOptions.ts +1 -3
  270. package/src/constants.ts +1 -0
  271. package/src/controls/Control.spec.ts +102 -0
  272. package/src/controls/Control.ts +71 -2
  273. package/src/controls/changeHeight.spec.ts +147 -0
  274. package/src/controls/changeWidth.ts +68 -35
  275. package/src/controls/controlRendering.ts +20 -48
  276. package/src/controls/index.ts +7 -1
  277. package/src/gradient/Gradient.spec.ts +101 -46
  278. package/src/gradient/Gradient.ts +27 -14
  279. package/src/shapes/Circle.spec.ts +10 -39
  280. package/src/shapes/Circle.ts +11 -11
  281. package/src/shapes/Ellipse.spec.ts +8 -37
  282. package/src/shapes/Ellipse.ts +7 -7
  283. package/src/shapes/Group.ts +3 -3
  284. package/src/shapes/IText/IText-click-behavior.spec.ts +36 -49
  285. package/src/shapes/IText/IText.ts +5 -6
  286. package/src/shapes/IText/ITextKeyBehavior.test.ts +0 -1
  287. package/src/shapes/IText/__snapshots__/ITextBehavior.test.ts.snap +6 -6
  288. package/src/shapes/Image.spec.ts +17 -33
  289. package/src/shapes/Image.ts +15 -11
  290. package/src/shapes/Line.spec.ts +4 -30
  291. package/src/shapes/Line.ts +11 -16
  292. package/src/shapes/Object/FabricObjectSVGExportMixin.ts +11 -4
  293. package/src/shapes/Object/InteractiveObject.ts +4 -4
  294. package/src/shapes/Object/Object.ts +6 -5
  295. package/src/shapes/Object/ObjectGeometry.spec.ts +15 -0
  296. package/src/shapes/Object/ObjectGeometry.ts +1 -1
  297. package/src/shapes/Object/objectSvgExport.spec.ts +112 -0
  298. package/src/shapes/Object/types/FabricObjectProps.ts +1 -4
  299. package/src/shapes/Object/types/ObjectProps.ts +1 -3
  300. package/src/shapes/Path.spec.ts +4 -27
  301. package/src/shapes/Path.ts +2 -4
  302. package/src/shapes/Polygon.spec.ts +4 -31
  303. package/src/shapes/Polyline.spec.ts +4 -31
  304. package/src/shapes/Polyline.ts +11 -12
  305. package/src/shapes/Rect.spec.ts +25 -33
  306. package/src/shapes/Rect.ts +7 -7
  307. package/src/shapes/Text/StyledText.ts +0 -3
  308. package/src/shapes/Text/Text.spec.ts +3 -32
  309. package/src/shapes/Text/Text.ts +5 -6
  310. package/src/shapes/Text/TextSVGExportMixin.spec.ts +9 -0
  311. package/src/shapes/Text/TextSVGExportMixin.ts +14 -16
  312. package/src/shapes/Text/__snapshots__/Text.spec.ts.snap +1 -1
  313. package/src/shapes/Text/__snapshots__/TextSVGExportMixin.spec.ts.snap +1 -1
  314. package/src/shapes/Textbox.spec.ts +5 -5
  315. package/src/shapes/Textbox.ts +6 -5
  316. package/src/shapes/Triangle.ts +4 -4
  317. package/src/shapes/__snapshots__/Image.spec.ts.snap +4 -4
  318. package/src/shapes/__snapshots__/Textbox.spec.ts.snap +5 -5
  319. package/src/util/lang_string.ts +3 -2
  320. package/src/util/misc/svgParsing.ts +2 -1
  321. package/tsconfig.spec.json +1 -0
  322. package/vitest.config.ts +12 -2
  323. package/vitest.extend.ts +6 -2
@@ -13,10 +13,10 @@ import { Group } from '../Group';
13
13
  import { config } from '../../config';
14
14
  import type {
15
15
  ObjectPointerEvents,
16
- TPointerEvent,
17
16
  TPointerEventInfo,
18
17
  } from '../../EventTypeDefs';
19
18
  import { Point } from '../../Point';
19
+ import { createPointerEvent } from '../../../test/utils';
20
20
 
21
21
  describe('iText click interaction', () => {
22
22
  let canvas: Canvas;
@@ -40,12 +40,11 @@ describe('iText click interaction', () => {
40
40
 
41
41
  iText.canvas = canvas;
42
42
 
43
- let eventData = {
44
- which: 1,
43
+ let eventData = createPointerEvent({
45
44
  target: canvas.upperCanvasEl,
46
45
  clientX: 40,
47
46
  clientY: 10,
48
- } as unknown as TPointerEvent;
47
+ });
49
48
 
50
49
  iText.enterEditing();
51
50
 
@@ -56,12 +55,11 @@ describe('iText click interaction', () => {
56
55
  expect(iText.selectionStart, 'dblClick selection start is').toBe(0);
57
56
  expect(iText.selectionEnd, 'dblClick selection end is').toBe(4);
58
57
 
59
- eventData = {
60
- which: 1,
58
+ eventData = createPointerEvent({
61
59
  target: canvas.upperCanvasEl,
62
60
  clientX: 40,
63
61
  clientY: 60,
64
- } as unknown as TPointerEvent;
62
+ });
65
63
 
66
64
  iText.doubleClickHandler({
67
65
  e: eventData,
@@ -76,12 +74,11 @@ describe('iText click interaction', () => {
76
74
 
77
75
  iText.canvas = canvas;
78
76
 
79
- const eventData = {
80
- which: 1,
77
+ const eventData = createPointerEvent({
81
78
  target: canvas.upperCanvasEl,
82
79
  clientX: 40,
83
80
  clientY: 10,
84
- } as unknown as TPointerEvent;
81
+ });
85
82
 
86
83
  iText.doubleClickHandler({
87
84
  e: eventData,
@@ -97,12 +94,11 @@ describe('iText click interaction', () => {
97
94
 
98
95
  iText.canvas = canvas;
99
96
 
100
- let eventData = {
101
- which: 1,
97
+ let eventData = createPointerEvent({
102
98
  target: canvas.upperCanvasEl,
103
99
  clientX: 40,
104
100
  clientY: 10,
105
- } as unknown as TPointerEvent;
101
+ });
106
102
 
107
103
  iText.enterEditing();
108
104
 
@@ -113,12 +109,11 @@ describe('iText click interaction', () => {
113
109
  expect(iText.selectionStart, 'tripleClick selection start is').toBe(0);
114
110
  expect(iText.selectionEnd, 'tripleClick selection end is').toBe(19);
115
111
 
116
- eventData = {
117
- which: 1,
112
+ eventData = createPointerEvent({
118
113
  target: canvas.upperCanvasEl,
119
114
  clientX: 40,
120
115
  clientY: 60,
121
- } as unknown as TPointerEvent;
116
+ });
122
117
 
123
118
  iText.tripleClickHandler({
124
119
  e: eventData,
@@ -137,12 +132,11 @@ describe('iText click interaction', () => {
137
132
 
138
133
  iText.canvas = canvas;
139
134
 
140
- const eventData = {
141
- which: 1,
135
+ const eventData = createPointerEvent({
142
136
  target: canvas.upperCanvasEl,
143
137
  clientX: 40,
144
138
  clientY: 10,
145
- } as unknown as TPointerEvent;
139
+ });
146
140
 
147
141
  iText.tripleClickHandler({
148
142
  e: eventData,
@@ -153,12 +147,11 @@ describe('iText click interaction', () => {
153
147
  });
154
148
 
155
149
  test('getSelectionStartFromPointer with scale', () => {
156
- const eventData = {
157
- which: 1,
150
+ const eventData = createPointerEvent({
158
151
  target: canvas.upperCanvasEl,
159
152
  clientX: 70,
160
153
  clientY: 10,
161
- } as unknown as TPointerEvent;
154
+ });
162
155
 
163
156
  const iText = new IText('test need some word\nsecond line', {
164
157
  scaleX: 3,
@@ -186,10 +179,7 @@ describe('iText click interaction', () => {
186
179
 
187
180
  expect(iText.getSelectionStartFromPointer(eventData), 'index').toBe(5);
188
181
  expect(
189
- iText.getSelectionStartFromPointer({
190
- ...eventData,
191
- clientY: 20,
192
- } as unknown as TPointerEvent),
182
+ iText.getSelectionStartFromPointer({ ...eventData, clientY: 20 }),
193
183
  'index',
194
184
  ).toBe(5);
195
185
  });
@@ -275,11 +265,11 @@ describe('iText click interaction', () => {
275
265
  canvas.add(group);
276
266
  // @ts-expect-error -- protected member
277
267
  iText.selected = true;
278
- const evt = {
268
+ const evt = createPointerEvent({
279
269
  clientX: 1,
280
270
  clientY: 1,
281
271
  target: canvas.upperCanvasEl,
282
- } as unknown as TPointerEvent;
272
+ });
283
273
  canvas._cacheTransformEventData(evt);
284
274
  canvas.__onMouseUp(evt);
285
275
  // @ts-expect-error -- protected member
@@ -309,11 +299,13 @@ describe('iText click interaction', () => {
309
299
  // @ts-expect-error -- protected member
310
300
  iText.selected = true;
311
301
 
312
- canvas._onMouseUp({
313
- clientX: 1,
314
- clientY: 1,
315
- target: canvas.upperCanvasEl,
316
- } as unknown as TPointerEvent);
302
+ canvas._onMouseUp(
303
+ createPointerEvent({
304
+ clientX: 1,
305
+ clientY: 1,
306
+ target: canvas.upperCanvasEl,
307
+ }),
308
+ );
317
309
 
318
310
  expect(iText.isEditing, 'iText should enter editing').toBe(true);
319
311
 
@@ -322,11 +314,13 @@ describe('iText click interaction', () => {
322
314
  // @ts-expect-error -- protected member
323
315
  iText.selected = true;
324
316
 
325
- canvas._onMouseUp({
326
- clientX: 1,
327
- clientY: 1,
328
- target: canvas.upperCanvasEl,
329
- } as unknown as TPointerEvent);
317
+ canvas._onMouseUp(
318
+ createPointerEvent({
319
+ clientX: 1,
320
+ clientY: 1,
321
+ target: canvas.upperCanvasEl,
322
+ }),
323
+ );
330
324
 
331
325
  expect(iText.isEditing, 'iText should not enter editing').toBe(false);
332
326
  });
@@ -376,19 +370,12 @@ describe('iText click interaction', () => {
376
370
  enableRetinaScaling,
377
371
  });
378
372
 
379
- eventData = {
380
- which: 1,
373
+ eventData = createPointerEvent({
381
374
  target: testCanvas.upperCanvasEl,
382
375
  ...(enableRetinaScaling
383
- ? {
384
- clientX: 60,
385
- clientY: 30,
386
- }
387
- : {
388
- clientX: 30,
389
- clientY: 15,
390
- }),
391
- } as unknown as TPointerEvent;
376
+ ? { clientX: 60, clientY: 30 }
377
+ : { clientX: 30, clientY: 15 }),
378
+ });
392
379
 
393
380
  count = 0;
394
381
  countCanvas = 0;
@@ -72,8 +72,7 @@ interface UniqueITextProps {
72
72
  }
73
73
 
74
74
  export interface SerializedITextProps
75
- extends SerializedTextProps,
76
- UniqueITextProps {}
75
+ extends SerializedTextProps, UniqueITextProps {}
77
76
 
78
77
  export interface ITextProps extends TextProps, UniqueITextProps {}
79
78
 
@@ -121,10 +120,10 @@ export interface ITextProps extends TextProps, UniqueITextProps {}
121
120
  * ```
122
121
  */
123
122
  export class IText<
124
- Props extends TOptions<ITextProps> = Partial<ITextProps>,
125
- SProps extends SerializedITextProps = SerializedITextProps,
126
- EventSpec extends ITextEvents = ITextEvents,
127
- >
123
+ Props extends TOptions<ITextProps> = Partial<ITextProps>,
124
+ SProps extends SerializedITextProps = SerializedITextProps,
125
+ EventSpec extends ITextEvents = ITextEvents,
126
+ >
128
127
  extends ITextClickBehavior<Props, SProps, EventSpec>
129
128
  implements UniqueITextProps
130
129
  {
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
2
1
  import { config } from '../../config';
3
2
  import { noop } from '../../constants';
4
3
  import { getEnv, getFabricWindow } from '../../env';
@@ -442,7 +442,7 @@ exports[`text imperative changes > insertChars 2`] = `
442
442
  "text": "tabest",
443
443
  "top": 0,
444
444
  "type": "IText",
445
- "width": 58,
445
+ "width": 58.31,
446
446
  }
447
447
  `;
448
448
 
@@ -563,7 +563,7 @@ exports[`text imperative changes > insertChars and removes chars 2`] = `
563
563
  "text": "tabst",
564
564
  "top": 0,
565
565
  "type": "IText",
566
- "width": 47,
566
+ "width": 47.22,
567
567
  }
568
568
  `;
569
569
 
@@ -646,7 +646,7 @@ exports[`text imperative changes > insertChars and removes chars 4`] = `
646
646
  "text": "tab",
647
647
  "top": 0,
648
648
  "type": "IText",
649
- "width": 31,
649
+ "width": 30.54,
650
650
  }
651
651
  `;
652
652
 
@@ -853,7 +853,7 @@ exports[`text imperative changes > insertChars can accept some style for the new
853
853
  aest",
854
854
  "top": 0,
855
855
  "type": "IText",
856
- "width": 39,
856
+ "width": 38.87,
857
857
  }
858
858
  `;
859
859
 
@@ -1027,7 +1027,7 @@ exports[`text imperative changes > insertChars handles new lines correctly 2`] =
1027
1027
  est",
1028
1028
  "top": 0,
1029
1029
  "type": "IText",
1030
- "width": 31,
1030
+ "width": 30.54,
1031
1031
  }
1032
1032
  `;
1033
1033
 
@@ -1105,6 +1105,6 @@ exports[`text imperative changes > removeChars 2`] = `
1105
1105
  "text": "tt",
1106
1106
  "top": 0,
1107
1107
  "type": "IText",
1108
- "width": 14,
1108
+ "width": 13.89,
1109
1109
  }
1110
1110
  `;
@@ -13,7 +13,6 @@ import {
13
13
  getFabricDocument,
14
14
  getFilterBackend,
15
15
  Rect,
16
- version,
17
16
  WebGLFilterBackend,
18
17
  } from '../../fabric';
19
18
  import { removeTransformMatrixForSvgParsing } from '../util';
@@ -21,6 +20,7 @@ import * as FilterBackend from '../filters/FilterBackend';
21
20
  import { FabricError } from '../util/internals/console';
22
21
  import TestImageGif from '../../test/fixtures/test_image.gif';
23
22
  import { isJSDOM } from '../../vitest.extend';
23
+ import { createReferenceObject } from '../../test/utils';
24
24
 
25
25
  const IMG_SRC = isJSDOM() ? 'test_image.gif' : TestImageGif;
26
26
  const imgSrcUrl = new URL(IMG_SRC, import.meta.url).pathname;
@@ -29,44 +29,16 @@ const IMG_WIDTH = 276;
29
29
  const IMG_HEIGHT = 110;
30
30
  const IMG_URL_NON_EXISTING = 'http://www.google.com/non-existing';
31
31
 
32
- const REFERENCE_IMG_OBJECT = {
33
- version: version,
34
- type: 'Image',
35
- originX: 'center' as const,
36
- originY: 'center' as const,
37
- left: 0,
38
- top: 0,
32
+ const REFERENCE_IMG_OBJECT = createReferenceObject('Image', {
39
33
  width: IMG_WIDTH,
40
34
  height: IMG_HEIGHT,
41
- fill: 'rgb(0,0,0)',
42
- stroke: null,
43
35
  strokeWidth: 0,
44
- strokeDashArray: null,
45
- strokeLineCap: 'butt' as const,
46
- strokeDashOffset: 0,
47
- strokeLineJoin: 'miter' as const,
48
- strokeMiterLimit: 4,
49
- scaleX: 1,
50
- scaleY: 1,
51
- angle: 0,
52
- flipX: false,
53
- flipY: false,
54
- opacity: 1,
55
36
  src: IMG_SRC,
56
- shadow: null,
57
- visible: true,
58
- backgroundColor: '',
59
37
  filters: [],
60
- fillRule: 'nonzero' as const,
61
- paintFirst: 'fill' as const,
62
- globalCompositeOperation: 'source-over' as const,
63
- skewX: 0,
64
- skewY: 0,
65
38
  crossOrigin: null,
66
39
  cropX: 0,
67
40
  cropY: 0,
68
- strokeUniform: false,
69
- };
41
+ });
70
42
 
71
43
  describe('FabricImage', () => {
72
44
  describe('Svg export', () => {
@@ -88,7 +60,7 @@ describe('FabricImage', () => {
88
60
  offsetY: 14,
89
61
  }),
90
62
  });
91
- expect(img.toSVG()).toMatchSnapshot();
63
+ expect(img.toSVG()).toMatchSVGSnapshot();
92
64
  });
93
65
  });
94
66
 
@@ -108,7 +80,7 @@ describe('FabricImage', () => {
108
80
  200,
109
81
  200,
110
82
  img.getElement(),
111
- 'texture3',
83
+ expect.stringMatching(/^texture\d+$/),
112
84
  );
113
85
  } finally {
114
86
  mockApply.mockRestore();
@@ -1000,6 +972,18 @@ describe('FabricImage', () => {
1000
972
  expect(img.scaleY).toBe(5);
1001
973
  });
1002
974
  });
975
+
976
+ describe('attribute injection', () => {
977
+ it('source injection', () => {
978
+ const element = newImg('javascript:alert(1)');
979
+ const img = new FabricImage(element, {
980
+ width: 100,
981
+ height: 100,
982
+ });
983
+ const svg = img.toSVG();
984
+ expect(svg).toContain('xlink:href="javascript:alert(1)"'); // Should be escaped
985
+ });
986
+ });
1003
987
  });
1004
988
 
1005
989
  export function newImg(src = IMG_SRC): HTMLImageElement {
@@ -31,6 +31,7 @@ import type { CSSRules } from '../parser/typedefs';
31
31
  import type { Resize, ResizeSerializedProps } from '../filters/Resize';
32
32
  import type { TCachedFabricObject } from './Object/Object';
33
33
  import { log } from '../util/internals/console';
34
+ import { escapeXml } from '../util/lang_string';
34
35
 
35
36
  // @todo Would be nice to have filtering code not imported directly.
36
37
 
@@ -86,10 +87,10 @@ const IMAGE_PROPS = ['cropX', 'cropY'] as const;
86
87
  * @see {@link http://fabric5.fabricjs.com/fabric-intro-part-1#images}
87
88
  */
88
89
  export class FabricImage<
89
- Props extends TOptions<ImageProps> = Partial<ImageProps>,
90
- SProps extends SerializedImageProps = SerializedImageProps,
91
- EventSpec extends ObjectEvents = ObjectEvents,
92
- >
90
+ Props extends TOptions<ImageProps> = Partial<ImageProps>,
91
+ SProps extends SerializedImageProps = SerializedImageProps,
92
+ EventSpec extends ObjectEvents = ObjectEvents,
93
+ >
93
94
  extends FabricObject<Props, SProps, EventSpec>
94
95
  implements ImageProps
95
96
  {
@@ -389,9 +390,9 @@ export class FabricImage<
389
390
  '" y="' +
390
391
  y +
391
392
  '" width="' +
392
- this.width +
393
+ escapeXml(this.width) +
393
394
  '" height="' +
394
- this.height +
395
+ escapeXml(this.height) +
395
396
  '" />\n',
396
397
  '</clipPath>\n',
397
398
  );
@@ -403,7 +404,7 @@ export class FabricImage<
403
404
  imageMarkup.push(
404
405
  '\t<image ',
405
406
  'COMMON_PARTS',
406
- `xlink:href="${this.getSvgSrc(true)}" x="${x - this.cropX}" y="${
407
+ `xlink:href="${escapeXml(this.getSrc(true))}" x="${x - this.cropX}" y="${
407
408
  y - this.cropY
408
409
  // we're essentially moving origin of transformation from top/left corner to the center of the shape
409
410
  // by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
@@ -419,9 +420,9 @@ export class FabricImage<
419
420
  const origFill = this.fill;
420
421
  this.fill = null;
421
422
  strokeSvg = [
422
- `\t<rect x="${x}" y="${y}" width="${this.width}" height="${
423
- this.height
424
- }" style="${this.getSvgStyles()}" />\n`,
423
+ `\t<rect x="${x}" y="${y}" width="${escapeXml(this.width)}" height="${escapeXml(
424
+ this.height,
425
+ )}" style="${this.getSvgStyles()}" />\n`,
425
426
  ];
426
427
  this.fill = origFill;
427
428
  }
@@ -470,7 +471,10 @@ export class FabricImage<
470
471
  * @param {String} src Source string (URL)
471
472
  * @param {LoadImageOptions} [options] Options object
472
473
  */
473
- setSrc(src: string, { crossOrigin, signal }: LoadImageOptions = {}) {
474
+ setSrc(
475
+ src: string,
476
+ { crossOrigin, signal }: LoadImageOptions = {},
477
+ ): Promise<void> {
474
478
  return loadImage(src, { crossOrigin, signal }).then((img) => {
475
479
  typeof crossOrigin !== 'undefined' && this.set({ crossOrigin });
476
480
  this.setElement(img);
@@ -1,46 +1,20 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { Line } from './Line';
3
- import { getFabricDocument, version } from '../../fabric';
3
+ import { getFabricDocument } from '../../fabric';
4
4
  import { FabricObject } from './Object/Object';
5
+ import { createReferenceObject } from '../../test/utils';
5
6
 
6
7
  describe('Line', () => {
7
- const LINE_OBJECT = {
8
- version: version,
9
- type: 'Line',
10
- originX: 'center',
11
- originY: 'center',
8
+ const LINE_OBJECT = createReferenceObject('Line', {
12
9
  left: 12,
13
10
  top: 13,
14
11
  width: 2,
15
12
  height: 2,
16
- fill: 'rgb(0,0,0)',
17
- stroke: null,
18
- strokeWidth: 1,
19
- strokeDashArray: null,
20
- strokeLineCap: 'butt',
21
- strokeDashOffset: 0,
22
- strokeLineJoin: 'miter',
23
- strokeMiterLimit: 4,
24
- scaleX: 1,
25
- scaleY: 1,
26
- angle: 0,
27
- flipX: false,
28
- flipY: false,
29
- opacity: 1,
30
13
  x1: -1,
31
14
  y1: -1,
32
15
  x2: 1,
33
16
  y2: 1,
34
- shadow: null,
35
- visible: true,
36
- backgroundColor: '',
37
- fillRule: 'nonzero',
38
- paintFirst: 'fill',
39
- globalCompositeOperation: 'source-over',
40
- skewX: 0,
41
- skewY: 0,
42
- strokeUniform: false,
43
- } as const;
17
+ });
44
18
 
45
19
  it('initializes constructor correctly', () => {
46
20
  expect(Line).toBeTruthy();
@@ -23,8 +23,7 @@ interface UniqueLineProps {
23
23
  }
24
24
 
25
25
  export interface SerializedLineProps
26
- extends SerializedObjectProps,
27
- UniqueLineProps {}
26
+ extends SerializedObjectProps, UniqueLineProps {}
28
27
 
29
28
  /**
30
29
  * A Class to draw a line
@@ -34,10 +33,10 @@ export interface SerializedLineProps
34
33
  * @deprecated
35
34
  */
36
35
  export class Line<
37
- Props extends TOptions<FabricObjectProps> = Partial<FabricObjectProps>,
38
- SProps extends SerializedLineProps = SerializedLineProps,
39
- EventSpec extends ObjectEvents = ObjectEvents,
40
- >
36
+ Props extends TOptions<FabricObjectProps> = Partial<FabricObjectProps>,
37
+ SProps extends SerializedLineProps = SerializedLineProps,
38
+ EventSpec extends ObjectEvents = ObjectEvents,
39
+ >
41
40
  extends FabricObject<Props, SProps, EventSpec>
42
41
  implements UniqueLineProps
43
42
  {
@@ -200,18 +199,14 @@ export class Line<
200
199
  */
201
200
  calcLinePoints(): UniqueLineProps {
202
201
  const { x1: _x1, x2: _x2, y1: _y1, y2: _y2, width, height } = this;
203
- const xMult = _x1 <= _x2 ? -1 : 1,
204
- yMult = _y1 <= _y2 ? -1 : 1,
205
- x1 = (xMult * width) / 2,
206
- y1 = (yMult * height) / 2,
207
- x2 = (xMult * -width) / 2,
208
- y2 = (yMult * -height) / 2;
202
+ const xMult = _x1 <= _x2 ? -0.5 : 0.5,
203
+ yMult = _y1 <= _y2 ? -0.5 : 0.5;
209
204
 
210
205
  return {
211
- x1,
212
- x2,
213
- y1,
214
- y2,
206
+ x1: xMult * width,
207
+ x2: xMult * -width,
208
+ y1: yMult * height,
209
+ y2: yMult * -height,
215
210
  };
216
211
  }
217
212
 
@@ -5,6 +5,7 @@ import { FILL, NONE, STROKE } from '../../constants';
5
5
  import type { FabricObject } from './FabricObject';
6
6
  import { isFiller } from '../../util/typeAssertions';
7
7
  import { matrixToSVG } from '../../util/misc/svgExport';
8
+ import { escapeXml } from '../../util/lang_string';
8
9
 
9
10
  export class FabricObjectSVGExportMixin {
10
11
  /**
@@ -67,7 +68,9 @@ export class FabricObjectSVGExportMixin {
67
68
  ';',
68
69
  filter,
69
70
  visibility,
70
- ].join('');
71
+ ]
72
+ .map((v) => escapeXml(v))
73
+ .join('');
71
74
  }
72
75
 
73
76
  /**
@@ -75,7 +78,9 @@ export class FabricObjectSVGExportMixin {
75
78
  * @return {String}
76
79
  */
77
80
  getSvgFilter(this: FabricObjectSVGExportMixin & FabricObject) {
78
- return this.shadow ? `filter: url(#SVGID_${this.shadow.id});` : '';
81
+ return this.shadow
82
+ ? `filter: url(#SVGID_${escapeXml(this.shadow.id)});`
83
+ : '';
79
84
  }
80
85
 
81
86
  /**
@@ -86,7 +91,7 @@ export class FabricObjectSVGExportMixin {
86
91
  this: FabricObjectSVGExportMixin & FabricObject & { id?: string },
87
92
  ) {
88
93
  return [
89
- this.id ? `id="${this.id}" ` : '',
94
+ this.id ? `id="${escapeXml(String(this.id))}" ` : '',
90
95
  this.clipPath
91
96
  ? `clip-path="url(#${
92
97
  (this.clipPath as FabricObjectSVGExportMixin & FabricObject)
@@ -248,6 +253,8 @@ export class FabricObjectSVGExportMixin {
248
253
  }
249
254
 
250
255
  addPaintOrder(this: FabricObjectSVGExportMixin & FabricObject) {
251
- return this.paintFirst !== FILL ? ` paint-order="${this.paintFirst}" ` : '';
256
+ return this.paintFirst !== FILL
257
+ ? ` paint-order="${escapeXml(this.paintFirst)}" `
258
+ : '';
252
259
  }
253
260
  }
@@ -41,10 +41,10 @@ export type TStyleOverride = ControlRenderingStyleOverride &
41
41
  >;
42
42
 
43
43
  export class InteractiveFabricObject<
44
- Props extends TFabricObjectProps = Partial<FabricObjectProps>,
45
- SProps extends SerializedObjectProps = SerializedObjectProps,
46
- EventSpec extends ObjectEvents = ObjectEvents,
47
- >
44
+ Props extends TFabricObjectProps = Partial<FabricObjectProps>,
45
+ SProps extends SerializedObjectProps = SerializedObjectProps,
46
+ EventSpec extends ObjectEvents = ObjectEvents,
47
+ >
48
48
  extends FabricObject<Props, SProps, EventSpec>
49
49
  implements FabricObjectProps
50
50
  {
@@ -176,11 +176,11 @@ export type DrawContext =
176
176
  * @fires drop
177
177
  */
178
178
  export class FabricObject<
179
- Props extends TOptions<ObjectProps> = Partial<ObjectProps>,
180
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
181
- SProps extends SerializedObjectProps = SerializedObjectProps,
182
- EventSpec extends ObjectEvents = ObjectEvents,
183
- >
179
+ Props extends TOptions<ObjectProps> = Partial<ObjectProps>,
180
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
181
+ SProps extends SerializedObjectProps = SerializedObjectProps,
182
+ EventSpec extends ObjectEvents = ObjectEvents,
183
+ >
184
184
  extends ObjectGeometry<EventSpec>
185
185
  implements ObjectProps
186
186
  {
@@ -834,6 +834,7 @@ export class FabricObject<
834
834
  } else {
835
835
  this._renderBackground(ctx);
836
836
  }
837
+ this.fire('before:render', { ctx });
837
838
  this._render(ctx);
838
839
  this._drawClipPath(ctx, this.clipPath, context);
839
840
  this.fill = originalFill;
@@ -692,6 +692,21 @@ describe('fabric.ObjectGeometry', () => {
692
692
  ]);
693
693
  });
694
694
 
695
+ it('calcOwnMatrix is cached', () => {
696
+ const cObj = new FabricObject({
697
+ width: 10,
698
+ height: 15,
699
+ strokeWidth: 0,
700
+ originX: LEFT,
701
+ originY: TOP,
702
+ });
703
+ cObj.scaleX = 2;
704
+ cObj.scaleY = 3;
705
+ const expectedMatrix = cObj.calcOwnMatrix();
706
+ expect(expectedMatrix).toEqual([2, 0, 0, 3, 10, 22.5]);
707
+ expect(cObj.calcOwnMatrix()).toBe(expectedMatrix);
708
+ });
709
+
695
710
  it('scaleToWidth', () => {
696
711
  const cObj = new FabricObject({ width: 560, strokeWidth: 0 });
697
712
  expect(cObj.scaleToWidth).toBeTypeOf('function');
@@ -513,7 +513,7 @@ export class ObjectGeometry<EventSpec extends ObjectEvents = ObjectEvents>
513
513
  calcOwnMatrix(): TMat2D {
514
514
  const key = this.transformMatrixKey(true),
515
515
  cache = this.ownMatrixCache;
516
- if (cache && cache.key === key) {
516
+ if (cache && cache.key.every((x, i) => x === key[i])) {
517
517
  return cache.value;
518
518
  }
519
519
  const center = this.getRelativeCenterPoint(),