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