diff --git a/common/src/app/common/types/modifiers.cljc b/common/src/app/common/types/modifiers.cljc index dbc0b52296..34a81365f1 100644 --- a/common/src/app/common/types/modifiers.cljc +++ b/common/src/app/common/types/modifiers.cljc @@ -500,9 +500,9 @@ shape-transform (:transform shape) shape-transform-inv (:transform-inverse shape) shape-center (gco/shape->center shape) - {sr-width :width sr-height :height} (:selrect shape) + {sr-width :width sr-height :height} (safe-size-rect shape) - origin (cond-> (gpt/point (:selrect shape)) + origin (cond-> (gpt/point (safe-size-rect shape)) (some? shape-transform) (gmt/transform-point-center shape-center shape-transform)) diff --git a/common/test/common_tests/types/modifiers_test.cljc b/common/test/common_tests/types/modifiers_test.cljc index 2cfb196fa8..405da89935 100644 --- a/common/test/common_tests/types/modifiers_test.cljc +++ b/common/test/common_tests/types/modifiers_test.cljc @@ -657,3 +657,35 @@ mods (ctm/rotation (ctm/empty) (gpt/point 50 25) 45) result (ctm/apply-structure-modifiers shape mods)] (t/is (mth/close? 45.0 (:rotation result)))))) + +;; ─── change-orientation-modifiers — degenerate selrect ──────────────────────── + +(defn- make-degenerate-shape + "Build a shape whose selrect has zero width/height, simulating a shape + decoded from the server via map->Rect (bypasses make-rect's 0.01 floor)." + [x y selrect-width selrect-height] + (let [shape (make-shape x y 100 50)] + (assoc shape :selrect (grc/map->Rect {:x x :y y + :width selrect-width + :height selrect-height + :x1 x :y1 y + :x2 (+ x selrect-width) + :y2 (+ y selrect-height)})))) + +(t/deftest change-orientation-zero-width-selrect-does-not-throw + (t/testing "orientation change on a shape with zero selrect width does not throw" + (let [shape (make-degenerate-shape 0 0 0 50) + mods (ctm/change-orientation-modifiers shape :horiz)] + (t/is (some? mods))))) + +(t/deftest change-orientation-zero-height-selrect-does-not-throw + (t/testing "orientation change on a shape with zero selrect height does not throw" + (let [shape (make-degenerate-shape 0 0 100 0) + mods (ctm/change-orientation-modifiers shape :vert)] + (t/is (some? mods))))) + +(t/deftest change-orientation-zero-width-and-height-selrect-does-not-throw + (t/testing "orientation change on a fully degenerate selrect does not throw" + (let [shape (make-degenerate-shape 0 0 0 0) + mods (ctm/change-orientation-modifiers shape :horiz)] + (t/is (some? mods))))) diff --git a/frontend/src/app/main/data/workspace/modifiers.cljs b/frontend/src/app/main/data/workspace/modifiers.cljs index 96a1605704..b5696414c8 100644 --- a/frontend/src/app/main/data/workspace/modifiers.cljs +++ b/frontend/src/app/main/data/workspace/modifiers.cljs @@ -256,8 +256,8 @@ (defn assoc-position-data [shape position-data old-shape] - (let [deltav (gpt/to-vec (gpt/point (:selrect old-shape)) - (gpt/point (:selrect shape))) + (let [deltav (gpt/to-vec (gpt/point (ctm/safe-size-rect old-shape)) + (gpt/point (ctm/safe-size-rect shape))) position-data (-> position-data (gsh/move-position-data deltav))] diff --git a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs index a22b82f46a..ae6f49f688 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/viewport_texts_html.cljs @@ -35,8 +35,8 @@ (if-let [modifiers (:modifiers shape)] (let [shape' (gsh/transform-shape shape modifiers) - old-sr (dm/get-prop shape :selrect) - new-sr (dm/get-prop shape' :selrect) + old-sr (ctm/safe-size-rect shape) + new-sr (ctm/safe-size-rect shape') ;; We need to remove the movement because the dynamic modifiers will have move it deltav (gpt/to-vec (gpt/point new-sr) diff --git a/frontend/test/frontend_tests/data/workspace_texts_test.cljs b/frontend/test/frontend_tests/data/workspace_texts_test.cljs index 15db703ef8..ee438672c5 100644 --- a/frontend/test/frontend_tests/data/workspace_texts_test.cljs +++ b/frontend/test/frontend_tests/data/workspace_texts_test.cljs @@ -9,9 +9,11 @@ [app.common.geom.rect :as grc] [app.common.test-helpers.files :as cthf] [app.common.test-helpers.shapes :as cths] + [app.common.types.modifiers :as ctm] [app.common.types.shape :as cts] [app.common.types.text :as txt] [app.main.data.workspace.texts :as dwt] + [app.main.ui.workspace.shapes.text.viewport-texts-html :as vth] [cljs.test :as t :include-macros true] [frontend-tests.helpers.state :as ths])) @@ -374,3 +376,34 @@ "exactly one typography was added") (t/is (= "0.1" (:letter-spacing (first typographies))) "float letter-spacing is normalised to 2-decimal string"))))))) + +;; --------------------------------------------------------------------------- +;; Tests: fix-position with degenerate selrect +;; --------------------------------------------------------------------------- + +(t/deftest fix-position-zero-width-selrect-does-not-throw + (t/testing "fix-position on a shape with zero selrect width does not throw" + (let [shape (make-degenerate-text-shape :x 0 :y 0 :width 0 :height 50) + modifiers (ctm/change-dimensions-modifiers shape :width 200 {:ignore-lock? true}) + shape' (assoc shape :modifiers modifiers) + result (vth/fix-position shape')] + (t/is (some? result)) + (t/is (some? (:selrect result)))))) + +(t/deftest fix-position-zero-height-selrect-does-not-throw + (t/testing "fix-position on a shape with zero selrect height does not throw" + (let [shape (make-degenerate-text-shape :x 0 :y 0 :width 100 :height 0) + modifiers (ctm/change-dimensions-modifiers shape :height 80 {:ignore-lock? true}) + shape' (assoc shape :modifiers modifiers) + result (vth/fix-position shape')] + (t/is (some? result)) + (t/is (some? (:selrect result)))))) + +(t/deftest fix-position-zero-width-and-height-selrect-does-not-throw + (t/testing "fix-position on a fully degenerate selrect does not throw" + (let [shape (make-degenerate-text-shape :x 0 :y 0 :width 0 :height 0) + modifiers (ctm/change-dimensions-modifiers shape :width 150 {:ignore-lock? true}) + shape' (assoc shape :modifiers modifiers) + result (vth/fix-position shape')] + (t/is (some? result)) + (t/is (some? (:selrect result))))))