mirror of
https://github.com/penpot/penpot.git
synced 2026-04-25 11:18:36 +00:00
🎉 Waiting for tiles complete in a non blocking way
This commit is contained in:
parent
c08c3bd160
commit
8775e234f3
@ -30,6 +30,7 @@
|
||||
[app.util.timers :as timers]
|
||||
[cuerdas.core :as str]
|
||||
[okulary.core :as l]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
;; FIXME: can we unify this two refs in one?
|
||||
@ -72,18 +73,21 @@
|
||||
(mf/use-fn
|
||||
(mf/deps id current-page-id)
|
||||
(fn []
|
||||
;; For the wasm renderer, apply a blur effect to the viewport canvas
|
||||
;; when we navigate to a different page.
|
||||
;; WASM page transitions:
|
||||
;; - Capture the current page (A) once
|
||||
;; - Show a blurred snapshot while the target page (B/C/...) renders
|
||||
;; - If the user clicks again during the transition, keep showing the original (A) snapshot
|
||||
(if (and (features/active-feature? @st/state "render-wasm/v1")
|
||||
(not= id current-page-id))
|
||||
(do
|
||||
(wasm.api/capture-canvas-pixels)
|
||||
(wasm.api/apply-canvas-blur)
|
||||
;; NOTE: it seems we need two RAF so the blur is actually applied and visible
|
||||
;; in the canvas :(
|
||||
(timers/raf
|
||||
(fn []
|
||||
(timers/raf navigate-fn))))
|
||||
(-> (wasm.api/apply-canvas-blur)
|
||||
(p/finally
|
||||
(fn []
|
||||
;; NOTE: it seems we need two RAF so the blur is actually applied and visible
|
||||
;; in the canvas :(
|
||||
(timers/raf
|
||||
(fn []
|
||||
(timers/raf navigate-fn)))))))
|
||||
(navigate-fn))))
|
||||
|
||||
on-delete
|
||||
|
||||
@ -132,21 +132,21 @@
|
||||
(apply-modifiers-to-objects base-objects wasm-modifiers))
|
||||
|
||||
;; STATE
|
||||
alt? (mf/use-state false)
|
||||
shift? (mf/use-state false)
|
||||
mod? (mf/use-state false)
|
||||
space? (mf/use-state false)
|
||||
z? (mf/use-state false)
|
||||
cursor (mf/use-state (utils/get-cursor :pointer-inner))
|
||||
hover-ids (mf/use-state nil)
|
||||
hover (mf/use-state nil)
|
||||
measure-hover (mf/use-state nil)
|
||||
hover-disabled? (mf/use-state false)
|
||||
hover-top-frame-id (mf/use-state nil)
|
||||
frame-hover (mf/use-state nil)
|
||||
active-frames (mf/use-state #{})
|
||||
canvas-init? (mf/use-state false)
|
||||
initialized? (mf/use-state false)
|
||||
alt? (mf/use-state false)
|
||||
shift? (mf/use-state false)
|
||||
mod? (mf/use-state false)
|
||||
space? (mf/use-state false)
|
||||
z? (mf/use-state false)
|
||||
cursor (mf/use-state (utils/get-cursor :pointer-inner))
|
||||
hover-ids (mf/use-state nil)
|
||||
hover (mf/use-state nil)
|
||||
measure-hover (mf/use-state nil)
|
||||
hover-disabled? (mf/use-state false)
|
||||
hover-top-frame-id (mf/use-state nil)
|
||||
frame-hover (mf/use-state nil)
|
||||
active-frames (mf/use-state #{})
|
||||
canvas-init? (mf/use-state false)
|
||||
initialized? (mf/use-state false)
|
||||
|
||||
;; REFS
|
||||
[viewport-ref
|
||||
@ -205,6 +205,9 @@
|
||||
|
||||
mode-inspect? (= options-mode :inspect)
|
||||
|
||||
;; True when we are opening a new file or switching to a new page
|
||||
page-transition? (mf/deref wasm.api/page-transition?)
|
||||
|
||||
on-click (actions/on-click hover selected edition path-drawing? drawing-tool space? selrect z?)
|
||||
on-context-menu (actions/on-context-menu hover hover-ids read-only?)
|
||||
on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id path-drawing? base-objects edition drawing-tool z? read-only?)
|
||||
@ -234,41 +237,46 @@
|
||||
show-cursor-tooltip? tooltip
|
||||
show-draw-area? drawing-obj
|
||||
show-gradient-handlers? (= (count selected) 1)
|
||||
show-grids? (contains? layout :display-guides)
|
||||
show-grids? (and (contains? layout :display-guides) (not page-transition?))
|
||||
|
||||
show-frame-outline? (and (= transform :move) (not panning))
|
||||
show-frame-outline? (and (= transform :move) (not panning) (not page-transition?))
|
||||
show-outlines? (and (nil? transform)
|
||||
(not panning)
|
||||
(not edition)
|
||||
(not drawing-obj)
|
||||
(not (#{:comments :path :curve} drawing-tool)))
|
||||
(not (#{:comments :path :curve} drawing-tool))
|
||||
(not page-transition?))
|
||||
|
||||
show-pixel-grid? (and (contains? layout :show-pixel-grid)
|
||||
(>= zoom 8))
|
||||
show-text-editor? (and editing-shape (= :text (:type editing-shape)))
|
||||
(>= zoom 8)
|
||||
(not page-transition?))
|
||||
show-text-editor? (and editing-shape (= :text (:type editing-shape)) (not page-transition?))
|
||||
|
||||
hover-grid? (and (some? @hover-top-frame-id)
|
||||
(ctl/grid-layout? objects @hover-top-frame-id))
|
||||
(ctl/grid-layout? objects @hover-top-frame-id)
|
||||
(not page-transition?))
|
||||
|
||||
show-grid-editor? (and editing-shape (ctl/grid-layout? editing-shape))
|
||||
show-presence? page-id
|
||||
show-prototypes? (= options-mode :prototype)
|
||||
show-selection-handlers? (and (seq selected) (not show-text-editor?))
|
||||
show-grid-editor? (and editing-shape (ctl/grid-layout? editing-shape) (not page-transition?))
|
||||
show-presence? (and page-id (not page-transition?))
|
||||
show-prototypes? (and (= options-mode :prototype) (not page-transition?))
|
||||
show-selection-handlers? (and (seq selected) (not show-text-editor?) (not page-transition?))
|
||||
show-snap-distance? (and (contains? layout :dynamic-alignment)
|
||||
(= transform :move)
|
||||
(seq selected))
|
||||
(seq selected)
|
||||
(not page-transition?))
|
||||
show-snap-points? (and (or (contains? layout :dynamic-alignment)
|
||||
(contains? layout :snap-guides))
|
||||
(or drawing-obj transform))
|
||||
show-selrect? (and selrect (empty? drawing) (not text-editing?))
|
||||
(or drawing-obj transform)
|
||||
(not page-transition?))
|
||||
show-selrect? (and selrect (empty? drawing) (not text-editing?) (not page-transition?))
|
||||
show-measures? (and (not transform)
|
||||
(not path-editing?)
|
||||
(or show-distances? mode-inspect?))
|
||||
show-artboard-names? (contains? layout :display-artboard-names)
|
||||
(or show-distances? mode-inspect?)
|
||||
(not page-transition?))
|
||||
show-artboard-names? (and (contains? layout :display-artboard-names) (not page-transition?))
|
||||
hide-ui? (contains? layout :hide-ui)
|
||||
show-rulers? (and (contains? layout :rulers) (not hide-ui?))
|
||||
|
||||
|
||||
disabled-guides? (or drawing-tool transform path-drawing? path-editing?)
|
||||
|
||||
single-select? (= (count selected-shapes) 1)
|
||||
@ -279,6 +287,8 @@
|
||||
(or (ctk/is-variant-container? first-shape)
|
||||
(ctk/is-variant? first-shape)))
|
||||
|
||||
show-scrollbar? (not page-transition?)
|
||||
|
||||
add-variant
|
||||
(mf/use-fn
|
||||
(mf/deps first-shape)
|
||||
@ -311,7 +321,8 @@
|
||||
rule-area-size (/ rulers/ruler-area-size zoom)
|
||||
preview-blend (-> refs/workspace-preview-blend
|
||||
(mf/deref))
|
||||
shapes-loading? (mf/deref wasm.api/shapes-loading?)]
|
||||
shapes-loading? (mf/deref wasm.api/shapes-loading?)
|
||||
transition-image-url (mf/deref wasm.api/transition-image-url*)]
|
||||
|
||||
;; NOTE: We need this page-id dependency to react to it and reset the
|
||||
;; canvas, even though we are not using `page-id` inside the hook.
|
||||
@ -341,15 +352,7 @@
|
||||
(cond
|
||||
init?
|
||||
(do
|
||||
(reset! canvas-init? true)
|
||||
(wasm.api/apply-canvas-blur)
|
||||
(if (wasm.api/has-captured-pixels?)
|
||||
;; Page switch: restore previously captured pixels (blurred)
|
||||
(wasm.api/restore-previous-canvas-pixels)
|
||||
;; First load: try to draw a blurred page thumbnail
|
||||
(when-let [frame-id (get page :thumbnail-frame-id)]
|
||||
(when-let [uri (dm/get-in @st/state [:thumbnails frame-id])]
|
||||
(wasm.api/draw-thumbnail-to-canvas uri)))))
|
||||
(reset! canvas-init? true))
|
||||
|
||||
(pos? retries)
|
||||
(vreset! timeout-id-ref
|
||||
@ -392,14 +395,15 @@
|
||||
(when @canvas-init?
|
||||
(if (not @initialized?)
|
||||
(do
|
||||
;; Initial file open uses the same transition workflow as page switches,
|
||||
;; but with a solid background-color blurred placeholder.
|
||||
(wasm.api/start-initial-load-transition! background)
|
||||
;; Keep the blurred previous-page preview (page switch) or
|
||||
;; blank canvas (first load) visible while shapes load.
|
||||
;; The loading overlay is suppressed because on-shapes-ready
|
||||
;; is set.
|
||||
(wasm.api/initialize-viewport
|
||||
base-objects zoom vbox background 1 nil
|
||||
(fn []
|
||||
(wasm.api/clear-canvas-pixels)))
|
||||
base-objects zoom vbox background)
|
||||
(reset! initialized? true)
|
||||
(mf/set-ref-val! last-file-version-id-ref file-version-id))
|
||||
(when (and (some? file-version-id)
|
||||
@ -476,6 +480,21 @@
|
||||
:style {:background-color background
|
||||
:pointer-events "none"}}]
|
||||
|
||||
;; Show the transition image when we are opening a new file or switching to a new page
|
||||
(when (and page-transition? (some? transition-image-url))
|
||||
(let [src transition-image-url]
|
||||
[:img {:data-testid "canvas-wasm-transition"
|
||||
:src src
|
||||
:draggable false
|
||||
:style {:position "absolute"
|
||||
:inset 0
|
||||
:width "100%"
|
||||
:height "100%"
|
||||
:object-fit "cover"
|
||||
:pointer-events "none"
|
||||
:filter "blur(4px)"}}]))
|
||||
|
||||
|
||||
[:svg.viewport-controls
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
@ -776,9 +795,10 @@
|
||||
(get objects-modified @hover-top-frame-id))
|
||||
:view-only (not show-grid-editor?)}])]
|
||||
|
||||
[:g.scrollbar-wrapper {:clipPath "url(#clip-handlers)"}
|
||||
[:> scroll-bars/viewport-scrollbars*
|
||||
{:objects base-objects
|
||||
:zoom zoom
|
||||
:vbox vbox
|
||||
:bottom-padding (when palete-size (+ palete-size 8))}]]]]]))
|
||||
(when show-scrollbar?
|
||||
[:g.scrollbar-wrapper {:clipPath "url(#clip-handlers)"}
|
||||
[:> scroll-bars/viewport-scrollbars*
|
||||
{:objects base-objects
|
||||
:zoom zoom
|
||||
:vbox vbox
|
||||
:bottom-padding (when palete-size (+ palete-size 8))}]])]]]))
|
||||
|
||||
@ -55,6 +55,109 @@
|
||||
|
||||
(def use-dpr? (contains? cf/flags :render-wasm-dpr))
|
||||
|
||||
;; --- Page transition state (WASM viewport)
|
||||
;;
|
||||
;; Goal: avoid showing tile-by-tile rendering during page switches (and initial load),
|
||||
;; by keeping a blurred snapshot overlay visible until WASM dispatches
|
||||
;; `penpot:wasm:tiles-complete`.
|
||||
;;
|
||||
;; - `page-transition?`: true while the overlay should be considered active.
|
||||
;; - `transition-image-url*`: URL used by the UI overlay (usually `blob:` from the
|
||||
;; current WebGL canvas snapshot; on initial load it may be a tiny SVG data-url
|
||||
;; derived from the page background color).
|
||||
;; - `transition-epoch*`: monotonic counter used to ignore stale async work/events
|
||||
;; when the user clicks pages rapidly (A -> B -> C).
|
||||
;; - `transition-tiles-handler*`: the currently installed DOM event handler for
|
||||
;; `penpot:wasm:tiles-complete`, so we can remove/replace it safely.
|
||||
(defonce page-transition? (atom false))
|
||||
(defonce transition-image-url* (atom nil))
|
||||
(defonce transition-epoch* (atom 0))
|
||||
(defonce transition-tiles-handler* (atom nil))
|
||||
|
||||
(def ^:private transition-blur-css "blur(4px)")
|
||||
|
||||
(defn- set-transition-blur!
|
||||
[]
|
||||
(when-let [canvas ^js wasm/canvas]
|
||||
(dom/set-style! canvas "filter" transition-blur-css))
|
||||
(when-let [nodes (.querySelectorAll ^js ug/document ".blurrable")]
|
||||
(doseq [^js node (array-seq nodes)]
|
||||
(dom/set-style! node "filter" transition-blur-css))))
|
||||
|
||||
(defn- clear-transition-blur!
|
||||
[]
|
||||
(when-let [canvas ^js wasm/canvas]
|
||||
(dom/set-style! canvas "filter" ""))
|
||||
(when-let [nodes (.querySelectorAll ^js ug/document ".blurrable")]
|
||||
(doseq [^js node (array-seq nodes)]
|
||||
(dom/set-style! node "filter" ""))))
|
||||
|
||||
(defn set-transition-image-from-background!
|
||||
"Sets `transition-image-url*` to a data URL representing a solid background color."
|
||||
[background]
|
||||
(when (string? background)
|
||||
(let [svg (str "<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'>"
|
||||
"<rect width='1' height='1' fill='" background "'/>"
|
||||
"</svg>")]
|
||||
(reset! transition-image-url*
|
||||
(str "data:image/svg+xml;charset=utf-8," (js/encodeURIComponent svg))))))
|
||||
|
||||
(defn begin-page-transition!
|
||||
[]
|
||||
(reset! page-transition? true)
|
||||
(swap! transition-epoch* inc))
|
||||
|
||||
(defn end-page-transition!
|
||||
[]
|
||||
(reset! page-transition? false)
|
||||
(when-let [prev @transition-tiles-handler*]
|
||||
(.removeEventListener ^js ug/document "penpot:wasm:tiles-complete" prev))
|
||||
(reset! transition-tiles-handler* nil)
|
||||
(reset! transition-image-url* nil)
|
||||
(clear-transition-blur!)
|
||||
;; Clear captured pixels so future transitions must explicitly capture again.
|
||||
(set! wasm/canvas-snapshot-url nil))
|
||||
|
||||
(defn- set-transition-tiles-complete-handler!
|
||||
"Installs a tiles-complete handler bound to the current transition epoch.
|
||||
Replaces any previous handler so rapid page switching doesn't end the wrong transition."
|
||||
[epoch f]
|
||||
(when-let [prev @transition-tiles-handler*]
|
||||
(.removeEventListener ^js ug/document "penpot:wasm:tiles-complete" prev))
|
||||
(letfn [(handler [_]
|
||||
(when (= epoch @transition-epoch*)
|
||||
(.removeEventListener ^js ug/document "penpot:wasm:tiles-complete" handler)
|
||||
(reset! transition-tiles-handler* nil)
|
||||
(f)))]
|
||||
(reset! transition-tiles-handler* handler)
|
||||
(.addEventListener ^js ug/document "penpot:wasm:tiles-complete" handler)))
|
||||
|
||||
(defn start-initial-load-transition!
|
||||
"Starts a page-transition workflow for initial file open.
|
||||
|
||||
- Sets `page-transition?` to true
|
||||
- Installs a tiles-complete handler to end the transition
|
||||
- Uses a solid background-color placeholder as the transition image"
|
||||
[background]
|
||||
;; If something already toggled `page-transition?` (e.g. legacy init code paths),
|
||||
;; ensure we still have a deterministic placeholder on initial load.
|
||||
(when (or (not @page-transition?) (nil? @transition-image-url*))
|
||||
(set-transition-image-from-background! background))
|
||||
(when-not @page-transition?
|
||||
;; Start transition + bind the tiles-complete handler to this epoch.
|
||||
(let [epoch (begin-page-transition!)]
|
||||
(set-transition-tiles-complete-handler! epoch end-page-transition!))))
|
||||
|
||||
(defn listen-tiles-render-complete-once!
|
||||
"Registers a one-shot listener for `penpot:wasm:tiles-complete`, dispatched from WASM
|
||||
when a full tile pass finishes."
|
||||
[f]
|
||||
(.addEventListener ^js ug/document
|
||||
"penpot:wasm:tiles-complete"
|
||||
(fn [_]
|
||||
(f))
|
||||
#js {:once true}))
|
||||
|
||||
(defn text-editor-wasm?
|
||||
[]
|
||||
(or (contains? cf/flags :feature-text-editor-wasm)
|
||||
@ -94,16 +197,9 @@
|
||||
(def ^:const TEXT_EDITOR_EVENT_NEEDS_LAYOUT 4)
|
||||
|
||||
;; Re-export public WebGL functions
|
||||
(def capture-canvas-pixels webgl/capture-canvas-pixels)
|
||||
(def restore-previous-canvas-pixels webgl/restore-previous-canvas-pixels)
|
||||
(def clear-canvas-pixels webgl/clear-canvas-pixels)
|
||||
(def capture-canvas-snapshot-url webgl/capture-canvas-snapshot-url)
|
||||
(def draw-thumbnail-to-canvas webgl/draw-thumbnail-to-canvas)
|
||||
|
||||
(defn has-captured-pixels?
|
||||
"Returns true if there are saved canvas pixels from a previous page."
|
||||
[]
|
||||
(some? wasm/canvas-pixels))
|
||||
|
||||
;; Re-export public text editor functions
|
||||
(def text-editor-focus text-editor/text-editor-focus)
|
||||
(def text-editor-blur text-editor/text-editor-blur)
|
||||
@ -1778,9 +1874,36 @@
|
||||
|
||||
(defn apply-canvas-blur
|
||||
[]
|
||||
(when wasm/canvas (dom/set-style! wasm/canvas "filter" "blur(4px)"))
|
||||
(let [controls-to-blur (dom/query-all (dom/get-element "viewport-controls") ".blurrable")]
|
||||
(run! #(dom/set-style! % "filter" "blur(4px)") controls-to-blur)))
|
||||
(let [already? @page-transition?
|
||||
epoch (begin-page-transition!)]
|
||||
(set-transition-tiles-complete-handler! epoch end-page-transition!)
|
||||
;; Two-phase transition:
|
||||
;; - Apply CSS blur to the live canvas immediately (no async wait), so the user
|
||||
;; sees the transition right away.
|
||||
;; - In parallel, capture a `blob:` snapshot URL; once ready, switch the overlay
|
||||
;; to that fixed image (and guard with `epoch` to avoid stale async updates).
|
||||
(set-transition-blur!)
|
||||
;; Lock the snapshot for the whole transition: if the user clicks to another page
|
||||
;; while the transition is active, keep showing the original page snapshot until
|
||||
;; the final target page finishes rendering.
|
||||
(if already?
|
||||
(p/resolved nil)
|
||||
(do
|
||||
;; If we already have a snapshot URL, use it immediately.
|
||||
(when-let [url wasm/canvas-snapshot-url]
|
||||
(when (string? url)
|
||||
(reset! transition-image-url* url)))
|
||||
|
||||
;; Capture a fresh snapshot asynchronously and update the overlay as soon
|
||||
;; as it is ready (guarded by `epoch` to avoid stale async updates).
|
||||
(-> (capture-canvas-snapshot-url)
|
||||
(p/then (fn [url]
|
||||
(when (and (string? url)
|
||||
@page-transition?
|
||||
(= epoch @transition-epoch*))
|
||||
(reset! transition-image-url* url))
|
||||
url))
|
||||
(p/catch (fn [_] nil)))))))
|
||||
|
||||
(defn render-shape-pixels
|
||||
[shape-id scale]
|
||||
|
||||
@ -9,7 +9,6 @@
|
||||
(:require
|
||||
[app.common.logging :as log]
|
||||
[app.render-wasm.wasm :as wasm]
|
||||
[app.util.dom :as dom]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(defn max-texture-size
|
||||
@ -144,38 +143,29 @@ void main() {
|
||||
(.bindTexture ^js gl (.-TEXTURE_2D ^js gl) nil)
|
||||
(.deleteTexture ^js gl texture))))
|
||||
|
||||
(defn restore-previous-canvas-pixels
|
||||
"Restores previous canvas pixels into the new canvas"
|
||||
[]
|
||||
(when-let [previous-canvas-pixels wasm/canvas-pixels]
|
||||
(when-let [gl wasm/gl-context]
|
||||
(draw-imagedata-to-webgl gl previous-canvas-pixels)
|
||||
(set! wasm/canvas-pixels nil))))
|
||||
(defn capture-canvas-snapshot-url
|
||||
"Captures the current viewport canvas as a PNG `blob:` URL and stores it in
|
||||
`wasm/canvas-snapshot-url`.
|
||||
|
||||
(defn clear-canvas-pixels
|
||||
Returns a promise resolving to the URL string (or nil)."
|
||||
[]
|
||||
(when wasm/canvas
|
||||
(let [context wasm/gl-context]
|
||||
(.clearColor ^js context 0 0 0 0.0)
|
||||
(.clear ^js context (.-COLOR_BUFFER_BIT ^js context))
|
||||
(.clear ^js context (.-DEPTH_BUFFER_BIT ^js context))
|
||||
(.clear ^js context (.-STENCIL_BUFFER_BIT ^js context)))
|
||||
(dom/set-style! wasm/canvas "filter" "none")
|
||||
(let [controls-to-unblur (dom/query-all (dom/get-element "viewport-controls") ".blurrable")]
|
||||
(run! #(dom/set-style! % "filter" "none") controls-to-unblur))
|
||||
(set! wasm/canvas-pixels nil)))
|
||||
|
||||
(defn capture-canvas-pixels
|
||||
"Captures the pixels of the viewport canvas"
|
||||
[]
|
||||
(when wasm/canvas
|
||||
(let [context wasm/gl-context
|
||||
width (.-width wasm/canvas)
|
||||
height (.-height wasm/canvas)
|
||||
buffer (js/Uint8ClampedArray. (* width height 4))
|
||||
_ (.readPixels ^js context 0 0 width height (.-RGBA ^js context) (.-UNSIGNED_BYTE ^js context) buffer)
|
||||
image-data (js/ImageData. buffer width height)]
|
||||
(set! wasm/canvas-pixels image-data))))
|
||||
(if-let [^js canvas wasm/canvas]
|
||||
(p/create
|
||||
(fn [resolve _reject]
|
||||
;; Revoke previous snapshot to avoid leaking blob URLs.
|
||||
(when-let [prev wasm/canvas-snapshot-url]
|
||||
(when (and (string? prev) (.startsWith ^js prev "blob:"))
|
||||
(js/URL.revokeObjectURL prev)))
|
||||
(set! wasm/canvas-snapshot-url nil)
|
||||
(.toBlob canvas
|
||||
(fn [^js blob]
|
||||
(if blob
|
||||
(let [url (js/URL.createObjectURL blob)]
|
||||
(set! wasm/canvas-snapshot-url url)
|
||||
(resolve url))
|
||||
(resolve nil)))
|
||||
"image/png")))
|
||||
(p/resolved nil)))
|
||||
|
||||
(defn draw-thumbnail-to-canvas
|
||||
"Loads an image from `uri` and draws it stretched to fill the WebGL canvas.
|
||||
|
||||
@ -12,8 +12,9 @@
|
||||
|
||||
;; Reference to the HTML canvas element.
|
||||
(defonce canvas nil)
|
||||
;; Reference to the captured pixels of the canvas (for page switching effect)
|
||||
(defonce canvas-pixels nil)
|
||||
;; Snapshot of the current canvas suitable for `<img src=...>` overlays.
|
||||
;; This is typically a `blob:` URL created via `canvas.toBlob`.
|
||||
(defonce canvas-snapshot-url nil)
|
||||
|
||||
;; Reference to the Emscripten GL context wrapper.
|
||||
(defonce gl-context-handle nil)
|
||||
|
||||
@ -43,6 +43,13 @@ const VIEWPORT_INTEREST_AREA_THRESHOLD: i32 = 3;
|
||||
|
||||
const MAX_BLOCKING_TIME_MS: i32 = 32;
|
||||
const NODE_BATCH_THRESHOLD: i32 = 3;
|
||||
|
||||
/// Dispatches `penpot:wasm:tiles-complete` on `document` so the UI can react when a full
|
||||
/// tile pass has finished (e.g. remove page-transition blur).
|
||||
fn notify_tiles_render_complete() {
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
crate::run_script!("document.dispatchEvent(new CustomEvent('penpot:wasm:tiles-complete'))");
|
||||
}
|
||||
const BLUR_DOWNSCALE_THRESHOLD: f32 = 8.0;
|
||||
|
||||
type ClipStack = Vec<(Rect, Option<Corners>, Matrix)>;
|
||||
@ -1750,6 +1757,7 @@ impl RenderState {
|
||||
self.cancel_animation_frame();
|
||||
self.render_request_id = Some(wapi::request_animation_frame!());
|
||||
} else {
|
||||
notify_tiles_render_complete();
|
||||
performance::end_measure!("render");
|
||||
}
|
||||
}
|
||||
@ -1767,6 +1775,7 @@ impl RenderState {
|
||||
self.render_shape_tree_partial(base_object, tree, timestamp, false)?;
|
||||
}
|
||||
self.flush_and_submit();
|
||||
notify_tiles_render_complete();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user