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