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