🐛 Fix scale viewer WASM canvas by devicePixelRatio like workspace

This commit is contained in:
Alejandro Alonso 2026-06-15 11:45:21 +02:00
parent 9d7a8eaeda
commit a01c4e1bad
3 changed files with 53 additions and 26 deletions

View File

@ -12,6 +12,7 @@
[app.render-wasm.wasm :as wasm]
[app.util.dom :as dom]
[app.util.timers :as ts]
[app.util.webapi :as webapi]
[goog.events :as events]
[promesa.core :as p]
[rumext.v2 :as mf]))
@ -30,14 +31,16 @@
(atom {:os-canvas nil
:page-key nil
:canvas-w 0
:canvas-h 0}))
:canvas-h 0
:dpr 1}))
(defn- reset-viewer-snapshot! []
(reset! viewer-snapshot
{:os-canvas nil
:page-key nil
:canvas-w 0
:canvas-h 0}))
:canvas-h 0
:dpr 1}))
(defn- draw-bitmap!
[canvas os-canvas object-id vis-w vis-h finish]
@ -135,9 +138,12 @@
(resolve nil))
vis-w (.-width canvas)
vis-h (.-height canvas)
dpr (wasm.api/get-dpr)
snap @viewer-snapshot
same-page? (and (some? page-key) (identical? page-key (:page-key snap)))
same-size? (and (= vis-w (:canvas-w snap)) (= vis-h (:canvas-h snap)))
same-size? (and (= vis-w (:canvas-w snap))
(= vis-h (:canvas-h snap))
(= dpr (:dpr snap)))
os (:os-canvas snap)
do-render! (fn [os-canvas]
(viewer-do-render! page-objects canvas os-canvas object-id
@ -151,7 +157,7 @@
(do
(when-not same-size?
(wasm.api/resize-offscreen-canvas! os vis-w vis-h)
(swap! viewer-snapshot assoc :canvas-w vis-w :canvas-h vis-h))
(swap! viewer-snapshot assoc :canvas-w vis-w :canvas-h vis-h :dpr dpr))
(do-render! os))
(let [os-canvas (js/OffscreenCanvas. vis-w vis-h)]
(when (wasm.api/initialized?)
@ -162,7 +168,8 @@
{:os-canvas os-canvas
:page-key page-key
:canvas-w vis-w
:canvas-h vis-h})
:canvas-h vis-h
:dpr dpr})
(wasm.api/initialize-viewport
page-objects scale size
:background-opacity 0
@ -192,11 +199,22 @@
(let [key (events/listen section "scroll" (fn [_] (sync!)))]
#(events/unlistenByKey key))))))))
(defn- use-viewer-dpr-key
"Bump a counter when browser zoom changes devicePixelRatio so WASM canvases
are resized like the workspace viewport."
[]
(let [dpr-key (mf/use-state 0)]
(mf/use-effect
(mf/deps [])
(fn []
(webapi/on-dpr-change (fn [_] (swap! dpr-key inc)))))
@dpr-key))
(defn- use-viewer-wasm-layers!
[page-id page-objects size scale frame-id not-fixed-ref fixed-ref
not-fixed-include-ids fixed-include-ids fixed-clear-fills-ids]
not-fixed-include-ids fixed-include-ids fixed-clear-fills-ids dpr-key]
(mf/use-layout-effect
(mf/deps page-id page-objects size scale frame-id
(mf/deps page-id page-objects size scale frame-id dpr-key
not-fixed-include-ids fixed-include-ids fixed-clear-fills-ids)
(fn []
(when (get page-objects frame-id)
@ -236,6 +254,8 @@
not-fixed-ref fixed-ref fixed-scroll-layer-ref
not-fixed-include-ids fixed-include-ids fixed-clear-fills-ids]
(use-fixed-scroll-sync! (some? fixed-scroll-layer-ref) fixed-scroll-layer-ref)
(use-viewer-wasm-layers! page-id page-objects size scale frame-id
not-fixed-ref fixed-ref
not-fixed-include-ids fixed-include-ids fixed-clear-fills-ids))
(let [dpr-key (use-viewer-dpr-key)]
(use-viewer-wasm-layers! page-id page-objects size scale frame-id
not-fixed-ref fixed-ref
not-fixed-include-ids fixed-include-ids fixed-clear-fills-ids
dpr-key)))

View File

@ -12,12 +12,17 @@
[app.main.render-viewer-wasm :as rwv]
[app.main.ui.viewer.shapes :as shapes]
[app.main.ui.viewer.viewport-common :as vpc]
[app.render-wasm.api :as wasm.api]
[rumext.v2 :as mf]))
(defn- canvas-dimensions
"Physical canvas pixels (CSS layout size × DPR), matching the workspace WASM path."
[scale size]
{:width (js/Math.round (* scale (:base-width size)))
:height (js/Math.round (* scale (:base-height size)))})
(let [css-w (js/Math.round (* scale (:base-width size)))
css-h (js/Math.round (* scale (:base-height size)))
dpr (wasm.api/get-dpr)]
{:width (js/Math.round (* css-w dpr))
:height (js/Math.round (* css-h dpr))}))
(mf/defc wasm-hotspots-svg*
[{:keys [vbox size class prepared prepared-all prepared-frame shape-filter]}]

View File

@ -1920,15 +1920,6 @@
(h/call wasm/internal-module "_set_view_end")
(reset! view-interaction-active? false)))
(defn resize-offscreen-canvas!
"Resize a persistent OffscreenCanvas to new physical-pixel dimensions and
update the WASM render surfaces accordingly (via `_resize_viewbox`). The
design state (shape pool) is preserved so `set-objects` is not needed again."
[canvas new-physical-w new-physical-h]
(set! (.-width canvas) new-physical-w)
(set! (.-height canvas) new-physical-h)
(resize-viewbox (/ new-physical-w dpr) (/ new-physical-h dpr)))
(defn- debug-flags
[]
(cond-> 0
@ -1939,6 +1930,22 @@
(contains? cf/flags :render-wasm-info)
(bit-or 2r00000000000000000000000000001000)))
(defn set-render-options!
"Updates WASM render options with a new DPR value."
[new-dpr]
(h/call wasm/internal-module "_set_render_options" (debug-flags) new-dpr))
(defn resize-offscreen-canvas!
"Resize a persistent OffscreenCanvas to new physical-pixel dimensions and
update the WASM render surfaces accordingly (via `_resize_viewbox`). The
design state (shape pool) is preserved so `set-objects` is not needed again."
[canvas new-physical-w new-physical-h]
(let [dpr (get-dpr)]
(set! (.-width canvas) new-physical-w)
(set! (.-height canvas) new-physical-h)
(set-render-options! dpr)
(resize-viewbox (/ new-physical-w dpr) (/ new-physical-h dpr))))
(defn- wasm-get-numeric-value
[name]
(when-let [raw (let [p (rt/get-params @st/state)]
@ -1953,11 +1960,6 @@
(let [setter-name (str/concat "_set_" (name param-name))]
(h/call wasm/internal-module setter-name value))))
(defn set-render-options!
"Updates WASM render options with a new DPR value."
[new-dpr]
(h/call wasm/internal-module "_set_render_options" (debug-flags) new-dpr))
(defn- canvas-css-size
"Return canvas size in CSS pixels.