Merge pull request #5333 from penpot/niwinz-render-wasm-improvements

 Improvements to wasm api call usability
This commit is contained in:
Belén Albeza 2024-11-20 09:34:48 +01:00 committed by GitHub
commit 59fdf64c66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 414 additions and 401 deletions

View file

@ -26,7 +26,6 @@
[app.common.types.pages-list :as ctpl]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctst]
[app.common.types.shape.impl :as shape.impl]
[app.common.types.token :as cto]
[app.common.types.token-theme :as ctot]
[app.common.types.tokens-lib :as ctob]
@ -541,7 +540,8 @@
(when verify?
(check-changes! items))
(binding [*touched-changes* (volatile! #{}) shape.impl/*wasm-sync* true]
(binding [*touched-changes* (volatile! #{})
cts/*wasm-sync* true]
(let [result (reduce #(or (process-change %1 %2) %1) data items)
result (reduce process-touched-change result @*touched-changes*)]
;; Validate result shapes (only on the backend)

View file

@ -6,6 +6,7 @@
(ns app.common.types.shape
(:require
#?(:clj [app.common.fressian :as fres])
[app.common.colors :as clr]
[app.common.data :as d]
[app.common.geom.matrix :as gmt]
@ -13,15 +14,16 @@
[app.common.geom.proportions :as gpr]
[app.common.geom.rect :as grc]
[app.common.geom.shapes :as gsh]
[app.common.record :as cr]
[app.common.schema :as sm]
[app.common.schema.generators :as sg]
[app.common.transit :as t]
[app.common.types.color :as ctc]
[app.common.types.grid :as ctg]
[app.common.types.plugins :as ctpg]
[app.common.types.shape.attrs :refer [default-color]]
[app.common.types.shape.blur :as ctsb]
[app.common.types.shape.export :as ctse]
[app.common.types.shape.impl :as impl]
[app.common.types.shape.interactions :as ctsi]
[app.common.types.shape.layout :as ctsl]
[app.common.types.shape.path :as ctsp]
@ -31,9 +33,31 @@
[app.common.uuid :as uuid]
[clojure.set :as set]))
(defonce ^:dynamic *wasm-sync* false)
(defonce wasm-enabled? false)
(defonce wasm-create-shape (constantly nil))
;; Marker protocol
(defprotocol IShape)
(cr/defrecord Shape [id name type x y width height rotation selrect points
transform transform-inverse parent-id frame-id flip-x flip-y]
IShape)
(defn shape?
[o]
(impl/shape? o))
#?(:cljs (implements? IShape o)
:clj (instance? Shape o)))
(defn create-shape
"A low level function that creates a Shape data structure
from a attrs map without performing other transformations"
[attrs]
#?(:cljs (if ^boolean wasm-enabled?
(^function wasm-create-shape attrs)
(map->Shape attrs))
:clj (map->Shape attrs)))
(def stroke-caps-line #{:round :square})
(def stroke-caps-marker #{:line-arrow :triangle-arrow :square-marker :circle-marker :diamond-marker})
@ -242,7 +266,7 @@
(defn- decode-shape
[o]
(if (map? o)
(impl/map->Shape o)
(create-shape o)
o))
(defn- shape-generator
@ -266,7 +290,7 @@
(= type :bool))
(merge attrs1 shape attrs3)
(merge attrs1 shape attrs2 attrs3)))))
(sg/fmap impl/map->Shape)))
(sg/fmap create-shape)))
(def schema:shape
[:and {:title "Shape"
@ -453,12 +477,6 @@
;; NOTE: used for create ephimeral shapes for multiple selection
:multiple minimal-multiple-attrs))
(defn create-shape
"A low level function that creates a Shape data structure
from a attrs map without performing other transformations"
[attrs]
(impl/create-shape attrs))
(defn- make-minimal-shape
[type]
(let [type (if (= type :curve) :path type)
@ -476,7 +494,7 @@
(assoc :parent-id uuid/zero)
(assoc :rotation 0))]
(impl/create-shape attrs)))
(create-shape attrs)))
(defn setup-rect
"Initializes the selrect and points for a shape."
@ -531,3 +549,17 @@
(assoc :transform-inverse (gmt/matrix)))
(gpr/setup-proportions))))
;; --- SHAPE SERIALIZATION
(t/add-handlers!
{:id "shape"
:class Shape
:wfn #(into {} %)
:rfn create-shape})
#?(:clj
(fres/add-handlers!
{:name "penpot/shape"
:class Shape
:wfn fres/write-map-like
:rfn (comp map->Shape fres/read-map-like)}))

View file

@ -1,185 +0,0 @@
;; 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 INC
(ns app.common.types.shape.impl
(:require
#?(:clj [app.common.fressian :as fres])
#?(:cljs [cuerdas.core :as str])
[app.common.record :as cr]
[app.common.transit :as t]
[clojure.core :as c]))
(defonce ^:dynamic *wasm-sync* false)
(defonce enabled-wasm-ready-shape false)
(defonce wasm-create-shape (constantly nil))
(defonce wasm-use-shape (constantly nil))
(defonce wasm-set-shape-selrect (constantly nil))
(defonce wasm-set-shape-transform (constantly nil))
(defonce wasm-set-shape-rotation (constantly nil))
(defonce wasm-set-shape-fills (constantly nil))
(defonce wasm-set-shape-blend-mode (constantly nil))
(defonce wasm-set-shape-children (constantly nil))
(cr/defrecord Shape [id name type x y width height rotation selrect points
transform transform-inverse parent-id frame-id flip-x flip-y])
(declare ^:private impl-assoc)
(declare ^:private impl-conj)
(declare ^:private impl-dissoc)
;; TODO: implement lazy MapEntry
#?(:cljs
(deftype ShapeProxy [delegate]
Object
(toString [coll]
(str "{" (str/join ", " (for [[k v] coll] (str k " " v))) "}"))
(equiv [this other]
(-equiv this other))
IWithMeta
(-with-meta [_ meta]
(ShapeProxy. (with-meta delegate meta)))
IMeta
(-meta [_] (meta delegate))
ICollection
(-conj [coll entry]
(impl-conj coll entry))
IEquiv
(-equiv [coll other]
(c/equiv-map coll other))
IHash
(-hash [coll] (hash (into {} coll)))
ISequential
ISeqable
(-seq [_]
(c/-seq delegate))
ICounted
(-count [_]
(+ 1 (count delegate)))
ILookup
(-lookup [coll k]
(-lookup coll k nil))
(-lookup [_ k not-found]
(c/-lookup delegate k not-found))
IFind
(-find [_ k]
(c/-find delegate k))
IAssociative
(-assoc [coll k v]
(impl-assoc coll k v))
(-contains-key? [_ k]
(contains? delegate k))
IMap
(-dissoc [coll k]
(impl-dissoc coll k))
IFn
(-invoke [coll k]
(-lookup coll k))
(-invoke [coll k not-found]
(-lookup coll k not-found))
IPrintWithWriter
(-pr-writer [_ writer _]
(-write writer (str "#penpot/shape " (:id delegate))))))
(defn shape?
[o]
#?(:clj (instance? Shape o)
:cljs (or (instance? Shape o)
(instance? ShapeProxy o))))
;; --- SHAPE IMPL
#?(:cljs
(defn- impl-assoc
[coll k v]
(when *wasm-sync*
(wasm-use-shape (:id coll))
(case k
:selrect (wasm-set-shape-selrect v)
:rotation (wasm-set-shape-rotation v)
:transform (wasm-set-shape-transform v)
:fills (wasm-set-shape-fills v)
:blend-mode (wasm-set-shape-blend-mode v)
:shapes (wasm-set-shape-children v)
nil))
(let [delegate (.-delegate ^ShapeProxy coll)
delegate' (assoc delegate k v)]
(if (identical? delegate' delegate)
coll
(ShapeProxy. delegate')))))
#?(:cljs
(defn- impl-dissoc
[coll k]
(let [delegate (.-delegate ^ShapeProxy coll)
delegate' (dissoc delegate k)]
(if (identical? delegate delegate')
coll
(ShapeProxy. delegate')))))
#?(:cljs
(defn- impl-conj
[coll entry]
(if (vector? entry)
(-assoc coll (-nth entry 0) (-nth entry 1))
(loop [ret coll es (seq entry)]
(if (nil? es)
ret
(let [e (first es)]
(if (vector? e)
(recur (-assoc ret (-nth e 0) (-nth e 1))
(next es))
(throw (js/Error. "conj on a map takes map entries or seqables of map entries")))))))))
(defn create-shape
"Instanciate a shape from a map"
[attrs]
#?(:cljs
(if enabled-wasm-ready-shape
(ShapeProxy. attrs)
(map->Shape attrs))
:clj (map->Shape attrs)))
;; --- SHAPE SERIALIZATION
(t/add-handlers!
{:id "shape"
:class Shape
:wfn #(into {} %)
:rfn create-shape})
#?(:cljs
(t/add-handlers!
{:id "shape"
:class ShapeProxy
:wfn #(into {} %)
:rfn create-shape}))
#?(:clj
(fres/add-handlers!
{:name "penpot/shape"
:class Shape
:wfn fres/write-map-like
:rfn (comp create-shape fres/read-map-like)}))