瀏覽代碼

fix: division by zero in findFocusPointForEllipse leads to infinite loop in wrapText freezing Excalidraw (#6377)

* Update collision.ts

* Update textElement.ts

* Update textElement.ts

* tweak

* fix

* remove unnecessary `Math.sign`

* change check and add doc

* Add a case for negative max width and specs

* fix

---------

Co-authored-by: dwelle <luzar.david@gmail.com>
Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
zsviczian 2 年之前
父節點
當前提交
5c8941467d
共有 3 個文件被更改,包括 20 次插入1 次删除
  1. 6 1
      src/element/collision.ts
  2. 7 0
      src/element/textElement.test.ts
  3. 7 0
      src/element/textElement.ts

+ 6 - 1
src/element/collision.ts

@@ -786,7 +786,12 @@ export const findFocusPointForEllipse = (
       orientation * py * Math.sqrt(Math.max(0, squares - a ** 2 * b ** 2))) /
     squares;
 
-  const n = (-m * px - 1) / py;
+  let n = (-m * px - 1) / py;
+
+  if (n === 0) {
+    // if zero {-0, 0}, fall back to a same-sign value in the similar range
+    n = (Object.is(n, -0) ? -1 : 1) * 0.01;
+  }
 
   const x = -(a ** 2 * m) / (n ** 2 * b ** 2 + m ** 2 * a ** 2);
   return GA.point(x, (-m * x - 1) / n);

+ 7 - 0
src/element/textElement.test.ts

@@ -184,6 +184,13 @@ break it now`,
     expect(res).toEqual(`Hello 
 Excalidraw`);
   });
+
+  it("should return the text as is if max width is invalid", () => {
+    const text = "Hello Excalidraw";
+    expect(wrapText(text, font, NaN)).toEqual(text);
+    expect(wrapText(text, font, -1)).toEqual(text);
+    expect(wrapText(text, font, Infinity)).toEqual(text);
+  });
 });
 
 describe("Test measureText", () => {

+ 7 - 0
src/element/textElement.ts

@@ -324,6 +324,13 @@ export const getTextHeight = (text: string, font: FontString) => {
 };
 
 export const wrapText = (text: string, font: FontString, maxWidth: number) => {
+  // if maxWidth is not finite or NaN which can happen in case of bugs in
+  // computation, we need to make sure we don't continue as we'll end up
+  // in an infinite loop
+  if (!Number.isFinite(maxWidth) || maxWidth < 0) {
+    return text;
+  }
+
   const lines: Array<string> = [];
   const originalLines = text.split("\n");
   const spaceWidth = getLineWidth(" ", font);