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