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