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