From 1fe4a7a4ea16d98f57355c9b61af600576f41e41 Mon Sep 17 00:00:00 2001 From: Ryan G Date: Wed, 15 Jan 2020 21:20:14 -0500 Subject: [PATCH] Add the ability to pass a prebuilt canvas (#1394) This allows Winit to take control of existing canvas elements in the DOM, which is useful for web applications with other content in the page. --- CHANGELOG.md | 1 + src/platform/web.rs | 33 ++++++++++++++++++++++++- src/platform_impl/web/stdweb/canvas.rs | 17 +++++++------ src/platform_impl/web/stdweb/mod.rs | 2 ++ src/platform_impl/web/web_sys/canvas.rs | 27 +++++++++++--------- src/platform_impl/web/web_sys/mod.rs | 2 ++ src/platform_impl/web/window.rs | 10 +++++--- 7 files changed, 69 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b048eb39..0eea9c87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - `WindowBuilder` now implements `Default`. - **Breaking:** `WindowEvent::CursorMoved` changed to `f64` units, preserving high-precision data supplied by most backends - On Wayland, fix coordinates in mouse events when scale factor isn't 1 +- On Web, add the ability to provide a custom canvas # 0.20.0 (2020-01-05) diff --git a/src/platform/web.rs b/src/platform/web.rs index 5fca0c42..6083f5cb 100644 --- a/src/platform/web.rs +++ b/src/platform/web.rs @@ -3,7 +3,10 @@ //! The web target does not automatically insert the canvas element object into the web page, to //! allow end users to determine how the page should be laid out. Use the `WindowExtStdweb` or //! `WindowExtWebSys` traits (depending on your web backend) to retrieve the canvas from the -//! Window. +//! Window. Alternatively, use the `WindowBuilderExtStdweb` or `WindowBuilderExtWebSys` to provide +//! your own canvas. + +use crate::window::WindowBuilder; #[cfg(feature = "stdweb")] use stdweb::web::html_element::CanvasElement; @@ -20,3 +23,31 @@ use web_sys::HtmlCanvasElement; pub trait WindowExtWebSys { fn canvas(&self) -> HtmlCanvasElement; } + +#[cfg(feature = "stdweb")] +pub trait WindowBuilderExtStdweb { + fn with_canvas(self, canvas: Option) -> Self; +} + +#[cfg(feature = "stdweb")] +impl WindowBuilderExtStdweb for WindowBuilder { + fn with_canvas(mut self, canvas: Option) -> Self { + self.platform_specific.canvas = canvas; + + self + } +} + +#[cfg(feature = "web-sys")] +pub trait WindowBuilderExtWebSys { + fn with_canvas(self, canvas: Option) -> Self; +} + +#[cfg(feature = "web-sys")] +impl WindowBuilderExtWebSys for WindowBuilder { + fn with_canvas(mut self, canvas: Option) -> Self { + self.platform_specific.canvas = canvas; + + self + } +} diff --git a/src/platform_impl/web/stdweb/canvas.rs b/src/platform_impl/web/stdweb/canvas.rs index 35bc8044..a3581917 100644 --- a/src/platform_impl/web/stdweb/canvas.rs +++ b/src/platform_impl/web/stdweb/canvas.rs @@ -2,7 +2,7 @@ use super::event; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; -use crate::platform_impl::OsError; +use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; use std::cell::RefCell; use std::rc::Rc; @@ -43,12 +43,15 @@ impl Drop for Canvas { } impl Canvas { - pub fn create() -> Result { - let canvas: CanvasElement = document() - .create_element("canvas") - .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))? - .try_into() - .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?; + pub fn create(attr: PlatformSpecificWindowBuilderAttributes) -> Result { + let canvas = match attr.canvas { + Some(canvas) => canvas, + None => document() + .create_element("canvas") + .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))? + .try_into() + .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))?, + }; // A tabindex is needed in order to capture local keyboard events. // A "0" value means that the element should be focusable in diff --git a/src/platform_impl/web/stdweb/mod.rs b/src/platform_impl/web/stdweb/mod.rs index 6b45e683..9274ab99 100644 --- a/src/platform_impl/web/stdweb/mod.rs +++ b/src/platform_impl/web/stdweb/mod.rs @@ -72,3 +72,5 @@ pub fn is_fullscreen(canvas: &CanvasElement) -> bool { None => false, } } + +pub type RawCanvasType = CanvasElement; diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 1d7e4746..970f87da 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -2,7 +2,7 @@ use super::event; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; -use crate::platform_impl::OsError; +use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; use std::cell::RefCell; use std::rc::Rc; @@ -35,18 +35,23 @@ impl Drop for Canvas { } impl Canvas { - pub fn create() -> Result { - let window = - web_sys::window().ok_or(os_error!(OsError("Failed to obtain window".to_owned())))?; + pub fn create(attr: PlatformSpecificWindowBuilderAttributes) -> Result { + let canvas = match attr.canvas { + Some(canvas) => canvas, + None => { + let window = web_sys::window() + .ok_or(os_error!(OsError("Failed to obtain window".to_owned())))?; - let document = window - .document() - .ok_or(os_error!(OsError("Failed to obtain document".to_owned())))?; + let document = window + .document() + .ok_or(os_error!(OsError("Failed to obtain document".to_owned())))?; - let canvas: HtmlCanvasElement = document - .create_element("canvas") - .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))? - .unchecked_into(); + document + .create_element("canvas") + .map_err(|_| os_error!(OsError("Failed to create canvas element".to_owned())))? + .unchecked_into() + } + }; // A tabindex is needed in order to capture local keyboard events. // A "0" value means that the element should be focusable in diff --git a/src/platform_impl/web/web_sys/mod.rs b/src/platform_impl/web/web_sys/mod.rs index fec86402..cafbae1f 100644 --- a/src/platform_impl/web/web_sys/mod.rs +++ b/src/platform_impl/web/web_sys/mod.rs @@ -91,3 +91,5 @@ pub fn is_fullscreen(canvas: &HtmlCanvasElement) -> bool { None => false, } } + +pub type RawCanvasType = HtmlCanvasElement; diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 8c1a1b91..bd525056 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -23,13 +23,13 @@ impl Window { pub fn new( target: &EventLoopWindowTarget, attr: WindowAttributes, - _: PlatformSpecificBuilderAttributes, + platform_attr: PlatformSpecificBuilderAttributes, ) -> Result { let runner = target.runner.clone(); let id = target.generate_id(); - let mut canvas = backend::Canvas::create()?; + let mut canvas = backend::Canvas::create(platform_attr)?; let register_redraw_request = Box::new(move || runner.request_redraw(RootWI(id))); @@ -281,5 +281,7 @@ impl Id { } } -#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct PlatformSpecificBuilderAttributes; +#[derive(Default, Clone)] +pub struct PlatformSpecificBuilderAttributes { + pub(crate) canvas: Option, +}