fabric 6.4.0 → 6.4.2

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 (85) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/index.js +123 -95
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.min.js +1 -1
  5. package/dist/index.min.js.map +1 -1
  6. package/dist/index.min.mjs +1 -1
  7. package/dist/index.min.mjs.map +1 -1
  8. package/dist/index.mjs +123 -95
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/index.node.cjs +123 -95
  11. package/dist/index.node.cjs.map +1 -1
  12. package/dist/index.node.mjs +123 -95
  13. package/dist/index.node.mjs.map +1 -1
  14. package/dist/package.json.min.mjs +1 -1
  15. package/dist/package.json.mjs +1 -1
  16. package/dist/src/canvas/DOMManagers/CanvasDOMManager.min.mjs +1 -1
  17. package/dist/src/canvas/DOMManagers/CanvasDOMManager.min.mjs.map +1 -1
  18. package/dist/src/canvas/DOMManagers/CanvasDOMManager.mjs +0 -1
  19. package/dist/src/canvas/DOMManagers/CanvasDOMManager.mjs.map +1 -1
  20. package/dist/src/canvas/SelectableCanvas.min.mjs +1 -1
  21. package/dist/src/canvas/SelectableCanvas.min.mjs.map +1 -1
  22. package/dist/src/canvas/SelectableCanvas.mjs +0 -1
  23. package/dist/src/canvas/SelectableCanvas.mjs.map +1 -1
  24. package/dist/src/config.d.ts +5 -1
  25. package/dist/src/config.d.ts.map +1 -1
  26. package/dist/src/config.min.mjs +1 -1
  27. package/dist/src/config.min.mjs.map +1 -1
  28. package/dist/src/config.mjs +6 -2
  29. package/dist/src/config.mjs.map +1 -1
  30. package/dist/src/parser/constants.d.ts +0 -1
  31. package/dist/src/parser/constants.d.ts.map +1 -1
  32. package/dist/src/parser/constants.min.mjs +1 -1
  33. package/dist/src/parser/constants.min.mjs.map +1 -1
  34. package/dist/src/parser/constants.mjs +1 -2
  35. package/dist/src/parser/constants.mjs.map +1 -1
  36. package/dist/src/shapes/Line.min.mjs +1 -1
  37. package/dist/src/shapes/Line.min.mjs.map +1 -1
  38. package/dist/src/shapes/Line.mjs +0 -1
  39. package/dist/src/shapes/Line.mjs.map +1 -1
  40. package/dist/src/shapes/Path.min.mjs +1 -1
  41. package/dist/src/shapes/Path.min.mjs.map +1 -1
  42. package/dist/src/shapes/Path.mjs +7 -1
  43. package/dist/src/shapes/Path.mjs.map +1 -1
  44. package/dist/src/shapes/Text/StyledText.min.mjs +1 -1
  45. package/dist/src/shapes/Text/StyledText.min.mjs.map +1 -1
  46. package/dist/src/shapes/Text/StyledText.mjs +0 -1
  47. package/dist/src/shapes/Text/StyledText.mjs.map +1 -1
  48. package/dist/src/util/misc/boundingBoxFromPoints.d.ts.map +1 -1
  49. package/dist/src/util/misc/boundingBoxFromPoints.min.mjs +1 -1
  50. package/dist/src/util/misc/boundingBoxFromPoints.min.mjs.map +1 -1
  51. package/dist/src/util/misc/boundingBoxFromPoints.mjs +17 -30
  52. package/dist/src/util/misc/boundingBoxFromPoints.mjs.map +1 -1
  53. package/dist/src/util/path/index.d.ts.map +1 -1
  54. package/dist/src/util/path/index.min.mjs +1 -1
  55. package/dist/src/util/path/index.min.mjs.map +1 -1
  56. package/dist/src/util/path/index.mjs +51 -47
  57. package/dist/src/util/path/index.mjs.map +1 -1
  58. package/dist/src/util/path/regex.d.ts +2 -1
  59. package/dist/src/util/path/regex.d.ts.map +1 -1
  60. package/dist/src/util/path/regex.min.mjs +1 -1
  61. package/dist/src/util/path/regex.min.mjs.map +1 -1
  62. package/dist/src/util/path/regex.mjs +41 -16
  63. package/dist/src/util/path/regex.mjs.map +1 -1
  64. package/dist/src/util/path/typedefs.d.ts +1 -0
  65. package/dist/src/util/path/typedefs.d.ts.map +1 -1
  66. package/dist-extensions/src/config.d.ts +5 -1
  67. package/dist-extensions/src/config.d.ts.map +1 -1
  68. package/dist-extensions/src/parser/constants.d.ts +0 -1
  69. package/dist-extensions/src/parser/constants.d.ts.map +1 -1
  70. package/dist-extensions/src/util/misc/boundingBoxFromPoints.d.ts.map +1 -1
  71. package/dist-extensions/src/util/path/index.d.ts.map +1 -1
  72. package/dist-extensions/src/util/path/regex.d.ts +2 -1
  73. package/dist-extensions/src/util/path/regex.d.ts.map +1 -1
  74. package/dist-extensions/src/util/path/typedefs.d.ts +1 -0
  75. package/dist-extensions/src/util/path/typedefs.d.ts.map +1 -1
  76. package/package.json +2 -2
  77. package/src/config.ts +6 -2
  78. package/src/parser/constants.ts +0 -2
  79. package/src/shapes/Path.ts +1 -1
  80. package/src/util/misc/boundingBoxFromPoints.ts +15 -24
  81. package/src/util/path/__snapshots__/index.spec.ts.snap +462 -0
  82. package/src/util/path/index.spec.ts +107 -1
  83. package/src/util/path/index.ts +56 -51
  84. package/src/util/path/regex.ts +29 -22
  85. package/src/util/path/typedefs.ts +22 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [next]
4
4
 
5
+ ## [6.4.2]
6
+
7
+ - Fix(): path parsing performance [#10123](https://github.com/fabricjs/fabric.js/pull/10123)
8
+
9
+ ## [6.4.1]
10
+
11
+ - fix(): Package.json had wrong path to types for extensions [#10115](https://github.com/fabricjs/fabric.js/pull/10115)
12
+
5
13
  ## [6.4.0]
6
14
 
7
15
  - fix(): Fix broken exports for filters that do not have a static defaults value. [#10102](https://github.com/fabricjs/fabric.js/pull/10102)
package/dist/index.js CHANGED
@@ -162,9 +162,13 @@
162
162
  _defineProperty(this, "forceGLPutImageData", false);
163
163
  /**
164
164
  * If disabled boundsOfCurveCache is not used. For apps that make heavy usage of pencil drawing probably disabling it is better
165
- * @default true
165
+ * With the standard behaviour of fabric to translate all curves in absolute commands and by not subtracting the starting point from
166
+ * the curve is very hard to hit any cache.
167
+ * Enable only if you know why it could be useful.
168
+ * Candidate for removal/simplification
169
+ * @default false
166
170
  */
167
- _defineProperty(this, "cachesBoundsOfCurve", true);
171
+ _defineProperty(this, "cachesBoundsOfCurve", false);
168
172
  /**
169
173
  * Map of font files
170
174
  * Map<fontFamily, pathToFile> of font files
@@ -407,7 +411,7 @@
407
411
  }
408
412
  const cache = new Cache();
409
413
 
410
- var version = "6.4.0";
414
+ var version = "6.4.2";
411
415
 
412
416
  // use this syntax so babel plugin see this import here
413
417
  const VERSION = version;
@@ -4291,36 +4295,25 @@
4291
4295
  * @return {Object} Object with left, top, width, height properties
4292
4296
  */
4293
4297
  const makeBoundingBoxFromPoints = points => {
4294
- if (points.length === 0) {
4295
- return {
4296
- left: 0,
4297
- top: 0,
4298
- width: 0,
4299
- height: 0
4300
- };
4298
+ let left = 0,
4299
+ top = 0,
4300
+ width = 0,
4301
+ height = 0;
4302
+ for (let i = 0, len = points.length; i < len; i++) {
4303
+ const {
4304
+ x,
4305
+ y
4306
+ } = points[i];
4307
+ if (x > width || !i) width = x;
4308
+ if (x < left || !i) left = x;
4309
+ if (y > height || !i) height = y;
4310
+ if (y < top || !i) top = y;
4301
4311
  }
4302
- const {
4303
- min,
4304
- max
4305
- } = points.reduce((_ref, curr) => {
4306
- let {
4307
- min,
4308
- max
4309
- } = _ref;
4310
- return {
4311
- min: min.min(curr),
4312
- max: max.max(curr)
4313
- };
4314
- }, {
4315
- min: new Point(points[0]),
4316
- max: new Point(points[0])
4317
- });
4318
- const size = max.subtract(min);
4319
4312
  return {
4320
- left: min.x,
4321
- top: min.y,
4322
- width: size.x,
4323
- height: size.y
4313
+ left,
4314
+ top,
4315
+ width: width - left,
4316
+ height: height - top
4324
4317
  };
4325
4318
  };
4326
4319
 
@@ -4819,10 +4812,9 @@
4819
4812
  return new RegExp('^(' + arr.join('|') + ')\\b', 'i');
4820
4813
  }
4821
4814
 
4822
- var _templateObject$2, _templateObject2$1;
4823
- const reNum = String.raw(_templateObject$2 || (_templateObject$2 = _taggedTemplateLiteral(["(?:[-+]?(?:d*.d+|d+.?)(?:[eE][-+]?d+)?)"], ["(?:[-+]?(?:\\d*\\.\\d+|\\d+\\.?)(?:[eE][-+]?\\d+)?)"])));
4815
+ var _templateObject$1;
4816
+ const reNum = String.raw(_templateObject$1 || (_templateObject$1 = _taggedTemplateLiteral(["(?:[-+]?(?:d*.d+|d+.?)(?:[eE][-+]?d+)?)"], ["(?:[-+]?(?:\\d*\\.\\d+|\\d+\\.?)(?:[eE][-+]?\\d+)?)"])));
4824
4817
  const svgNS = 'http://www.w3.org/2000/svg';
4825
- String.raw(_templateObject2$1 || (_templateObject2$1 = _taggedTemplateLiteral(["(?:s+,?s*|,s*|$)"], ["(?:\\s+,?\\s*|,\\s*|$)"])));
4826
4818
  const reFontDeclaration = new RegExp('(normal|italic)?\\s*(normal|small-caps)?\\s*' + '(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\s*(' + reNum + '(?:px|cm|mm|em|pt|pc|in)*)(?:\\/(normal|' + reNum + '))?\\s+(.*)');
4827
4819
  const svgValidTagNames = ['path', 'circle', 'polygon', 'polyline', 'ellipse', 'rect', 'line', 'image', 'text'],
4828
4820
  svgViewBoxElements = ['symbol', 'image', 'marker', 'pattern', 'view', 'svg'],
@@ -10488,11 +10480,11 @@
10488
10480
  // replace annoying commas and arbitrary whitespace with single spaces
10489
10481
  .replace(/,/gi, ' ').replace(/\s+/gi, ' ');
10490
10482
 
10491
- var _templateObject$1, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7;
10483
+ var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7;
10492
10484
 
10493
10485
  // == begin transform regexp
10494
10486
  const p$1 = "(".concat(reNum, ")");
10495
- const skewX = String.raw(_templateObject$1 || (_templateObject$1 = _taggedTemplateLiteral(["(skewX)(", ")"], ["(skewX)\\(", "\\)"])), p$1);
10487
+ const skewX = String.raw(_templateObject || (_templateObject = _taggedTemplateLiteral(["(skewX)(", ")"], ["(skewX)\\(", "\\)"])), p$1);
10496
10488
  const skewY = String.raw(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["(skewY)(", ")"], ["(skewY)\\(", "\\)"])), p$1);
10497
10489
  const rotate = String.raw(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["(rotate)(", "(?: ", " ", ")?)"], ["(rotate)\\(", "(?: ", " ", ")?\\)"])), p$1, p$1, p$1);
10498
10490
  const scale = String.raw(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["(scale)(", "(?: ", ")?)"], ["(scale)\\(", "(?: ", ")?\\)"])), p$1, p$1);
@@ -11945,24 +11937,50 @@
11945
11937
  */
11946
11938
  const findScaleToCover = (source, destination) => Math.max(destination.width / source.width, destination.height / source.height);
11947
11939
 
11948
- var _templateObject;
11940
+ const commaWsp = "\\s*,?\\s*";
11949
11941
 
11950
11942
  /**
11951
11943
  * p for param
11952
11944
  * using "bad naming" here because it makes the regex much easier to read
11945
+ * p is a number that is preceded by an arbitary number of spaces, maybe 0,
11946
+ * a comma or not, and then possibly more spaces or not.
11953
11947
  */
11954
- const p = "(".concat(reNum, ")");
11955
- const reMoveToCommand = "(M) (?:".concat(p, " ").concat(p, " ?)+");
11956
- const reLineCommand = "(L) (?:".concat(p, " ").concat(p, " ?)+");
11957
- const reHorizontalLineCommand = "(H) (?:".concat(p, " ?)+");
11958
- const reVerticalLineCommand = "(V) (?:".concat(p, " ?)+");
11959
- const reClosePathCommand = String.raw(_templateObject || (_templateObject = _taggedTemplateLiteral(["(Z)s*"], ["(Z)\\s*"])));
11960
- const reCubicCurveCommand = "(C) (?:".concat(p, " ").concat(p, " ").concat(p, " ").concat(p, " ").concat(p, " ").concat(p, " ?)+");
11961
- const reCubicCurveShortcutCommand = "(S) (?:".concat(p, " ").concat(p, " ").concat(p, " ").concat(p, " ?)+");
11962
- const reQuadraticCurveCommand = "(Q) (?:".concat(p, " ").concat(p, " ").concat(p, " ").concat(p, " ?)+");
11963
- const reQuadraticCurveShortcutCommand = "(T) (?:".concat(p, " ").concat(p, " ?)+");
11964
- const reArcCommand = "(A) (?:".concat(p, " ").concat(p, " ").concat(p, " ([01]) ?([01]) ").concat(p, " ").concat(p, " ?)+");
11965
- const rePathCommand = "(?:(?:".concat(reMoveToCommand, ")") + "|(?:".concat(reLineCommand, ")") + "|(?:".concat(reHorizontalLineCommand, ")") + "|(?:".concat(reVerticalLineCommand, ")") + "|(?:".concat(reClosePathCommand, ")") + "|(?:".concat(reCubicCurveCommand, ")") + "|(?:".concat(reCubicCurveShortcutCommand, ")") + "|(?:".concat(reQuadraticCurveCommand, ")") + "|(?:".concat(reQuadraticCurveShortcutCommand, ")") + "|(?:".concat(reArcCommand, "))");
11948
+ const p = "".concat(commaWsp, "(").concat(reNum, ")");
11949
+
11950
+ // const reMoveToCommand = `(M) ?(?:${p}${p} ?)+`;
11951
+
11952
+ // const reLineCommand = `(L) ?(?:${p}${p} ?)+`;
11953
+
11954
+ // const reHorizontalLineCommand = `(H) ?(?:${p} ?)+`;
11955
+
11956
+ // const reVerticalLineCommand = `(V) ?(?:${p} ?)+`;
11957
+
11958
+ // const reClosePathCommand = String.raw`(Z)\s*`;
11959
+
11960
+ // const reCubicCurveCommand = `(C) ?(?:${p}${p}${p}${p}${p}${p} ?)+`;
11961
+
11962
+ // const reCubicCurveShortcutCommand = `(S) ?(?:${p}${p}${p}${p} ?)+`;
11963
+
11964
+ // const reQuadraticCurveCommand = `(Q) ?(?:${p}${p}${p}${p} ?)+`;
11965
+
11966
+ // const reQuadraticCurveShortcutCommand = `(T) ?(?:${p}${p} ?)+`;
11967
+
11968
+ const reArcCommandPoints = "".concat(p).concat(p).concat(p).concat(commaWsp, "([01])").concat(commaWsp, "([01])").concat(p).concat(p);
11969
+ // const reArcCommand = `(A) ?(?:${reArcCommandPoints} ?)+`;
11970
+
11971
+ // export const rePathCommandGroups =
11972
+ // `(?:(?:${reMoveToCommand})` +
11973
+ // `|(?:${reLineCommand})` +
11974
+ // `|(?:${reHorizontalLineCommand})` +
11975
+ // `|(?:${reVerticalLineCommand})` +
11976
+ // `|(?:${reClosePathCommand})` +
11977
+ // `|(?:${reCubicCurveCommand})` +
11978
+ // `|(?:${reCubicCurveShortcutCommand})` +
11979
+ // `|(?:${reQuadraticCurveCommand})` +
11980
+ // `|(?:${reQuadraticCurveShortcutCommand})` +
11981
+ // `|(?:${reArcCommand}))`;
11982
+
11983
+ const rePathCommand = '[mzlhvcsqta][^mzlhvcsqta]*';
11966
11984
 
11967
11985
  /**
11968
11986
  * Commands that may be repeated
@@ -12592,8 +12610,19 @@
12592
12610
  }
12593
12611
  };
12594
12612
  const rePathCmdAll = new RegExp(rePathCommand, 'gi');
12595
- const rePathCmd = new RegExp(rePathCommand, 'i');
12596
-
12613
+ const regExpArcCommandPoints = new RegExp(reArcCommandPoints, 'g');
12614
+ const reMyNum = new RegExp(reNum, 'gi');
12615
+ const commandLengths = {
12616
+ m: 2,
12617
+ l: 2,
12618
+ h: 1,
12619
+ v: 1,
12620
+ c: 6,
12621
+ s: 4,
12622
+ q: 4,
12623
+ t: 2,
12624
+ a: 7
12625
+ };
12597
12626
  /**
12598
12627
  *
12599
12628
  * @param {string} pathString
@@ -12606,52 +12635,45 @@
12606
12635
  * ];
12607
12636
  */
12608
12637
  const parsePath = pathString => {
12609
- // clean the string
12610
- // add spaces around the numbers
12611
- pathString = cleanupSvgAttribute(pathString);
12612
- const res = [];
12613
- for (let [matchStr] of pathString.matchAll(rePathCmdAll)) {
12614
- const chain = [];
12615
- let paramArr;
12616
- do {
12617
- paramArr = rePathCmd.exec(matchStr);
12618
- if (!paramArr) {
12619
- break;
12620
- }
12621
- // ignore undefined match groups
12622
- const filteredGroups = paramArr.filter(g => g);
12623
- // remove the first element from the match array since it's just the whole command
12624
- filteredGroups.shift();
12625
- // if we can't parse the number, just interpret it as a string
12626
- // (since it's probably the path command)
12627
- const command = filteredGroups.map(g => {
12628
- const numParse = Number.parseFloat(g);
12629
- if (Number.isNaN(numParse)) {
12630
- return g;
12631
- } else {
12632
- return numParse;
12633
- }
12634
- });
12635
- chain.push(command);
12636
- // stop now if it's a z command
12637
- if (filteredGroups.length <= 1) {
12638
- break;
12638
+ var _pathString$match;
12639
+ const chain = [];
12640
+ const all = (_pathString$match = pathString.match(rePathCmdAll)) !== null && _pathString$match !== void 0 ? _pathString$match : [];
12641
+ for (const matchStr of all) {
12642
+ // take match string and save the first letter as the command
12643
+ const commandLetter = matchStr[0];
12644
+ // in case of Z we have very little to do
12645
+ if (commandLetter === 'z' || commandLetter === 'Z') {
12646
+ chain.push([commandLetter]);
12647
+ continue;
12648
+ }
12649
+ const commandLength = commandLengths[commandLetter.toLowerCase()];
12650
+ let paramArr = [];
12651
+ if (commandLetter === 'a' || commandLetter === 'A') {
12652
+ // the arc command ha some peculariaties that requires a special regex other than numbers
12653
+ // it is possible to avoid using a space between the sweep and large arc flags, making them either
12654
+ // 00, 01, 10 or 11, making them identical to a plain number for the regex reMyNum
12655
+ // reset the regexp
12656
+ regExpArcCommandPoints.lastIndex = 0;
12657
+ for (let out = null; out = regExpArcCommandPoints.exec(matchStr);) {
12658
+ paramArr.push(...out.slice(1));
12639
12659
  }
12640
- // remove the last part of the chained command
12641
- filteredGroups.shift();
12642
- // ` ?` is to support commands with optional spaces between flags
12643
- matchStr = matchStr.replace(new RegExp("".concat(filteredGroups.join(' ?'), " ?$")), '');
12644
- } while (paramArr);
12645
- // add the chain, convert multiple m's to l's in the process
12646
- chain.reverse().forEach((c, idx) => {
12647
- const transformed = repeatedCommands[c[0]];
12648
- if (idx > 0 && (transformed == 'l' || transformed == 'L')) {
12649
- c[0] = transformed;
12660
+ } else {
12661
+ paramArr = matchStr.match(reMyNum) || [];
12662
+ }
12663
+
12664
+ // inspect the length of paramArr, if is longer than commandLength
12665
+ // we are dealing with repeated commands
12666
+ for (let i = 0; i < paramArr.length; i += commandLength) {
12667
+ const newCommand = new Array(commandLength);
12668
+ const transformedCommand = repeatedCommands[commandLetter];
12669
+ newCommand[0] = i > 0 && transformedCommand ? transformedCommand : commandLetter;
12670
+ for (let j = 0; j < commandLength; j++) {
12671
+ newCommand[j + 1] = parseFloat(paramArr[i + j]);
12650
12672
  }
12651
- res.push(c);
12652
- });
12673
+ chain.push(newCommand);
12674
+ }
12653
12675
  }
12654
- return res;
12676
+ return chain;
12655
12677
  };
12656
12678
 
12657
12679
  /**
@@ -16575,7 +16597,13 @@
16575
16597
  // lineto, absolute
16576
16598
  x = command[1];
16577
16599
  y = command[2];
16578
- bounds.push(new Point(subpathStartX, subpathStartY), new Point(x, y));
16600
+ bounds.push({
16601
+ x: subpathStartX,
16602
+ y: subpathStartY
16603
+ }, {
16604
+ x,
16605
+ y
16606
+ });
16579
16607
  break;
16580
16608
  case 'M':
16581
16609
  // moveTo, absolute