iced_renderer/
fallback.rs

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