From 7914188b8a1ff5aa5505b9893040b3a752f7d767 Mon Sep 17 00:00:00 2001 From: dAxpeDDa Date: Sun, 4 Jun 2023 14:29:59 +0200 Subject: [PATCH] Use correct canvas size for scale factor change --- CHANGELOG.md | 2 + examples/web.rs | 5 ++- src/platform_impl/web/event_loop/runner.rs | 12 +++-- .../web/event_loop/window_target.rs | 24 +++++----- src/platform_impl/web/web_sys/canvas.rs | 44 ++++++++++++++----- src/platform_impl/web/web_sys/mod.rs | 19 +++++--- src/platform_impl/web/window.rs | 17 ++----- 7 files changed, 70 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8f3703fcb..486286c779 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -71,6 +71,8 @@ And please only add new entries to the top of this list, right below the `# Unre - On Web, `EventLoopProxy` now implements `Send`. - On Web, `Window` now implements `Send` and `Sync`. - **Breaking:** `WindowExtWebSys::canvas()` now returns an `Option`. +- On Web, use the correct canvas size when calculating the new size during scale factor change, + instead of using the output bitmap size. # 0.28.6 diff --git a/examples/web.rs b/examples/web.rs index 274c03b396..ea32f06e32 100644 --- a/examples/web.rs +++ b/examples/web.rs @@ -59,7 +59,10 @@ mod wasm { let body = document.body().unwrap(); // Set a background color for the canvas to make it easier to tell where the canvas is for debugging purposes. - canvas.style().set_css_text("background-color: crimson;"); + canvas + .style() + .set_property("background-color", "crimson") + .unwrap(); body.append_child(&canvas).unwrap(); let log_header = document.create_element("h2").unwrap(); diff --git a/src/platform_impl/web/event_loop/runner.rs b/src/platform_impl/web/event_loop/runner.rs index b2682312b2..f14b212e5c 100644 --- a/src/platform_impl/web/event_loop/runner.rs +++ b/src/platform_impl/web/event_loop/runner.rs @@ -327,16 +327,14 @@ impl Shared { // Now handle the `ScaleFactorChanged` events. for &(id, ref canvas) in &*self.0.all_canvases.borrow() { - let canvas = match canvas.upgrade() { - Some(rc) => rc.borrow().raw().clone(), + let rc = match canvas.upgrade() { + Some(rc) => rc, // This shouldn't happen, but just in case... None => continue, }; + let canvas = rc.borrow(); // First, we send the `ScaleFactorChanged` event: - let current_size = crate::dpi::PhysicalSize { - width: canvas.width(), - height: canvas.height(), - }; + let current_size = canvas.size().get(); let logical_size = current_size.to_logical::(old_scale); let mut new_size = logical_size.to_physical(new_scale); self.handle_single_event_sync( @@ -351,7 +349,7 @@ impl Shared { ); // Then we resize the canvas to the new size and send a `Resized` event: - backend::set_canvas_size(self.window(), &canvas, crate::dpi::Size::Physical(new_size)); + backend::set_canvas_size(&canvas, crate::dpi::Size::Physical(new_size)); self.handle_single_event_sync( Event::WindowEvent { window_id: id, diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index cf558af533..6b142e2d6c 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -16,7 +16,7 @@ use super::{ runner, window::WindowId, }; -use crate::dpi::{PhysicalSize, Size}; +use crate::dpi::Size; use crate::event::{ DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, WindowEvent, @@ -89,6 +89,7 @@ impl EventLoopWindowTarget { has_focus: Arc, ) { self.runner.add_canvas(RootWindowId(id), canvas); + let canvas_clone = canvas.clone(); let mut canvas = canvas.borrow_mut(); canvas.set_attribute("data-raw-handle", &id.0.to_string()); @@ -502,32 +503,27 @@ impl EventLoopWindowTarget { prevent_default, ); - let runner = self.runner.clone(); - let raw = canvas.raw().clone(); - // The size to restore to after exiting fullscreen. - let mut intended_size = PhysicalSize { - width: raw.width(), - height: raw.height(), - }; + let mut intended_size = canvas.size().get(); canvas.on_fullscreen_change({ let window = self.runner.window().clone(); + let runner = self.runner.clone(); + move || { + let canvas = canvas_clone.borrow(); + // If the canvas is marked as fullscreen, it is moving *into* fullscreen // If it is not, it is moving *out of* fullscreen - let new_size = if backend::is_fullscreen(&window, &raw) { - intended_size = PhysicalSize { - width: raw.width(), - height: raw.height(), - }; + let new_size = if backend::is_fullscreen(&window, canvas.raw()) { + intended_size = canvas.size().get(); backend::window_size(&window).to_physical(backend::scale_factor(&window)) } else { intended_size }; - backend::set_canvas_size(&window, &raw, Size::Physical(new_size)); + backend::set_canvas_size(&canvas, Size::Physical(new_size)); runner.send_event(Event::WindowEvent { window_id: RootWindowId(id), event: WindowEvent::Resized(new_size), diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 8979c7c097..4b5dde990c 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -2,13 +2,14 @@ use super::event_handle::EventListenerHandle; use super::media_query_handle::MediaQueryListHandle; use super::pointer::PointerHandler; use super::{event, ButtonsState}; -use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; +use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; use crate::event::{Force, MouseButton, MouseScrollDelta}; use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; +use crate::window::WindowAttributes; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::rc::Rc; use js_sys::Promise; @@ -39,15 +40,17 @@ pub struct Common { pub window: web_sys::Window, /// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained. pub raw: HtmlCanvasElement, + size: Rc>>, wants_fullscreen: Rc>, } impl Canvas { pub fn create( window: web_sys::Window, - attr: PlatformSpecificWindowBuilderAttributes, + attr: &WindowAttributes, + platform_attr: PlatformSpecificWindowBuilderAttributes, ) -> Result { - let canvas = match attr.canvas { + let canvas = match platform_attr.canvas { Some(canvas) => canvas, None => { let document = window @@ -66,16 +69,28 @@ impl Canvas { // sequential keyboard navigation, but its order is defined by the // document's source order. // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex - if attr.focusable { + if platform_attr.focusable { canvas .set_attribute("tabindex", "0") .map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?; } - Ok(Canvas { + let size = attr + .inner_size + .unwrap_or( + LogicalSize { + width: 1024.0, + height: 768.0, + } + .into(), + ) + .to_physical(super::scale_factor(&window)); + + let canvas = Canvas { common: Common { window, raw: canvas, + size: Rc::new(Cell::new(size)), wants_fullscreen: Rc::new(RefCell::new(false)), }, on_touch_start: None, @@ -88,7 +103,11 @@ impl Canvas { on_fullscreen_change: None, on_dark_mode: None, pointer_handler: PointerHandler::new(), - }) + }; + + super::set_canvas_size(&canvas, size.into()); + + Ok(canvas) } pub fn set_cursor_lock(&self, lock: bool) -> Result<(), RootOE> { @@ -121,11 +140,12 @@ impl Canvas { } } - pub fn size(&self) -> PhysicalSize { - PhysicalSize { - width: self.common.raw.width(), - height: self.common.raw.height(), - } + pub fn window(&self) -> &web_sys::Window { + &self.common.window + } + + pub fn size(&self) -> &Rc>> { + &self.common.size } pub fn raw(&self) -> &HtmlCanvasElement { diff --git a/src/platform_impl/web/web_sys/mod.rs b/src/platform_impl/web/web_sys/mod.rs index 2b6e3745ab..a7b9443f8f 100644 --- a/src/platform_impl/web/web_sys/mod.rs +++ b/src/platform_impl/web/web_sys/mod.rs @@ -76,12 +76,19 @@ pub fn scale_factor(window: &web_sys::Window) -> f64 { window.device_pixel_ratio() } -pub fn set_canvas_size(window: &web_sys::Window, raw: &HtmlCanvasElement, size: Size) { - let scale_factor = scale_factor(window); - let logical_size = size.to_logical::(scale_factor); - - set_canvas_style_property(raw, "width", &format!("{}px", logical_size.width)); - set_canvas_style_property(raw, "height", &format!("{}px", logical_size.height)); +pub fn set_canvas_size(canvas: &Canvas, new_size: Size) { + let scale_factor = scale_factor(canvas.window()); + + let physical_size = new_size.to_physical(scale_factor); + canvas.size().set(physical_size); + + let logical_size = new_size.to_logical::(scale_factor); + set_canvas_style_property(canvas.raw(), "width", &format!("{}px", logical_size.width)); + set_canvas_style_property( + canvas.raw(), + "height", + &format!("{}px", logical_size.height), + ); } pub fn set_canvas_style_property(raw: &HtmlCanvasElement, property: &str, value: &str) { diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 7368e19f40..9b1caefbbd 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -1,4 +1,4 @@ -use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}; +use crate::dpi::{PhysicalPosition, PhysicalSize, Position, Size}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOE}; use crate::event; use crate::icon::Icon; @@ -48,7 +48,7 @@ impl Window { let prevent_default = platform_attr.prevent_default; let window = target.runner.window(); - let canvas = backend::Canvas::create(window.clone(), platform_attr)?; + let canvas = backend::Canvas::create(window.clone(), &attr, platform_attr)?; let canvas = Rc::new(RefCell::new(canvas)); let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id))); @@ -67,15 +67,6 @@ impl Window { let runner = target.runner.clone(); let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id))); - backend::set_canvas_size( - window, - canvas.borrow().raw(), - attr.inner_size.unwrap_or(Size::Logical(LogicalSize { - width: 1024.0, - height: 768.0, - })), - ); - let window = Window { id, has_focus, @@ -171,7 +162,7 @@ impl Window { pub fn set_inner_size(&self, size: Size) { self.inner.dispatch(move |inner| { let old_size = inner.inner_size(); - backend::set_canvas_size(&inner.window, inner.canvas.borrow().raw(), size); + backend::set_canvas_size(&inner.canvas.borrow(), size); let new_size = inner.inner_size(); if old_size != new_size { (inner.resize_notify_fn)(new_size); @@ -454,7 +445,7 @@ impl Inner { #[inline] pub fn inner_size(&self) -> PhysicalSize { - self.canvas.borrow().size() + self.canvas.borrow().size().get() } }