Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use correct canvas size for scale factor change #2849

Merged
merged 1 commit into from
Jun 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 4 additions & 1 deletion examples/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
12 changes: 5 additions & 7 deletions src/platform_impl/web/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,16 +327,14 @@ impl<T: 'static> Shared<T> {

// 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::<f64>(old_scale);
let mut new_size = logical_size.to_physical(new_scale);
self.handle_single_event_sync(
Expand All @@ -351,7 +349,7 @@ impl<T: 'static> Shared<T> {
);

// 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,
Expand Down
24 changes: 10 additions & 14 deletions src/platform_impl/web/event_loop/window_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -89,6 +89,7 @@ impl<T> EventLoopWindowTarget<T> {
has_focus: Arc<AtomicBool>,
) {
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());

Expand Down Expand Up @@ -502,32 +503,27 @@ impl<T> EventLoopWindowTarget<T> {
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),
Expand Down
44 changes: 32 additions & 12 deletions src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Cell<PhysicalSize<u32>>>,
wants_fullscreen: Rc<RefCell<bool>>,
}

impl Canvas {
pub fn create(
window: web_sys::Window,
attr: PlatformSpecificWindowBuilderAttributes,
attr: &WindowAttributes,
platform_attr: PlatformSpecificWindowBuilderAttributes,
) -> Result<Self, RootOE> {
let canvas = match attr.canvas {
let canvas = match platform_attr.canvas {
Some(canvas) => canvas,
None => {
let document = window
Expand All @@ -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,
Expand All @@ -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> {
Expand Down Expand Up @@ -121,11 +140,12 @@ impl Canvas {
}
}

pub fn size(&self) -> PhysicalSize<u32> {
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<Cell<PhysicalSize<u32>>> {
&self.common.size
}

pub fn raw(&self) -> &HtmlCanvasElement {
Expand Down
19 changes: 13 additions & 6 deletions src/platform_impl/web/web_sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>(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::<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) {
Expand Down
17 changes: 4 additions & 13 deletions src/platform_impl/web/window.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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)));
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -454,7 +445,7 @@ impl Inner {

#[inline]
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.canvas.borrow().size()
self.canvas.borrow().size().get()
}
}

Expand Down