Skip to content

Commit

Permalink
Implement ResizeObserver
Browse files Browse the repository at this point in the history
Co-Authored-By: Liam Murphy <43807659+Liamolucko@users.noreply.github.com>
  • Loading branch information
daxpedda and Liamolucko committed Jun 7, 2023
1 parent f215015 commit 288ebdb
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 128 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Web, fix pen treated as mouse input.
- On Web, send mouse position on button release as well.
- On Web, fix touch input not gaining or loosing focus.
- **Breaking:** On Web, dropped support for Safari versions below 13.
- **Breaking:** On Web, dropped support for Safari versions below 13.1.
- On Web, prevent clicks on the canvas to select text.
- On Web, use high-frequency pointer input events when supported by the browser.
- On Web, `EventLoopProxy` now implements `Send`.
Expand All @@ -79,6 +79,8 @@ And please only add new entries to the top of this list, right below the `# Unre
- On Web, scale factor and dark mode detection are now more robust.
- On Web, fix the bfcache by not using the `beforeunload` event.
- On Web, fix scale factor resize suggestion always overwriting the canvas size.
- **Breaking:** On Web, the canvas size is not controlled by Winit anymore and external changes to
the canvas size will be reported through `WindowEvent::Resized`.

# 0.28.6

Expand Down
15 changes: 14 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,13 @@ redox_syscall = "0.3"

[target.'cfg(target_family = "wasm")'.dependencies.web_sys]
package = "web-sys"
version = "0.3.22"
version = "0.3.63"
features = [
'console',
'CssStyleDeclaration',
'Document',
'DomRect',
'DomRectReadOnly',
'Element',
'Event',
"EventListenerOptions",
Expand All @@ -146,6 +147,11 @@ features = [
'MediaQueryList',
'Node',
'PointerEvent',
'ResizeObserver',
'ResizeObserverBoxOptions',
'ResizeObserverEntry',
'ResizeObserverOptions',
'ResizeObserverSize',
'Window',
'WheelEvent'
]
Expand All @@ -165,3 +171,10 @@ web-sys = { version = "0.3.22", features = ['CanvasRenderingContext2d'] }
members = [
"run-wasm",
]

[patch.crates-io]
js-sys = { git = "https://github.com/daxpedda/wasm-bindgen", branch = "winit" }
wasm-bindgen = { git = "https://github.com/daxpedda/wasm-bindgen", branch = "winit" }
wasm-bindgen-cli-support = { git = "https://github.com/daxpedda/wasm-bindgen", branch = "winit" }
wasm-bindgen-futures = { git = "https://github.com/daxpedda/wasm-bindgen", branch = "winit" }
web-sys = { git = "https://github.com/daxpedda/wasm-bindgen", branch = "winit" }
24 changes: 22 additions & 2 deletions examples/web.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#![allow(clippy::disallowed_methods, clippy::single_match)]

use winit::{
event::{Event, WindowEvent},
event::{ElementState, Event, KeyEvent, WindowEvent},
event_loop::EventLoop,
window::WindowBuilder,
keyboard::KeyCode,
window::{Fullscreen, WindowBuilder},
};

pub fn main() {
Expand Down Expand Up @@ -31,6 +32,25 @@ pub fn main() {
Event::MainEventsCleared => {
window.request_redraw();
}
Event::WindowEvent {
window_id,
event:
WindowEvent::KeyboardInput {
event:
KeyEvent {
physical_key: KeyCode::KeyF,
state: ElementState::Released,
..
},
..
},
} if window_id == window.id() => {
if window.fullscreen().is_some() {
window.set_fullscreen(None);
} else {
window.set_fullscreen(Some(Fullscreen::Borderless(None)));
}
}
_ => (),
}
});
Expand Down
17 changes: 5 additions & 12 deletions src/platform_impl/web/event_loop/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,14 +327,13 @@ impl<T: 'static> Shared<T> {

// Now handle the `ScaleFactorChanged` events.
for &(id, ref canvas) in &*self.0.all_canvases.borrow() {
let rc = match canvas.upgrade() {
let canvas = 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 = canvas.size().get();
let current_size = canvas.borrow().inner_size();
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 @@ -348,16 +347,10 @@ impl<T: 'static> Shared<T> {
&mut control,
);

// Then we resize the canvas to the new size and send a `Resized` event:
// Then we resize the canvas to the new size, a new
// `Resized` event will be sent by the `ResizeObserver`:
if current_size != new_size {
backend::set_canvas_size(&canvas, crate::dpi::Size::Physical(new_size));
self.handle_single_event_sync(
Event::WindowEvent {
window_id: id,
event: crate::event::WindowEvent::Resized(new_size),
},
&mut control,
);
backend::set_canvas_size(canvas.borrow().raw(), new_size);
}
}

Expand Down
40 changes: 10 additions & 30 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,6 @@ use super::{
runner,
window::WindowId,
};
use crate::dpi::Size;
use crate::event::{
DeviceEvent, DeviceId as RootDeviceId, ElementState, Event, KeyEvent, Touch, TouchPhase,
WindowEvent,
Expand Down Expand Up @@ -503,35 +502,6 @@ impl<T> EventLoopWindowTarget<T> {
prevent_default,
);

// The size to restore to after exiting fullscreen.
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, canvas.raw()) {
intended_size = canvas.size().get();

backend::window_size(&window).to_physical(backend::scale_factor(&window))
} else {
intended_size
};

backend::set_canvas_size(&canvas, Size::Physical(new_size));
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Resized(new_size),
});
runner.request_redraw(RootWindowId(id));
}
});

let runner = self.runner.clone();
canvas.on_touch_cancel(move |device_id, location, force| {
runner.send_event(Event::WindowEvent {
Expand All @@ -558,6 +528,16 @@ impl<T> EventLoopWindowTarget<T> {
event: WindowEvent::ThemeChanged(theme),
});
});

let runner = self.runner.clone();
canvas.on_resize(move |size| {
canvas_clone.borrow().set_inner_size(size);
runner.send_event(Event::WindowEvent {
window_id: RootWindowId(id),
event: WindowEvent::Resized(size),
});
runner.request_redraw(RootWindowId(id));
});
}

pub fn available_monitors(&self) -> VecDequeIter<MonitorHandle> {
Expand Down
68 changes: 32 additions & 36 deletions src/platform_impl/web/web_sys/canvas.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use super::event_handle::EventListenerHandle;
use super::media_query_handle::MediaQueryListHandle;
use super::pointer::PointerHandler;
use super::resize::ResizeHandle;
use super::{event, ButtonsState};
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE;
use crate::event::{Force, MouseButton, MouseScrollDelta};
use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState};
Expand All @@ -29,9 +30,9 @@ pub struct Canvas {
on_keyboard_release: Option<EventListenerHandle<dyn FnMut(KeyboardEvent)>>,
on_keyboard_press: Option<EventListenerHandle<dyn FnMut(KeyboardEvent)>>,
on_mouse_wheel: Option<EventListenerHandle<dyn FnMut(WheelEvent)>>,
on_fullscreen_change: Option<EventListenerHandle<dyn FnMut(Event)>>,
on_dark_mode: Option<MediaQueryListHandle>,
pointer_handler: PointerHandler,
on_resize: Option<ResizeHandle>,
}

pub struct Common {
Expand Down Expand Up @@ -73,22 +74,16 @@ impl Canvas {
.map_err(|_| os_error!(OsError("Failed to set a tabindex".to_owned())))?;
}

let size = attr
.inner_size
.unwrap_or(
LogicalSize {
width: 1024.0,
height: 768.0,
}
.into(),
)
.to_physical(super::scale_factor(&window));
if let Some(size) = attr.inner_size {
let size = size.to_physical(super::scale_factor(&window));
super::set_canvas_size(&canvas, size);
}

let canvas = Canvas {
Ok(Canvas {
common: Common {
window,
raw: canvas,
size: Rc::new(Cell::new(size)),
size: Rc::default(),
wants_fullscreen: Rc::new(RefCell::new(false)),
},
on_touch_start: None,
Expand All @@ -98,14 +93,10 @@ impl Canvas {
on_keyboard_release: None,
on_keyboard_press: None,
on_mouse_wheel: None,
on_fullscreen_change: None,
on_dark_mode: None,
pointer_handler: PointerHandler::new(),
};

super::set_canvas_size(&canvas, size.into());

Ok(canvas)
on_resize: None,
})
}

pub fn set_cursor_lock(&self, lock: bool) -> Result<(), RootOE> {
Expand Down Expand Up @@ -138,12 +129,16 @@ impl Canvas {
}
}

pub fn window(&self) -> &web_sys::Window {
&self.common.window
pub fn inner_size(&self) -> PhysicalSize<u32> {
self.common.size.get()
}

pub fn size(&self) -> &Rc<Cell<PhysicalSize<u32>>> {
&self.common.size
pub fn set_inner_size(&self, size: PhysicalSize<u32>) {
self.common.size.set(size)
}

pub fn window(&self) -> &web_sys::Window {
&self.common.window
}

pub fn raw(&self) -> &HtmlCanvasElement {
Expand Down Expand Up @@ -327,16 +322,6 @@ impl Canvas {
}));
}

pub fn on_fullscreen_change<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(),
{
self.on_fullscreen_change = Some(
self.common
.add_event("fullscreenchange", move |_: Event| handler()),
);
}

pub fn on_dark_mode<F>(&mut self, mut handler: F)
where
F: 'static + FnMut(bool),
Expand All @@ -348,6 +333,17 @@ impl Canvas {
));
}

pub fn on_resize<F>(&mut self, handler: F)
where
F: 'static + FnMut(PhysicalSize<u32>),
{
self.on_resize = Some(ResizeHandle::new(
self.window().clone(),
self.raw().clone(),
handler,
));
}

pub fn request_fullscreen(&self) {
self.common.request_fullscreen()
}
Expand All @@ -362,9 +358,9 @@ impl Canvas {
self.on_keyboard_release = None;
self.on_keyboard_press = None;
self.on_mouse_wheel = None;
self.on_fullscreen_change = None;
self.on_dark_mode = None;
self.pointer_handler.remove_listeners()
self.pointer_handler.remove_listeners();
self.on_resize = None;
}
}

Expand Down
28 changes: 5 additions & 23 deletions src/platform_impl/web/web_sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod event;
mod event_handle;
mod media_query_handle;
mod pointer;
mod resize;
mod scaling;
mod timeout;

Expand All @@ -11,7 +12,7 @@ pub use self::event::ButtonsState;
pub use self::scaling::ScaleChangeDetector;
pub use self::timeout::{AnimationFrameRequest, Timeout};

use crate::dpi::{LogicalSize, Size};
use crate::dpi::PhysicalSize;
use crate::platform::web::WindowExtWebSys;
use crate::window::Window;
use wasm_bindgen::closure::Closure;
Expand Down Expand Up @@ -52,32 +53,13 @@ impl WindowExtWebSys for Window {
}
}

pub fn window_size(window: &web_sys::Window) -> LogicalSize<f64> {
let width = window
.inner_width()
.expect("Failed to get width")
.as_f64()
.expect("Failed to get width as f64");
let height = window
.inner_height()
.expect("Failed to get height")
.as_f64()
.expect("Failed to get height as f64");

LogicalSize { width, height }
}

pub fn scale_factor(window: &web_sys::Window) -> f64 {
window.device_pixel_ratio()
}

pub fn set_canvas_size(canvas: &Canvas, new_size: Size) {
let scale_factor = scale_factor(canvas.window());
let new_size = new_size.to_physical(scale_factor);

canvas.size().set(new_size);
set_canvas_style_property(canvas.raw(), "width", &format!("{}px", new_size.width));
set_canvas_style_property(canvas.raw(), "height", &format!("{}px", new_size.height));
pub fn set_canvas_size(raw: &HtmlCanvasElement, new_size: PhysicalSize<u32>) {
set_canvas_style_property(raw, "width", &format!("{}px", new_size.width));
set_canvas_style_property(raw, "height", &format!("{}px", new_size.height));
}

pub fn set_canvas_style_property(raw: &HtmlCanvasElement, property: &str, value: &str) {
Expand Down
Loading

0 comments on commit 288ebdb

Please sign in to comment.