penpot/exporter/src/app/wasm/serialize.cljs
Miguel de Benito Delgado f252439d84
♻️ Factor GL context initialization out of canvas init (#11931)
* ♻️ Factor GL context initialization out of canvas init

- fixes setting of gl-context-handle to be after _init so an exception
  does not leave invalid state behind.
- api.init-canvas-context uses a new webgl.init-context!
- this decouples config from init, so we can reuse it in benchmarks
- some helpers move to the webgl ns

AI-assisted-by: muse-spark-1.3, deepseek-flash, glm-5.3

* 🐛 Release acquired GL context when renderer init fails

- Properly release resources if init fails
- Rethrown exceptions with the original cause
- Fix vacuous check in clear-canvas

AI-assisted-by: muse-spark-1.3, deepseek-flash, glm-5.3

* ✨ Test webgl context init and release

AI-assisted-by: muse-spark, glm-5.3

* 💄 Address review comments

* 💄 Drop `!` from some function names
2026-10-07 18:19:34 +02:00

47 lines
2.1 KiB
Clojure

;; 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.wasm.serialize
"Browser-free shape serialization for the headless exporter: the counterpart
of `app.render-wasm.api/set-object`, which cannot be reused directly because
its namespace pulls React/DOM/store. Only the call sequencing lives here —
every byte layout comes from the shared serializers, so the bytes sent to
WASM are the editor's.
Covers everything except svg-raw. Image bytes and fonts are provisioned
separately by `app.renderer.wasm`."
(:require
[app.common.render-wasm.api.props :as props]
[app.common.render-wasm.helpers :as h]
[app.common.render-wasm.serialize-shape :as serialize-shape]
[app.common.render-wasm.wasm :as wasm]
[app.wasm.text :as text]))
(defn set-shape!
"Serializes a single shape into the WASM design state. The host-independent
properties (base props, children, blur, shadows, svg-attrs, mask, bool-type,
path geometry, grow-type) go through the shared `serialize-shape` — the same
code the workspace's `set-object` uses, so the two can't drift. Only the
host-specific parts are handled here: fills/strokes (image bytes are provisioned
separately) and text content (fonts provisioned separately)."
[shape]
(let [prepared (serialize-shape/serialize-shape shape)
type (:type prepared)]
(props/write-shape-fills! (:fills prepared))
(when-not (= type :group)
(props/write-shape-strokes! (:strokes prepared)))
(when (= type :text)
(text/set-shape-text! (:content prepared)))))
(defn serialize-scene!
"Loads every shape of an `objects` map into the WASM design state. Resets the
shapes pool first so repeated exports don't accumulate into the shared
state. Order is irrelevant: shapes reference each other by id and the tree
is resolved at render time."
[objects]
(h/call wasm/internal-module "_init_shapes_pool" (count objects))
(run! set-shape! (vals objects)))