mirror of
https://github.com/penpot/penpot.git
synced 2025-05-31 08:16:13 +02:00
🎉 Basic wasm support for svg attrs and svg defs
This commit is contained in:
parent
751df46dc9
commit
79df616108
12 changed files with 452 additions and 60 deletions
|
@ -128,11 +128,13 @@
|
|||
(defn svg-raw-wrapper-factory
|
||||
[objects]
|
||||
(let [shape-wrapper (shape-wrapper-factory objects)
|
||||
svg-raw-shape (svg-raw/svg-raw-shape shape-wrapper)]
|
||||
svg-raw-shape (svg-raw/svg-raw-shape shape-wrapper)]
|
||||
(mf/fnc svg-raw-wrapper
|
||||
[{:keys [shape] :as props}]
|
||||
(let [childs (mapv #(get objects %) (:shapes shape))]
|
||||
(if (and (map? (:content shape))
|
||||
;; tspan shouldn't be contained in a group or have svg defs
|
||||
(not= :tspan (get-in shape [:content :tag]))
|
||||
(or (= :svg (get-in shape [:content :tag]))
|
||||
(contains? shape :svg-attrs)))
|
||||
[:> shape-container {:shape shape}
|
||||
|
|
|
@ -13,15 +13,25 @@
|
|||
[app.main.ui.components.title-bar :refer [title-bar]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.functions :as uf]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc attribute-value [{:keys [attr value on-change on-delete] :as props}]
|
||||
(let [handle-change
|
||||
(let [last-value (mf/use-state value)
|
||||
|
||||
handle-change*
|
||||
(mf/use-fn
|
||||
(mf/deps attr on-change)
|
||||
(uf/debounce (fn [val]
|
||||
(on-change attr val))
|
||||
300))
|
||||
|
||||
handle-change
|
||||
(mf/use-fn
|
||||
(mf/deps attr on-change handle-change*)
|
||||
(fn [event]
|
||||
(on-change attr (dom/get-target-val event))))
|
||||
(reset! last-value (dom/get-target-val event))
|
||||
(handle-change* (dom/get-target-val event))))
|
||||
|
||||
handle-delete
|
||||
(mf/use-fn
|
||||
|
@ -35,7 +45,7 @@
|
|||
[:div {:class (stl/css :attr-content)}
|
||||
[:span {:class (stl/css :attr-name)} label]
|
||||
[:div {:class (stl/css :attr-input)}
|
||||
[:input {:value value
|
||||
[:input {:value @last-value
|
||||
:on-change handle-change}]]
|
||||
[:div {:class (stl/css :attr-actions)}
|
||||
[:button {:class (stl/css :attr-action-btn)
|
||||
|
|
|
@ -7,19 +7,26 @@
|
|||
(ns app.render-wasm.api
|
||||
"A WASM based render API"
|
||||
(:require
|
||||
["react-dom/server" :as rds]
|
||||
[app.common.colors :as cc]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.math :as mth]
|
||||
[app.common.svg.path :as path]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.render :as render]
|
||||
[app.render-wasm.helpers :as h]
|
||||
[app.util.debug :as dbg]
|
||||
[app.util.functions :as fns]
|
||||
[app.util.http :as http]
|
||||
[app.util.webapi :as wapi]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]
|
||||
[goog.object :as gobj]
|
||||
[promesa.core :as p]))
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defonce internal-frame-id nil)
|
||||
(defonce internal-module #js {})
|
||||
|
@ -28,6 +35,54 @@
|
|||
(def dpr
|
||||
(if use-dpr? js/window.devicePixelRatio 1.0))
|
||||
|
||||
;; (mf/defc svg-raw-element
|
||||
;; {::mf/props :obj}
|
||||
;; [{:keys [tag attrs content] :as props}]
|
||||
;; [:& (name tag) attrs
|
||||
;; (for [child content]
|
||||
;; (if (string? child)
|
||||
;; child
|
||||
;; [:& svg-raw-element child]))])
|
||||
|
||||
;; (mf/defc svg-raw
|
||||
;; {::mf/props :obj}
|
||||
;; [{:keys [shape] :as props}]
|
||||
;; (let [content (:content shape)]
|
||||
;; [:svg {:version "1.1"
|
||||
;; :xmlns "http://www.w3.org/2000/svg"
|
||||
;; :xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
;; :fill "none"}
|
||||
;; (if (string? content)
|
||||
;; content
|
||||
;; (let [svg-attrs (:svg-attrs shape)
|
||||
;; content (->
|
||||
;; (:content shape)
|
||||
;; (update :attrs merge svg-attrs))]
|
||||
;; (println "content" content)
|
||||
;; (println "svg-attrs" svg-attrs)
|
||||
;; [:& svg-raw-element content]))]))
|
||||
|
||||
;; Based on app.main.render/object-svg
|
||||
(mf/defc object-svg
|
||||
{::mf/props :obj}
|
||||
[{:keys [shape] :as props}]
|
||||
(let [objects (mf/deref refs/workspace-page-objects)
|
||||
shape-wrapper
|
||||
(mf/with-memo [shape]
|
||||
(render/shape-wrapper-factory objects))]
|
||||
|
||||
[:svg {:version "1.1"
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:fill "none"}
|
||||
[:& shape-wrapper {:shape shape}]]))
|
||||
|
||||
(defn get-static-markup
|
||||
[shape]
|
||||
(->
|
||||
(mf/element object-svg #js {:shape shape})
|
||||
(rds/renderToStaticMarkup)))
|
||||
|
||||
;; This should never be called from the outside.
|
||||
;; This function receives a "time" parameter that we're not using but maybe in the future could be useful (it is the time since
|
||||
;; the window started rendering elements so it could be useful to measure time between frames).
|
||||
|
@ -328,16 +383,44 @@
|
|||
(h/call internal-module "_add_shape_stroke_solid_fill" rgba)))))
|
||||
strokes))
|
||||
|
||||
(defn serialize-path-attrs
|
||||
[svg-attrs]
|
||||
(reduce
|
||||
(fn [acc [key value]]
|
||||
(str/concat
|
||||
acc
|
||||
(str/kebab key) "\0"
|
||||
value "\0")) "" svg-attrs))
|
||||
|
||||
(defn set-shape-path-attrs
|
||||
[attrs]
|
||||
(let [style (:style attrs)
|
||||
attrs (-> attrs
|
||||
(dissoc :style)
|
||||
(merge style))
|
||||
str (serialize-path-attrs attrs)
|
||||
size (count str)
|
||||
ptr (h/call internal-module "_alloc_bytes" size)]
|
||||
(h/call internal-module "stringToUTF8" str ptr size)
|
||||
(h/call internal-module "_set_shape_path_attrs" (count attrs))))
|
||||
|
||||
(defn set-shape-path-content
|
||||
[content]
|
||||
(let [buffer (path/content->buffer content)
|
||||
size (.-byteLength buffer)
|
||||
ptr (h/call internal-module "_alloc_bytes" size)
|
||||
(let [buffer (path/content->buffer content)
|
||||
size (.-byteLength buffer)
|
||||
ptr (h/call internal-module "_alloc_bytes" size)
|
||||
heap (gobj/get ^js internal-module "HEAPU8")
|
||||
mem (js/Uint8Array. (.-buffer heap) ptr size)]
|
||||
(.set mem (js/Uint8Array. buffer))
|
||||
(h/call internal-module "_set_shape_path_content")))
|
||||
|
||||
(defn set-shape-svg-raw-content
|
||||
[content]
|
||||
(let [size (get-string-length content)
|
||||
ptr (h/call internal-module "_alloc_bytes" size)]
|
||||
(h/call internal-module "stringToUTF8" content ptr size)
|
||||
(h/call internal-module "_set_shape_svg_raw_content")))
|
||||
|
||||
(defn- translate-blend-mode
|
||||
[blend-mode]
|
||||
(case blend-mode
|
||||
|
@ -453,7 +536,8 @@
|
|||
(dm/get-prop shape :r2)
|
||||
(dm/get-prop shape :r3)
|
||||
(dm/get-prop shape :r4)])
|
||||
bool-content (dm/get-prop shape :bool-content)]
|
||||
bool-content (dm/get-prop shape :bool-content)
|
||||
svg-attrs (dm/get-prop shape :svg-attrs)]
|
||||
|
||||
(use-shape id)
|
||||
(set-shape-type type)
|
||||
|
@ -462,12 +546,16 @@
|
|||
(set-shape-rotation rotation)
|
||||
(set-shape-transform transform)
|
||||
(set-shape-blend-mode blend-mode)
|
||||
(set-shape-children children)
|
||||
(set-shape-opacity opacity)
|
||||
(set-shape-hidden hidden)
|
||||
(set-shape-children children)
|
||||
(when (some? blur)
|
||||
(set-shape-blur blur))
|
||||
(when (and (some? content) (= type :path)) (set-shape-path-content content))
|
||||
(when (and (some? content) (= type :path))
|
||||
(set-shape-path-attrs svg-attrs)
|
||||
(set-shape-path-content content))
|
||||
(when (and (some? content) (= type :svg-raw))
|
||||
(set-shape-svg-raw-content (get-static-markup shape)))
|
||||
(when (some? bool-content) (set-shape-bool-content bool-content))
|
||||
(when (some? corners) (set-shape-corners corners))
|
||||
(let [pending' (concat (set-shape-fills fills) (set-shape-strokes strokes))]
|
||||
|
@ -486,6 +574,11 @@
|
|||
:stencil true
|
||||
:alpha true})
|
||||
|
||||
(defn clear-canvas
|
||||
[])
|
||||
;; TODO: Perform the corresponding cleanup."
|
||||
|
||||
|
||||
(defn resize-viewbox
|
||||
[width height]
|
||||
(h/call internal-module "_resize_viewbox" width height))
|
||||
|
|
|
@ -124,8 +124,15 @@
|
|||
:opacity (api/set-shape-opacity v)
|
||||
:hidden (api/set-shape-hidden v)
|
||||
:shapes (api/set-shape-children v)
|
||||
:content (when (= (:type self) :path) (api/set-shape-path-content v))
|
||||
:blur (api/set-shape-blur v)
|
||||
:svg-attrs (when (= (:type self) :path)
|
||||
(api/set-shape-path-attrs v))
|
||||
:content (cond
|
||||
(= (:type self) :path)
|
||||
(api/set-shape-path-content v)
|
||||
|
||||
(= (:type self) :svg-raw)
|
||||
(api/set-shape-svg-raw-content (api/get-static-markup self)))
|
||||
nil)
|
||||
;; when something synced with wasm
|
||||
;; is modified, we need to request
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue