Skip to content

Commit

Permalink
Add resize hint to the Web Renderer (#794)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
CryZe authored Apr 27, 2024
1 parent 2f6ade5 commit cb43b07
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 59 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ inherits = "release"
lto = true
panic = "abort"
codegen-units = 1
strip = true

[profile.max-opt.build-override]
opt-level = 0
69 changes: 19 additions & 50 deletions capi/bind_gen/src/wasm_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,65 +355,34 @@ declare class TextEncoder {
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 {
Expand All @@ -432,7 +401,7 @@ function decodeString(ptr: number): string {
}
function dealloc(slice: Slice) {
wasm.dealloc(slice.ptr, slice.len);
wasm.dealloc(slice.ptr, slice.cap);
}
"#,
Expand All @@ -449,24 +418,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) {
Expand All @@ -485,7 +454,7 @@ function decodeString(ptr) {
}
function dealloc(slice) {
wasm.dealloc(slice.ptr, slice.len);
wasm.dealloc(slice.ptr, slice.cap);
}"#,
)?;
}
Expand Down
16 changes: 9 additions & 7 deletions capi/src/web_rendering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ 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
/// default fonts. They are called "timer" and "fira". Make sure they are
/// 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(),
}
Expand All @@ -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::<usize, &LayoutState>(state) };
let image_cache = unsafe { core::mem::transmute::<usize, &ImageCache>(image_cache) };
self.inner.render(state, image_cache);
pub unsafe fn render(
&mut self,
state: *const LayoutState,
image_cache: *const ImageCache,
) -> Option<Box<[f32]>> {
self.inner.render(&*state, &*image_cache).map(Box::from)
}
}
9 changes: 7 additions & 2 deletions src/rendering/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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,
Expand Down Expand Up @@ -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]
})
}
}

Expand Down

0 comments on commit cb43b07

Please sign in to comment.