Skip to main content

iced_core/
renderer.rs

1//! Write your own renderer.
2#[cfg(debug_assertions)]
3mod null;
4
5use crate::image;
6use crate::{
7    Background, Border, Color, Font, Pixels, Rectangle, Shadow, Size, Transformation, Vector,
8};
9
10/// Whether anti-aliasing should be avoided by snapping primitive coordinates to the
11/// pixel grid.
12pub const CRISP: bool = cfg!(feature = "crisp");
13
14/// A component that can be used by widgets to draw themselves on a screen.
15pub trait Renderer {
16    /// Starts recording a new layer.
17    fn start_layer(&mut self, bounds: Rectangle);
18
19    /// Ends recording a new layer.
20    ///
21    /// The new layer will clip its contents to the provided `bounds`.
22    fn end_layer(&mut self);
23
24    /// Draws the primitives recorded in the given closure in a new layer.
25    ///
26    /// The layer will clip its contents to the provided `bounds`.
27    fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) {
28        self.start_layer(bounds);
29        f(self);
30        self.end_layer();
31    }
32
33    /// Starts recording with a new [`Transformation`].
34    fn start_transformation(&mut self, transformation: Transformation);
35
36    /// Ends recording a new layer.
37    ///
38    /// The new layer will clip its contents to the provided `bounds`.
39    fn end_transformation(&mut self);
40
41    /// Applies a [`Transformation`] to the primitives recorded in the given closure.
42    fn with_transformation(&mut self, transformation: Transformation, f: impl FnOnce(&mut Self)) {
43        self.start_transformation(transformation);
44        f(self);
45        self.end_transformation();
46    }
47
48    /// Applies a translation to the primitives recorded in the given closure.
49    fn with_translation(&mut self, translation: Vector, f: impl FnOnce(&mut Self)) {
50        self.with_transformation(Transformation::translate(translation.x, translation.y), f);
51    }
52
53    /// Fills a [`Quad`] with the provided [`Background`].
54    fn fill_quad(&mut self, quad: Quad, background: impl Into<Background>);
55
56    /// Creates an [`image::Allocation`] for the given [`image::Handle`] and calls the given callback with it.
57    fn allocate_image(
58        &mut self,
59        handle: &image::Handle,
60        callback: impl FnOnce(Result<image::Allocation, image::Error>) + Send + 'static,
61    );
62
63    /// Provides hints to the [`Renderer`] about the rendering target.
64    ///
65    /// This may be used internally by the [`Renderer`] to perform optimizations
66    /// and/or improve rendering quality.
67    ///
68    /// For instance, providing a [`Scale`] may be used by some renderers to
69    /// perform metrics hinting internally in physical coordinates while keeping
70    /// layout coordinates logical and, therefore, maintain linearity.
71    fn hint(&mut self, scale: Scale);
72
73    /// Returns the last [`Scale`] provided as a [`hint`](Self::hint).
74    fn scale(&self) -> Option<Scale>;
75
76    /// Returns the last hint factor provided as a [`hint`](Self::hint),
77    /// only if [`Settings::metrics_hinting`] is enabled.
78    fn hint_factor(&self) -> Option<f32> {
79        if !self.settings().metrics_hinting {
80            return None;
81        }
82
83        self.scale().map(Scale::total)
84    }
85
86    /// Resets the [`Renderer`] to start drawing in the `new_bounds` from scratch.
87    fn reset(&mut self, new_bounds: Rectangle);
88
89    /// Returns the [`Settings`] of this [`Renderer`].
90    fn settings(&self) -> Settings;
91
92    /// Polls any concurrent computations that may be pending in the [`Renderer`].
93    ///
94    /// By default, it does nothing.
95    fn tick(&mut self) {}
96}
97
98/// A polygon with four sides.
99#[derive(Debug, Clone, Copy, PartialEq)]
100pub struct Quad {
101    /// The bounds of the [`Quad`].
102    pub bounds: Rectangle,
103
104    /// The [`Border`] of the [`Quad`]. The border is drawn on the inside of the [`Quad`].
105    pub border: Border,
106
107    /// The [`Shadow`] of the [`Quad`].
108    pub shadow: Shadow,
109
110    /// Whether the [`Quad`] should be snapped to the pixel grid.
111    pub snap: bool,
112}
113
114impl Default for Quad {
115    fn default() -> Self {
116        Self {
117            bounds: Rectangle::with_size(Size::ZERO),
118            border: Border::default(),
119            shadow: Shadow::default(),
120            snap: CRISP,
121        }
122    }
123}
124
125/// The styling attributes of a [`Renderer`].
126#[derive(Debug, Clone, Copy, PartialEq)]
127pub struct Style {
128    /// The text color
129    pub text_color: Color,
130}
131
132impl Default for Style {
133    fn default() -> Self {
134        Style {
135            text_color: Color::BLACK,
136        }
137    }
138}
139
140/// A headless renderer is a renderer that can render offscreen without
141/// a window nor a compositor.
142pub trait Headless {
143    /// Creates a new [`Headless`] renderer;
144    fn new(settings: Settings, backend: Option<&str>) -> impl Future<Output = Option<Self>>
145    where
146        Self: Sized;
147
148    /// Returns the unique name of the renderer.
149    ///
150    /// This name may be used by testing libraries to uniquely identify
151    /// snapshots.
152    fn name(&self) -> String;
153
154    /// Draws offscreen into a screenshot, returning a collection of
155    /// bytes representing the rendered pixels in RGBA order.
156    fn screenshot(
157        &mut self,
158        size: Size<u32>,
159        scale_factor: f32,
160        background_color: Color,
161    ) -> Vec<u8>;
162}
163
164/// The settings of a [`Renderer`].
165#[derive(Debug, Clone, Copy, PartialEq)]
166pub struct Settings {
167    /// The default [`Font`] to use.
168    pub default_font: Font,
169
170    /// The default size of text.
171    ///
172    /// By default, it will be set to `16.0`.
173    pub default_text_size: Pixels,
174
175    /// Whether the [`Renderer`] should perform metrics hinting.
176    ///
177    /// By default, it is enabled.
178    pub metrics_hinting: bool,
179}
180
181impl Default for Settings {
182    fn default() -> Self {
183        Self {
184            default_font: Font::DEFAULT,
185            default_text_size: Pixels(16.0),
186            metrics_hinting: true,
187        }
188    }
189}
190
191/// The scale factor of a [`Renderer`].
192#[derive(Debug, Clone, Copy, PartialEq)]
193pub struct Scale {
194    /// The global scale factor of the window.
195    ///
196    /// This is normally controlled by the OS, and applied globally to all apps.
197    pub window: f32,
198
199    /// The local scale factor of the application.
200    pub application: f32,
201}
202
203impl Scale {
204    /// Returns the total scale factor applied by the [`Renderer`].
205    ///
206    /// This is the product of the window and application scale factors.
207    pub fn total(self) -> f32 {
208        self.window * self.application
209    }
210}
211
212impl Default for Scale {
213    fn default() -> Self {
214        Self {
215            window: 1.0,
216            application: 1.0,
217        }
218    }
219}