Skip to main content

ferroui_browser/rendering/
browser_surface.rs

1use crate::interop::canvas_helper::CanvasSurface;
2use ferroui_base::rendering::composition::Compositor;
3use ferroui_base::utilities::HandlerList;
4use ferroui_base::{PixelSize, Size};
5use std::cell::{Cell, RefCell};
6use std::rc::Rc;
7
8/// The state every surface of a view has: its canvas, its compositor and
9/// its size in device pixels and logical units.
10pub struct BrowserSurface {
11    compositor: Rc<Compositor>,
12    js_surface: RefCell<Option<CanvasSurface>>,
13    scaling: Cell<f64>,
14    client_size: Cell<Size>,
15    render_size: Cell<PixelSize>,
16    size_changed: HandlerList<dyn Fn()>,
17    scaling_changed: HandlerList<dyn Fn()>,
18}
19
20impl BrowserSurface {
21    /// Creates the surface state for a canvas of the page.
22    pub fn new(js_surface: CanvasSurface, compositor: Rc<Compositor>) -> Self {
23        Self {
24            compositor,
25            js_surface: RefCell::new(Some(js_surface)),
26            scaling: Cell::new(1.0),
27            client_size: Cell::new(Size::new(1.0, 1.0)),
28            render_size: Cell::new(PixelSize::new(1, 1)),
29            size_changed: HandlerList::new(),
30            scaling_changed: HandlerList::new(),
31        }
32    }
33
34    /// The compositor that renders to the surface.
35    pub fn compositor(&self) -> Rc<Compositor> {
36        self.compositor.clone()
37    }
38
39    /// The scaling from logical units to device pixels.
40    pub fn scaling(&self) -> f64 {
41        self.scaling.get()
42    }
43
44    /// The size in logical units.
45    pub fn client_size(&self) -> Size {
46        self.client_size.get()
47    }
48
49    /// The size in device pixels.
50    pub fn render_size(&self) -> PixelSize {
51        self.render_size.get()
52    }
53
54    /// Whether the surface has a size it can be rendered at.
55    pub fn is_valid(&self) -> bool {
56        let render_size = self.render_size.get();
57        render_size.width > 0 && render_size.height > 0 && self.scaling.get() > 0.0
58    }
59
60    /// Subscribes to changes of the client size.
61    pub fn size_changed(&self, handler: Rc<dyn Fn()>) -> u64 {
62        self.size_changed.add(handler)
63    }
64
65    /// Subscribes to changes of the scaling.
66    pub fn scaling_changed(&self, handler: Rc<dyn Fn()>) -> u64 {
67        self.scaling_changed.add(handler)
68    }
69
70    /// The size and the scaling the canvas has right now, as
71    /// `(pixel width, pixel height, scaling)`; `None` once disposed.
72    pub fn initial_size(&self) -> Option<(f64, f64, f64)> {
73        let js_surface = self.js_surface.borrow();
74        let js_surface = js_surface.as_ref()?;
75        Some((js_surface.width(), js_surface.height(), js_surface.scaling()))
76    }
77
78    /// Releases the canvas surface.
79    pub fn dispose(&self) {
80        let js_surface = self.js_surface.borrow_mut().take();
81        if let Some(js_surface) = js_surface {
82            CanvasSurface::destroy(&js_surface);
83        }
84        self.render_size.set(PixelSize::default());
85        self.client_size.set(Size::default());
86    }
87
88    /// Records the size of the canvas and raises the change events.
89    ///
90    /// `pixel_width` and `pixel_height` are in device pixels; `dpr` is the
91    /// device pixel ratio.
92    pub fn on_size_changed(&self, pixel_width: f64, pixel_height: f64, dpr: f64) {
93        let old_scaling = self.scaling.get();
94        let old_client_size = self.client_size.get();
95        self.render_size.set(PixelSize::new(pixel_width as i32, pixel_height as i32));
96        self.client_size.set(self.render_size.get().to_size(dpr));
97        self.scaling.set(dpr);
98        if old_client_size != self.client_size.get() {
99            for (_, handler) in self.size_changed.snapshot().iter() {
100                handler();
101            }
102        }
103        if (old_scaling - dpr).abs() > 0.0001 {
104            for (_, handler) in self.scaling_changed.snapshot().iter() {
105                handler();
106            }
107        }
108    }
109}