Use correct canvas size for scale factor change

This commit is contained in:
dAxpeDDa 2023-06-04 14:29:59 +02:00 committed by daxpedda
parent 8f7f3efc0d
commit c88a4ab221
7 changed files with 69 additions and 52 deletions

View file

@ -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, `EventLoopProxy` now implements `Send`.
- On Web, `Window` now implements `Send` and `Sync`. - On Web, `Window` now implements `Send` and `Sync`.
- **Breaking:** `WindowExtWebSys::canvas()` now returns an `Option`. - **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 # 0.28.6

View file

@ -59,7 +59,10 @@ mod wasm {
let body = document.body().unwrap(); 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. // 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(); body.append_child(&canvas).unwrap();
let log_header = document.create_element("h2").unwrap(); let log_header = document.create_element("h2").unwrap();

View file

@ -327,16 +327,14 @@ impl<T: 'static> Shared<T> {
// Now handle the `ScaleFactorChanged` events. // Now handle the `ScaleFactorChanged` events.
for &(id, ref canvas) in &*self.0.all_canvases.borrow() { for &(id, ref canvas) in &*self.0.all_canvases.borrow() {
let canvas = match canvas.upgrade() { let rc = match canvas.upgrade() {
Some(rc) => rc.borrow().raw().clone(), Some(rc) => rc,
// This shouldn't happen, but just in case... // This shouldn't happen, but just in case...
None => continue, None => continue,
}; };
let canvas = rc.borrow();
// First, we send the `ScaleFactorChanged` event: // First, we send the `ScaleFactorChanged` event:
let current_size = crate::dpi::PhysicalSize { let current_size = canvas.size().get();
width: canvas.width(),
height: canvas.height(),
};
let logical_size = current_size.to_logical::<f64>(old_scale); let logical_size = current_size.to_logical::<f64>(old_scale);
let mut new_size = logical_size.to_physical(new_scale); let mut new_size = logical_size.to_physical(new_scale);
self.handle_single_event_sync( self.handle_single_event_sync(
@ -351,7 +349,7 @@ impl<T: 'static> Shared<T> {
); );
// Then we resize the canvas to the new size and send a `Resized` event: // 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( self.handle_single_event_sync(
Event::WindowEvent { Event::WindowEvent {
window_id: id, window_id: id,

View file

@ -16,7 +16,7 @@ use super::{
runner, runner,
window::WindowId, window::WindowId,
}; };
use crate::dpi::{PhysicalSize, Size}; use crate::dpi::Size;
use crate::event::{ use crate::event::{
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase, DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
WindowEvent, WindowEvent,
@ -89,6 +89,7 @@ impl<T> EventLoopWindowTarget<T> {
has_focus: Arc<AtomicBool>, has_focus: Arc<AtomicBool>,
) { ) {
self.runner.add_canvas(RootWindowId(id), canvas); self.runner.add_canvas(RootWindowId(id), canvas);
let canvas_clone = canvas.clone();
let mut canvas = canvas.borrow_mut(); let mut canvas = canvas.borrow_mut();
canvas.set_attribute("data-raw-handle", &id.0.to_string()); canvas.set_attribute("data-raw-handle", &id.0.to_string());
@ -502,32 +503,27 @@ impl<T> EventLoopWindowTarget<T> {
prevent_default, prevent_default,
); );
let runner = self.runner.clone();
let raw = canvas.raw().clone();
// The size to restore to after exiting fullscreen. // The size to restore to after exiting fullscreen.
let mut intended_size = PhysicalSize { let mut intended_size = canvas.size().get();
width: raw.width(),
height: raw.height(),
};
canvas.on_fullscreen_change({ canvas.on_fullscreen_change({
let window = self.runner.window().clone(); let window = self.runner.window().clone();
let runner = self.runner.clone();
move || { move || {
let canvas = canvas_clone.borrow();
// If the canvas is marked as fullscreen, it is moving *into* fullscreen // If the canvas is marked as fullscreen, it is moving *into* fullscreen
// If it is not, it is moving *out of* fullscreen // If it is not, it is moving *out of* fullscreen
let new_size = if backend::is_fullscreen(&window, &raw) { let new_size = if backend::is_fullscreen(&window, canvas.raw()) {
intended_size = PhysicalSize { intended_size = canvas.size().get();
width: raw.width(),
height: raw.height(),
};
backend::window_size(&window).to_physical(backend::scale_factor(&window)) backend::window_size(&window).to_physical(backend::scale_factor(&window))
} else { } else {
intended_size 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 { runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id), window_id: RootWindowId(id),
event: WindowEvent::Resized(new_size), event: WindowEvent::Resized(new_size),

View file

@ -2,13 +2,14 @@ use super::event_handle::EventListenerHandle;
use super::media_query_handle::MediaQueryListHandle; use super::media_query_handle::MediaQueryListHandle;
use super::pointer::PointerHandler; use super::pointer::PointerHandler;
use super::{event, ButtonsState}; 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::error::OsError as RootOE;
use crate::event::{Force, MouseButton, MouseScrollDelta}; use crate::event::{Force, MouseButton, MouseScrollDelta};
use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState};
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
use crate::window::WindowAttributes;
use std::cell::RefCell; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
use js_sys::Promise; use js_sys::Promise;
@ -39,15 +40,17 @@ pub struct Common {
pub window: web_sys::Window, pub window: web_sys::Window,
/// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained. /// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained.
pub raw: HtmlCanvasElement, pub raw: HtmlCanvasElement,
size: Rc<Cell<PhysicalSize<u32>>>,
wants_fullscreen: Rc<RefCell<bool>>, wants_fullscreen: Rc<RefCell<bool>>,
} }
impl Canvas { impl Canvas {
pub fn create( pub fn create(
window: web_sys::Window, window: web_sys::Window,
attr: PlatformSpecificWindowBuilderAttributes, attr: &WindowAttributes,
platform_attr: PlatformSpecificWindowBuilderAttributes,
) -> Result<Self, RootOE> { ) -> Result<Self, RootOE> {
let canvas = match attr.canvas { let canvas = match platform_attr.canvas {
Some(canvas) => canvas, Some(canvas) => canvas,
None => { None => {
let document = window let document = window
@ -66,16 +69,28 @@ impl Canvas {
// sequential keyboard navigation, but its order is defined by the // sequential keyboard navigation, but its order is defined by the
// document's source order. // document's source order.
// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
if attr.focusable { if platform_attr.focusable {
canvas canvas
.set_attribute("tabindex", "0") .set_attribute("tabindex", "0")
.map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?; .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 { common: Common {
window, window,
raw: canvas, raw: canvas,
size: Rc::new(Cell::new(size)),
wants_fullscreen: Rc::new(RefCell::new(false)), wants_fullscreen: Rc::new(RefCell::new(false)),
}, },
on_touch_start: None, on_touch_start: None,
@ -88,7 +103,11 @@ impl Canvas {
on_fullscreen_change: None, on_fullscreen_change: None,
on_dark_mode: None, on_dark_mode: None,
pointer_handler: PointerHandler::new(), pointer_handler: PointerHandler::new(),
}) };
super::set_canvas_size(&canvas, size.into());
Ok(canvas)
} }
pub fn set_cursor_lock(&self, lock: bool) -> Result<(), RootOE> { pub fn set_cursor_lock(&self, lock: bool) -> Result<(), RootOE> {
@ -121,11 +140,12 @@ impl Canvas {
} }
} }
pub fn size(&self) -> PhysicalSize<u32> { pub fn window(&self) -> &web_sys::Window {
PhysicalSize { &self.common.window
width: self.common.raw.width(),
height: self.common.raw.height(),
} }
pub fn size(&self) -> &Rc<Cell<PhysicalSize<u32>>> {
&self.common.size
} }
pub fn raw(&self) -> &HtmlCanvasElement { pub fn raw(&self) -> &HtmlCanvasElement {

View file

@ -76,12 +76,19 @@ pub fn scale_factor(window: &web_sys::Window) -> f64 {
window.device_pixel_ratio() window.device_pixel_ratio()
} }
pub fn set_canvas_size(window: &web_sys::Window, raw: &HtmlCanvasElement, size: Size) { pub fn set_canvas_size(canvas: &Canvas, new_size: Size) {
let scale_factor = scale_factor(window); let scale_factor = scale_factor(canvas.window());
let logical_size = size.to_logical::<f64>(scale_factor);
set_canvas_style_property(raw, "width", &format!("{}px", logical_size.width)); let physical_size = new_size.to_physical(scale_factor);
set_canvas_style_property(raw, "height", &format!("{}px", logical_size.height)); canvas.size().set(physical_size);
let logical_size = new_size.to_logical::<f64>(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) { pub fn set_canvas_style_property(raw: &HtmlCanvasElement, property: &str, value: &str) {

View file

@ -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::error::{ExternalError, NotSupportedError, OsError as RootOE};
use crate::event; use crate::event;
use crate::icon::Icon; use crate::icon::Icon;
@ -48,7 +48,7 @@ impl Window {
let prevent_default = platform_attr.prevent_default; let prevent_default = platform_attr.prevent_default;
let window = target.runner.window(); 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 canvas = Rc::new(RefCell::new(canvas));
let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id))); let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id)));
@ -67,15 +67,6 @@ impl Window {
let runner = target.runner.clone(); let runner = target.runner.clone();
let destroy_fn = Box::new(move || runner.notify_destroy_window(RootWI(id))); 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 { let window = Window {
id, id,
has_focus, has_focus,
@ -171,7 +162,7 @@ impl Window {
pub fn set_inner_size(&self, size: Size) { pub fn set_inner_size(&self, size: Size) {
self.inner.dispatch(move |inner| { self.inner.dispatch(move |inner| {
let old_size = inner.inner_size(); 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(); let new_size = inner.inner_size();
if old_size != new_size { if old_size != new_size {
(inner.resize_notify_fn)(new_size); (inner.resize_notify_fn)(new_size);
@ -454,7 +445,7 @@ impl Inner {
#[inline] #[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> { pub fn inner_size(&self) -> PhysicalSize<u32> {
self.canvas.borrow().size() self.canvas.borrow().size().get()
} }
} }