blockworx_canvas2d/
fit.rs1use blockworx_geom::{Rect, Vec2, pos2};
9use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, Window};
10
11#[derive(Clone, Copy, PartialEq, Debug)]
14pub struct DevicePixelRatio(f32);
15
16impl DevicePixelRatio {
17 #[must_use]
20 pub fn new(ratio: f32) -> Self {
21 Self(if ratio.is_finite() && ratio > 1.0 {
22 ratio
23 } else {
24 1.0
25 })
26 }
27
28 #[must_use]
31 pub fn of(window: &Window) -> Self {
32 Self::new(window.device_pixel_ratio() as f32)
33 }
34}
35
36impl From<DevicePixelRatio> for f32 {
37 fn from(ratio: DevicePixelRatio) -> Self {
38 ratio.0
39 }
40}
41
42pub fn fit(
45 canvas: &HtmlCanvasElement,
46 ctx: &CanvasRenderingContext2d,
47 css_size: Vec2,
48 ratio: DevicePixelRatio,
49) -> Rect {
50 let scale = f32::from(ratio);
51 let backing = |css: f32| (css * scale).round().max(1.0) as u32;
52 let (width, height) = (backing(css_size.x), backing(css_size.y));
53 if canvas.width() != width || canvas.height() != height {
56 canvas.set_width(width);
57 canvas.set_height(height);
58 }
59 let _ = ctx.set_transform(scale.into(), 0.0, 0.0, scale.into(), 0.0, 0.0);
62 Rect::from_min_size(pos2(0.0, 0.0), css_size)
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn a_ratio_below_one_is_taken_as_one() {
71 assert_eq!(f32::from(DevicePixelRatio::new(0.0)), 1.0);
72 assert_eq!(f32::from(DevicePixelRatio::new(-2.0)), 1.0);
73 assert_eq!(f32::from(DevicePixelRatio::new(f32::NAN)), 1.0);
74 assert_eq!(f32::from(DevicePixelRatio::new(2.0)), 2.0);
75 }
76}