#[cfg(target_arch = "wasm32")]
use std::sync::Arc;
#[cfg(target_arch = "wasm32")]
use winit::window::Window;
#[cfg(target_arch = "wasm32")]
const MAX_DEVICE_PIXEL_RATIO: f64 = 1.5;
#[cfg(target_arch = "wasm32")]
fn web_viewport_css_size() -> Option<(f64, f64)> {
let window = web_sys::window()?;
let width = window.inner_width().ok()?.as_f64()?;
let height = window.inner_height().ok()?.as_f64()?;
Some((width, height))
}
#[cfg(target_arch = "wasm32")]
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub(super) fn web_viewport_layout_physical_size() -> Option<winit::dpi::PhysicalSize<u32>> {
let (width, height) = web_viewport_css_size()?;
let dpr = web_sys::window()?.device_pixel_ratio();
Some(winit::dpi::PhysicalSize::new(
(width * dpr).round() as u32,
(height * dpr).round() as u32,
))
}
#[cfg(any(target_arch = "wasm32", test))]
fn dpr_pointer_scale(real_dpr: f64, capped_dpr: f64) -> f64 {
(capped_dpr / real_dpr).min(1.0)
}
#[cfg(target_arch = "wasm32")]
pub(super) fn wasm_pointer_scale() -> f64 {
web_sys::window().map_or(1.0, |w| {
dpr_pointer_scale(w.device_pixel_ratio(), MAX_DEVICE_PIXEL_RATIO)
})
}
#[cfg(target_arch = "wasm32")]
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
pub(super) fn web_viewport_surface_physical_size() -> Option<winit::dpi::PhysicalSize<u32>> {
let (width, height) = web_viewport_css_size()?;
let dpr = web_sys::window()?
.device_pixel_ratio()
.min(MAX_DEVICE_PIXEL_RATIO);
Some(winit::dpi::PhysicalSize::new(
(width * dpr).round() as u32,
(height * dpr).round() as u32,
))
}
#[cfg(target_arch = "wasm32")]
pub(super) fn install_viewport_resize_listener(window: &Arc<Window>) {
use wasm_bindgen::JsCast;
use wasm_bindgen::prelude::Closure;
let Some(web_window) = web_sys::window() else {
return;
};
let window = window.clone();
let closure = Closure::<dyn FnMut()>::new(move || {
if let Some(size) = web_viewport_layout_physical_size() {
let _ = window.request_inner_size(size);
}
});
if web_window
.add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref())
.is_ok()
{
closure.forget();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dpr_pointer_scale_no_correction_below_cap() {
assert!((dpr_pointer_scale(1.0, 1.5) - 1.0).abs() < 1e-9);
assert!((dpr_pointer_scale(1.5, 1.5) - 1.0).abs() < 1e-9);
}
#[test]
fn dpr_pointer_scale_corrects_above_cap() {
assert!((dpr_pointer_scale(3.0, 1.5) - 0.5).abs() < 1e-9);
assert!((dpr_pointer_scale(2.0, 1.5) - 0.75).abs() < 1e-9);
}
}