🎉 Add text fills

This commit is contained in:
Elena Torro 2025-05-09 15:53:11 +02:00
parent c2ce7c6cf6
commit 42ef2f929a
11 changed files with 451 additions and 279 deletions

View file

@ -56,7 +56,7 @@
([{:keys [id points selrect] :as shape} content]
(wasm.api/use-shape id)
(wasm.api/set-shape-text-content content)
(wasm.api/set-shape-text content)
(let [dimension (wasm.api/text-dimensions)
resize-v
(gpt/point

View file

@ -188,7 +188,6 @@
(defn- store-image
[id]
(let [buffer (uuid/get-u32 id)
url (cf/resolve-file-media {:id id})]
(->> (http/send! {:method :get
@ -209,6 +208,33 @@
(aget buffer 3))
true))))))
(defn- get-fill-images
[leaf]
(filter :fill-image (:fills leaf)))
(defn- process-fill-image
[fill]
(rx/from
(when-let [image (:fill-image fill)]
(let [id (dm/get-prop image :id)
buffer (uuid/get-u32 id)
cached-image? (h/call wasm/internal-module "_is_image_cached"
(aget buffer 0)
(aget buffer 1)
(aget buffer 2)
(aget buffer 3))]
(when (zero? cached-image?)
(store-image id))))))
(defn set-shape-text-images
[content]
(let [paragraph-set (first (get content :children))
paragraphs (get paragraph-set :children)]
(->> paragraphs
(mapcat :children)
(mapcat get-fill-images)
(map process-fill-image))))
(defn set-shape-fills
[fills]
(h/call wasm/internal-module "_clear_shape_fills")
@ -218,23 +244,24 @@
gradient (:fill-color-gradient fill)
image (:fill-image fill)
offset (mem/alloc-bytes sr-fills/FILL-BYTE-SIZE)
heap (mem/get-heap-u32)]
heap (mem/get-heap-u8)
dview (js/DataView. (.-buffer heap))]
(cond
(some? color)
(let [argb (sr-clr/hex->u32argb color opacity)]
(sr-fills/write-solid-fill! offset heap argb)
(do
(sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity))
(h/call wasm/internal-module "_add_shape_fill"))
(some? gradient)
(do
(sr-fills/write-gradient-fill! offset heap gradient opacity)
(sr-fills/write-gradient-fill! offset dview gradient opacity)
(h/call wasm/internal-module "_add_shape_fill"))
(some? image)
(let [id (dm/get-prop image :id)
buffer (uuid/get-u32 id)
cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
(sr-fills/write-image-fill! offset heap id opacity (dm/get-prop image :width) (dm/get-prop image :height))
(sr-fills/write-image-fill! offset dview id opacity (dm/get-prop image :width) (dm/get-prop image :height))
(h/call wasm/internal-module "_add_shape_fill")
(when (== cached-image? 0)
(store-image id))))))
@ -254,7 +281,8 @@
cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap)
cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap)
offset (mem/alloc-bytes sr-fills/FILL-BYTE-SIZE)
heap (mem/get-heap-u32)]
heap (mem/get-heap-u8)
dview (js/DataView. (.-buffer heap))]
(case align
:inner (h/call wasm/internal-module "_add_shape_inner_stroke" width style cap-start cap-end)
:outer (h/call wasm/internal-module "_add_shape_outer_stroke" width style cap-start cap-end)
@ -262,22 +290,22 @@
(cond
(some? gradient)
(let [_ nil]
(sr-fills/write-gradient-fill! offset heap gradient opacity)
(do
(sr-fills/write-gradient-fill! offset dview gradient opacity)
(h/call wasm/internal-module "_add_shape_stroke_fill"))
(some? image)
(let [id (dm/get-prop image :id)
buffer (uuid/get-u32 id)
cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
(sr-fills/write-image-fill! offset heap id opacity (dm/get-prop image :width) (dm/get-prop image :height))
(sr-fills/write-image-fill! offset dview id opacity (dm/get-prop image :width) (dm/get-prop image :height))
(h/call wasm/internal-module "_add_shape_stroke_fill")
(when (== cached-image? 0)
(store-image id)))
(some? color)
(let [argb (sr-clr/hex->u32argb color opacity)]
(sr-fills/write-solid-fill! offset heap argb)
(do
(sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity))
(h/call wasm/internal-module "_add_shape_stroke_fill")))))
strokes))
@ -608,6 +636,12 @@
fonts)]
(f/store-fonts fonts))))
(defn set-shape-text
[content]
(concat
(set-shape-text-images content)
(set-shape-text-content content)))
(defn set-shape-grow-type
[grow-type]
(h/call wasm/internal-module "_set_shape_grow_type" (sr/translate-grow-type grow-type)))
@ -697,7 +731,7 @@
(when (some? corners) (set-shape-corners corners))
(when (some? shadows) (set-shape-shadows shadows))
(when (and (= type :text) (some? content))
(set-shape-text-content content))
(set-shape-text content))
(when (= type :text)
(set-shape-grow-type grow-type))
(when (or (ctl/any-layout? shape)
@ -711,9 +745,7 @@
(set-grid-layout shape))
(let [pending (into [] (concat
(if (and (= type :text) (some? content))
(set-shape-text-content content)
[])
(set-shape-text content)
(set-shape-fills fills)
(set-shape-strokes strokes)))]
(perf/end-measure "set-object")

View file

@ -6,30 +6,65 @@
(ns app.render-wasm.api.texts
(:require
[app.common.data.macros :as dm]
[app.render-wasm.api.fonts :as f]
[app.render-wasm.helpers :as h]
[app.render-wasm.mem :as mem]
[app.render-wasm.serializers :as sr]
[app.render-wasm.serializers.color :as sr-clr]
[app.render-wasm.serializers.fills :as sr-fills]
[app.render-wasm.wasm :as wasm]))
(defn utf8->buffer [text]
(let [encoder (js/TextEncoder.)]
(.encode encoder text)))
(defn set-text-leaf-fills
[fills current-offset dview]
(reduce (fn [offset fill]
(let [opacity (or (:fill-opacity fill) 1.0)
color (:fill-color fill)
gradient (:fill-color-gradient fill)
image (:fill-image fill)]
(cond
(some? color)
(sr-fills/write-solid-fill! offset dview (sr-clr/hex->u32argb color opacity))
(some? gradient)
(sr-fills/write-gradient-fill! offset dview gradient opacity)
(some? image)
(sr-fills/write-image-fill! offset dview
(dm/get-prop image :id)
opacity
(dm/get-prop image :width)
(dm/get-prop image :height)))
(+ offset sr-fills/FILL-BYTE-SIZE)))
current-offset
fills))
(defn total-fills-count
[leaves]
(reduce #(+ %1 (count (:fills %2))) 0 leaves))
(defn write-shape-text
;; buffer has the following format:
;; [<num-leaves> <paragraph_attributes> <leaves_attributes> <text>]
[leaves paragraph text]
(let [num-leaves (count leaves)
(let [le? true
num-leaves (count leaves)
paragraph-attr-size 48
leaf-attr-size 52
metadata-size (+ 1 paragraph-attr-size (* num-leaves leaf-attr-size))
total-fills (total-fills-count leaves)
total-fills-size (* sr-fills/FILL-BYTE-SIZE total-fills)
leaf-attr-size 56
metadata-size (+ paragraph-attr-size (* num-leaves leaf-attr-size) total-fills-size)
text-buffer (utf8->buffer text)
text-size (.-byteLength text-buffer)
buffer (js/ArrayBuffer. (+ metadata-size text-size))
dview (js/DataView. buffer)]
(.setUint32 dview 0 num-leaves)
(.setUint32 dview 0 num-leaves le?)
;; Serialize paragraph attributes
(let [text-align (sr/serialize-text-align (:text-align paragraph))
@ -41,26 +76,26 @@
typography-ref-file (sr/serialize-uuid (:typography-ref-file paragraph))
typography-ref-id (sr/serialize-uuid (:typography-ref-id paragraph))]
(.setUint8 dview 4 text-align)
(.setUint8 dview 5 text-direction)
(.setUint8 dview 6 text-decoration)
(.setUint8 dview 7 text-transform)
(.setUint8 dview 4 text-align le?)
(.setUint8 dview 5 text-direction le?)
(.setUint8 dview 6 text-decoration le?)
(.setUint8 dview 7 text-transform le?)
(.setFloat32 dview 8 line-height)
(.setFloat32 dview 12 letter-spacing)
(.setFloat32 dview 8 line-height le?)
(.setFloat32 dview 12 letter-spacing le?)
(.setUint32 dview 16 (aget typography-ref-file 0))
(.setUint32 dview 20 (aget typography-ref-file 1))
(.setUint32 dview 24 (aget typography-ref-file 2))
(.setInt32 dview 28 (aget typography-ref-file 3))
(.setUint32 dview 16 (aget typography-ref-file 0) le?)
(.setUint32 dview 20 (aget typography-ref-file 1) le?)
(.setUint32 dview 24 (aget typography-ref-file 2) le?)
(.setInt32 dview 28 (aget typography-ref-file 3) le?)
(.setUint32 dview 32 (aget typography-ref-id 0))
(.setUint32 dview 36 (aget typography-ref-id 1))
(.setUint32 dview 40 (aget typography-ref-id 2))
(.setInt32 dview 44 (aget typography-ref-id 3)))
(.setUint32 dview 32 (aget typography-ref-id 0) le?)
(.setUint32 dview 36 (aget typography-ref-id 1) le?)
(.setUint32 dview 40 (aget typography-ref-id 2) le?)
(.setInt32 dview 44 (aget typography-ref-id 3) le?))
;; Serialize leaves attributes
(loop [index 0 offset (+ 1 paragraph-attr-size)]
(loop [index 0 offset paragraph-attr-size]
(when (< index num-leaves)
(let [leaf (nth leaves index)
font-style (f/serialize-font-style (:font-style leaf))
@ -70,26 +105,30 @@
font-family (hash (:font-family leaf))
font-variant-id (sr/serialize-uuid (:font-variant-id leaf))
text-buffer (utf8->buffer (:text leaf))
text-length (.-byteLength text-buffer)]
text-length (.-byteLength text-buffer)
fills (:fills leaf)
total-fills (count fills)]
(.setUint8 dview offset font-style)
(.setFloat32 dview (+ offset 4) font-size)
(.setUint32 dview (+ offset 8) font-weight)
(.setUint32 dview (+ offset 12) (aget font-id 0))
(.setUint32 dview (+ offset 16) (aget font-id 1))
(.setUint32 dview (+ offset 20) (aget font-id 2))
(.setInt32 dview (+ offset 24) (aget font-id 3))
(.setUint8 dview offset font-style le?)
(.setFloat32 dview (+ offset 4) font-size le?)
(.setUint32 dview (+ offset 8) font-weight le?)
(.setUint32 dview (+ offset 12) (aget font-id 0) le?)
(.setUint32 dview (+ offset 16) (aget font-id 1) le?)
(.setUint32 dview (+ offset 20) (aget font-id 2) le?)
(.setInt32 dview (+ offset 24) (aget font-id 3) le?)
(.setInt32 dview (+ offset 28) font-family)
(.setInt32 dview (+ offset 28) font-family le?)
(.setUint32 dview (+ offset 32) (aget font-variant-id 0))
(.setUint32 dview (+ offset 36) (aget font-variant-id 1))
(.setUint32 dview (+ offset 40) (aget font-variant-id 2))
(.setInt32 dview (+ offset 44) (aget font-variant-id 3))
(.setUint32 dview (+ offset 32) (aget font-variant-id 0) le?)
(.setUint32 dview (+ offset 36) (aget font-variant-id 1) le?)
(.setUint32 dview (+ offset 40) (aget font-variant-id 2) le?)
(.setInt32 dview (+ offset 44) (aget font-variant-id 3) le?)
(.setInt32 dview (+ offset 48) text-length)
(.setInt32 dview (+ offset 48) text-length le?)
(.setInt32 dview (+ offset 52) total-fills le?)
(recur (inc index) (+ offset leaf-attr-size)))))
(let [new-offset (set-text-leaf-fills fills (+ offset leaf-attr-size) dview)]
(recur (inc index) new-offset)))))
;; Add text content to buffer
(let [text-offset metadata-size

View file

@ -15,16 +15,14 @@
(def FILL-BYTE-SIZE (+ 4 (max GRADIENT-BYTE-SIZE IMAGE-BYTE-SIZE SOLID-BYTE-SIZE)))
(defn write-solid-fill!
[offset heap-u32 argb]
(let [dview (js/DataView. (.-buffer heap-u32))]
(.setUint8 dview offset 0x00 true)
(.setUint32 dview (+ offset 4) argb true)
(+ offset FILL-BYTE-SIZE)))
[offset dview argb]
(.setUint8 dview offset 0x00 true)
(.setUint32 dview (+ offset 4) argb true)
(+ offset FILL-BYTE-SIZE))
(defn write-image-fill!
[offset heap-u32 id opacity width height]
(let [dview (js/DataView. (.-buffer heap-u32))
uuid-buffer (uuid/get-u32 id)]
[offset dview id opacity width height]
(let [uuid-buffer (uuid/get-u32 id)]
(.setUint8 dview offset 0x03 true)
(.setUint32 dview (+ offset 4) (aget uuid-buffer 0) true)
(.setUint32 dview (+ offset 8) (aget uuid-buffer 1) true)
@ -35,22 +33,19 @@
(.setInt32 dview (+ offset 28) height true)
(+ offset FILL-BYTE-SIZE)))
(defn write-gradient-fill!
[offset heap-u32 gradient opacity]
(let [dview (js/DataView. (.-buffer heap-u32))
start-x (:start-x gradient)
[offset dview gradient opacity]
(let [start-x (:start-x gradient)
start-y (:start-y gradient)
end-x (:end-x gradient)
end-y (:end-y gradient)
end-y (:end-y gradient)
width (or (:width gradient) 0)
stops (take shp/MAX-GRADIENT-STOPS (:stops gradient))
type (if (= (:type gradient) :linear) 0x01 0x02)]
(.setUint8 dview offset type true)
(.setFloat32 dview (+ offset 4) start-x true)
(.setFloat32 dview (+ offset 8) start-y true)
(.setFloat32 dview (+ offset 12) end-x true)
(.setFloat32 dview (+ offset 12) end-x true)
(.setFloat32 dview (+ offset 16) end-y true)
(.setFloat32 dview (+ offset 20) opacity true)
(.setFloat32 dview (+ offset 24) width true)
@ -60,8 +55,8 @@
(+ offset FILL-BYTE-SIZE)
(let [stop (first stops)
hex-color (:color stop)
opacity (:opacity stop)
argb (clr/hex->u32argb hex-color opacity)
stop-opacity (:opacity stop)
argb (clr/hex->u32argb hex-color stop-opacity)
stop-offset (:offset stop)]
(.setUint32 dview loop-offset argb true)
(.setFloat32 dview (+ loop-offset 4) stop-offset true)

View file

@ -150,7 +150,7 @@
(api/set-shape-svg-raw-content (api/get-static-markup shape))
(= (:type shape) :text)
(into [] (api/set-shape-text-content v)))
(api/set-shape-text v))
:grow-type
(api/set-shape-grow-type v)