From 3d632cd3335fdb99c5aed3b6e31b9b5945af61fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Proch=C3=A1zka?= Date: Thu, 6 Jun 2024 10:30:32 +0200 Subject: [PATCH] Move first `request_animation_frame` into resize observer (#4628) This PR ensures the first animation frame happens _after_ the resize observer has had a chance to do its job. * Closes https://github.com/emilk/egui/issues/4622 The first commit contains some `log` calls to observe the changed behavior: Before: ``` [eframe::web::app_runner] eframe/src/web/app_runner.rs:191: LOGIC [300.0 150.0] [eframe::web::events] eframe/src/web/events.rs:633: ResizeObserver canvas=[300.0 150.0] to=(1920, 993) [eframe::web::app_runner] eframe/src/web/app_runner.rs:191: LOGIC [1920.0 993.0] [eframe::web::app_runner] eframe/src/web/app_runner.rs:191: LOGIC [1920.0 993.0] ``` After: ``` [eframe::web::events] eframe/src/web/events.rs:633: ResizeObserver canvas=[300.0 150.0] to=(1920, 993) [eframe::web::app_runner] eframe/src/web/app_runner.rs:191: LOGIC [1920.0 993.0] [eframe::web::app_runner] eframe/src/web/app_runner.rs:191: LOGIC [1920.0 993.0] ``` --- crates/eframe/src/web/events.rs | 13 +++++++++++++ crates/eframe/src/web/web_runner.rs | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/crates/eframe/src/web/events.rs b/crates/eframe/src/web/events.rs index c8ddcf6c..acb162c0 100644 --- a/crates/eframe/src/web/events.rs +++ b/crates/eframe/src/web/events.rs @@ -608,6 +608,14 @@ pub(crate) fn install_canvas_events(runner_ref: &WebRunner) -> Result<(), JsValu Ok(()) } +/// Install a `ResizeObserver` to observe changes to the size of the canvas. +/// +/// This is the only way to ensure a canvas size change without an associated window `resize` event +/// actually results in a resize of the canvas. +/// +/// The resize observer is called the by the browser at `observe` time, instead of just on the first actual resize. +/// We use that to trigger the first `request_animation_frame` _after_ updating the size of the canvas to the correct dimensions, +/// to avoid [#4622](https://github.com/emilk/egui/issues/4622). pub(crate) fn install_resize_observer(runner_ref: &WebRunner) -> Result<(), JsValue> { let closure = Closure::wrap(Box::new({ let runner_ref = runner_ref.clone(); @@ -628,6 +636,11 @@ pub(crate) fn install_resize_observer(runner_ref: &WebRunner) -> Result<(), JsVa // force an immediate repaint runner_lock.needs_repaint.repaint_asap(); paint_if_needed(&mut runner_lock); + drop(runner_lock); + // we rely on the resize observer to trigger the first `request_animation_frame`: + if let Err(err) = runner_ref.request_animation_frame() { + log::error!("{}", super::string_from_js_value(&err)); + }; } } }) as Box); diff --git a/crates/eframe/src/web/web_runner.rs b/crates/eframe/src/web/web_runner.rs index 9c97b6a7..eea9ab64 100644 --- a/crates/eframe/src/web/web_runner.rs +++ b/crates/eframe/src/web/web_runner.rs @@ -79,9 +79,8 @@ impl WebRunner { events::install_color_scheme_change_event(self)?; } + // The resize observer handles calling `request_animation_frame` to start the render loop. events::install_resize_observer(self)?; - - self.request_animation_frame()?; } Ok(())