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