♻️ Refactor font-related wasm code into a sub-namespace

This commit is contained in:
Belén Albeza 2025-03-28 14:43:44 +01:00
parent f53cae0faa
commit c6bba54573
5 changed files with 261 additions and 236 deletions

View file

@ -4,7 +4,7 @@
"license": "MPL-2.0", "license": "MPL-2.0",
"author": "Kaleidos INC", "author": "Kaleidos INC",
"private": true, "private": true,
"packageManager": "yarn@4.7.0+sha512.5a0afa1d4c1d844b3447ee3319633797bcd6385d9a44be07993ae52ff4facabccafb4af5dcd1c2f9a94ac113e5e9ff56f6130431905884414229e284e37bb7c9", "packageManager": "yarn@4.8.0+sha512.85ec3149b1ec48f47c2690e13b29197a8a84b09c2c936cc596dddfb49c517e3bc3b1881ec52b5d35ca4b7c437c3f0daae3a80e39438c93bbcc5fcece2df5f15a",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/penpot/penpot" "url": "https://github.com/penpot/penpot"

View file

@ -4,7 +4,7 @@
"license": "MPL-2.0", "license": "MPL-2.0",
"author": "Kaleidos INC", "author": "Kaleidos INC",
"private": true, "private": true,
"packageManager": "yarn@4.7.0+sha512.5a0afa1d4c1d844b3447ee3319633797bcd6385d9a44be07993ae52ff4facabccafb4af5dcd1c2f9a94ac113e5e9ff56f6130431905884414229e284e37bb7c9", "packageManager": "yarn@4.8.0+sha512.85ec3149b1ec48f47c2690e13b29197a8a84b09c2c936cc596dddfb49c517e3bc3b1881ec52b5d35ca4b7c437c3f0daae3a80e39438c93bbcc5fcece2df5f15a",
"browserslist": [ "browserslist": [
"defaults" "defaults"
], ],

View file

@ -19,22 +19,20 @@
[app.main.fonts :as fonts] [app.main.fonts :as fonts]
[app.main.refs :as refs] [app.main.refs :as refs]
[app.main.render :as render] [app.main.render :as render]
[app.main.store :as st] [app.render-wasm.api.fonts :as f]
[app.render-wasm.helpers :as h] [app.render-wasm.helpers :as h]
[app.render-wasm.serializers :as sr] [app.render-wasm.serializers :as sr]
[app.render-wasm.wasm :as wasm]
[app.util.debug :as dbg] [app.util.debug :as dbg]
[app.util.http :as http] [app.util.http :as http]
[app.util.webapi :as wapi] [app.util.webapi :as wapi]
[beicon.v2.core :as rx] [beicon.v2.core :as rx]
[cuerdas.core :as str]
[goog.object :as gobj] [goog.object :as gobj]
[lambdaisland.uri :as u]
[okulary.core :as l]
[promesa.core :as p] [promesa.core :as p]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defonce internal-frame-id nil) ;; (defonce internal-frame-id nil)
(defonce internal-module #js {}) ;; (defonce internal-module #js {})
(defonce use-dpr? (contains? cf/flags :render-wasm-dpr)) (defonce use-dpr? (contains? cf/flags :render-wasm-dpr))
(def dpr (def dpr
@ -67,8 +65,8 @@
;; the window started rendering elements so it could be useful to measure time between frames). ;; the window started rendering elements so it could be useful to measure time between frames).
(defn- render (defn- render
[_] [_]
(h/call internal-module "_render") (h/call wasm/internal-module "_render")
(set! internal-frame-id nil)) (set! wasm/internal-frame-id nil))
(defn- rgba-from-hex (defn- rgba-from-hex
"Takes a hex color in #rrggbb format, and an opacity value from 0 to 1 and returns its 32-bit rgba representation" "Takes a hex color in #rrggbb format, and an opacity value from 0 to 1 and returns its 32-bit rgba representation"
@ -91,20 +89,20 @@
(defn cancel-render (defn cancel-render
[_] [_]
(when internal-frame-id (when wasm/internal-frame-id
(js/cancelAnimationFrame internal-frame-id) (js/cancelAnimationFrame wasm/internal-frame-id)
(set! internal-frame-id nil))) (set! wasm/internal-frame-id nil)))
(defn request-render (defn request-render
[requester] [requester]
(when internal-frame-id (cancel-render requester)) (when wasm/internal-frame-id (cancel-render requester))
(let [frame-id (js/requestAnimationFrame render)] (let [frame-id (js/requestAnimationFrame render)]
(set! internal-frame-id frame-id))) (set! wasm/internal-frame-id frame-id)))
(defn use-shape (defn use-shape
[id] [id]
(let [buffer (uuid/get-u32 id)] (let [buffer (uuid/get-u32 id)]
(h/call internal-module "_use_shape" (h/call wasm/internal-module "_use_shape"
(aget buffer 0) (aget buffer 0)
(aget buffer 1) (aget buffer 1)
(aget buffer 2) (aget buffer 2)
@ -113,7 +111,7 @@
(defn set-parent-id (defn set-parent-id
[id] [id]
(let [buffer (uuid/get-u32 id)] (let [buffer (uuid/get-u32 id)]
(h/call internal-module "_set_parent" (h/call wasm/internal-module "_set_parent"
(aget buffer 0) (aget buffer 0)
(aget buffer 1) (aget buffer 1)
(aget buffer 2) (aget buffer 2)
@ -121,19 +119,19 @@
(defn set-shape-clip-content (defn set-shape-clip-content
[clip-content] [clip-content]
(h/call internal-module "_set_shape_clip_content" clip-content)) (h/call wasm/internal-module "_set_shape_clip_content" clip-content))
(defn set-shape-type (defn set-shape-type
[type] [type]
(h/call internal-module "_set_shape_type" (sr/translate-shape-type type))) (h/call wasm/internal-module "_set_shape_type" (sr/translate-shape-type type)))
(defn set-masked (defn set-masked
[masked] [masked]
(h/call internal-module "_set_shape_masked_group" masked)) (h/call wasm/internal-module "_set_shape_masked_group" masked))
(defn set-shape-selrect (defn set-shape-selrect
[selrect] [selrect]
(h/call internal-module "_set_shape_selrect" (h/call wasm/internal-module "_set_shape_selrect"
(dm/get-prop selrect :x1) (dm/get-prop selrect :x1)
(dm/get-prop selrect :y1) (dm/get-prop selrect :y1)
(dm/get-prop selrect :x2) (dm/get-prop selrect :x2)
@ -141,7 +139,7 @@
(defn set-shape-transform (defn set-shape-transform
[transform] [transform]
(h/call internal-module "_set_shape_transform" (h/call wasm/internal-module "_set_shape_transform"
(dm/get-prop transform :a) (dm/get-prop transform :a)
(dm/get-prop transform :b) (dm/get-prop transform :b)
(dm/get-prop transform :c) (dm/get-prop transform :c)
@ -151,17 +149,17 @@
(defn set-shape-rotation (defn set-shape-rotation
[rotation] [rotation]
(h/call internal-module "_set_shape_rotation" rotation)) (h/call wasm/internal-module "_set_shape_rotation" rotation))
(defn set-shape-children (defn set-shape-children
[shape-ids] [shape-ids]
(let [ENTRY-SIZE 16 (let [ENTRY-SIZE 16
ptr ptr
(h/call internal-module "_alloc_bytes" (* ENTRY-SIZE (count shape-ids))) (h/call wasm/internal-module "_alloc_bytes" (* ENTRY-SIZE (count shape-ids)))
heap heap
(js/Uint8Array. (js/Uint8Array.
(.-buffer (gobj/get ^js internal-module "HEAPU8")) (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8"))
ptr ptr
(* ENTRY-SIZE (count shape-ids)))] (* ENTRY-SIZE (count shape-ids)))]
@ -172,89 +170,10 @@
(.set heap (sr/uuid->u8 id) offset) (.set heap (sr/uuid->u8 id) offset)
(recur (rest entries) (+ offset ENTRY-SIZE))))) (recur (rest entries) (+ offset ENTRY-SIZE)))))
(h/call internal-module "_set_children"))) (h/call wasm/internal-module "_set_children")))
(defn- get-string-length [string] (+ (count string) 1)) (defn- get-string-length [string] (+ (count string) 1))
(def ^:private fonts
(l/derived :fonts st/state))
(defn- google-font-id->uuid
[font-id]
(let [font (get @fonts/fontsdb font-id)]
(:uuid font)))
(defn ^:private font->ttf-id [font-uuid font-style font-weight]
(if (str/starts-with? font-uuid "gfont-")
font-uuid
(let [matching-font (d/seek (fn [[_ font]]
(and (= (:font-id font) font-uuid)
(= (:font-style font) font-style)
(= (:font-weight font) font-weight)))
(seq @fonts))]
(when matching-font
(:ttf-file-id (second matching-font))))))
;; IMPORTANT: It should be noted that only TTF fonts can be stored.
(defn- store-font-buffer
[font-data font-array-buffer]
(let [id-buffer (:family-id-buffer font-data)
size (.-byteLength font-array-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. font-array-buffer))
(h/call internal-module "_store_font"
(aget id-buffer 0)
(aget id-buffer 1)
(aget id-buffer 2)
(aget id-buffer 3)
(:weight font-data)
(:style font-data))
true))
(defn- store-font-url
[font-data font-url]
(->> (http/send! {:method :get
:uri font-url
:response-type :blob})
(rx/map :body)
(rx/mapcat wapi/read-file-as-array-buffer)
(rx/map (fn [array-buffer] (store-font-buffer font-data array-buffer)))))
(defn- google-font-ttf-url
[font-id font-variant-id]
(let [font (get @fonts/fontsdb font-id)
variant (d/seek (fn [variant]
(= (:id variant) font-variant-id))
(:variants font))
file (-> (:ttf-url variant)
(str/replace "http://fonts.gstatic.com/s/" (u/join cf/public-uri "/internal/gfonts/font/")))]
file))
(defn- font-id->ttf-url
[font-id font-variant-id]
(if (str/starts-with? font-id "gfont-")
;; if font-id is a google font (starts with gfont-), we need to get the ttf url from Google Fonts API.
(google-font-ttf-url font-id font-variant-id)
;; otherwise, we return the font from our public-uri
(str (u/join cf/public-uri "assets/by-id/" font-id))))
(defn- store-font-id
[font-data asset-id]
(when asset-id
(let [uri (font-id->ttf-url asset-id (:font-variant-id font-data))
id-buffer (uuid/get-u32 (:wasm-id font-data))
font-data (assoc font-data :family-id-buffer id-buffer)
font-stored? (not= 0 (h/call internal-module "_is_font_uploaded"
(aget id-buffer 0)
(aget id-buffer 1)
(aget id-buffer 2)
(aget id-buffer 3)
(:weight font-data)
(:style font-data)))]
(when-not font-stored? (store-font-url font-data uri)))))
(defn- store-image (defn- store-image
[id] [id]
@ -268,11 +187,11 @@
(rx/mapcat wapi/read-file-as-array-buffer) (rx/mapcat wapi/read-file-as-array-buffer)
(rx/map (fn [image] (rx/map (fn [image]
(let [image-size (.-byteLength image) (let [image-size (.-byteLength image)
image-ptr (h/call internal-module "_alloc_bytes" image-size) image-ptr (h/call wasm/internal-module "_alloc_bytes" image-size)
heap (gobj/get ^js internal-module "HEAPU8") heap (gobj/get ^js wasm/internal-module "HEAPU8")
mem (js/Uint8Array. (.-buffer heap) image-ptr image-size)] mem (js/Uint8Array. (.-buffer heap) image-ptr image-size)]
(.set mem (js/Uint8Array. image)) (.set mem (js/Uint8Array. image))
(h/call internal-module "_store_image" (h/call wasm/internal-module "_store_image"
(aget buffer 0) (aget buffer 0)
(aget buffer 1) (aget buffer 1)
(aget buffer 2) (aget buffer 2)
@ -281,7 +200,7 @@
(defn set-shape-fills (defn set-shape-fills
[fills] [fills]
(h/call internal-module "_clear_shape_fills") (h/call wasm/internal-module "_clear_shape_fills")
(keep (fn [fill] (keep (fn [fill]
(let [opacity (or (:fill-opacity fill) 1.0) (let [opacity (or (:fill-opacity fill) 1.0)
color (:fill-color fill) color (:fill-color fill)
@ -290,23 +209,23 @@
(cond (cond
(some? color) (some? color)
(let [rgba (rgba-from-hex color opacity)] (let [rgba (rgba-from-hex color opacity)]
(h/call internal-module "_add_shape_solid_fill" rgba)) (h/call wasm/internal-module "_add_shape_solid_fill" rgba))
(some? gradient) (some? gradient)
(let [stops (:stops gradient) (let [stops (:stops gradient)
n-stops (count stops) n-stops (count stops)
mem-size (* 5 n-stops) mem-size (* 5 n-stops)
stops-ptr (h/call internal-module "_alloc_bytes" mem-size) stops-ptr (h/call wasm/internal-module "_alloc_bytes" mem-size)
heap (gobj/get ^js internal-module "HEAPU8") heap (gobj/get ^js wasm/internal-module "HEAPU8")
mem (js/Uint8Array. (.-buffer heap) stops-ptr mem-size)] mem (js/Uint8Array. (.-buffer heap) stops-ptr mem-size)]
(if (= (:type gradient) :linear) (if (= (:type gradient) :linear)
(h/call internal-module "_add_shape_linear_fill" (h/call wasm/internal-module "_add_shape_linear_fill"
(:start-x gradient) (:start-x gradient)
(:start-y gradient) (:start-y gradient)
(:end-x gradient) (:end-x gradient)
(:end-y gradient) (:end-y gradient)
opacity) opacity)
(h/call internal-module "_add_shape_radial_fill" (h/call wasm/internal-module "_add_shape_radial_fill"
(:start-x gradient) (:start-x gradient)
(:start-y gradient) (:start-y gradient)
(:end-x gradient) (:end-x gradient)
@ -318,13 +237,13 @@
offset (:offset stop)] offset (:offset stop)]
[r g b a (* 100 offset)])) [r g b a (* 100 offset)]))
stops))))) stops)))))
(h/call internal-module "_add_shape_fill_stops")) (h/call wasm/internal-module "_add_shape_fill_stops"))
(some? image) (some? image)
(let [id (dm/get-prop image :id) (let [id (dm/get-prop image :id)
buffer (uuid/get-u32 id) buffer (uuid/get-u32 id)
cached-image? (h/call internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))] cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
(h/call internal-module "_add_shape_image_fill" (h/call wasm/internal-module "_add_shape_image_fill"
(aget buffer 0) (aget buffer 0)
(aget buffer 1) (aget buffer 1)
(aget buffer 2) (aget buffer 2)
@ -338,7 +257,7 @@
(defn set-shape-strokes (defn set-shape-strokes
[strokes] [strokes]
(h/call internal-module "_clear_shape_strokes") (h/call wasm/internal-module "_clear_shape_strokes")
(keep (fn [stroke] (keep (fn [stroke]
(let [opacity (or (:stroke-opacity stroke) 1.0) (let [opacity (or (:stroke-opacity stroke) 1.0)
color (:stroke-color stroke) color (:stroke-color stroke)
@ -350,26 +269,26 @@
cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap) cap-start (-> stroke :stroke-cap-start sr/translate-stroke-cap)
cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap)] cap-end (-> stroke :stroke-cap-end sr/translate-stroke-cap)]
(case align (case align
:inner (h/call internal-module "_add_shape_inner_stroke" width style cap-start cap-end) :inner (h/call wasm/internal-module "_add_shape_inner_stroke" width style cap-start cap-end)
:outer (h/call internal-module "_add_shape_outer_stroke" width style cap-start cap-end) :outer (h/call wasm/internal-module "_add_shape_outer_stroke" width style cap-start cap-end)
(h/call internal-module "_add_shape_center_stroke" width style cap-start cap-end)) (h/call wasm/internal-module "_add_shape_center_stroke" width style cap-start cap-end))
(cond (cond
(some? gradient) (some? gradient)
(let [stops (:stops gradient) (let [stops (:stops gradient)
n-stops (count stops) n-stops (count stops)
mem-size (* 5 n-stops) mem-size (* 5 n-stops)
stops-ptr (h/call internal-module "_alloc_bytes" mem-size) stops-ptr (h/call wasm/internal-module "_alloc_bytes" mem-size)
heap (gobj/get ^js internal-module "HEAPU8") heap (gobj/get ^js wasm/internal-module "HEAPU8")
mem (js/Uint8Array. (.-buffer heap) stops-ptr mem-size)] mem (js/Uint8Array. (.-buffer heap) stops-ptr mem-size)]
(if (= (:type gradient) :linear) (if (= (:type gradient) :linear)
(h/call internal-module "_add_shape_stroke_linear_fill" (h/call wasm/internal-module "_add_shape_stroke_linear_fill"
(:start-x gradient) (:start-x gradient)
(:start-y gradient) (:start-y gradient)
(:end-x gradient) (:end-x gradient)
(:end-y gradient) (:end-y gradient)
opacity) opacity)
(h/call internal-module "_add_shape_stroke_radial_fill" (h/call wasm/internal-module "_add_shape_stroke_radial_fill"
(:start-x gradient) (:start-x gradient)
(:start-y gradient) (:start-y gradient)
(:end-x gradient) (:end-x gradient)
@ -381,13 +300,13 @@
offset (:offset stop)] offset (:offset stop)]
[r g b a (* 100 offset)])) [r g b a (* 100 offset)]))
stops))))) stops)))))
(h/call internal-module "_add_shape_stroke_stops")) (h/call wasm/internal-module "_add_shape_stroke_stops"))
(some? image) (some? image)
(let [id (dm/get-prop image :id) (let [id (dm/get-prop image :id)
buffer (uuid/get-u32 id) buffer (uuid/get-u32 id)
cached-image? (h/call internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))] cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))]
(h/call internal-module "_add_shape_image_stroke" (h/call wasm/internal-module "_add_shape_image_stroke"
(aget buffer 0) (aget buffer 0)
(aget buffer 1) (aget buffer 1)
(aget buffer 2) (aget buffer 2)
@ -400,7 +319,7 @@
(some? color) (some? color)
(let [rgba (rgba-from-hex color opacity)] (let [rgba (rgba-from-hex color opacity)]
(h/call internal-module "_add_shape_stroke_solid_fill" rgba))))) (h/call wasm/internal-module "_add_shape_stroke_solid_fill" rgba)))))
strokes)) strokes))
@ -413,25 +332,25 @@
(merge style)) (merge style))
str (sr/serialize-path-attrs attrs) str (sr/serialize-path-attrs attrs)
size (count str) size (count str)
ptr (h/call internal-module "_alloc_bytes" size)] ptr (h/call wasm/internal-module "_alloc_bytes" size)]
(h/call internal-module "stringToUTF8" str ptr size) (h/call wasm/internal-module "stringToUTF8" str ptr size)
(h/call internal-module "_set_shape_path_attrs" (count attrs)))) (h/call wasm/internal-module "_set_shape_path_attrs" (count attrs))))
(defn set-shape-path-content (defn set-shape-path-content
[content] [content]
(let [pdata (path/path-data content) (let [pdata (path/path-data content)
size (* (count pdata) path/SEGMENT-BYTE-SIZE) size (* (count pdata) path/SEGMENT-BYTE-SIZE)
offset (h/call internal-module "_alloc_bytes" size) offset (h/call wasm/internal-module "_alloc_bytes" size)
heap (gobj/get ^js internal-module "HEAPU8")] heap (gobj/get ^js wasm/internal-module "HEAPU8")]
(path/-write-to pdata (.-buffer heap) offset) (path/-write-to pdata (.-buffer heap) offset)
(h/call internal-module "_set_shape_path_content"))) (h/call wasm/internal-module "_set_shape_path_content")))
(defn set-shape-svg-raw-content (defn set-shape-svg-raw-content
[content] [content]
(let [size (get-string-length content) (let [size (get-string-length content)
ptr (h/call internal-module "_alloc_bytes" size)] ptr (h/call wasm/internal-module "_alloc_bytes" size)]
(h/call internal-module "stringToUTF8" content ptr size) (h/call wasm/internal-module "stringToUTF8" content ptr size)
(h/call internal-module "_set_shape_svg_raw_content"))) (h/call wasm/internal-module "_set_shape_svg_raw_content")))
@ -439,31 +358,31 @@
[blend-mode] [blend-mode]
;; These values correspond to skia::BlendMode representation ;; These values correspond to skia::BlendMode representation
;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html ;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html
(h/call internal-module "_set_shape_blend_mode" (sr/translate-blend-mode blend-mode))) (h/call wasm/internal-module "_set_shape_blend_mode" (sr/translate-blend-mode blend-mode)))
(defn set-shape-opacity (defn set-shape-opacity
[opacity] [opacity]
(h/call internal-module "_set_shape_opacity" (or opacity 1))) (h/call wasm/internal-module "_set_shape_opacity" (or opacity 1)))
(defn set-constraints-h (defn set-constraints-h
[constraint] [constraint]
(when constraint (when constraint
(h/call internal-module "_set_shape_constraint_h" (sr/translate-constraint-h constraint)))) (h/call wasm/internal-module "_set_shape_constraint_h" (sr/translate-constraint-h constraint))))
(defn set-constraints-v (defn set-constraints-v
[constraint] [constraint]
(when constraint (when constraint
(h/call internal-module "_set_shape_constraint_v" (sr/translate-constraint-v constraint)))) (h/call wasm/internal-module "_set_shape_constraint_v" (sr/translate-constraint-v constraint))))
(defn set-shape-hidden (defn set-shape-hidden
[hidden] [hidden]
(h/call internal-module "_set_shape_hidden" hidden)) (h/call wasm/internal-module "_set_shape_hidden" hidden))
(defn set-shape-bool-type (defn set-shape-bool-type
[bool-type] [bool-type]
(h/call internal-module "_set_shape_bool_type" (sr/translate-bool-type bool-type))) (h/call wasm/internal-module "_set_shape_bool_type" (sr/translate-bool-type bool-type)))
(defn- translate-blur-type (defn- translate-blur-type
[blur-type] [blur-type]
@ -476,7 +395,7 @@
(let [type (-> blur :type sr/translate-blur-type) (let [type (-> blur :type sr/translate-blur-type)
hidden (:hidden blur) hidden (:hidden blur)
value (:value blur)] value (:value blur)]
(h/call internal-module "_set_shape_blur" type hidden value))) (h/call wasm/internal-module "_set_shape_blur" type hidden value)))
(defn set-shape-corners (defn set-shape-corners
[corners] [corners]
@ -484,7 +403,7 @@
r2 (or (get corners 1) 0) r2 (or (get corners 1) 0)
r3 (or (get corners 2) 0) r3 (or (get corners 2) 0)
r4 (or (get corners 3) 0)] r4 (or (get corners 3) 0)]
(h/call internal-module "_set_shape_corners" r1 r2 r3 r4))) (h/call wasm/internal-module "_set_shape_corners" r1 r2 r3 r4)))
(defn set-flex-layout (defn set-flex-layout
[shape] [shape]
@ -504,7 +423,7 @@
padding-right (or (dm/get-prop padding :p2) 0) padding-right (or (dm/get-prop padding :p2) 0)
padding-bottom (or (dm/get-prop padding :p3) 0) padding-bottom (or (dm/get-prop padding :p3) 0)
padding-left (or (dm/get-prop padding :p4) 0)] padding-left (or (dm/get-prop padding :p4) 0)]
(h/call internal-module (h/call wasm/internal-module
"_set_flex_layout_data" "_set_flex_layout_data"
dir dir
row-gap row-gap
@ -538,7 +457,7 @@
padding-bottom (or (dm/get-prop padding :p3) 0) padding-bottom (or (dm/get-prop padding :p3) 0)
padding-left (or (dm/get-prop padding :p4) 0)] padding-left (or (dm/get-prop padding :p4) 0)]
(h/call internal-module (h/call wasm/internal-module
"_set_grid_layout_data" "_set_grid_layout_data"
dir dir
row-gap row-gap
@ -555,11 +474,11 @@
;; Send Rows ;; Send Rows
(let [entry-size 5 (let [entry-size 5
entries (:layout-grid-rows shape) entries (:layout-grid-rows shape)
ptr (h/call internal-module "_alloc_bytes" (* entry-size (count entries))) ptr (h/call wasm/internal-module "_alloc_bytes" (* entry-size (count entries)))
heap heap
(js/Uint8Array. (js/Uint8Array.
(.-buffer (gobj/get ^js internal-module "HEAPU8")) (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8"))
ptr ptr
(* entry-size (count entries)))] (* entry-size (count entries)))]
(loop [entries (seq entries) (loop [entries (seq entries)
@ -569,16 +488,16 @@
(.set heap (sr/u8 (sr/translate-grid-track-type type)) (+ offset 0)) (.set heap (sr/u8 (sr/translate-grid-track-type type)) (+ offset 0))
(.set heap (sr/f32->u8 value) (+ offset 1)) (.set heap (sr/f32->u8 value) (+ offset 1))
(recur (rest entries) (+ offset entry-size))))) (recur (rest entries) (+ offset entry-size)))))
(h/call internal-module "_set_grid_rows")) (h/call wasm/internal-module "_set_grid_rows"))
;; Send Columns ;; Send Columns
(let [entry-size 5 (let [entry-size 5
entries (:layout-grid-columns shape) entries (:layout-grid-columns shape)
ptr (h/call internal-module "_alloc_bytes" (* entry-size (count entries))) ptr (h/call wasm/internal-module "_alloc_bytes" (* entry-size (count entries)))
heap heap
(js/Uint8Array. (js/Uint8Array.
(.-buffer (gobj/get ^js internal-module "HEAPU8")) (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8"))
ptr ptr
(* entry-size (count entries)))] (* entry-size (count entries)))]
(loop [entries (seq entries) (loop [entries (seq entries)
@ -588,16 +507,16 @@
(.set heap (sr/u8 (sr/translate-grid-track-type type)) (+ offset 0)) (.set heap (sr/u8 (sr/translate-grid-track-type type)) (+ offset 0))
(.set heap (sr/f32->u8 value) (+ offset 1)) (.set heap (sr/f32->u8 value) (+ offset 1))
(recur (rest entries) (+ offset entry-size))))) (recur (rest entries) (+ offset entry-size)))))
(h/call internal-module "_set_grid_columns")) (h/call wasm/internal-module "_set_grid_columns"))
;; Send cells ;; Send cells
(let [entry-size 37 (let [entry-size 37
entries (-> shape :layout-grid-cells vals) entries (-> shape :layout-grid-cells vals)
ptr (h/call internal-module "_alloc_bytes" (* entry-size (count entries))) ptr (h/call wasm/internal-module "_alloc_bytes" (* entry-size (count entries)))
heap heap
(js/Uint8Array. (js/Uint8Array.
(.-buffer (gobj/get ^js internal-module "HEAPU8")) (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8"))
ptr ptr
(* entry-size (count entries)))] (* entry-size (count entries)))]
@ -641,7 +560,7 @@
(recur (rest entries) (+ offset entry-size))))) (recur (rest entries) (+ offset entry-size)))))
(h/call internal-module "_set_grid_cells"))) (h/call wasm/internal-module "_set_grid_cells")))
(defn set-layout-child (defn set-layout-child
[shape] [shape]
@ -665,7 +584,7 @@
has-min-w (some? min-w) has-min-w (some? min-w)
is-absolute (boolean (dm/get-prop shape :layout-item-absolute)) is-absolute (boolean (dm/get-prop shape :layout-item-absolute))
z-index (-> (dm/get-prop shape :layout-item-z-index) (or 0))] z-index (-> (dm/get-prop shape :layout-item-z-index) (or 0))]
(h/call internal-module (h/call wasm/internal-module
"_set_layout_child_data" "_set_layout_child_data"
margin-top margin-top
margin-right margin-right
@ -688,7 +607,7 @@
(defn set-shape-shadows (defn set-shape-shadows
[shadows] [shadows]
(h/call internal-module "_clear_shape_shadows") (h/call wasm/internal-module "_clear_shape_shadows")
(let [total-shadows (count shadows)] (let [total-shadows (count shadows)]
(loop [index 0] (loop [index 0]
(when (< index total-shadows) (when (< index total-shadows)
@ -701,80 +620,34 @@
y (dm/get-prop shadow :offset-y) y (dm/get-prop shadow :offset-y)
spread (dm/get-prop shadow :spread) spread (dm/get-prop shadow :spread)
style (dm/get-prop shadow :style)] style (dm/get-prop shadow :style)]
(h/call internal-module "_add_shape_shadow" rgba blur spread x y (sr/translate-shadow-style style) hidden) (h/call wasm/internal-module "_add_shape_shadow" rgba blur spread x y (sr/translate-shadow-style style) hidden)
(recur (inc index))))))) (recur (inc index)))))))
(defn utf8->buffer [text] (defn utf8->buffer [text]
(let [encoder (js/TextEncoder.)] (let [encoder (js/TextEncoder.)]
(.encode encoder text))) (.encode encoder text)))
(defn- serialize-font-style
[font-style]
(case font-style
"normal" 0
"regular" 0
"italic" 1
0))
(defn- serialize-font-id
[font-id]
(let [google-font? (str/starts-with? font-id "gfont-")]
(if google-font?
(uuid/get-u32 (google-font-id->uuid font-id))
(let [no-prefix (subs font-id (inc (str/index-of font-id "-")))
as-uuid (uuid/uuid no-prefix)]
(uuid/get-u32 as-uuid)))))
(defn- serialize-font-weight
[font-weight]
(js/Number font-weight))
(defn- add-text-leaf [leaf] (defn- add-text-leaf [leaf]
(let [text (dm/get-prop leaf :text) (let [text (dm/get-prop leaf :text)
font-id (serialize-font-id (dm/get-prop leaf :font-id)) font-id (f/serialize-font-id (dm/get-prop leaf :font-id))
font-style (serialize-font-style (dm/get-prop leaf :font-style)) font-style (f/serialize-font-style (dm/get-prop leaf :font-style))
font-weight (serialize-font-weight (dm/get-prop leaf :font-weight)) font-weight (f/serialize-font-weight (dm/get-prop leaf :font-weight))
font-size (js/Number (dm/get-prop leaf :font-size)) font-size (js/Number (dm/get-prop leaf :font-size))
buffer (utf8->buffer text) buffer (utf8->buffer text)
size (.-byteLength buffer) size (.-byteLength buffer)
ptr (h/call internal-module "_alloc_bytes" size) ptr (h/call wasm/internal-module "_alloc_bytes" size)
heap (gobj/get ^js internal-module "HEAPU8") heap (gobj/get ^js wasm/internal-module "HEAPU8")
mem (js/Uint8Array. (.-buffer heap) ptr size)] mem (js/Uint8Array. (.-buffer heap) ptr size)]
(.set mem buffer) (.set mem buffer)
(h/call internal-module "_add_text_leaf" (h/call wasm/internal-module "_add_text_leaf"
(aget font-id 0) (aget font-id 0)
(aget font-id 1) (aget font-id 1)
(aget font-id 2) (aget font-id 2)
(aget font-id 3) (aget font-id 3)
font-weight font-style font-size))) font-weight font-style font-size)))
(defn- store-fonts
[fonts]
(keep (fn [font]
(let [font-id (dm/get-prop font :font-id)
google-font? (str/starts-with? font-id "gfont-")
font-variant-id (dm/get-prop font :font-variant-id)
variant-parts (str/split font-variant-id #"\-")
variant-parts (if (= (count variant-parts) 1)
(conj variant-parts "400")
variant-parts)
style (first variant-parts)
weight (serialize-font-weight (last variant-parts))
font-id (if google-font?
font-id
(uuid/uuid (subs font-id (inc (str/index-of font-id "-")))))
asset-id (font->ttf-id font-id style weight)
wasm-id (if google-font? (google-font-id->uuid font-id) font-id)
font-data {:family-id font-id
:wasm-id wasm-id
:font-variant-id font-variant-id
:style (serialize-font-style style)
:weight weight}]
(store-font-id font-data asset-id))) fonts))
(defn set-shape-text-content [content] (defn set-shape-text-content [content]
(h/call internal-module "_clear_shape_text") (h/call wasm/internal-module "_clear_shape_text")
(let [paragraph-set (first (dm/get-prop content :children)) (let [paragraph-set (first (dm/get-prop content :children))
paragraphs (dm/get-prop paragraph-set :children) paragraphs (dm/get-prop paragraph-set :children)
total-paragraphs (count paragraphs) total-paragraphs (count paragraphs)
@ -785,25 +658,25 @@
(let [paragraph (nth paragraphs index) (let [paragraph (nth paragraphs index)
leaves (dm/get-prop paragraph :children) leaves (dm/get-prop paragraph :children)
total-leaves (count leaves)] total-leaves (count leaves)]
(h/call internal-module "_add_text_paragraph") (h/call wasm/internal-module "_add_text_paragraph")
(loop [index-leaves 0] (loop [index-leaves 0]
(when (< index-leaves total-leaves) (when (< index-leaves total-leaves)
(let [leaf (nth leaves index-leaves)] (let [leaf (nth leaves index-leaves)]
(add-text-leaf leaf) (add-text-leaf leaf)
(recur (inc index-leaves)))))) (recur (inc index-leaves))))))
(recur (inc index)))) (recur (inc index))))
(store-fonts fonts))) (f/store-fonts fonts)))
(defn set-view-box (defn set-view-box
[zoom vbox] [zoom vbox]
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox))) (h/call wasm/internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
(render nil)) (render nil))
(defn clear-drawing-cache [] (defn clear-drawing-cache []
(h/call internal-module "_clear_drawing_cache")) (h/call wasm/internal-module "_clear_drawing_cache"))
(defn update-shape-tiles [] (defn update-shape-tiles []
(h/call internal-module "_update_shape_tiles")) (h/call wasm/internal-module "_update_shape_tiles"))
(defn set-object (defn set-object
[objects shape] [objects shape]
@ -927,11 +800,11 @@
(defn propagate-modifiers (defn propagate-modifiers
[entries] [entries]
(let [entry-size 40 (let [entry-size 40
ptr (h/call internal-module "_alloc_bytes" (* entry-size (count entries))) ptr (h/call wasm/internal-module "_alloc_bytes" (* entry-size (count entries)))
heap heap
(js/Uint8Array. (js/Uint8Array.
(.-buffer (gobj/get ^js internal-module "HEAPU8")) (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8"))
ptr ptr
(* entry-size (count entries)))] (* entry-size (count entries)))]
@ -943,35 +816,35 @@
(.set heap (sr/matrix->u8 transform) (+ offset 16)) (.set heap (sr/matrix->u8 transform) (+ offset 16))
(recur (rest entries) (+ offset entry-size))))) (recur (rest entries) (+ offset entry-size)))))
(let [result-ptr (h/call internal-module "_propagate_modifiers") (let [result-ptr (h/call wasm/internal-module "_propagate_modifiers")
heap (js/DataView. (.-buffer (gobj/get ^js internal-module "HEAPU8"))) heap (js/DataView. (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8")))
len (.getUint32 heap result-ptr true) len (.getUint32 heap result-ptr true)
result result
(->> (range 0 len) (->> (range 0 len)
(mapv #(data->entry heap (+ result-ptr 4 (* % entry-size)))))] (mapv #(data->entry heap (+ result-ptr 4 (* % entry-size)))))]
(h/call internal-module "_free_bytes") (h/call wasm/internal-module "_free_bytes")
result))) result)))
(defn set-canvas-background (defn set-canvas-background
[background] [background]
(let [rgba (rgba-from-hex background 1)] (let [rgba (rgba-from-hex background 1)]
(h/call internal-module "_set_canvas_background" rgba) (h/call wasm/internal-module "_set_canvas_background" rgba)
(request-render "set-canvas-background"))) (request-render "set-canvas-background")))
(defn set-modifiers (defn set-modifiers
[modifiers] [modifiers]
(if (empty? modifiers) (if (empty? modifiers)
(h/call internal-module "_clean_modifiers") (h/call wasm/internal-module "_clean_modifiers")
(let [ENTRY-SIZE 40 (let [ENTRY-SIZE 40
ptr ptr
(h/call internal-module "_alloc_bytes" (* ENTRY-SIZE (count modifiers))) (h/call wasm/internal-module "_alloc_bytes" (* ENTRY-SIZE (count modifiers)))
heap heap
(js/Uint8Array. (js/Uint8Array.
(.-buffer (gobj/get ^js internal-module "HEAPU8")) (.-buffer (gobj/get ^js wasm/internal-module "HEAPU8"))
ptr ptr
(* ENTRY-SIZE (count modifiers)))] (* ENTRY-SIZE (count modifiers)))]
@ -983,15 +856,15 @@
(.set heap (sr/matrix->u8 transform) (+ offset 16)) (.set heap (sr/matrix->u8 transform) (+ offset 16))
(recur (rest entries) (+ offset ENTRY-SIZE))))) (recur (rest entries) (+ offset ENTRY-SIZE)))))
(h/call internal-module "_set_modifiers") (h/call wasm/internal-module "_set_modifiers")
(request-render "set-modifiers")))) (request-render "set-modifiers"))))
(defn initialize (defn initialize
[base-objects zoom vbox background] [base-objects zoom vbox background]
(let [rgba (rgba-from-hex background 1)] (let [rgba (rgba-from-hex background 1)]
(h/call internal-module "_set_canvas_background" rgba) (h/call wasm/internal-module "_set_canvas_background" rgba)
(h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox))) (h/call wasm/internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox)))
(set-objects base-objects))) (set-objects base-objects)))
(def ^:private canvas-options (def ^:private canvas-options
@ -1003,7 +876,7 @@
(defn resize-viewbox (defn resize-viewbox
[width height] [width height]
(h/call internal-module "_resize_viewbox" width height)) (h/call wasm/internal-module "_resize_viewbox" width height))
(defn- debug-flags (defn- debug-flags
[] []
@ -1013,7 +886,7 @@
(defn assign-canvas (defn assign-canvas
[canvas] [canvas]
(let [gl (unchecked-get internal-module "GL") (let [gl (unchecked-get wasm/internal-module "GL")
flags (debug-flags) flags (debug-flags)
context (.getContext ^js canvas "webgl2" canvas-options) context (.getContext ^js canvas "webgl2" canvas-options)
;; Register the context with emscripten ;; Register the context with emscripten
@ -1024,15 +897,15 @@
(.getExtension context "WEBGL_debug_renderer_info") (.getExtension context "WEBGL_debug_renderer_info")
;; Initialize Wasm Render Engine ;; Initialize Wasm Render Engine
(h/call internal-module "_init" (/ (.-width ^js canvas) dpr) (/ (.-height ^js canvas) dpr)) (h/call wasm/internal-module "_init" (/ (.-width ^js canvas) dpr) (/ (.-height ^js canvas) dpr))
(h/call internal-module "_set_render_options" flags dpr)) (h/call wasm/internal-module "_set_render_options" flags dpr))
(set! (.-width canvas) (* dpr (.-clientWidth ^js canvas))) (set! (.-width canvas) (* dpr (.-clientWidth ^js canvas)))
(set! (.-height canvas) (* dpr (.-clientHeight ^js canvas)))) (set! (.-height canvas) (* dpr (.-clientHeight ^js canvas))))
(defn clear-canvas (defn clear-canvas
[] []
;; TODO: perform corresponding cleaning ;; TODO: perform corresponding cleaning
(h/call internal-module "_clean_up")) (h/call wasm/internal-module "_clean_up"))
(defonce module (defonce module
(delay (delay
@ -1043,7 +916,7 @@
(let [default (unchecked-get module "default")] (let [default (unchecked-get module "default")]
(default)))) (default))))
(p/fmap (fn [module] (p/fmap (fn [module]
(set! internal-module module) (set! wasm/internal-module module)
true)) true))
(p/merr (fn [cause] (p/merr (fn [cause]
(js/console.error cause) (js/console.error cause)

View file

@ -0,0 +1,148 @@
;; 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.render-wasm.api.fonts
(:require
[app.common.data :as d]
[app.common.data.macros :as dm]
[app.common.uuid :as uuid]
[app.config :as cf]
[app.main.fonts :as fonts]
[app.main.store :as st]
[app.render-wasm.helpers :as h]
[app.render-wasm.wasm :as wasm]
[app.util.http :as http]
[app.util.webapi :as wapi]
[beicon.v2.core :as rx]
[cuerdas.core :as str]
[goog.object :as gobj]
[lambdaisland.uri :as u]
[okulary.core :as l]))
(def ^:private fonts
(l/derived :fonts st/state))
(defn- google-font-id->uuid
[font-id]
(let [font (get @fonts/fontsdb font-id)]
(:uuid font)))
(defn ^:private font->ttf-id [font-uuid font-style font-weight]
(if (str/starts-with? font-uuid "gfont-")
font-uuid
(let [matching-font (d/seek (fn [[_ font]]
(and (= (:font-id font) font-uuid)
(= (:font-style font) font-style)
(= (:font-weight font) font-weight)))
(seq @fonts))]
(when matching-font
(:ttf-file-id (second matching-font))))))
;; IMPORTANT: It should be noted that only TTF fonts can be stored.
(defn- store-font-buffer
[font-data font-array-buffer]
(let [id-buffer (:family-id-buffer font-data)
size (.-byteLength font-array-buffer)
ptr (h/call wasm/internal-module "_alloc_bytes" size)
heap (gobj/get ^js wasm/internal-module "HEAPU8")
mem (js/Uint8Array. (.-buffer heap) ptr size)]
(.set mem (js/Uint8Array. font-array-buffer))
(h/call wasm/internal-module "_store_font"
(aget id-buffer 0)
(aget id-buffer 1)
(aget id-buffer 2)
(aget id-buffer 3)
(:weight font-data)
(:style font-data))
true))
(defn- store-font-url
[font-data font-url]
(->> (http/send! {:method :get
:uri font-url
:response-type :blob})
(rx/map :body)
(rx/mapcat wapi/read-file-as-array-buffer)
(rx/map (fn [array-buffer] (store-font-buffer font-data array-buffer)))))
(defn- google-font-ttf-url
[font-id font-variant-id]
(let [font (get @fonts/fontsdb font-id)
variant (d/seek (fn [variant]
(= (:id variant) font-variant-id))
(:variants font))
file (-> (:ttf-url variant)
(str/replace "http://fonts.gstatic.com/s/" (u/join cf/public-uri "/internal/gfonts/font/")))]
file))
(defn- font-id->ttf-url
[font-id font-variant-id]
(if (str/starts-with? font-id "gfont-")
;; if font-id is a google font (starts with gfont-), we need to get the ttf url from Google Fonts API.
(google-font-ttf-url font-id font-variant-id)
;; otherwise, we return the font from our public-uri
(str (u/join cf/public-uri "assets/by-id/" font-id))))
(defn- store-font-id
[font-data asset-id]
(when asset-id
(let [uri (font-id->ttf-url asset-id (:font-variant-id font-data))
id-buffer (uuid/get-u32 (:wasm-id font-data))
font-data (assoc font-data :family-id-buffer id-buffer)
font-stored? (not= 0 (h/call wasm/internal-module "_is_font_uploaded"
(aget id-buffer 0)
(aget id-buffer 1)
(aget id-buffer 2)
(aget id-buffer 3)
(:weight font-data)
(:style font-data)))]
(when-not font-stored? (store-font-url font-data uri)))))
(defn serialize-font-style
[font-style]
(case font-style
"normal" 0
"regular" 0
"italic" 1
0))
(defn serialize-font-id
[font-id]
(let [google-font? (str/starts-with? font-id "gfont-")]
(if google-font?
(uuid/get-u32 (google-font-id->uuid font-id))
(let [no-prefix (subs font-id (inc (str/index-of font-id "-")))
as-uuid (uuid/uuid no-prefix)]
(uuid/get-u32 as-uuid)))))
(defn serialize-font-weight
[font-weight]
(js/Number font-weight))
(defn store-fonts
[fonts]
(keep (fn [font]
(let [font-id (dm/get-prop font :font-id)
google-font? (str/starts-with? font-id "gfont-")
font-variant-id (dm/get-prop font :font-variant-id)
variant-parts (str/split font-variant-id #"\-")
variant-parts (if (= (count variant-parts) 1)
(conj variant-parts "400")
variant-parts)
style (first variant-parts)
weight (serialize-font-weight (last variant-parts))
font-id (if google-font?
font-id
(uuid/uuid (subs font-id (inc (str/index-of font-id "-")))))
asset-id (font->ttf-id font-id style weight)
wasm-id (if google-font? (google-font-id->uuid font-id) font-id)
font-data {:family-id font-id
:wasm-id wasm-id
:font-variant-id font-variant-id
:style (serialize-font-style style)
:weight weight}]
(store-font-id font-data asset-id))) fonts))

View file

@ -0,0 +1,4 @@
(ns app.render-wasm.wasm)
(defonce internal-frame-id nil)
(defonce internal-module #js {})