0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-10 17:00:36 -05:00

Fix masks for Firefox

This commit is contained in:
alonso.torres 2022-02-18 13:50:54 +01:00
parent 96eacb6efe
commit d0e008665f
3 changed files with 64 additions and 29 deletions

View file

@ -17,11 +17,15 @@
:width width
:height height})
(defn position-data-bounding-box
(defn position-data-points
[{:keys [position-data] :as shape}]
(let [points (->> position-data
(mapcat (comp gpr/rect->points position-data->rect)))
transform (gtr/transform-matrix shape)
points (gco/transform-points points transform)]
(gpr/points->selrect points)))
transform (gtr/transform-matrix shape)]
(gco/transform-points points transform)))
(defn position-data-bounding-box
[shape]
(gpr/points->selrect (position-data-points shape)))

View file

@ -6,7 +6,9 @@
(ns app.main.ui.shapes.mask
(:require
[app.common.data :as d]
[app.common.geom.shapes :as gsh]
[app.common.geom.shapes.text :as gst]
[app.main.ui.context :as muc]
[cuerdas.core :as str]
[rumext.alpha :as mf]))
@ -29,6 +31,17 @@
(defn filter-url [render-id mask]
(str "url(#" (filter-id render-id mask) ")"))
(defn set-white-fill
[shape]
(let [update-color
(fn [data]
(-> data
(dissoc :fill-color :fill-opacity :fill-color-gradient)
(assoc :fill-color "#FFFFFF" :fill-opacity 1)))]
(-> shape
(d/update-when :position-data #(mapv update-color %))
(assoc :stroke-color "#FFFFFF" :stroke-opacity 1))))
(defn mask-factory
[shape-wrapper]
(mf/fnc mask-shape
@ -36,25 +49,44 @@
[props]
(let [mask (unchecked-get props "mask")
render-id (mf/use-ctx muc/render-ctx)
mask' (gsh/transform-shape mask)]
[:defs
[:filter {:id (filter-id render-id mask)}
[:feFlood {:flood-color "white"
:result "FloodResult"}]
[:feComposite {:in "FloodResult"
:in2 "SourceGraphic"
:operator "in"
:result "comp"}]]
;; Clip path is necessary so the elements inside the mask won't affect
;; the events outside. Clip hides the elements but mask doesn't (like display vs visibility)
;; we cannot use clips instead of mask because clips can only be simple shapes
[:clipPath {:class "mask-clip-path"
:id (clip-id render-id mask)}
[:polyline {:points (->> (:points mask')
(map #(str (:x %) "," (:y %)))
(str/join " "))}]]
[:mask {:class "mask-shape"
:id (mask-id render-id mask)}
[:g {:filter (filter-url render-id mask)}
[:& shape-wrapper {:shape (dissoc mask :shadow :blur)}]]]])))
svg-text? (and (= :text (:type mask)) (some? (:position-data mask)))
mask (cond-> mask svg-text? set-white-fill)
mask-bb
(cond
svg-text?
(gst/position-data-points mask)
:else
(-> (gsh/transform-shape mask)
(:points)))]
[:*
[:g {:opacity 0}
[:g {:id (str "shape-" (mask-id render-id mask))}
[:& shape-wrapper {:shape (dissoc mask :shadow :blur)}]]]
[:defs
[:filter {:id (filter-id render-id mask)}
[:feFlood {:flood-color "white"
:result "FloodResult"}]
[:feComposite {:in "FloodResult"
:in2 "SourceGraphic"
:operator "in"
:result "comp"}]]
;; Clip path is necessary so the elements inside the mask won't affect
;; the events outside. Clip hides the elements but mask doesn't (like display vs visibility)
;; we cannot use clips instead of mask because clips can only be simple shapes
[:clipPath {:class "mask-clip-path"
:id (clip-id render-id mask)}
[:polyline {:points (->> mask-bb
(map #(str (:x %) "," (:y %)))
(str/join " "))}]]
[:mask {:class "mask-shape"
:id (mask-id render-id mask)}
;; SVG texts are broken in Firefox with the filter. When the masking shapes is a text
;; we use the `set-white-fill` instead of using the filter
[:g {:filter (when-not svg-text? (filter-url render-id mask))}
[:use {:href (str "#shape-" (mask-id render-id mask))}]]]]])))

View file

@ -7,7 +7,6 @@
(ns app.main.ui.workspace.shapes.text
(:require
[app.common.attrs :as attrs]
[app.common.data :as d]
[app.common.geom.matrix :as gmt]
[app.common.geom.shapes :as gsh]
[app.common.logging :as log]
@ -123,7 +122,7 @@
(mf/defc text-wrapper
{::mf/wrap-props false}
[props]
(let [{:keys [id content points] :as shape} (unchecked-get props "shape")
(let [{:keys [id] :as shape} (unchecked-get props "shape")
edition-ref (mf/use-memo (mf/deps id) #(l/derived (fn [o] (= id (:edition o))) refs/workspace-local))
edition? (mf/deref edition-ref)
@ -150,7 +149,7 @@
(gsh/transform-rect mtx)))))]
(reset! local-position-data position-data))))
[shape-ref on-change-node] (use-mutable-observer handle-change-foreign-object)
[_ on-change-node] (use-mutable-observer handle-change-foreign-object)
show-svg-text? (or (some? (:position-data shape)) (some? @local-position-data))
@ -170,7 +169,7 @@
(fn []
;; Timer to update the shape. We do this so a lot of changes won't produce
;; a lot of updates (kind of a debounce)
(let [sid (timers/schedule 250 update-position-data)]
(let [sid (timers/schedule 100 update-position-data)]
(fn []
(rx/dispose! sid)))))