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