diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d12102d..68586ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,10 +28,14 @@ jobs: os: [ubuntu-latest, windows-latest, macOS-latest] runs-on: ${{ matrix.os }} steps: - - if: matrix.os == 'ubuntu-latest' - run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev - - uses: actions/checkout@v2 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose + - if: matrix.os == 'ubuntu-latest' + run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev + - uses: actions/checkout@v2 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose + - name: Install wasm target + run: rustup target add wasm32-unknown-unknown + - name: Check wasm build + run: cargo check --target wasm32-unknown-unknown --no-default-features diff --git a/src/lib.rs b/src/lib.rs index 6d72cce..cb22688 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,8 +27,6 @@ use std::{ffi::c_void, fmt, time::Duration}; #[cfg(target_arch = "wasm32")] use std::panic; -#[cfg(target_arch = "wasm32")] -use web_sys::HtmlElement; #[cfg(target_os = "macos")] use os::macos as imp; diff --git a/src/os/wasm/mod.rs b/src/os/wasm/mod.rs index 5b543a8..d11c729 100644 --- a/src/os/wasm/mod.rs +++ b/src/os/wasm/mod.rs @@ -41,19 +41,25 @@ struct MouseState { middle_button: Cell, } +struct Context2D { + context: CanvasRenderingContext2d, + img_data: ImageData, +} + // IDEA(stefano): possibly have this contain a "document" field, so not to recompute it every time pub struct Window { width: u32, height: u32, bg_color: u32, window_scale: usize, - img_data: ImageData, canvas: HtmlCanvasElement, - context: Rc, + // 2D context is created lazily since its creation preculdes creation of webgl & webgpu contexts. + context2d: Option, mouse_state: Rc, key_handler: Rc>, menu_counter: MenuHandle, menus: Vec, + raw_handle_id: u32, } impl Window { @@ -83,6 +89,13 @@ impl Window { .dyn_into::() .unwrap(); + // Raw handle requires to inject an id into the canvas' data attributes. + // TODO assign a different ID to each window + let raw_handle_id = 0; + canvas + .set_attribute("data-raw-handle", &raw_handle_id.to_string()) + .unwrap(); + let container = document .get_element_by_id(container) .unwrap() @@ -97,15 +110,6 @@ impl Window { canvas.set_tab_index(0); // Create an image buffer - let context: CanvasRenderingContext2d = canvas - .get_context("2d") - .unwrap() - .unwrap() - .dyn_into::() - .unwrap(); - context.set_image_smoothing_enabled(false); - let img_data = ImageData::new_with_sw(width as u32, height as u32).unwrap(); - let context = Rc::new(context); let key_handler = Rc::new(RefCell::new(KeyHandler::new())); let mouse_struct = MouseState { pos: Cell::new(None), @@ -180,21 +184,31 @@ impl Window { closure.forget(); } - let mut window = Window { + Ok(Window { width: width as u32, height: height as u32, bg_color: 0, window_scale, - img_data, canvas, - context: context.clone(), + context2d: None, key_handler, mouse_state, menu_counter: MenuHandle(0), menus: Vec::new(), - }; + raw_handle_id, + }) + } - Ok(window) + fn create_2d_context(&self) -> CanvasRenderingContext2d { + let context: CanvasRenderingContext2d = self + .canvas + .get_context("2d") + .unwrap() + .unwrap() + .dyn_into::() + .unwrap(); + context.set_image_smoothing_enabled(false); + context } #[inline] @@ -204,7 +218,7 @@ impl Window { } #[inline] - pub fn set_rate(&mut self, rate: Option) {} + pub fn set_rate(&mut self, _rate: Option) {} #[inline] pub fn update_rate(&mut self) {} @@ -215,7 +229,7 @@ impl Window { } #[inline] - pub fn topmost(&self, topmost: bool) { + pub fn topmost(&self, _topmost: bool) { // TODO? } @@ -262,13 +276,22 @@ impl Window { )?; let mut data = u32_as_u8(buffer); - self.img_data = ImageData::new_with_u8_clamped_array_and_sh( + let image_data = ImageData::new_with_u8_clamped_array_and_sh( Clamped(&mut data), self.width, self.height, ) .unwrap(); + if let Some(context2d) = &mut self.context2d { + context2d.img_data = image_data; + } else { + self.context2d = Some(Context2D { + context: self.create_2d_context(), + img_data: image_data, + }); + } + self.update(); Ok(()) @@ -277,16 +300,20 @@ impl Window { #[inline] pub fn update(&mut self) { self.key_handler.borrow_mut().update(); - self.context - .put_image_data(&self.img_data, 0.0, 0.0) - .unwrap(); + + if let Some(context2d) = &self.context2d { + context2d + .context + .put_image_data(&context2d.img_data, 0.0, 0.0) + .unwrap(); + } } #[inline] - pub fn set_icon(&mut self, icon: Icon) {} + pub fn set_icon(&mut self, _icon: Icon) {} #[inline] - pub fn set_position(&mut self, x: isize, y: isize) {} + pub fn set_position(&mut self, _x: isize, _y: isize) {} #[inline] pub fn get_position(&self) -> (isize, isize) { @@ -343,7 +370,7 @@ impl Window { } #[inline] - pub fn set_cursor_style(&mut self, cursor: CursorStyle) {} + pub fn set_cursor_style(&mut self, _cursor: CursorStyle) {} #[inline] pub fn get_keys(&self) -> Vec { @@ -397,8 +424,10 @@ impl Window { #[inline] pub fn is_active(&mut self) -> bool { - let document = window().unwrap().document().unwrap(); - document.active_element().unwrap_or(return false) == **self.canvas + window() + .and_then(|window| window.document()) + .and_then(|document| document.active_element()) + .map_or(false, |element| element == **self.canvas) } #[inline] @@ -445,7 +474,7 @@ impl Menu { } #[inline] - pub fn add_sub_menu(&mut self, name: &str, sub_menu: &Menu) {} + pub fn add_sub_menu(&mut self, _name: &str, _sub_menu: &Menu) {} #[inline] fn next_item_handle(&mut self) -> MenuItemHandle { @@ -470,13 +499,12 @@ impl Menu { } #[inline] - pub fn remove_item(&mut self, handle: &MenuItemHandle) {} + pub fn remove_item(&mut self, _handle: &MenuItemHandle) {} } impl HasWindowHandle for Window { fn window_handle(&self) -> std::result::Result { - // TODO assign a different ID to each window - let handle = WebWindowHandle::new(0); + let handle = WebWindowHandle::new(self.raw_handle_id); let raw_handle = RawWindowHandle::Web(handle); unsafe { Ok(WindowHandle::borrow_raw(raw_handle)) } } diff --git a/src/rate.rs b/src/rate.rs index ab340dd..39ef936 100644 --- a/src/rate.rs +++ b/src/rate.rs @@ -5,11 +5,13 @@ use instant::{Duration, Instant}; #[cfg(not(target_arch = "wasm32"))] use std::time::{Duration, Instant}; +#[cfg_attr(target_arch = "wasm32", allow(unused))] pub struct UpdateRate { target_rate: Option, prev_time: Instant, } +#[cfg_attr(target_arch = "wasm32", allow(unused))] impl UpdateRate { pub fn new() -> UpdateRate { UpdateRate {