mirror of
https://github.com/penpot/penpot.git
synced 2026-10-03 01:06:14 +00:00
♻️ Move use-shape into app.common.render_wasm (#11917)
- Introduces a new ns since there wasn't a suitable one - Simplifies serialize-shapes-batch! and allows usage outside the frontend
This commit is contained in:
parent
494d60a671
commit
efbb554af1
28
common/src/app/common/render_wasm/api/select.cljs
Normal file
28
common/src/app/common/render_wasm/api/select.cljs
Normal file
@ -0,0 +1,28 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS SUBSIDIARY SL
|
||||
|
||||
(ns app.common.render-wasm.api.select
|
||||
"WASM cursor selection.
|
||||
Note that setters in `app.common.render-wasm.api.props` assume the caller
|
||||
selected first."
|
||||
(:require
|
||||
[app.common.render-wasm.helpers :as h]
|
||||
[app.common.render-wasm.wasm :as wasm]
|
||||
[app.common.uuid :as uuid]))
|
||||
|
||||
(defn use-shape
|
||||
"Makes the shape with `id` current in WASM so subsequent setters apply to it.
|
||||
This is a no-op when there is no WASM context."
|
||||
[id]
|
||||
;; Use `wasm/live?` (not `initialized?`) so context-restore reload can
|
||||
;; select shapes while `reloading?` still blocks external app callers.
|
||||
(when (wasm/live?)
|
||||
(let [buffer (uuid/get-u32 id)]
|
||||
(h/call wasm/internal-module "_use_shape"
|
||||
(aget buffer 0)
|
||||
(aget buffer 1)
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)))))
|
||||
@ -25,6 +25,7 @@
|
||||
dispatching per changed key through the same underlying `props` setters."
|
||||
(:require
|
||||
[app.common.render-wasm.api.props :as props]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.render-wasm.api.upload :as upload]
|
||||
[app.common.render-wasm.svg-derived :as svg-derived]))
|
||||
|
||||
@ -62,15 +63,15 @@
|
||||
"Structural batch upload plus per-shape svg-attrs/path tail.
|
||||
|
||||
Derives via svg-derived, uploads one `_set_shapes_batch` with `opts`,
|
||||
then selects each shape needing svg-attrs/path content and applies it.
|
||||
Host text/grid/image sequencing stays in callers. Returns the prepared
|
||||
vector for the downstream host-attrs loop."
|
||||
[shapes opts select-fn]
|
||||
then selects each shape needing svg-attrs/path content via `use-shape!`
|
||||
and applies the tail. Host text/grid/image sequencing stays in callers.
|
||||
Returns the prepared vector for the downstream host-attrs loop."
|
||||
[shapes opts]
|
||||
(let [prepared (mapv svg-derived/apply-svg-derived shapes)]
|
||||
(when (seq prepared)
|
||||
(upload/flush-shapes-batch! prepared opts)
|
||||
(doseq [shape prepared]
|
||||
(when (needs-shape-tail? shape)
|
||||
(select-fn (:id shape))
|
||||
(wselect/use-shape (:id shape))
|
||||
(write-shape-tail! shape))))
|
||||
prepared))
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.logging :as log]
|
||||
[app.common.math :as mth]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.modifiers :as ctm]
|
||||
@ -813,7 +814,7 @@
|
||||
;; propagating geometry, so propagate_modifiers sees the updated state.
|
||||
(doseq [[id {:keys [property value]}] (extract-property-changes modif-tree)]
|
||||
(when (= property :grow-type)
|
||||
(wasm.api/use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(wasm.api/set-shape-grow-type value)))
|
||||
|
||||
(let [objects (dsh/lookup-page-objects state)
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
[app.common.geom.shapes.grid-layout :as gslg]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.math :as mth]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.modifiers :as ctm]
|
||||
@ -791,7 +792,7 @@
|
||||
[target-frame objects position]
|
||||
(if (features/active-feature? @st/state "render-wasm/v1")
|
||||
(do
|
||||
(wasm.api/use-shape target-frame)
|
||||
(wselect/use-shape target-frame)
|
||||
(let [cell (wasm.api/get-grid-coords position)]
|
||||
(when (not= cell [-1 -1]) cell)))
|
||||
(gslg/get-drop-cell target-frame objects position)))
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.types.modifiers :as ctm]
|
||||
[app.common.types.text :as ctt]
|
||||
[app.main.data.helpers :as dsh]
|
||||
@ -40,7 +41,7 @@
|
||||
;; text shape is being edited): there is no design state to query, and
|
||||
;; returning nil makes callers skip the WASM resize/modifier path.
|
||||
(when (and id (wasm.api/initialized?))
|
||||
(wasm.api/use-shape id)
|
||||
(wselect/use-shape id)
|
||||
;; While the WASM text editor is actively editing it already holds the live
|
||||
;; content and layout. Re-pushing the content here calls `_clear_shape_text`
|
||||
;; + `_update_shape_text_layout`, which resets the editor and drops every
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.render-wasm.wasm :as wasm]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.util.dom :as dom]
|
||||
@ -83,14 +84,14 @@
|
||||
(when (seq include-ids)
|
||||
(wasm.api/set-render-include-filter! include-ids))
|
||||
(doseq [id clear-fills-ids]
|
||||
(wasm.api/use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(wasm.api/clear-shape-fills!)))
|
||||
|
||||
(defn- viewer-restore-layer-mask!
|
||||
[page-objects clear-fills-ids]
|
||||
(wasm.api/clear-render-include-filter!)
|
||||
(doseq [id clear-fills-ids]
|
||||
(wasm.api/use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(wasm.api/set-shape-fills id (get-in page-objects [id :fills] []) false)))
|
||||
|
||||
(defn- viewer-do-render!
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.tokens.application :as dwta]
|
||||
@ -116,7 +117,7 @@
|
||||
|
||||
(when wasm-renderer-enabled?
|
||||
(doseq [id ids]
|
||||
(wasm.api/use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(wasm.api/set-shape-blend-mode value)
|
||||
(wasm.api/request-render "preview-blend-mode")))
|
||||
|
||||
@ -130,7 +131,7 @@
|
||||
(swap! state* assoc :preview-complete? true)
|
||||
(when wasm-renderer-enabled?
|
||||
(doseq [id ids]
|
||||
(wasm.api/use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(wasm.api/set-shape-blend-mode current-blend-mode)
|
||||
(wasm.api/request-render "preview-blend-mode")))
|
||||
(st/emit! (dw/unset-preview-blend-mode ids))))
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.types.color :as clr]
|
||||
[app.common.types.component :as ctk]
|
||||
[app.common.types.shape :as cts]
|
||||
@ -502,7 +503,7 @@
|
||||
(let [content (-> active-editor-state
|
||||
(ted/get-editor-current-content)
|
||||
(ted/export-content))]
|
||||
(wasm.api/use-shape edition)
|
||||
(wselect/use-shape edition)
|
||||
(wasm.api/set-shape-text-content edition content)
|
||||
(let [dimension (wasm.api/get-text-dimensions)]
|
||||
(st/emit! (dwt/resize-text-editor edition dimension))
|
||||
@ -651,12 +652,12 @@
|
||||
|
||||
(mf/with-effect [path-editing? edition @initialized?]
|
||||
(when (and path-editing? edition @initialized?)
|
||||
(wasm.api/use-shape edition)
|
||||
(wselect/use-shape edition)
|
||||
(wasm.api/set-shape-hidden true)
|
||||
(wasm.api/request-render "start-path-edition")
|
||||
(fn []
|
||||
(when (wasm.api/initialized?)
|
||||
(wasm.api/use-shape edition)
|
||||
(wselect/use-shape edition)
|
||||
(wasm.api/set-shape-hidden false)
|
||||
(wasm.api/request-render "stop-path-edition")))))
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
[app.common.logging :as log]
|
||||
[app.common.math :as mth]
|
||||
[app.common.render-wasm.api.props :as props]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.render-wasm.helpers :as h]
|
||||
[app.common.render-wasm.mem :as mem]
|
||||
[app.common.render-wasm.mem.heap32 :as mem.h32]
|
||||
@ -727,18 +728,6 @@
|
||||
|
||||
(declare get-text-dimensions)
|
||||
|
||||
(defn use-shape
|
||||
[id]
|
||||
;; Use `wasm/live?` (not `initialized?`) so context-restore reload can
|
||||
;; select shapes while `reloading?` still blocks external app callers.
|
||||
(when (wasm/live?)
|
||||
(let [buffer (uuid/get-u32 id)]
|
||||
(h/call wasm/internal-module "_use_shape"
|
||||
(aget buffer 0)
|
||||
(aget buffer 1)
|
||||
(aget buffer 2)
|
||||
(aget buffer 3)))))
|
||||
|
||||
(defn has-shape
|
||||
[id]
|
||||
(when (wasm/live?)
|
||||
@ -793,7 +782,7 @@
|
||||
Updates the cached content, pushes to WASM, and returns {:shape-id :content} for saving.
|
||||
`:with-fills?` also returns the selection's `:fills`."
|
||||
[styles & [opts]]
|
||||
(let [result (text-editor/apply-styles-to-selection styles use-shape set-shape-text-content opts)]
|
||||
(let [result (text-editor/apply-styles-to-selection styles wselect/use-shape set-shape-text-content opts)]
|
||||
(request-render "apply-styles-to-selection")
|
||||
result))
|
||||
|
||||
@ -801,7 +790,7 @@
|
||||
"Apply paragraph attrs to the paragraphs the editor selection touches.
|
||||
Returns {:shape-id :content} for saving."
|
||||
[attrs]
|
||||
(let [result (text-editor/apply-paragraph-attrs-to-selection attrs use-shape set-shape-text-content)]
|
||||
(let [result (text-editor/apply-paragraph-attrs-to-selection attrs wselect/use-shape set-shape-text-content)]
|
||||
(request-render "apply-paragraph-attrs-to-selection")
|
||||
result))
|
||||
|
||||
@ -811,7 +800,7 @@
|
||||
[shape-id range]
|
||||
(when-let [styles (text-editor/get-pending-caret-styles shape-id)]
|
||||
(let [result (text-editor/apply-styles-to-range
|
||||
shape-id range styles use-shape set-shape-text-content)]
|
||||
shape-id range styles wselect/use-shape set-shape-text-content)]
|
||||
(text-editor/clear-pending-caret-styles!)
|
||||
(request-render "apply-pending-caret-styles")
|
||||
result)))
|
||||
@ -1130,7 +1119,7 @@
|
||||
(h/call wasm/internal-module "_set_shape_hidden" hidden))
|
||||
|
||||
(defn clear-shape-fills!
|
||||
"Clear the fills of the currently-selected shape (call `use-shape` first).
|
||||
"Clear the fills of the currently-selected shape (call `use-shape!` first).
|
||||
Equivalent to `set-shape-fills` with an empty collection."
|
||||
[]
|
||||
(when (initialized?)
|
||||
@ -1407,7 +1396,7 @@
|
||||
|
||||
(defn get-text-dimensions
|
||||
([id]
|
||||
(use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(get-text-dimensions))
|
||||
([]
|
||||
(if-not (initialized?)
|
||||
@ -1588,7 +1577,7 @@
|
||||
`skip-fills-strokes?` is true, fill/stroke records were already in the batch;
|
||||
only image fetches remain.
|
||||
|
||||
Always `use-shape` first: after a multi-shape batch the WASM current shape is
|
||||
Always `use-shape!` first: after a multi-shape batch the WASM current shape is
|
||||
the last record in the chunk, not this shape."
|
||||
[shape skip-layout? & {:keys [skip-fills-strokes?] :or {skip-fills-strokes? false}}]
|
||||
(let [id (dm/get-prop shape :id)
|
||||
@ -1608,7 +1597,7 @@
|
||||
true))]
|
||||
|
||||
(when needs-current?
|
||||
(use-shape id))
|
||||
(wselect/use-shape id))
|
||||
|
||||
(when (and (some? content) (= type :svg-raw))
|
||||
(set-shape-svg-raw-content (get-static-markup shape)))
|
||||
@ -1814,8 +1803,7 @@
|
||||
prepared (serialize-shape/serialize-shapes-batch!
|
||||
chunk
|
||||
{:include-layout? true
|
||||
:include-fills-strokes? true}
|
||||
use-shape)]
|
||||
:include-fills-strokes? true})]
|
||||
|
||||
(loop [xs prepared
|
||||
t-acc (transient thumbnails-acc)
|
||||
@ -1964,8 +1952,7 @@
|
||||
(let [prepared (serialize-shape/serialize-shapes-batch!
|
||||
shapes
|
||||
{:include-layout? true
|
||||
:include-fills-strokes? true}
|
||||
use-shape)
|
||||
:include-fills-strokes? true})
|
||||
total-shapes (count prepared)
|
||||
{:keys [thumbnails full text-font-state]}
|
||||
(loop [index 0
|
||||
@ -2772,7 +2759,7 @@
|
||||
(defn shape-to-path
|
||||
[id]
|
||||
(when (initialized?)
|
||||
(use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(try
|
||||
(let [offset (-> (h/call wasm/internal-module "_current_to_path")
|
||||
(mem/->offset-32))
|
||||
@ -2796,7 +2783,7 @@
|
||||
the fill rule itself)."
|
||||
[id stroke-index]
|
||||
(when (initialized?)
|
||||
(use-shape id)
|
||||
(wselect/use-shape id)
|
||||
(try
|
||||
(let [offset (-> (h/call wasm/internal-module "_convert_stroke_to_path" stroke-index)
|
||||
(mem/->offset-32))
|
||||
@ -2886,7 +2873,7 @@
|
||||
(defn calculate-position-data
|
||||
[shape]
|
||||
(when (initialized?)
|
||||
(use-shape (:id shape))
|
||||
(wselect/use-shape (:id shape))
|
||||
(let [heapf32 (mem/get-heap-f32)
|
||||
heapu32 (mem/get-heap-u32)
|
||||
offset (-> (h/call wasm/internal-module "_calculate_position_data")
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.render-wasm.svg-derived :as svg-derived]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.shape :as shape]
|
||||
@ -321,7 +322,7 @@
|
||||
(let [shape-id (dm/get-prop shape :id)]
|
||||
(if (shape-in-current-page? shape-id)
|
||||
(do
|
||||
(api/use-shape shape-id)
|
||||
(wselect/use-shape shape-id)
|
||||
(->> properties
|
||||
(mapcat #(set-wasm-attr! shape %))
|
||||
(d/index-by :key :callback)
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
verify the WASM code path was exercised."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.render-wasm.api :as wasm.api]
|
||||
[app.render-wasm.api.fonts :as wasm.fonts]))
|
||||
|
||||
@ -198,7 +199,7 @@
|
||||
;; Save originals
|
||||
(reset! originals
|
||||
{:initialized? wasm.api/initialized?
|
||||
:use-shape wasm.api/use-shape
|
||||
:use-shape wselect/use-shape
|
||||
:calculate-position-data wasm.api/calculate-position-data
|
||||
:request-render wasm.api/request-render
|
||||
:clean-modifiers wasm.api/clean-modifiers
|
||||
@ -217,7 +218,7 @@
|
||||
:get-content-fonts wasm.fonts/get-content-fonts})
|
||||
;; Install mocks
|
||||
(set! wasm.api/initialized? mock-initialized?)
|
||||
(set! wasm.api/use-shape mock-use-shape)
|
||||
(set! wselect/use-shape mock-use-shape)
|
||||
(set! wasm.api/calculate-position-data mock-calculate-position-data)
|
||||
(set! wasm.api/request-render mock-request-render)
|
||||
(set! wasm.api/clean-modifiers mock-clean-modifiers)
|
||||
@ -248,7 +249,7 @@
|
||||
[]
|
||||
(when-let [orig (not-empty @originals)]
|
||||
(set! wasm.api/initialized? (:initialized? orig))
|
||||
(set! wasm.api/use-shape (:use-shape orig))
|
||||
(set! wselect/use-shape (:use-shape orig))
|
||||
(set! wasm.api/calculate-position-data (:calculate-position-data orig))
|
||||
(set! wasm.api/request-render (:request-render orig))
|
||||
(set! wasm.api/clean-modifiers (:clean-modifiers orig))
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
render output below the FFI line needs headed or exporter pixel runs."
|
||||
(:require
|
||||
[app.common.render-wasm.api.props :as props]
|
||||
[app.common.render-wasm.api.select :as wselect]
|
||||
[app.common.render-wasm.api.upload :as upload]
|
||||
[app.common.render-wasm.serialize-shape :as serialize-shape]
|
||||
[app.common.render-wasm.svg-derived :as svg-derived]
|
||||
@ -22,22 +23,26 @@
|
||||
|
||||
(defn- with-ffi-stubs*
|
||||
"Stubs the single-arity FFI boundary fns (`flush-shapes-batch!`,
|
||||
`set-shape-svg-attrs`, `set-shape-path-content`). `set-shape-upload!` is
|
||||
deliberately left real: it is a trivial one-liner over the stubbed flush,
|
||||
so the single test exercises its actual delegation and default opts. A
|
||||
plain fn `set!` onto a multi-arity var breaks under the `:esm` test build
|
||||
(call sites dispatch via `cljs$core$IFn$_invoke$arity$N`; see `mock/stub`)."
|
||||
`use-shape!`, `set-shape-svg-attrs`, `set-shape-path-content`).
|
||||
`set-shape-upload!` is deliberately left real: it is a trivial one-liner
|
||||
over the stubbed flush, so the single test exercises its actual delegation
|
||||
and default opts. A plain fn `set!` onto a multi-arity var breaks under
|
||||
the `:esm` test build (call sites dispatch via
|
||||
`cljs$core$IFn$_invoke$arity$N`; see `mock/stub`)."
|
||||
[stubs thunk]
|
||||
(let [orig-flush upload/flush-shapes-batch!
|
||||
orig-select wselect/use-shape
|
||||
orig-svg-attrs props/set-shape-svg-attrs
|
||||
orig-path props/set-shape-path-content]
|
||||
(set! upload/flush-shapes-batch! (:flush stubs))
|
||||
(set! wselect/use-shape (or (:select stubs) (fn [_] nil)))
|
||||
(set! props/set-shape-svg-attrs (:svg-attrs stubs))
|
||||
(set! props/set-shape-path-content (:path stubs))
|
||||
(try
|
||||
(thunk)
|
||||
(finally
|
||||
(set! upload/flush-shapes-batch! orig-flush)
|
||||
(set! wselect/use-shape orig-select)
|
||||
(set! props/set-shape-svg-attrs orig-svg-attrs)
|
||||
(set! props/set-shape-path-content orig-path)))))
|
||||
|
||||
@ -109,14 +114,14 @@
|
||||
flush-calls (atom [])
|
||||
events (atom [])
|
||||
current (atom nil)
|
||||
select-fn (fn [id]
|
||||
(reset! current id)
|
||||
(swap! events conj [:select id]))
|
||||
stubs {:flush (fn [s o] (swap! flush-calls conj {:shapes s :opts o}) nil)
|
||||
:select (fn [id]
|
||||
(reset! current id)
|
||||
(swap! events conj [:select id]))
|
||||
:svg-attrs (fn [attrs] (swap! events conj [:svg-attrs @current attrs]) nil)
|
||||
:path (fn [content] (swap! events conj [:path @current content]) nil)}
|
||||
result (with-ffi-stubs* stubs
|
||||
#(serialize-shape/serialize-shapes-batch! shapes opts select-fn))
|
||||
#(serialize-shape/serialize-shapes-batch! shapes opts))
|
||||
flushed (first @flush-calls)]
|
||||
(t/is (= 1 (count @flush-calls)) "exactly one flush")
|
||||
(t/is (= opts (:opts flushed)) "flush carries passed opts")
|
||||
@ -152,13 +157,11 @@
|
||||
flush-calls (atom [])
|
||||
selected (atom [])
|
||||
stubs {:flush (fn [s o] (swap! flush-calls conj {:shapes s :opts o}) nil)
|
||||
:select (fn [id] (swap! selected conj id))
|
||||
:svg-attrs (fn [_] (t/is false "no svg-attrs write on empty batch") nil)
|
||||
:path (fn [_] (t/is false "no path write on empty batch") nil)}
|
||||
result (with-ffi-stubs* stubs
|
||||
#(serialize-shape/serialize-shapes-batch!
|
||||
[]
|
||||
opts
|
||||
(fn [id] (swap! selected conj id))))]
|
||||
#(serialize-shape/serialize-shapes-batch! [] opts))]
|
||||
(t/is (= [] result) "returns empty prepared")
|
||||
(t/is (empty? @flush-calls) "no flush on empty batch")
|
||||
(t/is (empty? @selected) "no select on empty batch")))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user