Skip to main content

floem_renderer/
lib.rs

1//! Rendering abstraction layer for the Floem UI framework.
2//!
3//! This crate defines the [`Renderer`] trait that all Floem rendering backends must
4//! implement, along with supporting types for passing images and SVGs to the renderer.
5//! Floem ships with three backend implementations:
6//!
7//! - **Vello** (`floem_vello_renderer`) — GPU-accelerated renderer using the Vello scene graph (default).
8//! - **Skia** (`floem_skia_renderer`) — GPU-accelerated renderer using AnyRender's Skia backend.
9//! - **Vger** (`floem_vger_renderer`) — GPU-accelerated renderer using the Vger library.
10//! - **tiny-skia** (`floem_tiny_skia_renderer`) — CPU software renderer using tiny-skia.
11//!
12//! # Modules
13//!
14//! - [`text`] — Text layout, shaping, and font management built on [Parley](https://docs.rs/parley).
15//! - [`gpu_resources`] — Asynchronous wgpu adapter/device acquisition for GPU backends.
16//!
17//! # Re-exports
18//!
19//! [`tiny_skia`] and [`usvg`] are re-exported from [`resvg`](https://docs.rs/resvg) so that
20//! renderer backends and downstream crates can use consistent versions of these libraries
21//! without adding them as direct dependencies.
22
23pub mod text;
24use peniko::{
25    BlendMode, BrushRef,
26    kurbo::{Affine, Point, Rect, Shape, Stroke},
27};
28pub use resvg::tiny_skia;
29pub use resvg::usvg;
30
31pub mod gpu_resources;
32
33/// A reference to a parsed SVG tree paired with a cache key.
34///
35/// # Example
36///
37/// ```no_run
38/// use floem_renderer::{Svg, usvg};
39///
40/// let svg_text = r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
41///   <circle cx="12" cy="12" r="10" fill="currentColor"/>
42/// </svg>"#;
43///
44/// let tree = usvg::Tree::from_str(svg_text, &usvg::Options::default()).unwrap();
45/// let hash = b"my-icon-cache-key";
46///
47/// let svg = Svg {
48///     tree: &tree,
49///     hash: hash.as_slice(),
50/// };
51/// ```
52pub struct Svg<'a> {
53    /// The parsed SVG document.
54    pub tree: &'a usvg::Tree,
55    /// An opaque byte slice used as a cache key by the renderer.
56    pub hash: &'a [u8],
57}
58
59/// A raster image paired with a cache key.
60///
61/// # Example
62///
63/// ```no_run
64/// use floem_renderer::Img;
65///
66/// # fn make_image_brush() -> peniko::ImageBrush { todo!() }
67/// let brush = make_image_brush();
68/// let hash = b"photo-abc123";
69///
70/// let img = Img {
71///     img: brush,
72///     hash: hash.as_slice(),
73/// };
74/// ```
75pub struct Img<'a> {
76    /// The image data as a [`peniko::ImageBrush`].
77    pub img: peniko::ImageBrush,
78    /// An opaque byte slice used as a cache key by the renderer.
79    pub hash: &'a [u8],
80}
81
82/// The core rendering trait that every Floem backend must implement.
83///
84/// A frame is bracketed by [`begin`](Renderer::begin) and [`finish`](Renderer::finish).
85/// Between those calls the framework issues drawing commands — fills, strokes, text,
86/// images, SVGs — which the backend records or executes immediately depending on its
87/// architecture.
88///
89/// The typical call sequence within a single frame looks like:
90///
91/// ```text
92/// renderer.begin(capture);
93/// renderer.set_transform(..);
94/// renderer.fill(..);          // background
95/// renderer.clip(..);          // restrict drawing area
96/// renderer.draw_text_lines(..); // labels, editors
97/// renderer.draw_svg(..);      // icons
98/// renderer.draw_img(..);      // photos
99/// renderer.stroke(..);        // borders
100/// renderer.clear_clip();
101/// renderer.finish();
102/// ```
103pub trait Renderer {
104    /// Begin a new frame.
105    ///
106    /// Must be called exactly once before any drawing commands.
107    /// When `capture` is `true` the renderer should record the frame into an
108    /// off-screen buffer so that [`finish`](Renderer::finish) can return it as
109    /// an [`ImageBrush`](peniko::ImageBrush). This is used by the Floem
110    /// inspector to take snapshots.
111    fn begin(&mut self, capture: bool);
112
113    /// Set the current affine transform in device/render-target coordinates.
114    ///
115    /// All subsequent drawing commands are transformed by `transform` until it
116    /// is changed again. The framework provides this as the final transform for
117    /// the current visual node, including window scaling, so backends should not
118    /// apply an additional global window-scale multiply to ordinary geometry.
119    ///
120    /// Raster-backed operations such as glyph and SVG caching may still derive
121    /// a rasterization scale from this transform to choose an appropriate pixel
122    /// resolution.
123    fn set_transform(&mut self, transform: Affine);
124
125    /// Set the z-index for subsequent draw commands.
126    ///
127    /// Not all backends honour this — Vello and tiny-skia rely on painter's
128    /// order instead.
129    fn set_z_index(&mut self, z_index: i32);
130
131    /// Clip all subsequent drawing to the interior of `shape`.
132    ///
133    /// The clip remains in effect until [`clear_clip`](Renderer::clear_clip) is
134    /// called. On the Vello backend clipping is implemented via
135    /// [`push_layer`](Renderer::push_layer) / [`pop_layer`](Renderer::pop_layer)
136    /// instead, so this method may be a no-op there.
137    fn clip(&mut self, shape: &impl Shape);
138
139    /// Remove the current clip region, allowing drawing to the full surface.
140    fn clear_clip(&mut self);
141
142    /// Stroke the outline of a [`Shape`].
143    ///
144    /// The `brush` defines the color or gradient and `stroke` controls the
145    /// line width, join style, dash pattern, etc.
146    fn stroke<'b, 's>(
147        &mut self,
148        shape: &impl Shape,
149        brush: impl Into<peniko::BrushRef<'b>>,
150        stroke: &'s Stroke,
151    );
152
153    /// Fill the interior of a [`Shape`] using the [non-zero fill rule].
154    ///
155    /// When `blur_radius` is greater than zero the fill is drawn with a
156    /// Gaussian blur, which is used for box shadows.
157    ///
158    /// [non-zero fill rule]: https://en.wikipedia.org/wiki/Nonzero-rule
159    fn fill<'b>(&mut self, path: &impl Shape, brush: impl Into<BrushRef<'b>>, blur_radius: f64);
160
161    /// Push a compositing layer onto the layer stack.
162    ///
163    /// Drawing commands issued after this call are composited into the layer.
164    /// Call [`pop_layer`](Renderer::pop_layer) to flatten the layer back into
165    /// the parent using the specified `blend` mode and `alpha`.
166    ///
167    /// The `clip` shape restricts drawing within the layer, and `transform` is
168    /// applied to the layer contents.
169    fn push_layer(
170        &mut self,
171        blend: impl Into<BlendMode>,
172        alpha: f32,
173        transform: Affine,
174        clip: &impl Shape,
175    );
176
177    /// Pop the topmost compositing layer pushed by [`push_layer`](Renderer::push_layer).
178    ///
179    /// The layer contents are composited into the parent surface using the
180    /// blend mode and alpha that were specified when the layer was pushed.
181    fn pop_layer(&mut self);
182
183    /// Draw a single glyph run.
184    fn draw_glyphs<'a>(
185        &mut self,
186        origin: Point,
187        props: &text::GlyphRunProps<'a>,
188        glyphs: impl Iterator<Item = text::Glyph> + 'a,
189    );
190
191    /// Draw an SVG image inside `rect`.
192    ///
193    /// When `brush` is `Some`, the SVG is rendered as a mask and filled with
194    /// the given brush — this is how Floem applies a color override to icons.
195    fn draw_svg<'b>(&mut self, svg: Svg<'b>, rect: Rect, brush: Option<impl Into<BrushRef<'b>>>);
196
197    /// Draw a raster image inside `rect`.
198    ///
199    /// The image is scaled to fit the destination rectangle.
200    fn draw_img(&mut self, img: Img<'_>, rect: Rect);
201
202    /// Finish the current frame and present it.
203    ///
204    /// If the frame was started with `capture = true`, the rendered content is
205    /// returned as an [`ImageBrush`](peniko::ImageBrush). Otherwise returns
206    /// `None` after presenting the frame to the screen.
207    fn finish(&mut self) -> Option<peniko::ImageBrush>;
208
209    /// Return a human-readable string identifying the renderer backend.
210    ///
211    /// Used by the Floem inspector. Implementations typically return a string
212    /// like `"name: Vello\ninfo: …"`.
213    fn debug_info(&self) -> String {
214        "Unknown".into()
215    }
216}