Skip to main content

iced_renderer/
fallback.rs

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