Skip to main content

iced_renderer/
fallback.rs

1//! Compose existing renderers and create type-safe fallback strategies.
2use crate::core::backend;
3use crate::core::font;
4use crate::core::image;
5use crate::core::renderer;
6use crate::core::svg;
7use crate::core::{self, Background, Color, Image, Point, Rectangle, Size, Svg, Transformation};
8use crate::graphics::compositor;
9use crate::graphics::mesh;
10use crate::graphics::text;
11use crate::graphics::{self, Shell};
12
13use std::borrow::Cow;
14
15/// A renderer `A` with a fallback strategy `B`.
16///
17/// This type can be used to easily compose existing renderers and
18/// create custom, type-safe fallback strategies.
19#[derive(Debug)]
20pub enum Renderer<A, B> {
21    /// The primary rendering option.
22    Primary(A),
23    /// The secondary (or fallback) rendering option.
24    Secondary(B),
25}
26
27macro_rules! delegate {
28    ($renderer:expr, $name:ident, $body:expr) => {
29        match $renderer {
30            Self::Primary($name) => $body,
31            Self::Secondary($name) => $body,
32        }
33    };
34}
35
36impl<A, B> core::Renderer for Renderer<A, B>
37where
38    A: core::Renderer,
39    B: core::Renderer,
40{
41    fn fill_quad(&mut self, quad: renderer::Quad, background: impl Into<Background>) {
42        delegate!(self, renderer, renderer.fill_quad(quad, background.into()));
43    }
44
45    fn start_layer(&mut self, bounds: Rectangle) {
46        delegate!(self, renderer, renderer.start_layer(bounds));
47    }
48
49    fn end_layer(&mut self) {
50        delegate!(self, renderer, renderer.end_layer());
51    }
52
53    fn start_transformation(&mut self, transformation: Transformation) {
54        delegate!(
55            self,
56            renderer,
57            renderer.start_transformation(transformation)
58        );
59    }
60
61    fn end_transformation(&mut self) {
62        delegate!(self, renderer, renderer.end_transformation());
63    }
64
65    fn allocate_image(
66        &self,
67        handle: &image::Handle,
68        callback: impl FnOnce(Result<image::Allocation, image::Error>) + Send + 'static,
69    ) {
70        delegate!(self, renderer, renderer.allocate_image(handle, callback));
71    }
72
73    fn hint(&mut self, scale: renderer::Scale) {
74        delegate!(self, renderer, renderer.hint(scale));
75    }
76
77    fn scale(&self) -> Option<renderer::Scale> {
78        delegate!(self, renderer, renderer.scale())
79    }
80
81    fn tick(&mut self) {
82        delegate!(self, renderer, renderer.tick());
83    }
84
85    fn reset(&mut self, new_bounds: Rectangle) {
86        delegate!(self, renderer, renderer.reset(new_bounds));
87    }
88
89    fn settings(&self) -> renderer::Settings {
90        delegate!(self, renderer, renderer.settings())
91    }
92}
93
94impl<A, B> core::text::Renderer for Renderer<A, B>
95where
96    A: core::text::Renderer,
97    B: core::text::Renderer<Paragraph = A::Paragraph, Editor = A::Editor>,
98{
99    type Paragraph = A::Paragraph;
100    type Editor = A::Editor;
101
102    const ICON_FONT: core::Font = A::ICON_FONT;
103    const CHECKMARK_ICON: char = A::CHECKMARK_ICON;
104    const ARROW_DOWN_ICON: char = A::ARROW_DOWN_ICON;
105    const SCROLL_UP_ICON: char = A::SCROLL_UP_ICON;
106    const SCROLL_DOWN_ICON: char = A::SCROLL_DOWN_ICON;
107    const SCROLL_LEFT_ICON: char = A::SCROLL_LEFT_ICON;
108    const SCROLL_RIGHT_ICON: char = A::SCROLL_RIGHT_ICON;
109    const ICED_LOGO: char = A::ICED_LOGO;
110
111    fn fill_paragraph(
112        &mut self,
113        text: &Self::Paragraph,
114        position: Point,
115        color: Color,
116        clip_bounds: Rectangle,
117    ) {
118        delegate!(
119            self,
120            renderer,
121            renderer.fill_paragraph(text, position, color, clip_bounds)
122        );
123    }
124
125    fn fill_editor(
126        &mut self,
127        editor: &Self::Editor,
128        position: Point,
129        color: Color,
130        clip_bounds: Rectangle,
131    ) {
132        delegate!(
133            self,
134            renderer,
135            renderer.fill_editor(editor, position, color, clip_bounds)
136        );
137    }
138
139    fn fill_text(
140        &mut self,
141        text: core::Text<String>,
142        position: Point,
143        color: Color,
144        clip_bounds: Rectangle,
145    ) {
146        delegate!(
147            self,
148            renderer,
149            renderer.fill_text(text, position, color, clip_bounds)
150        );
151    }
152}
153
154impl<A, B> text::Renderer for Renderer<A, B>
155where
156    A: text::Renderer,
157    B: text::Renderer,
158{
159    fn fill_raw(&mut self, raw: text::Raw) {
160        delegate!(self, renderer, renderer.fill_raw(raw));
161    }
162}
163
164impl<A, B> image::Renderer for Renderer<A, B>
165where
166    A: image::Renderer,
167    B: image::Renderer<Handle = A::Handle>,
168{
169    type Handle = A::Handle;
170
171    fn load_image(&self, handle: &Self::Handle) -> Result<image::Allocation, image::Error> {
172        delegate!(self, renderer, renderer.load_image(handle))
173    }
174
175    fn measure_image(&self, handle: &Self::Handle) -> Option<Size<u32>> {
176        delegate!(self, renderer, renderer.measure_image(handle))
177    }
178
179    fn draw_image(&mut self, image: Image<A::Handle>, bounds: Rectangle, clip_bounds: Rectangle) {
180        delegate!(
181            self,
182            renderer,
183            renderer.draw_image(image, bounds, clip_bounds)
184        );
185    }
186}
187
188impl<A, B> svg::Renderer for Renderer<A, B>
189where
190    A: svg::Renderer,
191    B: svg::Renderer,
192{
193    fn measure_svg(&self, handle: &svg::Handle) -> Size<u32> {
194        delegate!(self, renderer, renderer.measure_svg(handle))
195    }
196
197    fn draw_svg(&mut self, svg: Svg, bounds: Rectangle, clip_bounds: Rectangle) {
198        delegate!(self, renderer, renderer.draw_svg(svg, bounds, clip_bounds));
199    }
200}
201
202impl<A, B> mesh::Renderer for Renderer<A, B>
203where
204    A: mesh::Renderer,
205    B: mesh::Renderer,
206{
207    fn draw_mesh(&mut self, mesh: graphics::Mesh) {
208        delegate!(self, renderer, renderer.draw_mesh(mesh));
209    }
210
211    fn draw_mesh_cache(&mut self, cache: mesh::Cache) {
212        delegate!(self, renderer, renderer.draw_mesh_cache(cache));
213    }
214}
215
216/// A compositor `A` with a fallback strategy `B`.
217///
218/// It works analogously to [`Renderer`].
219#[derive(Debug)]
220pub enum Compositor<A, B>
221where
222    A: graphics::Compositor,
223    B: graphics::Compositor,
224{
225    /// The primary compositing option.
226    Primary(A),
227    /// The secondary (or fallback) compositing option.
228    Secondary(B),
229}
230
231/// A surface `A` with a fallback strategy `B`.
232///
233/// It works analogously to [`Renderer`].
234#[derive(Debug)]
235pub enum Surface<A, B> {
236    /// The primary surface option.
237    Primary(A),
238    /// The secondary (or fallback) surface option.
239    Secondary(B),
240}
241
242impl<A, B> graphics::Compositor for Compositor<A, B>
243where
244    A: graphics::Compositor,
245    B: graphics::Compositor,
246{
247    type Renderer = Renderer<A::Renderer, B::Renderer>;
248    type Surface = Surface<A::Surface, B::Surface>;
249
250    async fn new(
251        settings: backend::Settings,
252        display: impl compositor::Display + Clone,
253        compatible_window: impl compositor::Window + Clone,
254        shell: Shell,
255    ) -> Result<Self, backend::Error> {
256        let mut errors = vec![];
257
258        match A::new(
259            settings.clone(),
260            display.clone(),
261            compatible_window.clone(),
262            shell.clone(),
263        )
264        .await
265        {
266            Ok(compositor) => return Ok(Self::Primary(compositor)),
267            Err(error) => {
268                errors.push(error);
269            }
270        }
271
272        match B::new(
273            settings,
274            display.clone(),
275            compatible_window.clone(),
276            shell.clone(),
277        )
278        .await
279        {
280            Ok(compositor) => return Ok(Self::Secondary(compositor)),
281            Err(error) => {
282                errors.push(error);
283            }
284        }
285
286        Err(backend::Error::List(errors))
287    }
288
289    fn create_renderer(&self, settings: renderer::Settings) -> Self::Renderer {
290        match self {
291            Self::Primary(compositor) => Renderer::Primary(compositor.create_renderer(settings)),
292            Self::Secondary(compositor) => {
293                Renderer::Secondary(compositor.create_renderer(settings))
294            }
295        }
296    }
297
298    fn create_surface(&mut self, window: impl compositor::Window + Clone) -> Self::Surface {
299        match self {
300            Self::Primary(compositor) => Surface::Primary(compositor.create_surface(window)),
301            Self::Secondary(compositor) => Surface::Secondary(compositor.create_surface(window)),
302        }
303    }
304
305    fn configure_surface(&mut self, surface: &mut Self::Surface, width: u32, height: u32) {
306        match (self, surface) {
307            (Self::Primary(compositor), Surface::Primary(surface)) => {
308                compositor.configure_surface(surface, width, height);
309            }
310            (Self::Secondary(compositor), Surface::Secondary(surface)) => {
311                compositor.configure_surface(surface, width, height);
312            }
313            _ => unreachable!(),
314        }
315    }
316
317    fn load_font(&mut self, font: Cow<'static, [u8]>) -> Result<(), font::Error> {
318        delegate!(self, compositor, compositor.load_font(font))
319    }
320
321    fn list_fonts(&mut self) -> Result<Vec<font::Family>, font::Error> {
322        delegate!(self, compositor, compositor.list_fonts())
323    }
324
325    fn information(&self) -> compositor::Information {
326        delegate!(self, compositor, compositor.information())
327    }
328
329    fn present(
330        &mut self,
331        renderer: &mut Self::Renderer,
332        surface: &mut Self::Surface,
333        viewport: &graphics::Viewport,
334        background_color: Color,
335        on_pre_present: impl FnOnce(),
336    ) -> Result<(), compositor::SurfaceError> {
337        match (self, renderer, surface) {
338            (Self::Primary(compositor), Renderer::Primary(renderer), Surface::Primary(surface)) => {
339                compositor.present(
340                    renderer,
341                    surface,
342                    viewport,
343                    background_color,
344                    on_pre_present,
345                )
346            }
347            (
348                Self::Secondary(compositor),
349                Renderer::Secondary(renderer),
350                Surface::Secondary(surface),
351            ) => compositor.present(
352                renderer,
353                surface,
354                viewport,
355                background_color,
356                on_pre_present,
357            ),
358            _ => unreachable!(),
359        }
360    }
361
362    fn screenshot(
363        &mut self,
364        renderer: &mut Self::Renderer,
365        viewport: &graphics::Viewport,
366        background_color: Color,
367    ) -> Vec<u8> {
368        match (self, renderer) {
369            (Self::Primary(compositor), Renderer::Primary(renderer)) => {
370                compositor.screenshot(renderer, viewport, background_color)
371            }
372            (Self::Secondary(compositor), Renderer::Secondary(renderer)) => {
373                compositor.screenshot(renderer, viewport, background_color)
374            }
375            _ => unreachable!(),
376        }
377    }
378}
379
380#[cfg(feature = "wgpu-bare")]
381impl<A, B> iced_wgpu::primitive::Renderer for Renderer<A, B>
382where
383    A: iced_wgpu::primitive::Renderer,
384    B: core::Renderer,
385{
386    fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl iced_wgpu::Primitive) {
387        match self {
388            Self::Primary(renderer) => {
389                renderer.draw_primitive(bounds, primitive);
390            }
391            Self::Secondary(_) => {
392                log::warn!("Custom shader primitive is not supported with this renderer.");
393            }
394        }
395    }
396}
397
398#[cfg(feature = "geometry")]
399mod geometry {
400    use super::Renderer;
401    use crate::core::{Point, Radians, Rectangle, Size, Svg, Vector};
402    use crate::graphics::cache::{self, Cached};
403    use crate::graphics::geometry::{self, Fill, Image, Path, Stroke, Text};
404
405    impl<A, B> geometry::Renderer for Renderer<A, B>
406    where
407        A: geometry::Renderer,
408        B: geometry::Renderer,
409    {
410        type Geometry = Geometry<A::Geometry, B::Geometry>;
411        type Frame = Frame<A::Frame, B::Frame>;
412
413        fn new_frame(&self, bounds: Rectangle) -> Self::Frame {
414            match self {
415                Self::Primary(renderer) => Frame::Primary(renderer.new_frame(bounds)),
416                Self::Secondary(renderer) => Frame::Secondary(renderer.new_frame(bounds)),
417            }
418        }
419
420        fn draw_geometry(&mut self, geometry: Self::Geometry) {
421            match (self, geometry) {
422                (Self::Primary(renderer), Geometry::Primary(geometry)) => {
423                    renderer.draw_geometry(geometry);
424                }
425                (Self::Secondary(renderer), Geometry::Secondary(geometry)) => {
426                    renderer.draw_geometry(geometry);
427                }
428                _ => unreachable!(),
429            }
430        }
431    }
432
433    #[derive(Debug, Clone)]
434    pub enum Geometry<A, B> {
435        Primary(A),
436        Secondary(B),
437    }
438
439    impl<A, B> Cached for Geometry<A, B>
440    where
441        A: Cached,
442        B: Cached,
443    {
444        type Cache = Geometry<A::Cache, B::Cache>;
445
446        fn load(cache: &Self::Cache) -> Self {
447            match cache {
448                Geometry::Primary(cache) => Self::Primary(A::load(cache)),
449                Geometry::Secondary(cache) => Self::Secondary(B::load(cache)),
450            }
451        }
452
453        fn cache(self, group: cache::Group, previous: Option<Self::Cache>) -> Self::Cache {
454            match (self, previous) {
455                (Self::Primary(geometry), Some(Geometry::Primary(previous))) => {
456                    Geometry::Primary(geometry.cache(group, Some(previous)))
457                }
458                (Self::Primary(geometry), None) => Geometry::Primary(geometry.cache(group, None)),
459                (Self::Secondary(geometry), Some(Geometry::Secondary(previous))) => {
460                    Geometry::Secondary(geometry.cache(group, Some(previous)))
461                }
462                (Self::Secondary(geometry), None) => {
463                    Geometry::Secondary(geometry.cache(group, None))
464                }
465                _ => unreachable!(),
466            }
467        }
468    }
469
470    #[derive(Debug)]
471    pub enum Frame<A, B> {
472        Primary(A),
473        Secondary(B),
474    }
475
476    impl<A, B> geometry::frame::Backend for Frame<A, B>
477    where
478        A: geometry::frame::Backend,
479        B: geometry::frame::Backend,
480    {
481        type Geometry = Geometry<A::Geometry, B::Geometry>;
482
483        fn width(&self) -> f32 {
484            delegate!(self, frame, frame.width())
485        }
486
487        fn height(&self) -> f32 {
488            delegate!(self, frame, frame.height())
489        }
490
491        fn size(&self) -> Size {
492            delegate!(self, frame, frame.size())
493        }
494
495        fn center(&self) -> Point {
496            delegate!(self, frame, frame.center())
497        }
498
499        fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
500            delegate!(self, frame, frame.fill(path, fill));
501        }
502
503        fn fill_rectangle(&mut self, top_left: Point, size: Size, fill: impl Into<Fill>) {
504            delegate!(self, frame, frame.fill_rectangle(top_left, size, fill));
505        }
506
507        fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
508            delegate!(self, frame, frame.stroke(path, stroke));
509        }
510
511        fn stroke_rectangle<'a>(
512            &mut self,
513            top_left: Point,
514            size: Size,
515            stroke: impl Into<Stroke<'a>>,
516        ) {
517            delegate!(self, frame, frame.stroke_rectangle(top_left, size, stroke));
518        }
519
520        fn stroke_text<'a>(&mut self, text: impl Into<Text>, stroke: impl Into<Stroke<'a>>) {
521            delegate!(self, frame, frame.stroke_text(text, stroke));
522        }
523
524        fn fill_text(&mut self, text: impl Into<Text>) {
525            delegate!(self, frame, frame.fill_text(text));
526        }
527
528        fn draw_image(&mut self, bounds: Rectangle, image: impl Into<Image>) {
529            delegate!(self, frame, frame.draw_image(bounds, image));
530        }
531
532        fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {
533            delegate!(self, frame, frame.draw_svg(bounds, svg));
534        }
535
536        fn push_transform(&mut self) {
537            delegate!(self, frame, frame.push_transform());
538        }
539
540        fn pop_transform(&mut self) {
541            delegate!(self, frame, frame.pop_transform());
542        }
543
544        fn draft(&mut self, bounds: Rectangle) -> Self {
545            match self {
546                Self::Primary(frame) => Self::Primary(frame.draft(bounds)),
547                Self::Secondary(frame) => Self::Secondary(frame.draft(bounds)),
548            }
549        }
550
551        fn paste(&mut self, frame: Self) {
552            match (self, frame) {
553                (Self::Primary(target), Self::Primary(source)) => {
554                    target.paste(source);
555                }
556                (Self::Secondary(target), Self::Secondary(source)) => {
557                    target.paste(source);
558                }
559                _ => unreachable!(),
560            }
561        }
562
563        fn translate(&mut self, translation: Vector) {
564            delegate!(self, frame, frame.translate(translation));
565        }
566
567        fn rotate(&mut self, angle: impl Into<Radians>) {
568            delegate!(self, frame, frame.rotate(angle));
569        }
570
571        fn scale(&mut self, scale: f32) {
572            delegate!(self, frame, frame.scale(scale));
573        }
574
575        fn scale_nonuniform(&mut self, scale: impl Into<Vector>) {
576            delegate!(self, frame, frame.scale_nonuniform(scale));
577        }
578
579        fn into_geometry(self) -> Self::Geometry {
580            match self {
581                Frame::Primary(frame) => Geometry::Primary(frame.into_geometry()),
582                Frame::Secondary(frame) => Geometry::Secondary(frame.into_geometry()),
583            }
584        }
585    }
586}
587
588impl<A, B> renderer::Headless for Renderer<A, B>
589where
590    A: renderer::Headless,
591    B: renderer::Headless,
592{
593    async fn new(settings: renderer::Settings, backend: Option<&str>) -> Option<Self> {
594        if let Some(renderer) = A::new(settings, backend).await {
595            return Some(Self::Primary(renderer));
596        }
597
598        B::new(settings, backend).await.map(Self::Secondary)
599    }
600
601    fn name(&self) -> String {
602        delegate!(self, renderer, renderer.name())
603    }
604
605    fn screenshot(
606        &mut self,
607        size: Size<u32>,
608        scale_factor: f32,
609        background_color: Color,
610    ) -> Vec<u8> {
611        match self {
612            crate::fallback::Renderer::Primary(renderer) => {
613                renderer.screenshot(size, scale_factor, background_color)
614            }
615            crate::fallback::Renderer::Secondary(renderer) => {
616                renderer.screenshot(size, scale_factor, background_color)
617            }
618        }
619    }
620}
621
622impl<A, B> compositor::Default for Renderer<A, B>
623where
624    A: compositor::Default,
625    B: compositor::Default,
626{
627    type Compositor = Compositor<A::Compositor, B::Compositor>;
628}