Skip to content

Commit b20aaa9

Browse files
authored
[wasm] Fix raw handles, delay getContext call to be WebGPU compatible (#368)
* inject data-raw-handle into canvas * create web context lazily * add check for wasm build to ci * fix unused variable warnings on web build * fix ci config * fist rust warnings & bypassed `is_active` implementation * add wasm target install to ci
1 parent cc7267f commit b20aaa9

File tree

4 files changed

+72
-40
lines changed

4 files changed

+72
-40
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ jobs:
2828
os: [ubuntu-latest, windows-latest, macOS-latest]
2929
runs-on: ${{ matrix.os }}
3030
steps:
31-
- if: matrix.os == 'ubuntu-latest'
32-
run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
33-
- uses: actions/checkout@v2
34-
- name: Build
35-
run: cargo build --verbose
36-
- name: Run tests
37-
run: cargo test --verbose
31+
- if: matrix.os == 'ubuntu-latest'
32+
run: sudo apt install libwayland-cursor0 libxkbcommon-dev libwayland-dev
33+
- uses: actions/checkout@v2
34+
- name: Build
35+
run: cargo build --verbose
36+
- name: Run tests
37+
run: cargo test --verbose
38+
- name: Install wasm target
39+
run: rustup target add wasm32-unknown-unknown
40+
- name: Check wasm build
41+
run: cargo check --target wasm32-unknown-unknown --no-default-features

src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ use std::{ffi::c_void, fmt, time::Duration};
2727

2828
#[cfg(target_arch = "wasm32")]
2929
use std::panic;
30-
#[cfg(target_arch = "wasm32")]
31-
use web_sys::HtmlElement;
3230

3331
#[cfg(target_os = "macos")]
3432
use os::macos as imp;

src/os/wasm/mod.rs

Lines changed: 59 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,25 @@ struct MouseState {
4141
middle_button: Cell<bool>,
4242
}
4343

44+
struct Context2D {
45+
context: CanvasRenderingContext2d,
46+
img_data: ImageData,
47+
}
48+
4449
// IDEA(stefano): possibly have this contain a "document" field, so not to recompute it every time
4550
pub struct Window {
4651
width: u32,
4752
height: u32,
4853
bg_color: u32,
4954
window_scale: usize,
50-
img_data: ImageData,
5155
canvas: HtmlCanvasElement,
52-
context: Rc<CanvasRenderingContext2d>,
56+
// 2D context is created lazily since its creation preculdes creation of webgl & webgpu contexts.
57+
context2d: Option<Context2D>,
5358
mouse_state: Rc<MouseState>,
5459
key_handler: Rc<RefCell<KeyHandler>>,
5560
menu_counter: MenuHandle,
5661
menus: Vec<UnixMenu>,
62+
raw_handle_id: u32,
5763
}
5864

5965
impl Window {
@@ -83,6 +89,13 @@ impl Window {
8389
.dyn_into::<HtmlCanvasElement>()
8490
.unwrap();
8591

92+
// Raw handle requires to inject an id into the canvas' data attributes.
93+
// TODO assign a different ID to each window
94+
let raw_handle_id = 0;
95+
canvas
96+
.set_attribute("data-raw-handle", &raw_handle_id.to_string())
97+
.unwrap();
98+
8699
let container = document
87100
.get_element_by_id(container)
88101
.unwrap()
@@ -97,15 +110,6 @@ impl Window {
97110
canvas.set_tab_index(0);
98111

99112
// Create an image buffer
100-
let context: CanvasRenderingContext2d = canvas
101-
.get_context("2d")
102-
.unwrap()
103-
.unwrap()
104-
.dyn_into::<CanvasRenderingContext2d>()
105-
.unwrap();
106-
context.set_image_smoothing_enabled(false);
107-
let img_data = ImageData::new_with_sw(width as u32, height as u32).unwrap();
108-
let context = Rc::new(context);
109113
let key_handler = Rc::new(RefCell::new(KeyHandler::new()));
110114
let mouse_struct = MouseState {
111115
pos: Cell::new(None),
@@ -180,21 +184,31 @@ impl Window {
180184
closure.forget();
181185
}
182186

183-
let mut window = Window {
187+
Ok(Window {
184188
width: width as u32,
185189
height: height as u32,
186190
bg_color: 0,
187191
window_scale,
188-
img_data,
189192
canvas,
190-
context: context.clone(),
193+
context2d: None,
191194
key_handler,
192195
mouse_state,
193196
menu_counter: MenuHandle(0),
194197
menus: Vec::new(),
195-
};
198+
raw_handle_id,
199+
})
200+
}
196201

197-
Ok(window)
202+
fn create_2d_context(&self) -> CanvasRenderingContext2d {
203+
let context: CanvasRenderingContext2d = self
204+
.canvas
205+
.get_context("2d")
206+
.unwrap()
207+
.unwrap()
208+
.dyn_into::<CanvasRenderingContext2d>()
209+
.unwrap();
210+
context.set_image_smoothing_enabled(false);
211+
context
198212
}
199213

200214
#[inline]
@@ -204,7 +218,7 @@ impl Window {
204218
}
205219

206220
#[inline]
207-
pub fn set_rate(&mut self, rate: Option<Duration>) {}
221+
pub fn set_rate(&mut self, _rate: Option<Duration>) {}
208222

209223
#[inline]
210224
pub fn update_rate(&mut self) {}
@@ -215,7 +229,7 @@ impl Window {
215229
}
216230

217231
#[inline]
218-
pub fn topmost(&self, topmost: bool) {
232+
pub fn topmost(&self, _topmost: bool) {
219233
// TODO?
220234
}
221235

@@ -262,13 +276,22 @@ impl Window {
262276
)?;
263277
let mut data = u32_as_u8(buffer);
264278

265-
self.img_data = ImageData::new_with_u8_clamped_array_and_sh(
279+
let image_data = ImageData::new_with_u8_clamped_array_and_sh(
266280
Clamped(&mut data),
267281
self.width,
268282
self.height,
269283
)
270284
.unwrap();
271285

286+
if let Some(context2d) = &mut self.context2d {
287+
context2d.img_data = image_data;
288+
} else {
289+
self.context2d = Some(Context2D {
290+
context: self.create_2d_context(),
291+
img_data: image_data,
292+
});
293+
}
294+
272295
self.update();
273296

274297
Ok(())
@@ -277,16 +300,20 @@ impl Window {
277300
#[inline]
278301
pub fn update(&mut self) {
279302
self.key_handler.borrow_mut().update();
280-
self.context
281-
.put_image_data(&self.img_data, 0.0, 0.0)
282-
.unwrap();
303+
304+
if let Some(context2d) = &self.context2d {
305+
context2d
306+
.context
307+
.put_image_data(&context2d.img_data, 0.0, 0.0)
308+
.unwrap();
309+
}
283310
}
284311

285312
#[inline]
286-
pub fn set_icon(&mut self, icon: Icon) {}
313+
pub fn set_icon(&mut self, _icon: Icon) {}
287314

288315
#[inline]
289-
pub fn set_position(&mut self, x: isize, y: isize) {}
316+
pub fn set_position(&mut self, _x: isize, _y: isize) {}
290317

291318
#[inline]
292319
pub fn get_position(&self) -> (isize, isize) {
@@ -343,7 +370,7 @@ impl Window {
343370
}
344371

345372
#[inline]
346-
pub fn set_cursor_style(&mut self, cursor: CursorStyle) {}
373+
pub fn set_cursor_style(&mut self, _cursor: CursorStyle) {}
347374

348375
#[inline]
349376
pub fn get_keys(&self) -> Vec<Key> {
@@ -397,8 +424,10 @@ impl Window {
397424

398425
#[inline]
399426
pub fn is_active(&mut self) -> bool {
400-
let document = window().unwrap().document().unwrap();
401-
document.active_element().unwrap_or(return false) == **self.canvas
427+
window()
428+
.and_then(|window| window.document())
429+
.and_then(|document| document.active_element())
430+
.map_or(false, |element| element == **self.canvas)
402431
}
403432

404433
#[inline]
@@ -445,7 +474,7 @@ impl Menu {
445474
}
446475

447476
#[inline]
448-
pub fn add_sub_menu(&mut self, name: &str, sub_menu: &Menu) {}
477+
pub fn add_sub_menu(&mut self, _name: &str, _sub_menu: &Menu) {}
449478

450479
#[inline]
451480
fn next_item_handle(&mut self) -> MenuItemHandle {
@@ -470,13 +499,12 @@ impl Menu {
470499
}
471500

472501
#[inline]
473-
pub fn remove_item(&mut self, handle: &MenuItemHandle) {}
502+
pub fn remove_item(&mut self, _handle: &MenuItemHandle) {}
474503
}
475504

476505
impl HasWindowHandle for Window {
477506
fn window_handle(&self) -> std::result::Result<WindowHandle, HandleError> {
478-
// TODO assign a different ID to each window
479-
let handle = WebWindowHandle::new(0);
507+
let handle = WebWindowHandle::new(self.raw_handle_id);
480508
let raw_handle = RawWindowHandle::Web(handle);
481509
unsafe { Ok(WindowHandle::borrow_raw(raw_handle)) }
482510
}

src/rate.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ use instant::{Duration, Instant};
55
#[cfg(not(target_arch = "wasm32"))]
66
use std::time::{Duration, Instant};
77

8+
#[cfg_attr(target_arch = "wasm32", allow(unused))]
89
pub struct UpdateRate {
910
target_rate: Option<Duration>,
1011
prev_time: Instant,
1112
}
1213

14+
#[cfg_attr(target_arch = "wasm32", allow(unused))]
1315
impl UpdateRate {
1416
pub fn new() -> UpdateRate {
1517
UpdateRate {

0 commit comments

Comments
 (0)