Skip to main content

iced_renderer/
fallback.rs

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