Implement hidpi for web platform (#1233)

* fix: use a 'static lifetime for the web backend's `Event` types

* implement hidpi for stdweb (web-sys wip?)

* fix: make all canvas resizes go through backend::set_canvas_size

* update Window docs for web, make `inner/outer_position` return the position in the viewport
This commit is contained in:
Michael Tang 2019-12-31 14:39:33 -08:00 committed by Osspial
parent 28a20aec10
commit 777d9edeaa
11 changed files with 137 additions and 91 deletions

View file

@ -90,6 +90,7 @@ version = "0.3.22"
optional = true optional = true
features = [ features = [
'console', 'console',
'CssStyleDeclaration',
'BeforeUnloadEvent', 'BeforeUnloadEvent',
'Document', 'Document',
'DomRect', 'DomRect',

View file

@ -37,7 +37,8 @@ impl<T> EventLoop<T> {
pub fn run<F>(self, mut event_handler: F) -> ! pub fn run<F>(self, mut event_handler: F) -> !
where where
F: 'static + FnMut(Event<T>, &root::EventLoopWindowTarget<T>, &mut root::ControlFlow), F: 'static
+ FnMut(Event<'static, T>, &root::EventLoopWindowTarget<T>, &mut root::ControlFlow),
{ {
let target = root::EventLoopWindowTarget { let target = root::EventLoopWindowTarget {
p: self.elw.p.clone(), p: self.elw.p.clone(),

View file

@ -11,7 +11,7 @@ use std::{
rc::Rc, rc::Rc,
}; };
pub struct Shared<T>(Rc<Execution<T>>); pub struct Shared<T: 'static>(Rc<Execution<T>>);
impl<T> Clone for Shared<T> { impl<T> Clone for Shared<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -19,21 +19,21 @@ impl<T> Clone for Shared<T> {
} }
} }
pub struct Execution<T> { pub struct Execution<T: 'static> {
runner: RefCell<Option<Runner<T>>>, runner: RefCell<Option<Runner<T>>>,
events: RefCell<VecDeque<Event<T>>>, events: RefCell<VecDeque<Event<'static, T>>>,
id: RefCell<u32>, id: RefCell<u32>,
redraw_pending: RefCell<HashSet<WindowId>>, redraw_pending: RefCell<HashSet<WindowId>>,
} }
struct Runner<T> { struct Runner<T: 'static> {
state: State, state: State,
is_busy: bool, is_busy: bool,
event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>, event_handler: Box<dyn FnMut(Event<'static, T>, &mut root::ControlFlow)>,
} }
impl<T: 'static> Runner<T> { impl<T: 'static> Runner<T> {
pub fn new(event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>) -> Self { pub fn new(event_handler: Box<dyn FnMut(Event<'static, T>, &mut root::ControlFlow)>) -> Self {
Runner { Runner {
state: State::Init, state: State::Init,
is_busy: false, is_busy: false,
@ -55,7 +55,10 @@ impl<T: 'static> Shared<T> {
// Set the event callback to use for the event loop runner // Set the event callback to use for the event loop runner
// This the event callback is a fairly thin layer over the user-provided callback that closes // This the event callback is a fairly thin layer over the user-provided callback that closes
// over a RootEventLoopWindowTarget reference // over a RootEventLoopWindowTarget reference
pub fn set_listener(&self, event_handler: Box<dyn FnMut(Event<T>, &mut root::ControlFlow)>) { pub fn set_listener(
&self,
event_handler: Box<dyn FnMut(Event<'static, T>, &mut root::ControlFlow)>,
) {
self.0.runner.replace(Some(Runner::new(event_handler))); self.0.runner.replace(Some(Runner::new(event_handler)));
self.send_event(Event::NewEvents(StartCause::Init)); self.send_event(Event::NewEvents(StartCause::Init));
@ -79,7 +82,7 @@ impl<T: 'static> Shared<T> {
// Add an event to the event loop runner // Add an event to the event loop runner
// //
// It will determine if the event should be immediately sent to the user or buffered for later // It will determine if the event should be immediately sent to the user or buffered for later
pub fn send_event(&self, event: Event<T>) { pub fn send_event(&self, event: Event<'static, T>) {
// If the event loop is closed, it should discard any new events // If the event loop is closed, it should discard any new events
if self.is_closed() { if self.is_closed() {
return; return;
@ -153,7 +156,7 @@ impl<T: 'static> Shared<T> {
// handle_event takes in events and either queues them or applies a callback // handle_event takes in events and either queues them or applies a callback
// //
// It should only ever be called from send_event // It should only ever be called from send_event
fn handle_event(&self, event: Event<T>, control: &mut root::ControlFlow) { fn handle_event(&self, event: Event<'static, T>, control: &mut root::ControlFlow) {
let is_closed = self.is_closed(); let is_closed = self.is_closed();
match *self.0.runner.borrow_mut() { match *self.0.runner.borrow_mut() {

View file

@ -1,5 +1,5 @@
use super::{backend, device, proxy::Proxy, runner, window}; use super::{backend, device, proxy::Proxy, runner, window};
use crate::dpi::LogicalSize; use crate::dpi::{PhysicalSize, Size};
use crate::event::{DeviceId, ElementState, Event, KeyboardInput, TouchPhase, WindowEvent}; use crate::event::{DeviceId, ElementState, Event, KeyboardInput, TouchPhase, WindowEvent};
use crate::event_loop::ControlFlow; use crate::event_loop::ControlFlow;
use crate::window::WindowId; use crate::window::WindowId;
@ -28,7 +28,7 @@ impl<T> WindowTarget<T> {
Proxy::new(self.runner.clone()) Proxy::new(self.runner.clone())
} }
pub fn run(&self, event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>) { pub fn run(&self, event_handler: Box<dyn FnMut(Event<'static, T>, &mut ControlFlow)>) {
self.runner.set_listener(event_handler); self.runner.set_listener(event_handler);
} }
@ -170,25 +170,27 @@ impl<T> WindowTarget<T> {
let runner = self.runner.clone(); let runner = self.runner.clone();
let raw = canvas.raw().clone(); let raw = canvas.raw().clone();
let mut intended_size = LogicalSize {
width: raw.width() as f64, // The size to restore to after exiting fullscreen.
height: raw.height() as f64, let mut intended_size = PhysicalSize {
width: raw.width() as u32,
height: raw.height() as u32,
}; };
canvas.on_fullscreen_change(move || { canvas.on_fullscreen_change(move || {
// 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(&raw) { let new_size = if backend::is_fullscreen(&raw) {
intended_size = LogicalSize { intended_size = PhysicalSize {
width: raw.width() as f64, width: raw.width() as u32,
height: raw.height() as f64, height: raw.height() as u32,
}; };
backend::window_size() backend::window_size().to_physical(backend::hidpi_factor())
} else { } else {
intended_size intended_size
}; };
raw.set_width(new_size.width as u32);
raw.set_height(new_size.height as u32); backend::set_canvas_size(&raw, Size::Physical(new_size));
runner.send_event(Event::WindowEvent { runner.send_event(Event::WindowEvent {
window_id: WindowId(id), window_id: WindowId(id),
event: WindowEvent::Resized(new_size), event: WindowEvent::Resized(new_size),

View file

@ -10,7 +10,7 @@ impl Handle {
} }
pub fn position(&self) -> PhysicalPosition<i32> { pub fn position(&self) -> PhysicalPosition<i32> {
PhysicalPosition { x: 0.0, y: 0.0 } PhysicalPosition { x: 0, y: 0 }
} }
pub fn name(&self) -> Option<String> { pub fn name(&self) -> Option<String> {
@ -19,8 +19,8 @@ impl Handle {
pub fn size(&self) -> PhysicalSize<u32> { pub fn size(&self) -> PhysicalSize<u32> {
PhysicalSize { PhysicalSize {
width: 0.0, width: 0,
height: 0.0, height: 0,
} }
} }

View file

@ -1,5 +1,5 @@
use super::event; use super::event;
use crate::dpi::{LogicalPosition, LogicalSize}; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE; use crate::error::OsError as RootOE;
use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode};
use crate::platform_impl::OsError; use crate::platform_impl::OsError;
@ -19,6 +19,7 @@ use stdweb::web::{
}; };
pub struct Canvas { pub struct Canvas {
/// Note: resizing the CanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained.
raw: CanvasElement, raw: CanvasElement,
on_focus: Option<EventListenerHandle>, on_focus: Option<EventListenerHandle>,
on_blur: Option<EventListenerHandle>, on_blur: Option<EventListenerHandle>,
@ -82,23 +83,20 @@ impl Canvas {
.expect(&format!("Set attribute: {}", attribute)); .expect(&format!("Set attribute: {}", attribute));
} }
pub fn position(&self) -> (f64, f64) { pub fn position(&self) -> LogicalPosition<f64> {
let bounds = self.raw.get_bounding_client_rect(); let bounds = self.raw.get_bounding_client_rect();
(bounds.get_x(), bounds.get_y()) LogicalPosition {
x: bounds.get_x(),
y: bounds.get_y(),
}
} }
pub fn width(&self) -> f64 { pub fn size(&self) -> PhysicalSize<u32> {
self.raw.width() as f64 PhysicalSize {
width: self.raw.width() as u32,
height: self.raw.height() as u32,
} }
pub fn height(&self) -> f64 {
self.raw.height() as f64
}
pub fn set_size(&self, size: LogicalSize<f64>) {
self.raw.set_width(size.width as u32);
self.raw.set_height(size.height as u32);
} }
pub fn raw(&self) -> &CanvasElement { pub fn raw(&self) -> &CanvasElement {
@ -209,12 +207,13 @@ impl Canvas {
pub fn on_cursor_move<F>(&mut self, mut handler: F) pub fn on_cursor_move<F>(&mut self, mut handler: F)
where where
F: 'static + FnMut(i32, LogicalPosition, ModifiersState), F: 'static + FnMut(i32, PhysicalPosition<i32>, ModifiersState),
{ {
// todo
self.on_cursor_move = Some(self.add_event(move |event: PointerMoveEvent| { self.on_cursor_move = Some(self.add_event(move |event: PointerMoveEvent| {
handler( handler(
event.pointer_id(), event.pointer_id(),
event::mouse_position(&event), event::mouse_position(&event).to_physical(super::hidpi_factor()),
event::mouse_modifiers(&event), event::mouse_modifiers(&event),
); );
})); }));

View file

@ -5,7 +5,7 @@ mod timeout;
pub use self::canvas::Canvas; pub use self::canvas::Canvas;
pub use self::timeout::Timeout; pub use self::timeout::Timeout;
use crate::dpi::LogicalSize; use crate::dpi::{LogicalSize, Size};
use crate::platform::web::WindowExtStdweb; use crate::platform::web::WindowExtStdweb;
use crate::window::Window; use crate::window::Window;
@ -41,6 +41,28 @@ pub fn window_size() -> LogicalSize<f64> {
LogicalSize { width, height } LogicalSize { width, height }
} }
pub fn hidpi_factor() -> f64 {
let window = window();
window.device_pixel_ratio()
}
pub fn set_canvas_size(raw: &CanvasElement, size: Size) {
use stdweb::*;
let hidpi_factor = hidpi_factor();
let physical_size = size.to_physical::<u32>(hidpi_factor);
let logical_size = size.to_logical::<f64>(hidpi_factor);
raw.set_width(physical_size.width);
raw.set_height(physical_size.height);
js! {
@{raw.as_ref()}.style.width = @{logical_size.width} + "px";
@{raw.as_ref()}.style.height = @{logical_size.height} + "px";
}
}
pub fn is_fullscreen(canvas: &CanvasElement) -> bool { pub fn is_fullscreen(canvas: &CanvasElement) -> bool {
match document().fullscreen_element() { match document().fullscreen_element() {
Some(elem) => { Some(elem) => {

View file

@ -1,5 +1,5 @@
use super::event; use super::event;
use crate::dpi::{LogicalPosition, LogicalSize}; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
use crate::error::OsError as RootOE; use crate::error::OsError as RootOE;
use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode};
use crate::platform_impl::OsError; use crate::platform_impl::OsError;
@ -11,6 +11,7 @@ use wasm_bindgen::{closure::Closure, JsCast};
use web_sys::{Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, PointerEvent, WheelEvent}; use web_sys::{Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, PointerEvent, WheelEvent};
pub struct Canvas { pub struct Canvas {
/// Note: resizing the HTMLCanvasElement should go through `backend::set_canvas_size` to ensure the DPI factor is maintained.
raw: HtmlCanvasElement, raw: HtmlCanvasElement,
on_focus: Option<Closure<dyn FnMut(FocusEvent)>>, on_focus: Option<Closure<dyn FnMut(FocusEvent)>>,
on_blur: Option<Closure<dyn FnMut(FocusEvent)>>, on_blur: Option<Closure<dyn FnMut(FocusEvent)>>,
@ -80,23 +81,20 @@ impl Canvas {
.expect(&format!("Set attribute: {}", attribute)); .expect(&format!("Set attribute: {}", attribute));
} }
pub fn position(&self) -> (f64, f64) { pub fn position(&self) -> LogicalPosition<f64> {
let bounds = self.raw.get_bounding_client_rect(); let bounds = self.raw.get_bounding_client_rect();
(bounds.x(), bounds.y()) LogicalPosition {
x: bounds.x(),
y: bounds.y(),
}
} }
pub fn width(&self) -> f64 { pub fn size(&self) -> PhysicalSize<u32> {
self.raw.width() as f64 PhysicalSize {
width: self.raw.width(),
height: self.raw.height(),
} }
pub fn height(&self) -> f64 {
self.raw.height() as f64
}
pub fn set_size(&self, size: LogicalSize<f64>) {
self.raw.set_width(size.width as u32);
self.raw.set_height(size.height as u32);
} }
pub fn raw(&self) -> &HtmlCanvasElement { pub fn raw(&self) -> &HtmlCanvasElement {
@ -218,12 +216,12 @@ impl Canvas {
pub fn on_cursor_move<F>(&mut self, mut handler: F) pub fn on_cursor_move<F>(&mut self, mut handler: F)
where where
F: 'static + FnMut(i32, LogicalPosition, ModifiersState), F: 'static + FnMut(i32, PhysicalPosition<i32>, ModifiersState),
{ {
self.on_cursor_move = Some(self.add_event("pointermove", move |event: PointerEvent| { self.on_cursor_move = Some(self.add_event("pointermove", move |event: PointerEvent| {
handler( handler(
event.pointer_id(), event.pointer_id(),
event::mouse_position(&event), event::mouse_position(&event).to_physical(super::hidpi_factor()),
event::mouse_modifiers(&event), event::mouse_modifiers(&event),
); );
})); }));

View file

@ -5,7 +5,7 @@ mod timeout;
pub use self::canvas::Canvas; pub use self::canvas::Canvas;
pub use self::timeout::Timeout; pub use self::timeout::Timeout;
use crate::dpi::LogicalSize; use crate::dpi::{LogicalSize, Size};
use crate::platform::web::WindowExtWebSys; use crate::platform::web::WindowExtWebSys;
use crate::window::Window; use crate::window::Window;
use wasm_bindgen::{closure::Closure, JsCast}; use wasm_bindgen::{closure::Closure, JsCast};
@ -56,6 +56,29 @@ pub fn window_size() -> LogicalSize<f64> {
LogicalSize { width, height } LogicalSize { width, height }
} }
pub fn hidpi_factor() -> f64 {
let window = web_sys::window().expect("Failed to obtain window");
window.device_pixel_ratio()
}
pub fn set_canvas_size(raw: &HtmlCanvasElement, size: Size) {
let hidpi_factor = hidpi_factor();
let physical_size = size.to_physical::<u32>(hidpi_factor);
let logical_size = size.to_logical::<f64>(hidpi_factor);
raw.set_width(physical_size.width);
raw.set_height(physical_size.height);
let style = raw.style();
style
.set_property("width", &format!("{}px", logical_size.width))
.expect("Failed to set canvas width");
style
.set_property("height", &format!("{}px", logical_size.height))
.expect("Failed to set canvas height");
}
pub fn is_fullscreen(canvas: &HtmlCanvasElement) -> bool { pub fn is_fullscreen(canvas: &HtmlCanvasElement) -> bool {
let window = window().expect("Failed to obtain window"); let window = window().expect("Failed to obtain window");
let document = window.document().expect("Failed to obtain document"); let document = window.document().expect("Failed to obtain document");

View file

@ -1,4 +1,4 @@
use crate::dpi::{LogicalPosition, LogicalSize}; use crate::dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size};
use crate::error::{ExternalError, NotSupportedError, OsError as RootOE}; use crate::error::{ExternalError, NotSupportedError, OsError as RootOE};
use crate::icon::Icon; use crate::icon::Icon;
use crate::monitor::MonitorHandle as RootMH; use crate::monitor::MonitorHandle as RootMH;
@ -15,7 +15,6 @@ use std::collections::VecDeque;
pub struct Window { pub struct Window {
canvas: backend::Canvas, canvas: backend::Canvas,
previous_pointer: RefCell<&'static str>, previous_pointer: RefCell<&'static str>,
position: RefCell<LogicalPosition<f64>>,
id: Id, id: Id,
register_redraw_request: Box<dyn Fn()>, register_redraw_request: Box<dyn Fn()>,
} }
@ -39,15 +38,14 @@ impl Window {
let window = Window { let window = Window {
canvas, canvas,
previous_pointer: RefCell::new("auto"), previous_pointer: RefCell::new("auto"),
position: RefCell::new(LogicalPosition { x: 0.0, y: 0.0 }),
id, id,
register_redraw_request, register_redraw_request,
}; };
window.set_inner_size(attr.inner_size.unwrap_or(LogicalSize { window.set_inner_size(attr.inner_size.unwrap_or(Size::Logical(LogicalSize {
width: 1024.0, width: 1024.0,
height: 768.0, height: 768.0,
})); })));
window.set_title(&attr.title); window.set_title(&attr.title);
window.set_maximized(attr.maximized); window.set_maximized(attr.maximized);
window.set_visible(attr.visible); window.set_visible(attr.visible);
@ -72,18 +70,17 @@ impl Window {
(self.register_redraw_request)(); (self.register_redraw_request)();
} }
pub fn outer_position(&self) -> Result<LogicalPosition<f64>, NotSupportedError> { pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
let (x, y) = self.canvas.position(); Ok(self.canvas.position().to_physical(self.hidpi_factor()))
Ok(LogicalPosition { x, y })
} }
pub fn inner_position(&self) -> Result<LogicalPosition<f64>, NotSupportedError> { pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
Ok(*self.position.borrow()) // Note: the canvas element has no window decorations, so this is equal to `outer_position`.
self.outer_position()
} }
pub fn set_outer_position(&self, position: LogicalPosition<f64>) { pub fn set_outer_position(&self, position: Position) {
*self.position.borrow_mut() = position; let position = position.to_logical::<f64>(self.hidpi_factor());
self.canvas.set_attribute("position", "fixed"); self.canvas.set_attribute("position", "fixed");
self.canvas.set_attribute("left", &position.x.to_string()); self.canvas.set_attribute("left", &position.x.to_string());
@ -91,33 +88,28 @@ impl Window {
} }
#[inline] #[inline]
pub fn inner_size(&self) -> LogicalSize<f64> { pub fn inner_size(&self) -> PhysicalSize<u32> {
LogicalSize { self.canvas.size()
width: self.canvas.width() as f64,
height: self.canvas.height() as f64,
}
} }
#[inline] #[inline]
pub fn outer_size(&self) -> LogicalSize<f64> { pub fn outer_size(&self) -> PhysicalSize<u32> {
LogicalSize { // Note: the canvas element has no window decorations, so this is equal to `inner_size`.
width: self.canvas.width() as f64, self.inner_size()
height: self.canvas.height() as f64,
}
} }
#[inline] #[inline]
pub fn set_inner_size(&self, size: LogicalSize<f64>) { pub fn set_inner_size(&self, size: Size) {
self.canvas.set_size(size); backend::set_canvas_size(self.canvas.raw(), size);
} }
#[inline] #[inline]
pub fn set_min_inner_size(&self, _dimensions: Option<LogicalSize<f64>>) { pub fn set_min_inner_size(&self, _dimensions: Option<Size>) {
// Intentionally a no-op: users can't resize canvas elements // Intentionally a no-op: users can't resize canvas elements
} }
#[inline] #[inline]
pub fn set_max_inner_size(&self, _dimensions: Option<LogicalSize<f64>>) { pub fn set_max_inner_size(&self, _dimensions: Option<Size>) {
// Intentionally a no-op: users can't resize canvas elements // Intentionally a no-op: users can't resize canvas elements
} }
@ -128,7 +120,7 @@ impl Window {
#[inline] #[inline]
pub fn hidpi_factor(&self) -> f64 { pub fn hidpi_factor(&self) -> f64 {
1.0 super::backend::hidpi_factor()
} }
#[inline] #[inline]
@ -178,10 +170,7 @@ impl Window {
} }
#[inline] #[inline]
pub fn set_cursor_position( pub fn set_cursor_position(&self, _position: Position) -> Result<(), ExternalError> {
&self,
_position: LogicalPosition<f64>,
) -> Result<(), ExternalError> {
// Intentionally a no-op, as the web does not support setting cursor positions // Intentionally a no-op, as the web does not support setting cursor positions
Ok(()) Ok(())
} }
@ -246,7 +235,7 @@ impl Window {
} }
#[inline] #[inline]
pub fn set_ime_position(&self, _position: LogicalPosition<f64>) { pub fn set_ime_position(&self, _position: Position) {
// Currently a no-op as it does not seem there is good support for this on web // Currently a no-op as it does not seem there is good support for this on web
} }

View file

@ -419,6 +419,8 @@ impl Window {
/// ///
/// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
/// window's [safe area] in the screen space coordinate system. /// window's [safe area] in the screen space coordinate system.
/// - **Web:** Returns the top-left coordinates relative to the viewport. _Note: this returns the
/// same value as `outer_position`._
/// ///
/// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
#[inline] #[inline]
@ -440,6 +442,7 @@ impl Window {
/// ///
/// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the /// - **iOS:** Can only be called on the main thread. Returns the top left coordinates of the
/// window in the screen space coordinate system. /// window in the screen space coordinate system.
/// - **Web:** Returns the top-left coordinates relative to the viewport.
#[inline] #[inline]
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> { pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
self.window.outer_position() self.window.outer_position()
@ -454,6 +457,7 @@ impl Window {
/// ///
/// - **iOS:** Can only be called on the main thread. Sets the top left coordinates of the /// - **iOS:** Can only be called on the main thread. Sets the top left coordinates of the
/// window in the screen space coordinate system. /// window in the screen space coordinate system.
/// - **Web:** Sets the top-left coordinates relative to the viewport.
#[inline] #[inline]
pub fn set_outer_position<P: Into<Position>>(&self, position: P) { pub fn set_outer_position<P: Into<Position>>(&self, position: P) {
self.window.set_outer_position(position.into()) self.window.set_outer_position(position.into())
@ -467,6 +471,7 @@ impl Window {
/// ///
/// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window's /// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window's
/// [safe area] in screen space coordinates. /// [safe area] in screen space coordinates.
/// - **Web:** Returns the size of the canvas element.
/// ///
/// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc /// [safe area]: https://developer.apple.com/documentation/uikit/uiview/2891103-safeareainsets?language=objc
#[inline] #[inline]
@ -483,6 +488,7 @@ impl Window {
/// ///
/// - **iOS:** Unimplemented. Currently this panics, as it's not clear what `set_inner_size` /// - **iOS:** Unimplemented. Currently this panics, as it's not clear what `set_inner_size`
/// would mean for iOS. /// would mean for iOS.
/// - **Web:** Sets the size of the canvas element.
#[inline] #[inline]
pub fn set_inner_size<S: Into<Size>>(&self, size: S) { pub fn set_inner_size<S: Into<Size>>(&self, size: S) {
self.window.set_inner_size(size.into()) self.window.set_inner_size(size.into())
@ -497,6 +503,8 @@ impl Window {
/// ///
/// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window in /// - **iOS:** Can only be called on the main thread. Returns the `PhysicalSize` of the window in
/// screen space coordinates. /// screen space coordinates.
/// - **Web:** Returns the size of the canvas element. _Note: this returns the same value as
/// `inner_size`._
#[inline] #[inline]
pub fn outer_size(&self) -> PhysicalSize<u32> { pub fn outer_size(&self) -> PhysicalSize<u32> {
self.window.outer_size() self.window.outer_size()