From a7c9df2ef1da927e743bd4a0783a5266d70ac402 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Sat, 27 Apr 2024 17:58:49 +0200 Subject: [PATCH] Add resize hint to the Web Renderer (#794) The web renderer now returns the new size whenever the element is supposed to be resized. This is important so adding or removing a component to the layout or loading a new layout will adjust the size of the element accordingly. This is the same way the other renderers handle it, so we should do the same for the web renderer. Additionally this fixes a bug in the way the strings got passed from JavaScript to Rust, where we introduced a difference between the length of a string and the capacity of its allocation, but didn't properly differentiate between them everywhere. --- Cargo.toml | 1 + capi/bind_gen/src/wasm_bindgen.rs | 75 ++++++++----------------------- capi/src/web_rendering.rs | 16 ++++--- src/rendering/web/mod.rs | 9 +++- 4 files changed, 36 insertions(+), 65 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c56c7b7e..62e081c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -223,6 +223,7 @@ inherits = "release" lto = true panic = "abort" codegen-units = 1 +strip = true [profile.max-opt.build-override] opt-level = 0 diff --git a/capi/bind_gen/src/wasm_bindgen.rs b/capi/bind_gen/src/wasm_bindgen.rs index 35f2cde3..3f8f442f 100644 --- a/capi/bind_gen/src/wasm_bindgen.rs +++ b/capi/bind_gen/src/wasm_bindgen.rs @@ -349,71 +349,34 @@ pub fn write( import * as wasm from "./livesplit_core_bg.wasm"; import "./livesplit_core.js"; -declare class TextEncoder { - constructor(label?: string, options?: TextEncoding.TextEncoderOptions); - encoding: string; - encode(input?: string, options?: TextEncoding.TextEncodeOptions): Uint8Array; -} - -declare class TextDecoder { - constructor(utfLabel?: string, options?: TextEncoding.TextDecoderOptions) - encoding: string; - fatal: boolean; - ignoreBOM: boolean; - decode(input?: ArrayBufferView, options?: TextEncoding.TextDecodeOptions): string; -} - -declare namespace TextEncoding { - interface TextDecoderOptions { - fatal?: boolean; - ignoreBOM?: boolean; - } - - interface TextDecodeOptions { - stream?: boolean; - } - - interface TextEncoderOptions { - NONSTANDARD_allowLegacyEncoding?: boolean; - } - - interface TextEncodeOptions { - stream?: boolean; - } - - interface TextEncodingStatic { - TextDecoder: typeof TextDecoder; - TextEncoder: typeof TextEncoder; - } -} - const encoder = new TextEncoder(); const decoder = new TextDecoder(); interface Slice { ptr: number, len: number, + cap: number, } function allocUint8Array(src: Uint8Array): Slice { - const len = src.length; - const ptr = wasm.alloc(len); - const slice = new Uint8Array(wasm.memory.buffer, ptr, len); + const cap = src.length; + const ptr = wasm.alloc(cap); + const slice = new Uint8Array(wasm.memory.buffer, ptr, cap); slice.set(src); - return { ptr, len }; + return { ptr, len: cap, cap }; } function allocString(str: string): Slice { - const len = 3 * str.length + 1; - const ptr = wasm.alloc(len); - const slice = new Uint8Array(wasm.memory.buffer, ptr, len); + const cap = 3 * str.length + 1; + const ptr = wasm.alloc(cap); + const slice = new Uint8Array(wasm.memory.buffer, ptr, cap); const stats = encoder.encodeInto(str, slice); slice[stats.written] = 0; - return { ptr, len }; + return { ptr, len: stats.written, cap }; } function decodeSlice(ptr: number): Uint8Array { @@ -432,7 +395,7 @@ function decodeString(ptr: number): string { } function dealloc(slice: Slice) { - wasm.dealloc(slice.ptr, slice.len); + wasm.dealloc(slice.ptr, slice.cap); } "#, @@ -449,24 +412,24 @@ const encoder = new TextEncoder(); const decoder = new TextDecoder(); function allocUint8Array(src) { - const len = src.length; - const ptr = wasm.alloc(len); - const slice = new Uint8Array(wasm.memory.buffer, ptr, len); + const cap = src.length; + const ptr = wasm.alloc(cap); + const slice = new Uint8Array(wasm.memory.buffer, ptr, cap); slice.set(src); - return { ptr, len }; + return { ptr, len: cap, cap }; } function allocString(str) { - const len = 3 * str.length + 1; - const ptr = wasm.alloc(len); - const slice = new Uint8Array(wasm.memory.buffer, ptr, len); + const cap = 3 * str.length + 1; + const ptr = wasm.alloc(cap); + const slice = new Uint8Array(wasm.memory.buffer, ptr, cap); const stats = encoder.encodeInto(str, slice); slice[stats.written] = 0; - return { ptr, len }; + return { ptr, len: stats.written, cap }; } function decodeSlice(ptr) { @@ -485,7 +448,7 @@ function decodeString(ptr) { } function dealloc(slice) { - wasm.dealloc(slice.ptr, slice.len); + wasm.dealloc(slice.ptr, slice.cap); }"#, )?; } diff --git a/capi/src/web_rendering.rs b/capi/src/web_rendering.rs index 987ad226..356bc8fd 100644 --- a/capi/src/web_rendering.rs +++ b/capi/src/web_rendering.rs @@ -8,12 +8,12 @@ use web_sys::Element; /// The web renderer renders into a canvas element. The element can then be /// attached anywhere in the DOM with any desired positioning and size. #[wasm_bindgen] -pub struct CanvasRenderer { +pub struct WebRenderer { inner: web::Renderer, } #[wasm_bindgen] -impl CanvasRenderer { +impl WebRenderer { /// Creates a new web renderer that renders into a canvas element. The /// element can then be attached anywhere in the DOM with any desired /// positioning and size. There are two CSS fonts that are used as the @@ -21,7 +21,7 @@ impl CanvasRenderer { /// fully loaded before creating the renderer as otherwise information about /// a fallback font is cached instead. #[allow(clippy::new_without_default)] - pub fn new() -> CanvasRenderer { + pub fn new() -> Self { Self { inner: web::Renderer::new(), } @@ -35,9 +35,11 @@ impl CanvasRenderer { /// Renders the layout state into the canvas. The image cache is used to /// retrieve images that are used in the layout state. - pub unsafe fn render(&mut self, state: usize, image_cache: usize) { - let state = unsafe { core::mem::transmute::(state) }; - let image_cache = unsafe { core::mem::transmute::(image_cache) }; - self.inner.render(state, image_cache); + pub unsafe fn render( + &mut self, + state: *const LayoutState, + image_cache: *const ImageCache, + ) -> Option> { + self.inner.render(&*state, &*image_cache).map(Box::from) } } diff --git a/src/rendering/web/mod.rs b/src/rendering/web/mod.rs index ee4a022e..702c6137 100644 --- a/src/rendering/web/mod.rs +++ b/src/rendering/web/mod.rs @@ -560,7 +560,7 @@ impl Renderer { /// Renders the layout state into the canvas. The image cache is used to /// retrieve images that are used in the layout state. - pub fn render(&mut self, state: &LayoutState, image_cache: &ImageCache) { + pub fn render(&mut self, state: &LayoutState, image_cache: &ImageCache) -> Option<[f32; 2]> { // Scaling is based on: // https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html @@ -579,7 +579,7 @@ impl Renderer { self.canvas_top.set_height(height as _); } - self.manager.update_scene( + let new_dims = self.manager.update_scene( &mut self.allocator, [width as _, height as _], state, @@ -670,6 +670,11 @@ impl Renderer { } self.top_layer_is_cleared = layer.is_empty(); render_layer(ctx, &mut self.cache, str_buf, layer, &self.allocator.digits); + + new_dims.map(|[width, height]| { + let ratio = (1.0 / ratio) as f32; + [width * ratio, height * ratio] + }) } }