From 8dc8069832d6929406257f679ae53dfb7b035e9a Mon Sep 17 00:00:00 2001 From: Paul Dufour Date: Sun, 29 Mar 2026 22:30:38 -0700 Subject: [PATCH 1/6] Make resume method async --- Cargo.lock | 3 +- crates/anyrender/src/lib.rs | 7 +++- crates/anyrender/src/null_backend.rs | 4 +- crates/anyrender_skia/src/window_renderer.rs | 2 +- crates/anyrender_vello/src/window_renderer.rs | 39 ++++++++++-------- crates/anyrender_vello_hybrid/Cargo.toml | 1 - .../src/window_renderer.rs | 41 ++++++++++--------- crates/pixels_window_renderer/src/lib.rs | 2 +- crates/softbuffer_window_renderer/src/lib.rs | 2 +- examples/bunnymark/Cargo.toml | 1 + examples/bunnymark/src/main.rs | 4 +- examples/player/Cargo.toml | 1 + examples/player/src/main.rs | 2 +- 13 files changed, 62 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c054313..9b7bef5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -252,7 +252,6 @@ dependencies = [ "debug_timer", "kurbo", "peniko", - "pollster 0.4.0", "rustc-hash 2.1.1", "vello_common", "vello_hybrid", @@ -461,6 +460,7 @@ dependencies = [ "kurbo", "peniko", "pixels_window_renderer", + "pollster 0.4.0", "winit", ] @@ -2626,6 +2626,7 @@ dependencies = [ "anyrender_vello_hybrid", "kurbo", "peniko", + "pollster 0.4.0", "winit", ] diff --git a/crates/anyrender/src/lib.rs b/crates/anyrender/src/lib.rs index f4759c5..9a4f612 100644 --- a/crates/anyrender/src/lib.rs +++ b/crates/anyrender/src/lib.rs @@ -51,7 +51,12 @@ pub trait WindowRenderer { type ScenePainter<'a>: PaintScene where Self: 'a; - fn resume(&mut self, window: Arc, width: u32, height: u32); + fn resume( + &mut self, + window: Arc, + width: u32, + height: u32, + ) -> impl std::future::Future + '_; fn suspend(&mut self); fn is_active(&self) -> bool; fn set_size(&mut self, width: u32, height: u32); diff --git a/crates/anyrender/src/null_backend.rs b/crates/anyrender/src/null_backend.rs index 3af5dcf..3978a40 100644 --- a/crates/anyrender/src/null_backend.rs +++ b/crates/anyrender/src/null_backend.rs @@ -3,7 +3,7 @@ use crate::{ImageRenderer, PaintScene, WindowHandle, WindowRenderer}; use std::sync::Arc; -#[derive(Copy, Clone, Default)] +#[derive(Clone, Default)] pub struct NullWindowRenderer { is_active: bool, } @@ -20,7 +20,7 @@ impl WindowRenderer for NullWindowRenderer { where Self: 'a; - fn resume(&mut self, _window: Arc, _width: u32, _height: u32) { + async fn resume(&mut self, _window: Arc, _width: u32, _height: u32) { self.is_active = true; } diff --git a/crates/anyrender_skia/src/window_renderer.rs b/crates/anyrender_skia/src/window_renderer.rs index 076cd72..93ca62f 100644 --- a/crates/anyrender_skia/src/window_renderer.rs +++ b/crates/anyrender_skia/src/window_renderer.rs @@ -49,7 +49,7 @@ impl WindowRenderer for SkiaWindowRenderer { where Self: 'a; - fn resume(&mut self, window: Arc, width: u32, height: u32) { + async fn resume(&mut self, window: Arc, width: u32, height: u32) { graphics::set_font_cache_count_limit(100); graphics::set_typeface_cache_count_limit(100); graphics::set_resource_cache_total_bytes_limit(10485760); diff --git a/crates/anyrender_vello/src/window_renderer.rs b/crates/anyrender_vello/src/window_renderer.rs index f58a787..d38ad77 100644 --- a/crates/anyrender_vello/src/window_renderer.rs +++ b/crates/anyrender_vello/src/window_renderer.rs @@ -127,25 +127,28 @@ impl WindowRenderer for VelloWindowRenderer { matches!(self.render_state, RenderState::Active(_)) } - fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { + async fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { // Create wgpu_context::SurfaceRenderer - let render_surface = pollster::block_on(self.wgpu_context.create_surface( - window_handle.clone(), - SurfaceRendererConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - formats: vec![TextureFormat::Rgba8Unorm, TextureFormat::Bgra8Unorm], - width, - height, - present_mode: PresentMode::AutoVsync, - desired_maximum_frame_latency: 2, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - view_formats: vec![], - }, - Some(TextureConfiguration { - usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING, - }), - )) - .expect("Error creating surface"); + let render_surface = self + .wgpu_context + .create_surface( + window_handle.clone(), + SurfaceRendererConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + formats: vec![TextureFormat::Rgba8Unorm, TextureFormat::Bgra8Unorm], + width, + height, + present_mode: PresentMode::AutoVsync, + desired_maximum_frame_latency: 2, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![], + }, + Some(TextureConfiguration { + usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING, + }), + ) + .await + .expect("Error creating surface"); // Create vello::Renderer let renderer = VelloRenderer::new( diff --git a/crates/anyrender_vello_hybrid/Cargo.toml b/crates/anyrender_vello_hybrid/Cargo.toml index 384641b..c17fc01 100644 --- a/crates/anyrender_vello_hybrid/Cargo.toml +++ b/crates/anyrender_vello_hybrid/Cargo.toml @@ -20,6 +20,5 @@ peniko = { workspace = true } vello_hybrid = { workspace = true } vello_common = { workspace = true } wgpu = { workspace = true } -pollster = { workspace = true } rustc-hash = { workspace = true } wgpu_context = { workspace = true } \ No newline at end of file diff --git a/crates/anyrender_vello_hybrid/src/window_renderer.rs b/crates/anyrender_vello_hybrid/src/window_renderer.rs index 4e9b0c9..a8a7ee5 100644 --- a/crates/anyrender_vello_hybrid/src/window_renderer.rs +++ b/crates/anyrender_vello_hybrid/src/window_renderer.rs @@ -122,26 +122,29 @@ impl WindowRenderer for VelloHybridWindowRenderer { matches!(self.render_state, RenderState::Active(_)) } - fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { + async fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { // Create wgpu_context::SurfaceRenderer - let render_surface = pollster::block_on(self.wgpu_context.create_surface( - window_handle.clone(), - SurfaceRendererConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - formats: vec![DEFAULT_TEXTURE_FORMAT], - width, - height, - present_mode: PresentMode::AutoVsync, - desired_maximum_frame_latency: 2, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - view_formats: vec![], - }, - None, - // Some(TextureConfiguration { - // usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING, - // }), - )) - .expect("Error creating surface"); + let render_surface = self + .wgpu_context + .create_surface( + window_handle.clone(), + SurfaceRendererConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + formats: vec![DEFAULT_TEXTURE_FORMAT], + width, + height, + present_mode: PresentMode::AutoVsync, + desired_maximum_frame_latency: 2, + alpha_mode: wgpu::CompositeAlphaMode::Auto, + view_formats: vec![], + }, + None, + // Some(TextureConfiguration { + // usage: TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING, + // }), + ) + .await + .expect("Error creating surface"); // Create vello::Renderer let renderer = VelloHybridRenderer::new( diff --git a/crates/pixels_window_renderer/src/lib.rs b/crates/pixels_window_renderer/src/lib.rs index e36986f..4650710 100644 --- a/crates/pixels_window_renderer/src/lib.rs +++ b/crates/pixels_window_renderer/src/lib.rs @@ -52,7 +52,7 @@ impl WindowRenderer for PixelsWindowRenderer matches!(self.render_state, RenderState::Active(_)) } - fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { + async fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { let surface = SurfaceTexture::new(width, height, window_handle.clone()); let mut pixels = Pixels::new(width, height, surface).unwrap(); pixels.enable_vsync(true); diff --git a/crates/softbuffer_window_renderer/src/lib.rs b/crates/softbuffer_window_renderer/src/lib.rs index 30ee68d..2fc5d6a 100644 --- a/crates/softbuffer_window_renderer/src/lib.rs +++ b/crates/softbuffer_window_renderer/src/lib.rs @@ -54,7 +54,7 @@ impl WindowRenderer for SoftbufferWindowRenderer, width: u32, height: u32) { + async fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { let context = Context::new(window_handle.clone()).unwrap(); let surface = Surface::new(&context, window_handle.clone()).unwrap(); self.render_state = RenderState::Active(ActiveRenderState { diff --git a/examples/bunnymark/Cargo.toml b/examples/bunnymark/Cargo.toml index 97c8120..7b5893f 100644 --- a/examples/bunnymark/Cargo.toml +++ b/examples/bunnymark/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true publish = false [dependencies] +pollster = { workspace = true } kurbo = { workspace = true } winit = { workspace = true } peniko = { workspace = true } diff --git a/examples/bunnymark/src/main.rs b/examples/bunnymark/src/main.rs index 9e94b4a..8e709bc 100644 --- a/examples/bunnymark/src/main.rs +++ b/examples/bunnymark/src/main.rs @@ -148,7 +148,9 @@ impl App { self.scale_factor = window.scale_factor(); let physical_size = window.inner_size(); - renderer.resume(window.clone(), physical_size.width, physical_size.height); + pollster::block_on( + renderer.resume(window.clone(), physical_size.width, physical_size.height), + ); self.render_state = RenderState::Active { window, renderer: f(renderer), diff --git a/examples/player/Cargo.toml b/examples/player/Cargo.toml index 0640151..796fb80 100644 --- a/examples/player/Cargo.toml +++ b/examples/player/Cargo.toml @@ -6,6 +6,7 @@ license.workspace = true publish = false [dependencies] +pollster = { workspace = true } kurbo = { workspace = true } winit = { workspace = true } peniko = { workspace = true } diff --git a/examples/player/src/main.rs b/examples/player/src/main.rs index fd08d50..50124f2 100644 --- a/examples/player/src/main.rs +++ b/examples/player/src/main.rs @@ -140,7 +140,7 @@ impl App { Arc::new(event_loop.create_window(attr).unwrap()) }); - renderer.resume(window.clone(), self.width, self.height); + pollster::block_on(renderer.resume(window.clone(), self.width, self.height)); let renderer = renderer.into(); self.render_state = RenderState::Active { window, renderer }; self.request_redraw(); From 96c5664c3b6cf162086875b747463e4f914986ad Mon Sep 17 00:00:00 2001 From: Paul Dufour Date: Mon, 30 Mar 2026 07:47:18 -0700 Subject: [PATCH 2/6] Add wasm example --- Cargo.lock | 443 +++++++++++++++++++++++++++++++-- Cargo.toml | 4 +- examples/wasm/Cargo.toml | 27 ++ examples/wasm/README.md | 23 ++ examples/wasm/src/bin/serve.rs | 36 +++ examples/wasm/src/index.html | 238 ++++++++++++++++++ examples/wasm/src/lib.rs | 176 +++++++++++++ 7 files changed, 923 insertions(+), 24 deletions(-) create mode 100644 examples/wasm/Cargo.toml create mode 100644 examples/wasm/README.md create mode 100644 examples/wasm/src/bin/serve.rs create mode 100644 examples/wasm/src/index.html create mode 100644 examples/wasm/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9b7bef5..0164c88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,6 +259,24 @@ dependencies = [ "wgpu_context", ] +[[package]] +name = "anyrender_wasm_example" +version = "0.1.0" +dependencies = [ + "anyrender", + "anyrender_vello", + "axum", + "console_error_panic_hook", + "kurbo", + "peniko", + "raw-window-handle", + "tokio", + "tower-http", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -315,6 +333,17 @@ dependencies = [ "raw-window-metal", ] +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -327,6 +356,61 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "base64" version = "0.22.1" @@ -750,6 +834,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1233,6 +1327,24 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.32" @@ -1250,6 +1362,12 @@ dependencies = [ "parking_lot", ] +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + [[package]] name = "futures-task" version = "0.3.32" @@ -1302,9 +1420,9 @@ dependencies = [ [[package]] name = "gif" -version = "0.14.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b" dependencies = [ "color_quant", "weezl", @@ -1609,6 +1727,93 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "icu_locale_core" version = "2.1.1" @@ -1624,18 +1829,17 @@ dependencies = [ [[package]] name = "image" -version = "0.25.10" +version = "0.25.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" dependencies = [ "bytemuck", "byteorder-lite", "color_quant", "gif", "image-webp", - "moxcms", "num-traits", - "png", + "png 0.17.16", "zune-core", "zune-jpeg", ] @@ -1902,6 +2106,12 @@ dependencies = [ "libc", ] +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + [[package]] name = "memchr" version = "2.8.0" @@ -1947,6 +2157,22 @@ dependencies = [ "paste", ] +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1964,13 +2190,14 @@ dependencies = [ ] [[package]] -name = "moxcms" -version = "0.8.1" +name = "mio" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ - "num-traits", - "pxfm", + "libc", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -2579,6 +2806,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pixels" version = "0.15.0" @@ -2630,6 +2863,19 @@ dependencies = [ "winit", ] +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + [[package]] name = "png" version = "0.18.1" @@ -2724,12 +2970,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" -[[package]] -name = "pxfm" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a041e753da8b807c9255f28de81879c78c876392ff2469cde94799b2896b9d" - [[package]] name = "quick-error" version = "2.0.1" @@ -2771,6 +3011,9 @@ name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +dependencies = [ + "wasm-bindgen", +] [[package]] name = "raw-window-metal" @@ -2973,6 +3216,12 @@ dependencies = [ "unicode-script", ] +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "safe_arch" version = "0.7.4" @@ -3075,6 +3324,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_spanned" version = "1.1.0" @@ -3084,6 +3344,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serialize" version = "0.1.0" @@ -3271,6 +3543,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "softbuffer" version = "0.4.8" @@ -3391,6 +3673,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "tar" version = "0.4.45" @@ -3524,6 +3812,45 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "1.1.0+spec-1.1.0" @@ -3575,12 +3902,67 @@ version = "1.1.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed" +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "http-range-header", + "httpdate", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-core", ] @@ -3590,6 +3972,9 @@ name = "tracing-core" version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] [[package]] name = "ttf-parser" @@ -3627,6 +4012,12 @@ dependencies = [ "wide", ] +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -3736,7 +4127,7 @@ dependencies = [ "futures-intrusive", "log", "peniko", - "png", + "png 0.18.1", "skrifa 0.40.0", "static_assertions", "thiserror 2.0.18", @@ -3767,7 +4158,7 @@ dependencies = [ "hashbrown 0.16.1", "log", "peniko", - "png", + "png 0.18.1", "skrifa 0.40.0", "smallvec", "thiserror 2.0.18", @@ -3858,6 +4249,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" @@ -4856,15 +5253,15 @@ dependencies = [ [[package]] name = "zune-core" -version = "0.5.1" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" [[package]] name = "zune-jpeg" -version = "0.5.14" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7a1c0af6e5d8d1363f4994b7a091ccf963d8b694f7da5b0b9cceb82da2c0a6" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" dependencies = [ "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index 094950b..4938581 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ members = [ "examples/player", "examples/bunnymark", "examples/serialize", + "examples/wasm", ] resolver = "2" @@ -78,7 +79,8 @@ pollster = "0.4" # Dev-dependencies winit = { version = "0.30.2", features = ["rwh_06"] } -# [patch.crates-io] +[patch.crates-io] +anyrender = { path = "./crates/anyrender" } # vello = { path = "../vello/vello" } # vello_cpu = { path = "../vello/sparse_strips/vello_cpu" } # vello_hybrid = { path = "../vello/sparse_strips/vello_hybrid" } diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml new file mode 100644 index 0000000..8e07929 --- /dev/null +++ b/examples/wasm/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "anyrender_wasm_example" +version = "0.1.0" +publish = false +edition = "2024" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +anyrender = { workspace = true } +anyrender_vello = { workspace = true } +console_error_panic_hook = "0.1.7" +kurbo = { workspace = true } +peniko = { workspace = true } +raw-window-handle = { workspace = true, features = ["wasm-bindgen-0-2"] } +wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" + +[dependencies.web-sys] +version = "0.3" +features = ["HtmlCanvasElement"] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +axum = "0.7" +tokio = { version = "1.37", features = ["macros", "net", "rt-multi-thread"] } +tower-http = { version = "0.6", features = ["fs"] } diff --git a/examples/wasm/README.md b/examples/wasm/README.md new file mode 100644 index 0000000..9c80dd6 --- /dev/null +++ b/examples/wasm/README.md @@ -0,0 +1,23 @@ +## Build with `wasm-pack` + +From the repo root: + +```bash +# one-time +rustup toolchain install 1.92.0 +rustup target add wasm32-unknown-unknown --toolchain 1.92.0 +cargo +1.92.0 install wasm-pack + +# build into examples/wasm/src/pkg so index.html can import it +wasm-pack build examples/wasm --target web --out-dir src/pkg +``` + +## Run the demo + +Serve the `examples/wasm/src` folder (needs a web server; `file://` won't work). + +```bash +cargo run -p anyrender_wasm_example --bin serve -- 8080 +``` + +Then open `http://localhost:8080` and click **Paint** (or just edit the HTML). diff --git a/examples/wasm/src/bin/serve.rs b/examples/wasm/src/bin/serve.rs new file mode 100644 index 0000000..c80b8ce --- /dev/null +++ b/examples/wasm/src/bin/serve.rs @@ -0,0 +1,36 @@ +//! Serves `src/` over HTTP so `index.html` and the WASM ES module load correctly (not `file://`). +use std::net::SocketAddr; +use std::path::PathBuf; + +use axum::Router; +use tokio::net::TcpListener; +use tower_http::services::ServeDir; + +#[tokio::main] +async fn main() -> Result<(), Box> { + let web_root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src"); + if !web_root.join("index.html").is_file() { + eprintln!( + "expected {} (run wasm-pack first for src/pkg).", + web_root.join("index.html").display() + ); + } + + let port: u16 = std::env::args() + .nth(1) + .and_then(|s| s.parse().ok()) + .unwrap_or(8080); + + let addr = SocketAddr::from(([127, 0, 0, 1], port)); + let listener = TcpListener::bind(addr).await?; + + let service = ServeDir::new(&web_root).append_index_html_on_directories(true); + let app = Router::new().fallback_service(service); + + let url = format!("http://{}", addr); + eprintln!("Serving {} -> {}", web_root.display(), url); + eprintln!("Open {url}/ in your browser."); + + axum::serve(listener, app).await?; + Ok(()) +} diff --git a/examples/wasm/src/index.html b/examples/wasm/src/index.html new file mode 100644 index 0000000..0dd8a57 --- /dev/null +++ b/examples/wasm/src/index.html @@ -0,0 +1,238 @@ + + + + + + anyrender wasm + + + + + + +
+
+
anyrender wasm
+
WebGPU required (Chrome/Edge/Safari TP)
+
+ +
+
+
+
Code
+ +
+ +
+ +
+
+
Normal Output
+
+ +
+ +
+
+
Canvas Output
+
+ +
+
+
+ + + + diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs new file mode 100644 index 0000000..39cf679 --- /dev/null +++ b/examples/wasm/src/lib.rs @@ -0,0 +1,176 @@ +//! Minimal WASM example: paint a simple scene onto an `HtmlCanvasElement`. +#![cfg(target_arch = "wasm32")] + +use anyrender::{PaintScene, WindowHandle, WindowRenderer}; +use anyrender_vello::VelloWindowRenderer; +use kurbo::{Affine, Circle, Point, Rect, Stroke}; +use peniko::{Color, Fill}; +use raw_window_handle::{ + DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawWindowHandle, + WebCanvasWindowHandle, WindowHandle as RwhWindowHandle, +}; +use std::cell::RefCell; +use std::sync::Arc; +use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; +use web_sys::HtmlCanvasElement; + +#[wasm_bindgen(start)] +pub fn main() { + console_error_panic_hook::set_once(); +} + +struct RendererState { + renderer: VelloWindowRenderer, + canvas: Option>, + width: u32, + height: u32, +} + +impl RendererState { + fn new() -> Self { + Self { + renderer: VelloWindowRenderer::new(), + canvas: None, + width: 0, + height: 0, + } + } +} + +thread_local! { + static RENDERER_STATE: RefCell> = RefCell::new(Some(RendererState::new())); +} + +struct CanvasPresentationTarget { + canvas: Arc, +} + +impl HasDisplayHandle for CanvasPresentationTarget { + fn display_handle(&self) -> Result, HandleError> { + Ok(DisplayHandle::web()) + } +} + +impl HasWindowHandle for CanvasPresentationTarget { + fn window_handle(&self) -> Result, HandleError> { + let js: &wasm_bindgen::JsValue = self.canvas.as_ref().unchecked_ref(); + let wh = WebCanvasWindowHandle::from_wasm_bindgen_0_2(js); + let raw = RawWindowHandle::WebCanvas(wh); + Ok(unsafe { RwhWindowHandle::borrow_raw(raw) }) + } +} + +/// Paint `html` into `canvas`. +#[wasm_bindgen(js_name = paintHtml)] +pub async fn paint_html( + canvas: &HtmlCanvasElement, + html: &str, + css_width: f64, + css_height: f64, + device_pixel_ratio: f64, +) -> Result<(), JsValue> { + let dpr = device_pixel_ratio.max(1.0); + let css_width = css_width.max(1.0); + let css_height = css_height.max(1.0); + + let phys_w = (css_width * dpr).round().max(1.0) as u32; + let phys_h = (css_height * dpr).round().max(1.0) as u32; + + if canvas.width() != phys_w { + canvas.set_width(phys_w); + } + if canvas.height() != phys_h { + canvas.set_height(phys_h); + } + + let _ = html; + let canvas_arc = Arc::new(canvas.clone()); + + let mut renderer_state = RENDERER_STATE + .with(|slot| slot.borrow_mut().take()) + .ok_or_else(|| JsValue::from_str("Renderer state already in use."))?; + + let result = async { + let canvas_changed = renderer_state + .canvas + .as_ref() + .map_or(true, |existing| !existing.is_same_node(Some(canvas.as_ref()))); + + if canvas_changed { + renderer_state.renderer.suspend(); + renderer_state.canvas = Some(canvas_arc.clone()); + } + + if !renderer_state.renderer.is_active() { + let window: Arc = Arc::new(CanvasPresentationTarget { + canvas: canvas_arc.clone(), + }); + renderer_state.renderer.resume(window, phys_w, phys_h).await; + } + + if !renderer_state.renderer.is_active() { + return Err(JsValue::from_str( + "Failed to create WebGPU surface for this canvas.", + )); + } + + if renderer_state.width != phys_w || renderer_state.height != phys_h { + renderer_state.renderer.set_size(phys_w, phys_h); + renderer_state.width = phys_w; + renderer_state.height = phys_h; + } + + renderer_state + .renderer + .render(|scene| paint_simple_scene(scene, css_width, css_height, dpr)); + + Ok(()) + } + .await; + + RENDERER_STATE.with(|slot| { + *slot.borrow_mut() = Some(renderer_state); + }); + + result +} + +fn paint_simple_scene( + scene: &mut impl PaintScene, + css_width: f64, + css_height: f64, + dpr: f64, +) { + let width = css_width.max(1.0); + let height = css_height.max(1.0); + let transform = Affine::scale(dpr); + + scene.fill( + Fill::NonZero, + transform, + Color::WHITE, + None, + &Rect::new(0.0, 0.0, width, height), + ); + + let inset = 8.0; + if width > inset && height > inset { + scene.stroke( + &Stroke::new(2.0), + transform, + Color::from_rgb8(30, 41, 59), + None, + &Rect::new(inset, inset, width - inset, height - inset), + ); + } + + let radius = (width.min(height) * 0.18).max(6.0); + scene.fill( + Fill::NonZero, + transform, + Color::from_rgb8(59, 130, 246), + None, + &Circle::new(Point::new(width * 0.5, height * 0.5), radius), + ); +} From 2282cc568f049aac21ba68ebd2000c034db2292b Mon Sep 17 00:00:00 2001 From: Paul Dufour Date: Mon, 30 Mar 2026 08:55:57 -0700 Subject: [PATCH 3/6] Fully working renderer --- Cargo.lock | 1083 +++++++++++++++++++++++++++++++++- examples/wasm/Cargo.toml | 10 +- examples/wasm/README.md | 1 + examples/wasm/src/index.html | 35 +- examples/wasm/src/lib.rs | 191 ++++-- 5 files changed, 1242 insertions(+), 78 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0164c88..5e88dab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,7 +186,7 @@ dependencies = [ "anyrender", "ash 0.38.0+1.3.281", "ash-window", - "debug_timer", + "debug_timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "gl", "glutin", "hashbrown 0.16.1", @@ -216,12 +216,25 @@ dependencies = [ "usvg", ] +[[package]] +name = "anyrender_svg" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21afa29f9105f5e7b4deb6738cb81d207554d27e810e77dbf6084b18150c6404" +dependencies = [ + "anyrender", + "image", + "kurbo", + "peniko", + "usvg", +] + [[package]] name = "anyrender_vello" version = "0.8.0" dependencies = [ "anyrender", - "debug_timer", + "debug_timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "kurbo", "peniko", "pollster 0.4.0", @@ -236,7 +249,7 @@ name = "anyrender_vello_cpu" version = "0.10.0" dependencies = [ "anyrender", - "debug_timer", + "debug_timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "kurbo", "peniko", "pixels_window_renderer", @@ -249,7 +262,7 @@ name = "anyrender_vello_hybrid" version = "0.3.0" dependencies = [ "anyrender", - "debug_timer", + "debug_timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "kurbo", "peniko", "rustc-hash 2.1.1", @@ -266,9 +279,13 @@ dependencies = [ "anyrender", "anyrender_vello", "axum", + "blitz-dom", + "blitz-html", + "blitz-paint", + "blitz-traits", "console_error_panic_hook", - "kurbo", - "peniko", + "js-sys", + "linebender_resource_handle", "raw-window-handle", "tokio", "tower-http", @@ -277,6 +294,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "app_units" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "467b60e4ee6761cd6fd4e03ea58acefc8eec0d1b1def995c1b3b783fa7be8a60" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -350,6 +377,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atomic_refcell" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e67cd8309bbd06cd603a9e693a784ac2e5d1e955f11286e355089fcab3047c" + [[package]] name = "autocfg" version = "1.5.0" @@ -426,7 +459,7 @@ dependencies = [ "bitflags 2.11.0", "cexpr", "clang-sys", - "itertools", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", @@ -478,6 +511,95 @@ name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "blitz-dom" +version = "0.2.2" +source = "git+https://github.com/DioxusLabs/blitz#781ae63fdb6e76baa0969ba8cbce557327c7dfca" +dependencies = [ + "app_units", + "atomic_refcell", + "bitflags 2.11.0", + "blitz-traits", + "color", + "cssparser", + "cursor-icon", + "debug_timer 0.1.3 (git+https://github.com/DioxusLabs/blitz)", + "euclid", + "fastrand", + "html-escape", + "image", + "keyboard-types", + "kurbo", + "linebender_resource_handle", + "markup5ever", + "objc2 0.6.4", + "parley 0.8.0", + "percent-encoding", + "rayon", + "selectors", + "skrifa 0.40.0", + "slab", + "smallvec", + "stylo", + "stylo_dom", + "stylo_static_prefs", + "stylo_taffy", + "stylo_traits", + "taffy", + "thread_local", + "url", + "usvg", + "wuff", +] + +[[package]] +name = "blitz-html" +version = "0.2.0" +source = "git+https://github.com/DioxusLabs/blitz#781ae63fdb6e76baa0969ba8cbce557327c7dfca" +dependencies = [ + "blitz-dom", + "blitz-traits", + "html5ever", + "xml5ever", +] + +[[package]] +name = "blitz-paint" +version = "0.2.1" +source = "git+https://github.com/DioxusLabs/blitz#781ae63fdb6e76baa0969ba8cbce557327c7dfca" +dependencies = [ + "anyrender", + "anyrender_svg 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blitz-dom", + "blitz-traits", + "color", + "euclid", + "kurbo", + "parley 0.8.0", + "peniko", + "stylo", + "taffy", + "usvg", +] + +[[package]] +name = "blitz-traits" +version = "0.2.0" +source = "git+https://github.com/DioxusLabs/blitz#781ae63fdb6e76baa0969ba8cbce557327c7dfca" +dependencies = [ + "bitflags 2.11.0", + "bytes", + "cursor-icon", + "http", + "keyboard-types", + "serde", + "smol_str 0.3.6", + "url", +] [[package]] name = "block" @@ -503,6 +625,16 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "borsh" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +dependencies = [ + "bytes", + "cfg_aliases 0.2.1", +] + [[package]] name = "brotli" version = "8.0.2" @@ -982,6 +1114,30 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "serde", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.117", +] + [[package]] name = "ctor-lite" version = "0.1.2" @@ -1005,6 +1161,40 @@ dependencies = [ "winapi", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + [[package]] name = "data-url" version = "0.3.2" @@ -1017,6 +1207,11 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da220af51a1a335e9a930beaaef53d261e41ea9eecfb3d973a3ddae1a7284b9c" +[[package]] +name = "debug_timer" +version = "0.1.3" +source = "git+https://github.com/DioxusLabs/blitz#781ae63fdb6e76baa0969ba8cbce557327c7dfca" + [[package]] name = "derive_arbitrary" version = "1.4.2" @@ -1028,6 +1223,27 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.117", +] + [[package]] name = "digest" version = "0.10.7" @@ -1135,12 +1351,36 @@ dependencies = [ "linux-raw-sys 0.9.4", ] +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1164,6 +1404,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" dependencies = [ "num-traits", + "serde", ] [[package]] @@ -1300,6 +1541,19 @@ dependencies = [ "smallvec", ] +[[package]] +name = "fontique" +version = "0.8.0" +source = "git+https://github.com/linebender/parley?rev=07980878fc9ea4b16ddc197ac789d01fb8ada7a3#07980878fc9ea4b16ddc197ac789d01fb8ada7a3" +dependencies = [ + "hashbrown 0.16.1", + "linebender_resource_handle", + "memmap2", + "parlance", + "read-fonts 0.37.0", + "smallvec", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1627,6 +1881,12 @@ dependencies = [ "bitflags 2.11.0", ] +[[package]] +name = "grid" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220" + [[package]] name = "guillotiere" version = "0.7.0" @@ -1662,6 +1922,19 @@ dependencies = [ "smallvec", ] +[[package]] +name = "harfrust" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9da2e5ae821f6e96664977bf974d6d6a2d6682f9ccee23e62ec1d134246845f9" +dependencies = [ + "bitflags 2.11.0", + "bytemuck", + "core_maths", + "read-fonts 0.37.0", + "smallvec", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -1727,6 +2000,25 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "html5ever" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5935f02fdc02823ff15fec27c2b3d7ca19d629e996f7a0ae4d7d500e62e54c76" +dependencies = [ + "log", + "markup5ever", +] + [[package]] name = "http" version = "1.4.0" @@ -1814,6 +2106,34 @@ dependencies = [ "tower-service", ] +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + [[package]] name = "icu_locale_core" version = "2.1.1" @@ -1825,6 +2145,119 @@ dependencies = [ "serde", "tinystr", "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c5f1d16b4c3a2642d3a719f18f6b06070ab0aef246a6418130c955ae08aa831" + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a807a7488f3f758629ae86d99d9d30dce24da2fb2945d74c80a4f4a62c71db73" +dependencies = [ + "core_maths", + "icu_collections", + "icu_locale", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ebbb7321d9e21d25f5660366cb6c08201d0175898a3a6f7a41ee9685af21c80" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1885,6 +2318,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" @@ -1969,6 +2411,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.11.0", + "serde", + "unicode-segmentation", +] + [[package]] name = "khronos-egl" version = "6.0.0" @@ -2106,6 +2559,28 @@ dependencies = [ "libc", ] +[[package]] +name = "malloc_size_of_derive" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f44db74bde26fdf427af23f1d146c211aed857c59e3be750cf2617f6b0b05c94" +dependencies = [ + "proc-macro2", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "markup5ever" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cfb33ea12d5d83b1ba9a55ae7d05faec4f2189d47b79c04d4cea6bbe9f5b083" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + [[package]] name = "matchit" version = "0.7.3" @@ -2285,6 +2760,12 @@ dependencies = [ "jni-sys 0.3.1", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nom" version = "7.1.3" @@ -2295,6 +2776,26 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2305,6 +2806,16 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "num_enum" version = "0.7.6" @@ -2734,20 +3245,50 @@ dependencies = [ "windows-link", ] +[[package]] +name = "parlance" +version = "0.1.0" +source = "git+https://github.com/linebender/parley?rev=07980878fc9ea4b16ddc197ac789d01fb8ada7a3#07980878fc9ea4b16ddc197ac789d01fb8ada7a3" + [[package]] name = "parley" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ada5338c3a9794af7342e6f765b6e78740db37378aced034d7bf72c96b94ed94" dependencies = [ - "fontique", - "harfrust", + "fontique 0.7.0", + "harfrust 0.3.2", "hashbrown 0.16.1", "linebender_resource_handle", "skrifa 0.37.0", "swash", ] +[[package]] +name = "parley" +version = "0.8.0" +source = "git+https://github.com/linebender/parley?rev=07980878fc9ea4b16ddc197ac789d01fb8ada7a3#07980878fc9ea4b16ddc197ac789d01fb8ada7a3" +dependencies = [ + "fontique 0.8.0", + "harfrust 0.5.2", + "hashbrown 0.16.1", + "icu_normalizer", + "icu_properties", + "icu_segmenter", + "linebender_resource_handle", + "parlance", + "parley_data", + "skrifa 0.40.0", +] + +[[package]] +name = "parley_data" +version = "0.8.0" +source = "git+https://github.com/linebender/parley?rev=07980878fc9ea4b16ddc197ac789d01fb8ada7a3#07980878fc9ea4b16ddc197ac789d01fb8ada7a3" +dependencies = [ + "icu_properties", +] + [[package]] name = "paste" version = "1.0.15" @@ -2774,6 +3315,59 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + [[package]] name = "pico-args" version = "0.5.0" @@ -2831,7 +3425,7 @@ name = "pixels_window_renderer" version = "0.3.0" dependencies = [ "anyrender", - "debug_timer", + "debug_timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "pixels", ] @@ -2930,6 +3524,23 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "presser" version = "0.3.1" @@ -3065,6 +3676,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b634fabf032fab15307ffd272149b622260f55974d9fad689292a5d33df02e5" dependencies = [ "bytemuck", + "core_maths", "font-types 0.11.1", ] @@ -3258,11 +3870,32 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" dependencies = [ - "ab_glyph", + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit", + "tiny-skia", +] + +[[package]] +name = "selectors" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.11.0", + "cssparser", + "derive_more", "log", - "memmap2", - "smithay-client-toolkit", - "tiny-skia", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash 2.1.1", + "servo_arc", + "smallvec", + "to_shmem", + "to_shmem_derive", ] [[package]] @@ -3365,10 +3998,20 @@ dependencies = [ "anyrender_vello_cpu", "image", "kurbo", - "parley", + "parley 0.7.0", "peniko", ] +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "serde", + "stable_deref_trait", +] + [[package]] name = "sha2" version = "0.10.9" @@ -3500,6 +4143,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "smallbitvec" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d31d263dd118560e1a492922182ab6ca6dc1d03a3bf54e7699993f31a4150e3f" + [[package]] name = "smallvec" version = "1.15.1" @@ -3543,6 +4192,16 @@ dependencies = [ "serde", ] +[[package]] +name = "smol_str" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" +dependencies = [ + "borsh", + "serde_core", +] + [[package]] name = "socket2" version = "0.6.3" @@ -3590,7 +4249,7 @@ name = "softbuffer_window_renderer" version = "0.3.0" dependencies = [ "anyrender", - "debug_timer", + "debug_timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "softbuffer", ] @@ -3603,6 +4262,12 @@ dependencies = [ "bitflags 2.11.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -3618,12 +4283,201 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9628de9b8791db39ceda2b119bbe13134770b56c138ec1d3af810d045c04f9bd" + +[[package]] +name = "strum_macros" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "stylo" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db1bbd0d306397f76ab4bc2d08bee9eda5eb5f70ce18abce5f429e14a93bc50" +dependencies = [ + "app_units", + "arrayvec", + "atomic_refcell", + "bitflags 2.11.0", + "byteorder", + "cssparser", + "derive_more", + "encoding_rs", + "euclid", + "icu_segmenter", + "indexmap", + "itertools 0.14.0", + "itoa", + "log", + "malloc_size_of_derive", + "mime", + "new_debug_unreachable", + "num-derive", + "num-integer", + "num-traits", + "num_cpus", + "parking_lot", + "precomputed-hash", + "rayon", + "rayon-core", + "rustc-hash 2.1.1", + "selectors", + "serde", + "servo_arc", + "smallbitvec", + "smallvec", + "static_assertions", + "string_cache", + "strum", + "strum_macros", + "stylo_atoms", + "stylo_derive", + "stylo_dom", + "stylo_malloc_size_of", + "stylo_static_prefs", + "stylo_traits", + "thin-vec", + "to_shmem", + "to_shmem_derive", + "uluru", + "url", + "void", + "walkdir", + "web_atoms", +] + +[[package]] +name = "stylo_atoms" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d42e774cee69976c2ecd3bb20807f6aed425d755e9d6f452c0b6db44076f325" +dependencies = [ + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "stylo_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a288f2c2ac1ac7e99aea3b5863989234eb02d4703d3a7676bf1e371d07f83357" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "stylo_dom" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0e8a383ccc3c4f6a821a47da1411b3857a7274d2d1568d1e01ca15341963ca" +dependencies = [ + "bitflags 2.11.0", + "stylo_malloc_size_of", +] + +[[package]] +name = "stylo_malloc_size_of" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdff8744ef9ccdd7381e28566413446608759cb5eeec418a798c72ae95d86fd" +dependencies = [ + "app_units", + "cssparser", + "euclid", + "selectors", + "servo_arc", + "smallbitvec", + "smallvec", + "string_cache", + "thin-vec", + "void", +] + +[[package]] +name = "stylo_static_prefs" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61b56e722f192b3716459e30f3d5ae4825f476757703446a3580086668784a8c" + +[[package]] +name = "stylo_taffy" +version = "0.2.0" +source = "git+https://github.com/DioxusLabs/blitz#781ae63fdb6e76baa0969ba8cbce557327c7dfca" +dependencies = [ + "stylo", + "stylo_atoms", + "taffy", +] + +[[package]] +name = "stylo_traits" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "354e851d78b99d3ab591a76a9f768048493540d3575d1acc1e59ad640f36e449" +dependencies = [ + "app_units", + "bitflags 2.11.0", + "cssparser", + "euclid", + "malloc_size_of_derive", + "selectors", + "serde", + "servo_arc", + "stylo_atoms", + "stylo_malloc_size_of", + "thin-vec", + "to_shmem", + "to_shmem_derive", + "url", +] + [[package]] name = "svg_fmt" version = "0.4.5" @@ -3679,6 +4533,28 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "taffy" +version = "0.9.2" +source = "git+https://github.com/DioxusLabs/taffy?rev=4b6687da0ca1e9d71da4e48b4c659f5c45060707#4b6687da0ca1e9d71da4e48b4c659f5c45060707" +dependencies = [ + "arrayvec", + "grid", + "serde", + "slotmap", +] + [[package]] name = "tar" version = "0.4.45" @@ -3690,6 +4566,16 @@ dependencies = [ "xattr", ] +[[package]] +name = "tendril" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24" +dependencies = [ + "new_debug_unreachable", + "utf-8", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -3699,6 +4585,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thin-vec" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "144f754d318415ac792f9d69fc87abbbfc043ce2ef041c60f16ad828f638717d" + [[package]] name = "thiserror" version = "1.0.69" @@ -3812,6 +4704,33 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "to_shmem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab187810ca1e6aaa4c97a06492aac9ade2ffae6a301fd2aac103656f5a69edb" +dependencies = [ + "cssparser", + "servo_arc", + "smallbitvec", + "smallvec", + "string_cache", + "thin-vec", +] + +[[package]] +name = "to_shmem_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba1f5563024b63bb6acb4558452d9ba737518c1d11fcc1861febe98d1e31cf4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + [[package]] name = "tokio" version = "1.50.0" @@ -4012,6 +4931,15 @@ dependencies = [ "wide", ] +[[package]] +name = "uluru" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c8a2469e56e6e5095c82ccd3afb98dad95f7af7929aab6d8ba8d6e0f73657da" +dependencies = [ + "arrayvec", +] + [[package]] name = "unicase" version = "2.9.0" @@ -4084,6 +5012,19 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + [[package]] name = "usvg" version = "0.46.0" @@ -4111,6 +5052,24 @@ dependencies = [ "xmlwriter", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "utf8parse" version = "0.2.2" @@ -4239,6 +5198,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "walkdir" version = "2.5.0" @@ -4452,6 +5417,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web_atoms" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a9779e9f04d2ac1ce317aee707aa2f6b773afba7b931222bff6983843b1576" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "weezl" version = "0.1.12" @@ -5025,7 +6002,7 @@ dependencies = [ "rustix 0.38.44", "sctk-adwaita", "smithay-client-toolkit", - "smol_str", + "smol_str 0.2.2", "tracing", "unicode-segmentation", "wasm-bindgen", @@ -5162,6 +6139,16 @@ version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" +[[package]] +name = "xml5ever" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b16d30e6fa45d0969f5f0878048df440603569a1cbd5156d101f9772f3c45b2" +dependencies = [ + "log", + "markup5ever", +] + [[package]] name = "xmlwriter" version = "0.1.0" @@ -5174,6 +6161,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01738255b5a16e78bbb83e7fbba0a1e7dd506905cfc53f4622d89015a03fbb5" +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + [[package]] name = "zeno" version = "0.3.3" @@ -5205,6 +6215,32 @@ name = "zerofrom" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] [[package]] name = "zerovec" @@ -5213,7 +6249,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "serde", + "yoke", "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 8e07929..8593770 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -10,16 +10,20 @@ crate-type = ["cdylib", "rlib"] [dependencies] anyrender = { workspace = true } anyrender_vello = { workspace = true } +blitz-dom = { git = "https://github.com/DioxusLabs/blitz", package = "blitz-dom", default-features = false, features = ["woff-rust"] } +blitz-html = { git = "https://github.com/DioxusLabs/blitz", package = "blitz-html", default-features = false } +blitz-paint = { git = "https://github.com/DioxusLabs/blitz", package = "blitz-paint", default-features = false, features = ["svg"] } +blitz-traits = { git = "https://github.com/DioxusLabs/blitz", package = "blitz-traits", default-features = false } console_error_panic_hook = "0.1.7" -kurbo = { workspace = true } -peniko = { workspace = true } +js-sys = "0.3" +linebender_resource_handle = { workspace = true } raw-window-handle = { workspace = true, features = ["wasm-bindgen-0-2"] } wasm-bindgen = "0.2" wasm-bindgen-futures = "0.4" [dependencies.web-sys] version = "0.3" -features = ["HtmlCanvasElement"] +features = ["HtmlCanvasElement", "Response", "Window"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies] axum = "0.7" diff --git a/examples/wasm/README.md b/examples/wasm/README.md index 9c80dd6..39ee429 100644 --- a/examples/wasm/README.md +++ b/examples/wasm/README.md @@ -9,6 +9,7 @@ rustup target add wasm32-unknown-unknown --toolchain 1.92.0 cargo +1.92.0 install wasm-pack # build into examples/wasm/src/pkg so index.html can import it +export RUSTUP_TOOLCHAIN=1.92 wasm-pack build examples/wasm --target web --out-dir src/pkg ``` diff --git a/examples/wasm/src/index.html b/examples/wasm/src/index.html index 0dd8a57..75e6a45 100644 --- a/examples/wasm/src/index.html +++ b/examples/wasm/src/index.html @@ -7,7 +7,7 @@ @@ -193,25 +199,34 @@

Hello from WASM

`; let painting = false; - let pending = false; + let queued = false; + let waitingOnResources = false; async function renderCanvas() { if (painting) { - pending = true; + queued = true; return; } painting = true; try { - do { - pending = false; - const rect = canvas.getBoundingClientRect(); - const dpr = window.devicePixelRatio || 1; - await paintHtml(canvas, ta.value, rect.width, rect.height, dpr); - } while (pending); + const rect = canvas.getBoundingClientRect(); + const dpr = window.devicePixelRatio || 1; + const done = await paintHtml(canvas, ta.value, rect.width, rect.height, dpr); + if (!done && !waitingOnResources) { + waitingOnResources = true; + requestAnimationFrame(() => { + waitingOnResources = false; + renderCanvas(); + }); + } } catch (err) { console.error("paintHtml failed", err); } finally { painting = false; + if (queued) { + queued = false; + renderCanvas(); + } } } diff --git a/examples/wasm/src/lib.rs b/examples/wasm/src/lib.rs index 39cf679..8999716 100644 --- a/examples/wasm/src/lib.rs +++ b/examples/wasm/src/lib.rs @@ -1,20 +1,47 @@ -//! Minimal WASM example: paint a simple scene onto an `HtmlCanvasElement`. +//! Minimal WASM example: paint HTML onto an `HtmlCanvasElement`. #![cfg(target_arch = "wasm32")] -use anyrender::{PaintScene, WindowHandle, WindowRenderer}; +use anyrender::{WindowHandle, WindowRenderer}; +use blitz_dom::{DocumentConfig, FontContext, DEFAULT_CSS}; use anyrender_vello::VelloWindowRenderer; -use kurbo::{Affine, Circle, Point, Rect, Stroke}; -use peniko::{Color, Fill}; +use blitz_html::HtmlDocument; +use blitz_paint::paint_scene; +use blitz_traits::net::{Bytes, NetHandler, NetProvider, Request}; +use blitz_traits::shell::{ColorScheme, Viewport}; +use js_sys::Uint8Array; use raw_window_handle::{ DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawWindowHandle, WebCanvasWindowHandle, WindowHandle as RwhWindowHandle, }; use std::cell::RefCell; -use std::sync::Arc; +use std::sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, +}; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; +use wasm_bindgen_futures::JsFuture; use web_sys::HtmlCanvasElement; +/// Blitz is built with `default-features = false`, so there is no system font backend on wasm. +/// Ship a small font and point UA styles at it so body text can shape and paint. +fn wasm_font_context() -> FontContext { + use linebender_resource_handle::Blob; + + let mut font_ctx = FontContext::new(); + font_ctx.collection.register_fonts( + Blob::new(Arc::new( + include_bytes!("../../../assets/fonts/roboto/Roboto.ttf").to_vec(), + )), + None, + ); + font_ctx.collection.register_fonts( + Blob::new(Arc::new(blitz_dom::BULLET_FONT.to_vec())), + None, + ); + font_ctx +} + #[wasm_bindgen(start)] pub fn main() { console_error_panic_hook::set_once(); @@ -25,6 +52,9 @@ struct RendererState { canvas: Option>, width: u32, height: u32, + doc: Option, + doc_html: String, + net_provider: Arc, } impl RendererState { @@ -34,6 +64,9 @@ impl RendererState { canvas: None, width: 0, height: 0, + doc: None, + doc_html: String::new(), + net_provider: Arc::new(WasmNetProvider::new()), } } } @@ -61,6 +94,77 @@ impl HasWindowHandle for CanvasPresentationTarget { } } +struct WasmNetProvider { + in_flight: Arc, +} + +impl WasmNetProvider { + fn new() -> Self { + Self { + in_flight: Arc::new(AtomicUsize::new(0)), + } + } + + fn has_in_flight(&self) -> bool { + self.in_flight.load(Ordering::SeqCst) > 0 + } +} + +struct InFlightGuard { + counter: Arc, +} + +impl Drop for InFlightGuard { + fn drop(&mut self) { + self.counter.fetch_sub(1, Ordering::SeqCst); + } +} + +impl NetProvider for WasmNetProvider { + fn fetch(&self, _doc_id: usize, request: Request, handler: Box) { + let url = request.url.to_string(); + let counter = self.in_flight.clone(); + counter.fetch_add(1, Ordering::SeqCst); + wasm_bindgen_futures::spawn_local(async move { + let _guard = InFlightGuard { counter }; + let window = web_sys::window(); + let bytes = match window { + Some(window) => { + let resp_value = match JsFuture::from(window.fetch_with_str(&url)).await { + Ok(value) => value, + Err(_) => { + handler.bytes(url, Bytes::new()); + return; + } + }; + let resp: web_sys::Response = match resp_value.dyn_into() { + Ok(resp) => resp, + Err(_) => { + handler.bytes(url, Bytes::new()); + return; + } + }; + let resp_url = resp.url(); + let buffer = match JsFuture::from(resp.array_buffer().unwrap()).await { + Ok(buffer) => buffer, + Err(_) => { + handler.bytes(resp_url, Bytes::new()); + return; + } + }; + let array = Uint8Array::new(&buffer); + let mut data = vec![0u8; array.length() as usize]; + array.copy_to(&mut data); + handler.bytes(resp_url, Bytes::from(data)); + return; + } + None => Bytes::new(), + }; + handler.bytes(url, bytes); + }); + } +} + /// Paint `html` into `canvas`. #[wasm_bindgen(js_name = paintHtml)] pub async fn paint_html( @@ -69,7 +173,7 @@ pub async fn paint_html( css_width: f64, css_height: f64, device_pixel_ratio: f64, -) -> Result<(), JsValue> { +) -> Result { let dpr = device_pixel_ratio.max(1.0); let css_width = css_width.max(1.0); let css_height = css_height.max(1.0); @@ -84,7 +188,6 @@ pub async fn paint_html( canvas.set_height(phys_h); } - let _ = html; let canvas_arc = Arc::new(canvas.clone()); let mut renderer_state = RENDERER_STATE @@ -121,11 +224,42 @@ pub async fn paint_html( renderer_state.height = phys_h; } + let html_changed = renderer_state.doc_html != html; + if html_changed || renderer_state.doc.is_none() { + let mut config = DocumentConfig::default(); + config.net_provider = Some(renderer_state.net_provider.clone()); + config.font_ctx = Some(wasm_font_context()); + config.ua_stylesheets = Some(vec![ + DEFAULT_CSS.to_string(), + "html, body, p { font-family: Roboto, ui-sans-serif, system-ui, sans-serif !important; }\n\ + code, kbd, pre, samp { font-family: Roboto, ui-monospace, monospace !important; }\n" + .to_string(), + ]); + let mut doc = HtmlDocument::from_html(html, config); + doc.set_viewport(Viewport::new(phys_w, phys_h, dpr as f32, ColorScheme::Light)); + renderer_state.doc = Some(doc); + renderer_state.doc_html = html.to_string(); + } + + let doc = renderer_state + .doc + .as_mut() + .ok_or_else(|| JsValue::from_str("Document not initialized."))?; + + doc.handle_messages(); + doc.set_viewport(Viewport::new(phys_w, phys_h, dpr as f32, ColorScheme::Light)); + doc.resolve(0.0); + doc.handle_messages(); + + let (width, height) = doc.viewport().window_size; + let scale = doc.viewport().scale_f64(); + let pending_resources = + doc.has_pending_critical_resources() || renderer_state.net_provider.has_in_flight(); renderer_state .renderer - .render(|scene| paint_simple_scene(scene, css_width, css_height, dpr)); + .render(|scene| paint_scene(scene, &*doc, scale, width, height, 0, 0)); - Ok(()) + Ok(!pending_resources) } .await; @@ -135,42 +269,3 @@ pub async fn paint_html( result } - -fn paint_simple_scene( - scene: &mut impl PaintScene, - css_width: f64, - css_height: f64, - dpr: f64, -) { - let width = css_width.max(1.0); - let height = css_height.max(1.0); - let transform = Affine::scale(dpr); - - scene.fill( - Fill::NonZero, - transform, - Color::WHITE, - None, - &Rect::new(0.0, 0.0, width, height), - ); - - let inset = 8.0; - if width > inset && height > inset { - scene.stroke( - &Stroke::new(2.0), - transform, - Color::from_rgb8(30, 41, 59), - None, - &Rect::new(inset, inset, width - inset, height - inset), - ); - } - - let radius = (width.min(height) * 0.18).max(6.0); - scene.fill( - Fill::NonZero, - transform, - Color::from_rgb8(59, 130, 246), - None, - &Circle::new(Point::new(width * 0.5, height * 0.5), radius), - ); -} From c4c6728e704760d52681aeaae36598b042d59109 Mon Sep 17 00:00:00 2001 From: Paul Dufour Date: Mon, 30 Mar 2026 09:22:06 -0700 Subject: [PATCH 4/6] Roboto swap --- examples/wasm/src/index.html | 21 ++++++++++++++++----- examples/wasm/src/lib.rs | 9 ++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/wasm/src/index.html b/examples/wasm/src/index.html index 75e6a45..4ce451b 100644 --- a/examples/wasm/src/index.html +++ b/examples/wasm/src/index.html @@ -7,7 +7,7 @@