Skip to main content

widgetkit_render/
surface.rs

1use crate::{Canvas, frame::Frame, raster::Rasterizer, unstable::RenderFrame};
2use widgetkit_core::{Color, Error, Result};
3
4/// Low-level pixel surface consumed by renderer backends.
5///
6/// This contract is still part of WidgetKit's evolving render internals and is not promoted by
7/// the top-level `widgetkit` facade.
8pub trait RenderSurface {
9    fn size(&self) -> (u32, u32);
10    fn present(&mut self, pixels: &[Color]) -> Result<()>;
11}
12
13/// Low-level renderer backend contract.
14///
15/// `SoftwareRenderer` is the stable renderer users are expected to construct today. Implementing
16/// custom backends directly depends on the unstable frame/command model.
17pub trait Renderer: Send {
18    fn render_frame(&mut self, frame: RenderFrame, surface: &mut dyn RenderSurface) -> Result<()>;
19
20    fn render_canvas(&mut self, canvas: Canvas, surface: &mut dyn RenderSurface) -> Result<()> {
21        self.render_frame(canvas.into_frame(), surface)
22    }
23}
24
25pub struct SoftwareRenderer {
26    pixels: Vec<Color>,
27}
28
29impl SoftwareRenderer {
30    pub fn new() -> Self {
31        Self { pixels: Vec::new() }
32    }
33
34    fn ensure_buffer(&mut self, width: u32, height: u32) -> Result<()> {
35        let len = usize::try_from(width)
36            .ok()
37            .and_then(|w| usize::try_from(height).ok().map(|h| w.saturating_mul(h)))
38            .ok_or_else(|| Error::render("surface dimensions exceed addressable memory"))?;
39        if self.pixels.len() != len {
40            self.pixels.resize(len, Color::TRANSPARENT);
41        }
42        Ok(())
43    }
44}
45
46impl Default for SoftwareRenderer {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52impl Renderer for SoftwareRenderer {
53    fn render_frame(
54        &mut self,
55        render_frame: RenderFrame,
56        surface: &mut dyn RenderSurface,
57    ) -> Result<()> {
58        let (width, height) = surface.size();
59        self.ensure_buffer(width, height)?;
60        let surface_frame = Frame::new(width, height, &mut self.pixels);
61        let mut raster = Rasterizer::new(surface_frame);
62        raster.execute(render_frame);
63        drop(raster);
64        surface.present(&self.pixels)
65    }
66}
67
68// TODO(v0.3): allow alternate renderer implementations
69// TODO(v0.7): evaluate compatibility path for web/tauri-backed rendering