mirror of
https://github.com/penpot/penpot.git
synced 2026-07-20 21:17:44 +00:00
🐛 Fix crash with degenerate selrect in text pipeline (#10618)
Guard remaining text pipeline locations that accessed :selrect directly against nil/zero-dimension selrects by using safe-size-rect, which provides a 4-level fallback chain (selrect -> points -> shape fields -> empty 0.01x0.01 rect). Fixes: - fix-position in viewport_texts_html.cljs: replaced dm/get-prop :selrect with ctm/safe-size-rect for both old and new shape - assoc-position-data in modifiers.cljs: replaced (:selrect ...) with ctm/safe-size-rect for delta computation - change-orientation-modifiers in modifiers.cljc: replaced raw :selrect access with safe-size-rect for scale and origin computation Closes #10617 AI-assisted-by: mimo-v2.5-pro
This commit is contained in:
parent
47a3158602
commit
28fd798c52
@ -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))
|
||||
|
||||
|
||||
@ -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)))))
|
||||
|
||||
@ -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))]
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user