rust-windowing / rust-windowing/winit

[wasm] `common.{current,old}_size` is not updated until after `resize` event.

Open
#4,397 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

B - bug DS - web
Dominant language
Rust
Stars
6.2k
Forks
1.3k
Avg merge
2d 19h
Merged PRs (30d)
9

Description

Description

on wasm, window.surface_size() returns 0x0 immediately after create_window(), even when the canvas has explicit dimensions and with_surface_size() is used. the size only updates after the first resize event.

in winit-web/src/web_sys/canvas.rs, Canvas::create() calls set_canvas_size() to update the dom but never updates the current_size cache that surface_size() returns.

i think the fix would be to update the cache after setting the canvas size:

if let Some(size) = attr.surface_size {
    let logical_size = size.to_logical(super::scale_factor(&common.window));
    super::set_canvas_size(&common.document, &common.raw, &common.style, logical_size);
    // can we update common.current_size and common.old_size here?
}

minimally reproducible example

// src/main.rs
use wasm_bindgen::prelude::*;
use winit::{
    application::ApplicationHandler,
    dpi::{PhysicalSize, Size},
    event::WindowEvent,
    event_loop::{ActiveEventLoop, EventLoop},
    platform::web::{WindowAttributesWeb},
    window::{Window, WindowId}
};

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

#[derive(Default)]
struct App(Option<Box<dyn Window>>);

impl ApplicationHandler for App {
    fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
        let mut attribs = winit::window::WindowAttributes::default()
            .with_surface_size(Size::Physical(PhysicalSize::new(1280, 720)));

            let window = web_sys::window().unwrap();
            let document = window.document().unwrap();
            let canvas = document
                .get_element_by_id("canvas")
                .expect("no #canvas found")
                .dyn_into::<web_sys::HtmlCanvasElement>()
                .unwrap();

            log(&format!("canvas size according to html/web_sys: {}x{}", canvas.width(), canvas.height()));

            attribs = attribs.with_platform_attributes(Box::new(
                WindowAttributesWeb::default().with_canvas(Some(canvas.into())),
            ));

        let window = event_loop.create_window(attribs).unwrap();
        let surface_size = window.surface_size();
        log(&format!("window.surface_size() returns: {}x{}", surface_size.width, surface_size.height));

        self.0 = Some(window);
    }

    fn window_event(&mut self, _: &dyn ActiveEventLoop, _: WindowId, event: WindowEvent) {
        if let WindowEvent::SurfaceResized(new_size) = event {
            let window = self.0.as_ref().unwrap();
            let size = window.surface_size();
            log(&format!("SurfaceResized -> surface_size() now returns: {}x{}", size.width, size.height));
        }
    }
}

fn main() {
    use winit::platform::web::EventLoopExtWeb;
    let event_loop = EventLoop::new().unwrap();
    let app = App::default();
    event_loop.spawn_app(app);
}
# Cargo.toml
[package]
name = "winit-surface-size-bug"
version = "0.1.0"
edition = "2021"

[dependencies]
winit = { git = "https://github.com/rust-windowing/winit" }

[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = { version = "0.3", features = ["Window", "Document", "HtmlCanvasElement", "console"] }
wasm-bindgen = "0.2"
<!doctype html>
<html lang="en">
<body>
    <canvas id="canvas" width="800" height="600"></canvas>
    <script type="module">
        import init from './winit-surface-size-bug.js';
        init()
    </script>
</body>
</html>
#!/bin/bash
set -e
cargo build --target wasm32-unknown-unknown --release
mkdir -p pkg
wasm-bindgen --out-dir pkg --target web target/wasm32-unknown-unknown/release/winit-surface-size-bug.wasm
cp index.html pkg/
cd pkg && python3 -m http.server 8080
Tested browsers

Chrome, Safari (newer than listed)

Tested devices

iPhone 12 Pro Max Safari, iPad Pro Safari

Winit version

latest development version at the time of this pull request a9c189a4

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in winit-web/src/web_sys/canvas.rs at Canvas::create(), where set_canvas_size() is called, and inspect the current surface_size() cache behavior. Reproduce the wasm example and verify that surface_size() reports the configured dimensions immediately after create_window(), before any resize event.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, wasm
Domain
web-dev
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
54/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.