From 3645d34d6a1ba1247238e830e9eefd52d9e5b986 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 21 Mar 2024 22:27:17 +0100 Subject: Implement composable, type-safe renderer fallback --- renderer/src/fallback.rs | 562 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 562 insertions(+) create mode 100644 renderer/src/fallback.rs (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs new file mode 100644 index 00000000..a4c725c0 --- /dev/null +++ b/renderer/src/fallback.rs @@ -0,0 +1,562 @@ +use crate::core::image; +use crate::core::renderer; +use crate::core::svg; +use crate::core::{ + self, Background, Color, Point, Rectangle, Size, Transformation, +}; +use crate::graphics; +use crate::graphics::compositor; +use crate::graphics::mesh; + +pub enum Renderer +where + L: core::Renderer, + R: core::Renderer, +{ + Left(L), + Right(R), +} + +macro_rules! delegate { + ($renderer:expr, $name:ident, $body:expr) => { + match $renderer { + Self::Left($name) => $body, + Self::Right($name) => $body, + } + }; +} + +impl Renderer +where + L: core::Renderer, + R: core::Renderer, +{ + #[cfg(feature = "geometry")] + pub fn draw_geometry( + &mut self, + layers: impl IntoIterator, + ) where + L: graphics::geometry::Renderer, + R: graphics::geometry::Renderer, + + Geometry: Into>, + { + use graphics::geometry::Renderer; + + for layer in layers { + ::draw_geometry(self, layer.into()); + } + } +} + +impl core::Renderer for Renderer +where + L: core::Renderer, + R: core::Renderer, +{ + fn fill_quad( + &mut self, + quad: renderer::Quad, + background: impl Into, + ) { + delegate!(self, renderer, renderer.fill_quad(quad, background.into())); + } + + fn clear(&mut self) { + delegate!(self, renderer, renderer.clear()); + } + + fn start_layer(&mut self) { + delegate!(self, renderer, renderer.start_layer()); + } + + fn end_layer(&mut self, bounds: Rectangle) { + delegate!(self, renderer, renderer.end_layer(bounds)); + } + + fn start_transformation(&mut self) { + delegate!(self, renderer, renderer.start_transformation()); + } + + fn end_transformation(&mut self, transformation: Transformation) { + delegate!(self, renderer, renderer.end_transformation(transformation)); + } +} + +impl core::text::Renderer for Renderer +where + L: core::text::Renderer, + R: core::text::Renderer< + Font = L::Font, + Paragraph = L::Paragraph, + Editor = L::Editor, + >, +{ + type Font = L::Font; + type Paragraph = L::Paragraph; + type Editor = L::Editor; + + const ICON_FONT: Self::Font = L::ICON_FONT; + const CHECKMARK_ICON: char = L::CHECKMARK_ICON; + const ARROW_DOWN_ICON: char = L::ARROW_DOWN_ICON; + + fn default_font(&self) -> Self::Font { + delegate!(self, renderer, renderer.default_font()) + } + + fn default_size(&self) -> core::Pixels { + delegate!(self, renderer, renderer.default_size()) + } + + fn load_font(&mut self, font: std::borrow::Cow<'static, [u8]>) { + delegate!(self, renderer, renderer.load_font(font)); + } + + fn fill_paragraph( + &mut self, + text: &Self::Paragraph, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.fill_paragraph(text, position, color, clip_bounds) + ); + } + + fn fill_editor( + &mut self, + editor: &Self::Editor, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.fill_editor(editor, position, color, clip_bounds) + ); + } + + fn fill_text( + &mut self, + text: core::Text<'_, Self::Font>, + position: Point, + color: Color, + clip_bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.fill_text(text, position, color, clip_bounds) + ); + } +} + +impl image::Renderer for Renderer +where + L: image::Renderer, + R: image::Renderer, +{ + type Handle = L::Handle; + + fn measure_image(&self, handle: &Self::Handle) -> Size { + delegate!(self, renderer, renderer.measure_image(handle)) + } + + fn draw_image( + &mut self, + handle: Self::Handle, + filter_method: image::FilterMethod, + bounds: Rectangle, + ) { + delegate!( + self, + renderer, + renderer.draw_image(handle, filter_method, bounds) + ); + } +} + +impl svg::Renderer for Renderer +where + L: svg::Renderer, + R: svg::Renderer, +{ + fn measure_svg(&self, handle: &svg::Handle) -> Size { + delegate!(self, renderer, renderer.measure_svg(handle)) + } + + fn draw_svg( + &mut self, + handle: svg::Handle, + color: Option, + bounds: Rectangle, + ) { + delegate!(self, renderer, renderer.draw_svg(handle, color, bounds)); + } +} + +impl mesh::Renderer for Renderer +where + L: mesh::Renderer, + R: mesh::Renderer, +{ + fn draw_mesh(&mut self, mesh: graphics::Mesh) { + delegate!(self, renderer, renderer.draw_mesh(mesh)); + } +} + +pub enum Compositor +where + L: graphics::Compositor, + R: graphics::Compositor, +{ + Left(L), + Right(R), +} + +pub enum Surface { + Left(L), + Right(R), +} + +impl graphics::Compositor for Compositor +where + L: graphics::Compositor, + R: graphics::Compositor, + L::Settings: From, + R::Settings: From, +{ + type Settings = crate::Settings; + type Renderer = Renderer; + type Surface = Surface; + + async fn new( + settings: Self::Settings, + compatible_window: W, + ) -> Result { + if let Ok(left) = L::new(settings.into(), compatible_window.clone()) + .await + .map(Self::Left) + { + return Ok(left); + } + + R::new(settings.into(), compatible_window) + .await + .map(Self::Right) + } + + fn create_renderer(&self) -> Self::Renderer { + match self { + Self::Left(compositor) => { + Renderer::Left(compositor.create_renderer()) + } + Self::Right(compositor) => { + Renderer::Right(compositor.create_renderer()) + } + } + } + + fn create_surface( + &mut self, + window: W, + width: u32, + height: u32, + ) -> Self::Surface { + match self { + Self::Left(compositor) => { + Surface::Left(compositor.create_surface(window, width, height)) + } + Self::Right(compositor) => { + Surface::Right(compositor.create_surface(window, width, height)) + } + } + } + + fn configure_surface( + &mut self, + surface: &mut Self::Surface, + width: u32, + height: u32, + ) { + match (self, surface) { + (Self::Left(compositor), Surface::Left(surface)) => { + compositor.configure_surface(surface, width, height); + } + (Self::Right(compositor), Surface::Right(surface)) => { + compositor.configure_surface(surface, width, height); + } + _ => unreachable!(), + } + } + + fn fetch_information(&self) -> compositor::Information { + delegate!(self, compositor, compositor.fetch_information()) + } + + fn present>( + &mut self, + renderer: &mut Self::Renderer, + surface: &mut Self::Surface, + viewport: &graphics::Viewport, + background_color: Color, + overlay: &[T], + ) -> Result<(), compositor::SurfaceError> { + match (self, renderer, surface) { + ( + Self::Left(compositor), + Renderer::Left(renderer), + Surface::Left(surface), + ) => compositor.present( + renderer, + surface, + viewport, + background_color, + overlay, + ), + ( + Self::Right(compositor), + Renderer::Right(renderer), + Surface::Right(surface), + ) => compositor.present( + renderer, + surface, + viewport, + background_color, + overlay, + ), + _ => unreachable!(), + } + } + + fn screenshot>( + &mut self, + renderer: &mut Self::Renderer, + surface: &mut Self::Surface, + viewport: &graphics::Viewport, + background_color: Color, + overlay: &[T], + ) -> Vec { + match (self, renderer, surface) { + ( + Self::Left(compositor), + Renderer::Left(renderer), + Surface::Left(surface), + ) => compositor.screenshot( + renderer, + surface, + viewport, + background_color, + overlay, + ), + ( + Self::Right(compositor), + Renderer::Right(renderer), + Surface::Right(surface), + ) => compositor.screenshot( + renderer, + surface, + viewport, + background_color, + overlay, + ), + _ => unreachable!(), + } + } +} + +#[cfg(feature = "wgpu")] +impl iced_wgpu::primitive::pipeline::Renderer for Renderer +where + L: iced_wgpu::primitive::pipeline::Renderer, + R: core::Renderer, +{ + fn draw_pipeline_primitive( + &mut self, + bounds: Rectangle, + primitive: impl iced_wgpu::primitive::pipeline::Primitive, + ) { + match self { + Self::Left(renderer) => { + renderer.draw_pipeline_primitive(bounds, primitive); + } + Self::Right(_) => { + log::warn!( + "Custom shader primitive is not supported with this renderer." + ); + } + } + } +} + +#[cfg(feature = "geometry")] +mod geometry { + use super::Renderer; + use crate::core::{Point, Radians, Size, Vector}; + use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; + + impl geometry::Renderer for Renderer + where + L: geometry::Renderer, + R: geometry::Renderer, + { + type Geometry = Geometry; + type Frame = Frame; + + fn new_frame(&self, size: iced_graphics::core::Size) -> Self::Frame { + match self { + Self::Left(renderer) => Frame::Left(renderer.new_frame(size)), + Self::Right(renderer) => Frame::Right(renderer.new_frame(size)), + } + } + + fn draw_geometry(&mut self, geometry: Self::Geometry) { + match (self, geometry) { + (Self::Left(renderer), Geometry::Left(geometry)) => { + renderer.draw_geometry(geometry); + } + (Self::Right(renderer), Geometry::Right(geometry)) => { + renderer.draw_geometry(geometry); + } + _ => unreachable!(), + } + } + } + + pub enum Geometry { + Left(L), + Right(R), + } + + impl geometry::Geometry for Geometry + where + L: geometry::Geometry, + R: geometry::Geometry, + { + type Cache = Geometry; + + fn load(cache: &Self::Cache) -> Self { + match cache { + Geometry::Left(cache) => Self::Left(L::load(cache)), + Geometry::Right(cache) => Self::Right(R::load(cache)), + } + } + + fn cache(self) -> Self::Cache { + match self { + Self::Left(geometry) => Geometry::Left(geometry.cache()), + Self::Right(geometry) => Geometry::Right(geometry.cache()), + } + } + } + + pub enum Frame { + Left(L), + Right(R), + } + + impl geometry::Frame for Frame + where + L: geometry::Frame, + R: geometry::Frame, + { + type Geometry = Geometry; + + fn width(&self) -> f32 { + delegate!(self, frame, frame.width()) + } + + fn height(&self) -> f32 { + delegate!(self, frame, frame.height()) + } + + fn size(&self) -> Size { + delegate!(self, frame, frame.size()) + } + + fn center(&self) -> Point { + delegate!(self, frame, frame.center()) + } + + fn fill(&mut self, path: &Path, fill: impl Into) { + delegate!(self, frame, frame.fill(path, fill)); + } + + fn fill_rectangle( + &mut self, + top_left: Point, + size: Size, + fill: impl Into, + ) { + delegate!(self, frame, frame.fill_rectangle(top_left, size, fill)); + } + + fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { + delegate!(self, frame, frame.stroke(path, stroke)); + } + + fn fill_text(&mut self, text: impl Into) { + delegate!(self, frame, frame.fill_text(text)); + } + + fn push_transform(&mut self) { + delegate!(self, frame, frame.push_transform()); + } + + fn pop_transform(&mut self) { + delegate!(self, frame, frame.pop_transform()); + } + + fn draft(&mut self, size: Size) -> Self { + match self { + Self::Left(frame) => Self::Left(frame.draft(size)), + Self::Right(frame) => Self::Right(frame.draft(size)), + } + } + + fn paste(&mut self, frame: Self, at: Point) { + match (self, frame) { + (Self::Left(target), Self::Left(source)) => { + target.paste(source, at); + } + (Self::Right(target), Self::Right(source)) => { + target.paste(source, at); + } + _ => unreachable!(), + } + } + + fn translate(&mut self, translation: Vector) { + delegate!(self, frame, frame.translate(translation)); + } + + fn rotate(&mut self, angle: impl Into) { + delegate!(self, frame, frame.rotate(angle)); + } + + fn scale(&mut self, scale: impl Into) { + delegate!(self, frame, frame.scale(scale)); + } + + fn scale_nonuniform(&mut self, scale: impl Into) { + delegate!(self, frame, frame.scale_nonuniform(scale)); + } + } + + impl From> for Geometry + where + L: geometry::Frame, + R: geometry::Frame, + { + fn from(frame: Frame) -> Self { + match frame { + Frame::Left(frame) => Self::Left(frame.into()), + Frame::Right(frame) => Self::Right(frame.into()), + } + } + } +} -- cgit From 53a183fe0d6aed460fbb8155ac9541757277aab3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:35:14 +0100 Subject: Restore `canvas::Frame` API --- renderer/src/fallback.rs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index a4c725c0..659f253d 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -459,10 +459,10 @@ mod geometry { Right(R), } - impl geometry::Frame for Frame + impl geometry::frame::Backend for Frame where - L: geometry::Frame, - R: geometry::Frame, + L: geometry::frame::Backend, + R: geometry::frame::Backend, { type Geometry = Geometry; @@ -545,17 +545,11 @@ mod geometry { fn scale_nonuniform(&mut self, scale: impl Into) { delegate!(self, frame, frame.scale_nonuniform(scale)); } - } - impl From> for Geometry - where - L: geometry::Frame, - R: geometry::Frame, - { - fn from(frame: Frame) -> Self { - match frame { - Frame::Left(frame) => Self::Left(frame.into()), - Frame::Right(frame) => Self::Right(frame.into()), + fn into_geometry(self) -> Self::Geometry { + match self { + Frame::Left(frame) => Geometry::Left(frame.into_geometry()), + Frame::Right(frame) => Geometry::Right(frame.into_geometry()), } } } -- cgit From 85800c99ab285efd244c0addfdcf3c732a98de1d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 01:53:48 +0100 Subject: Fix broken links in documentation --- renderer/src/fallback.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 659f253d..249da9e9 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -398,6 +398,7 @@ mod geometry { use super::Renderer; use crate::core::{Point, Radians, Size, Vector}; use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; + use crate::graphics::Cached; impl geometry::Renderer for Renderer where @@ -432,10 +433,10 @@ mod geometry { Right(R), } - impl geometry::Geometry for Geometry + impl Cached for Geometry where - L: geometry::Geometry, - R: geometry::Geometry, + L: Cached, + R: Cached, { type Cache = Geometry; -- cgit From 1f13a91361258a1607c71f4840a26a6437f88612 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 05:27:31 +0100 Subject: Make `iced_tiny_skia` optional with a `tiny-skia` feature --- renderer/src/fallback.rs | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 249da9e9..4431606a 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -8,11 +8,7 @@ use crate::graphics; use crate::graphics::compositor; use crate::graphics::mesh; -pub enum Renderer -where - L: core::Renderer, - R: core::Renderer, -{ +pub enum Renderer { Left(L), Right(R), } @@ -26,29 +22,6 @@ macro_rules! delegate { }; } -impl Renderer -where - L: core::Renderer, - R: core::Renderer, -{ - #[cfg(feature = "geometry")] - pub fn draw_geometry( - &mut self, - layers: impl IntoIterator, - ) where - L: graphics::geometry::Renderer, - R: graphics::geometry::Renderer, - - Geometry: Into>, - { - use graphics::geometry::Renderer; - - for layer in layers { - ::draw_geometry(self, layer.into()); - } - } -} - impl core::Renderer for Renderer where L: core::Renderer, -- cgit From 5137d655e6bbd29581fc1469d0385515113f2999 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 07:09:51 +0100 Subject: Allow custom renderers in `Program` and `Application` --- renderer/src/fallback.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 4431606a..28e73dd8 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -200,15 +200,12 @@ impl graphics::Compositor for Compositor where L: graphics::Compositor, R: graphics::Compositor, - L::Settings: From, - R::Settings: From, { - type Settings = crate::Settings; type Renderer = Renderer; type Surface = Surface; async fn new( - settings: Self::Settings, + settings: graphics::Settings, compatible_window: W, ) -> Result { if let Ok(left) = L::new(settings.into(), compatible_window.clone()) @@ -528,3 +525,11 @@ mod geometry { } } } + +impl compositor::Renderer for Renderer +where + L: compositor::Renderer, + R: compositor::Renderer, +{ + type Compositor = Compositor; +} -- cgit From a2c897792ccb8f91a8479c1eca9146c439e9173b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 07:12:46 +0100 Subject: Fix unnecessary `into` calls in `iced_renderer::fallback` --- renderer/src/fallback.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 28e73dd8..8daab74f 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -208,16 +208,14 @@ where settings: graphics::Settings, compatible_window: W, ) -> Result { - if let Ok(left) = L::new(settings.into(), compatible_window.clone()) + if let Ok(left) = L::new(settings, compatible_window.clone()) .await .map(Self::Left) { return Ok(left); } - R::new(settings.into(), compatible_window) - .await - .map(Self::Right) + R::new(settings, compatible_window).await.map(Self::Right) } fn create_renderer(&self) -> Self::Renderer { -- cgit From 441e9237cd1c9c9b61d9b144b5b4dafa236ace28 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 22 Mar 2024 19:35:19 +0100 Subject: Rename `compositor::Renderer` to `Default` --- renderer/src/fallback.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 8daab74f..ca445746 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -524,10 +524,10 @@ mod geometry { } } -impl compositor::Renderer for Renderer +impl compositor::Default for Renderer where - L: compositor::Renderer, - R: compositor::Renderer, + L: compositor::Default, + R: compositor::Default, { type Compositor = Compositor; } -- cgit From 4f5b63f1f4cd7d3ab72289c697f4abc767114eca Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 24 Mar 2024 08:04:28 +0100 Subject: Reintroduce backend selection through `ICED_BACKEND` env var --- renderer/src/fallback.rs | 51 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index ca445746..ef9cc9a9 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -204,18 +204,55 @@ where type Renderer = Renderer; type Surface = Surface; - async fn new( + async fn with_backend( settings: graphics::Settings, compatible_window: W, + backend: Option<&str>, ) -> Result { - if let Ok(left) = L::new(settings, compatible_window.clone()) - .await - .map(Self::Left) - { - return Ok(left); + use std::env; + + let backends = backend + .map(str::to_owned) + .or_else(|| env::var("ICED_BACKEND").ok()); + + let mut candidates: Vec<_> = backends + .map(|backends| { + backends + .split(',') + .filter(|candidate| !candidate.is_empty()) + .map(str::to_owned) + .map(Some) + .collect() + }) + .unwrap_or_default(); + + if candidates.is_empty() { + candidates.push(None); } - R::new(settings, compatible_window).await.map(Self::Right) + let mut errors = vec![]; + + for backend in candidates.iter().map(Option::as_deref) { + match L::with_backend(settings, compatible_window.clone(), backend) + .await + { + Ok(compositor) => return Ok(Self::Left(compositor)), + Err(error) => { + errors.push(error); + } + } + + match R::with_backend(settings, compatible_window.clone(), backend) + .await + { + Ok(compositor) => return Ok(Self::Right(compositor)), + Err(error) => { + errors.push(error); + } + } + } + + Err(graphics::Error::List(errors)) } fn create_renderer(&self) -> Self::Renderer { -- cgit From 6216c513d5e5853bf1d43342094e91a74981f4f2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 1 Apr 2024 11:30:01 +0200 Subject: Use generic `Content` in `Text` to avoid reallocation in `fill_text` --- renderer/src/fallback.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index ef9cc9a9..b9ceb4b2 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -115,7 +115,7 @@ where fn fill_text( &mut self, - text: core::Text<'_, Self::Font>, + text: core::Text, position: Point, color: Color, clip_bounds: Rectangle, -- cgit From b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 3 Apr 2024 21:07:54 +0200 Subject: Redesign `iced_wgpu` layering architecture --- renderer/src/fallback.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index b9ceb4b2..b6459243 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -39,16 +39,20 @@ where delegate!(self, renderer, renderer.clear()); } - fn start_layer(&mut self) { - delegate!(self, renderer, renderer.start_layer()); + fn start_layer(&mut self, bounds: Rectangle) { + delegate!(self, renderer, renderer.start_layer(bounds)); } fn end_layer(&mut self, bounds: Rectangle) { delegate!(self, renderer, renderer.end_layer(bounds)); } - fn start_transformation(&mut self) { - delegate!(self, renderer, renderer.start_transformation()); + fn start_transformation(&mut self, transformation: Transformation) { + delegate!( + self, + renderer, + renderer.start_transformation(transformation) + ); } fn end_transformation(&mut self, transformation: Transformation) { @@ -433,6 +437,7 @@ mod geometry { } } + #[derive(Clone)] pub enum Geometry { Left(L), Right(R), @@ -452,10 +457,21 @@ mod geometry { } } - fn cache(self) -> Self::Cache { - match self { - Self::Left(geometry) => Geometry::Left(geometry.cache()), - Self::Right(geometry) => Geometry::Right(geometry.cache()), + fn cache(self, previous: Option) -> Self::Cache { + match (self, previous) { + (Self::Left(geometry), Some(Geometry::Left(previous))) => { + Geometry::Left(geometry.cache(Some(previous))) + } + (Self::Left(geometry), None) => { + Geometry::Left(geometry.cache(None)) + } + (Self::Right(geometry), Some(Geometry::Right(previous))) => { + Geometry::Right(geometry.cache(Some(previous))) + } + (Self::Right(geometry), None) => { + Geometry::Right(geometry.cache(None)) + } + _ => unreachable!(), } } } -- cgit From 6d3e1d835e1688fbc58622a03a784ed25ed3f0e1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 5 Apr 2024 23:59:21 +0200 Subject: Decouple caching from layering and simplify everything --- renderer/src/fallback.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index b6459243..60b57604 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -405,7 +405,7 @@ where #[cfg(feature = "geometry")] mod geometry { use super::Renderer; - use crate::core::{Point, Radians, Size, Vector}; + use crate::core::{Point, Radians, Rectangle, Size, Vector}; use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; use crate::graphics::Cached; @@ -533,10 +533,10 @@ mod geometry { delegate!(self, frame, frame.pop_transform()); } - fn draft(&mut self, size: Size) -> Self { + fn draft(&mut self, bounds: Rectangle) -> Self { match self { - Self::Left(frame) => Self::Left(frame.draft(size)), - Self::Right(frame) => Self::Right(frame.draft(size)), + Self::Left(frame) => Self::Left(frame.draft(bounds)), + Self::Right(frame) => Self::Right(frame.draft(bounds)), } } -- cgit From 5cd98f069dea8720bca7748d6c12fa410cbe79b5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 7 Apr 2024 12:42:12 +0200 Subject: Use built-in `[lints]` table in `Cargo.toml` --- renderer/src/fallback.rs | 258 ++++++++++++++++++++++++++--------------------- 1 file changed, 145 insertions(+), 113 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index b9ceb4b2..85ac3d93 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -1,3 +1,4 @@ +//! Compose existing renderers and create type-safe fallback strategies. use crate::core::image; use crate::core::renderer; use crate::core::svg; @@ -8,24 +9,31 @@ use crate::graphics; use crate::graphics::compositor; use crate::graphics::mesh; -pub enum Renderer { - Left(L), - Right(R), +/// A renderer `A` with a fallback strategy `B`. +/// +/// This type can be used to easily compose existing renderers and +/// create custom, type-safe fallback strategies. +#[derive(Debug)] +pub enum Renderer { + /// The primary rendering option. + Primary(A), + /// The secondary (or fallback) rendering option. + Secondary(B), } macro_rules! delegate { ($renderer:expr, $name:ident, $body:expr) => { match $renderer { - Self::Left($name) => $body, - Self::Right($name) => $body, + Self::Primary($name) => $body, + Self::Secondary($name) => $body, } }; } -impl core::Renderer for Renderer +impl core::Renderer for Renderer where - L: core::Renderer, - R: core::Renderer, + A: core::Renderer, + B: core::Renderer, { fn fill_quad( &mut self, @@ -56,22 +64,22 @@ where } } -impl core::text::Renderer for Renderer +impl core::text::Renderer for Renderer where - L: core::text::Renderer, - R: core::text::Renderer< - Font = L::Font, - Paragraph = L::Paragraph, - Editor = L::Editor, + A: core::text::Renderer, + B: core::text::Renderer< + Font = A::Font, + Paragraph = A::Paragraph, + Editor = A::Editor, >, { - type Font = L::Font; - type Paragraph = L::Paragraph; - type Editor = L::Editor; + type Font = A::Font; + type Paragraph = A::Paragraph; + type Editor = A::Editor; - const ICON_FONT: Self::Font = L::ICON_FONT; - const CHECKMARK_ICON: char = L::CHECKMARK_ICON; - const ARROW_DOWN_ICON: char = L::ARROW_DOWN_ICON; + const ICON_FONT: Self::Font = A::ICON_FONT; + const CHECKMARK_ICON: char = A::CHECKMARK_ICON; + const ARROW_DOWN_ICON: char = A::ARROW_DOWN_ICON; fn default_font(&self) -> Self::Font { delegate!(self, renderer, renderer.default_font()) @@ -128,12 +136,12 @@ where } } -impl image::Renderer for Renderer +impl image::Renderer for Renderer where - L: image::Renderer, - R: image::Renderer, + A: image::Renderer, + B: image::Renderer, { - type Handle = L::Handle; + type Handle = A::Handle; fn measure_image(&self, handle: &Self::Handle) -> Size { delegate!(self, renderer, renderer.measure_image(handle)) @@ -153,10 +161,10 @@ where } } -impl svg::Renderer for Renderer +impl svg::Renderer for Renderer where - L: svg::Renderer, - R: svg::Renderer, + A: svg::Renderer, + B: svg::Renderer, { fn measure_svg(&self, handle: &svg::Handle) -> Size { delegate!(self, renderer, renderer.measure_svg(handle)) @@ -172,37 +180,49 @@ where } } -impl mesh::Renderer for Renderer +impl mesh::Renderer for Renderer where - L: mesh::Renderer, - R: mesh::Renderer, + A: mesh::Renderer, + B: mesh::Renderer, { fn draw_mesh(&mut self, mesh: graphics::Mesh) { delegate!(self, renderer, renderer.draw_mesh(mesh)); } } -pub enum Compositor +/// A compositor `A` with a fallback strategy `B`. +/// +/// It works analogously to [`Renderer`]. +#[derive(Debug)] +pub enum Compositor where - L: graphics::Compositor, - R: graphics::Compositor, + A: graphics::Compositor, + B: graphics::Compositor, { - Left(L), - Right(R), + /// The primary compositing option. + Primary(A), + /// The secondary (or fallback) compositing option. + Secondary(B), } -pub enum Surface { - Left(L), - Right(R), +/// A surface `A` with a fallback strategy `B`. +/// +/// It works analogously to [`Renderer`]. +#[derive(Debug)] +pub enum Surface { + /// The primary surface option. + Primary(A), + /// The secondary (or fallback) surface option. + Secondary(B), } -impl graphics::Compositor for Compositor +impl graphics::Compositor for Compositor where - L: graphics::Compositor, - R: graphics::Compositor, + A: graphics::Compositor, + B: graphics::Compositor, { - type Renderer = Renderer; - type Surface = Surface; + type Renderer = Renderer; + type Surface = Surface; async fn with_backend( settings: graphics::Settings, @@ -233,19 +253,19 @@ where let mut errors = vec![]; for backend in candidates.iter().map(Option::as_deref) { - match L::with_backend(settings, compatible_window.clone(), backend) + match A::with_backend(settings, compatible_window.clone(), backend) .await { - Ok(compositor) => return Ok(Self::Left(compositor)), + Ok(compositor) => return Ok(Self::Primary(compositor)), Err(error) => { errors.push(error); } } - match R::with_backend(settings, compatible_window.clone(), backend) + match B::with_backend(settings, compatible_window.clone(), backend) .await { - Ok(compositor) => return Ok(Self::Right(compositor)), + Ok(compositor) => return Ok(Self::Secondary(compositor)), Err(error) => { errors.push(error); } @@ -257,11 +277,11 @@ where fn create_renderer(&self) -> Self::Renderer { match self { - Self::Left(compositor) => { - Renderer::Left(compositor.create_renderer()) + Self::Primary(compositor) => { + Renderer::Primary(compositor.create_renderer()) } - Self::Right(compositor) => { - Renderer::Right(compositor.create_renderer()) + Self::Secondary(compositor) => { + Renderer::Secondary(compositor.create_renderer()) } } } @@ -273,12 +293,12 @@ where height: u32, ) -> Self::Surface { match self { - Self::Left(compositor) => { - Surface::Left(compositor.create_surface(window, width, height)) - } - Self::Right(compositor) => { - Surface::Right(compositor.create_surface(window, width, height)) - } + Self::Primary(compositor) => Surface::Primary( + compositor.create_surface(window, width, height), + ), + Self::Secondary(compositor) => Surface::Secondary( + compositor.create_surface(window, width, height), + ), } } @@ -289,10 +309,10 @@ where height: u32, ) { match (self, surface) { - (Self::Left(compositor), Surface::Left(surface)) => { + (Self::Primary(compositor), Surface::Primary(surface)) => { compositor.configure_surface(surface, width, height); } - (Self::Right(compositor), Surface::Right(surface)) => { + (Self::Secondary(compositor), Surface::Secondary(surface)) => { compositor.configure_surface(surface, width, height); } _ => unreachable!(), @@ -313,9 +333,9 @@ where ) -> Result<(), compositor::SurfaceError> { match (self, renderer, surface) { ( - Self::Left(compositor), - Renderer::Left(renderer), - Surface::Left(surface), + Self::Primary(compositor), + Renderer::Primary(renderer), + Surface::Primary(surface), ) => compositor.present( renderer, surface, @@ -324,9 +344,9 @@ where overlay, ), ( - Self::Right(compositor), - Renderer::Right(renderer), - Surface::Right(surface), + Self::Secondary(compositor), + Renderer::Secondary(renderer), + Surface::Secondary(surface), ) => compositor.present( renderer, surface, @@ -348,9 +368,9 @@ where ) -> Vec { match (self, renderer, surface) { ( - Self::Left(compositor), - Renderer::Left(renderer), - Surface::Left(surface), + Self::Primary(compositor), + Renderer::Primary(renderer), + Surface::Primary(surface), ) => compositor.screenshot( renderer, surface, @@ -359,9 +379,9 @@ where overlay, ), ( - Self::Right(compositor), - Renderer::Right(renderer), - Surface::Right(surface), + Self::Secondary(compositor), + Renderer::Secondary(renderer), + Surface::Secondary(surface), ) => compositor.screenshot( renderer, surface, @@ -375,10 +395,10 @@ where } #[cfg(feature = "wgpu")] -impl iced_wgpu::primitive::pipeline::Renderer for Renderer +impl iced_wgpu::primitive::pipeline::Renderer for Renderer where - L: iced_wgpu::primitive::pipeline::Renderer, - R: core::Renderer, + A: iced_wgpu::primitive::pipeline::Renderer, + B: core::Renderer, { fn draw_pipeline_primitive( &mut self, @@ -386,10 +406,10 @@ where primitive: impl iced_wgpu::primitive::pipeline::Primitive, ) { match self { - Self::Left(renderer) => { + Self::Primary(renderer) => { renderer.draw_pipeline_primitive(bounds, primitive); } - Self::Right(_) => { + Self::Secondary(_) => { log::warn!( "Custom shader primitive is not supported with this renderer." ); @@ -405,27 +425,31 @@ mod geometry { use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; use crate::graphics::Cached; - impl geometry::Renderer for Renderer + impl geometry::Renderer for Renderer where - L: geometry::Renderer, - R: geometry::Renderer, + A: geometry::Renderer, + B: geometry::Renderer, { - type Geometry = Geometry; - type Frame = Frame; + type Geometry = Geometry; + type Frame = Frame; fn new_frame(&self, size: iced_graphics::core::Size) -> Self::Frame { match self { - Self::Left(renderer) => Frame::Left(renderer.new_frame(size)), - Self::Right(renderer) => Frame::Right(renderer.new_frame(size)), + Self::Primary(renderer) => { + Frame::Primary(renderer.new_frame(size)) + } + Self::Secondary(renderer) => { + Frame::Secondary(renderer.new_frame(size)) + } } } fn draw_geometry(&mut self, geometry: Self::Geometry) { match (self, geometry) { - (Self::Left(renderer), Geometry::Left(geometry)) => { + (Self::Primary(renderer), Geometry::Primary(geometry)) => { renderer.draw_geometry(geometry); } - (Self::Right(renderer), Geometry::Right(geometry)) => { + (Self::Secondary(renderer), Geometry::Secondary(geometry)) => { renderer.draw_geometry(geometry); } _ => unreachable!(), @@ -433,44 +457,48 @@ mod geometry { } } - pub enum Geometry { - Left(L), - Right(R), + #[derive(Debug)] + pub enum Geometry { + Primary(A), + Secondary(B), } - impl Cached for Geometry + impl Cached for Geometry where - L: Cached, - R: Cached, + A: Cached, + B: Cached, { - type Cache = Geometry; + type Cache = Geometry; fn load(cache: &Self::Cache) -> Self { match cache { - Geometry::Left(cache) => Self::Left(L::load(cache)), - Geometry::Right(cache) => Self::Right(R::load(cache)), + Geometry::Primary(cache) => Self::Primary(A::load(cache)), + Geometry::Secondary(cache) => Self::Secondary(B::load(cache)), } } fn cache(self) -> Self::Cache { match self { - Self::Left(geometry) => Geometry::Left(geometry.cache()), - Self::Right(geometry) => Geometry::Right(geometry.cache()), + Self::Primary(geometry) => Geometry::Primary(geometry.cache()), + Self::Secondary(geometry) => { + Geometry::Secondary(geometry.cache()) + } } } } - pub enum Frame { - Left(L), - Right(R), + #[derive(Debug)] + pub enum Frame { + Primary(A), + Secondary(B), } - impl geometry::frame::Backend for Frame + impl geometry::frame::Backend for Frame where - L: geometry::frame::Backend, - R: geometry::frame::Backend, + A: geometry::frame::Backend, + B: geometry::frame::Backend, { - type Geometry = Geometry; + type Geometry = Geometry; fn width(&self) -> f32 { delegate!(self, frame, frame.width()) @@ -519,17 +547,17 @@ mod geometry { fn draft(&mut self, size: Size) -> Self { match self { - Self::Left(frame) => Self::Left(frame.draft(size)), - Self::Right(frame) => Self::Right(frame.draft(size)), + Self::Primary(frame) => Self::Primary(frame.draft(size)), + Self::Secondary(frame) => Self::Secondary(frame.draft(size)), } } fn paste(&mut self, frame: Self, at: Point) { match (self, frame) { - (Self::Left(target), Self::Left(source)) => { + (Self::Primary(target), Self::Primary(source)) => { target.paste(source, at); } - (Self::Right(target), Self::Right(source)) => { + (Self::Secondary(target), Self::Secondary(source)) => { target.paste(source, at); } _ => unreachable!(), @@ -554,17 +582,21 @@ mod geometry { fn into_geometry(self) -> Self::Geometry { match self { - Frame::Left(frame) => Geometry::Left(frame.into_geometry()), - Frame::Right(frame) => Geometry::Right(frame.into_geometry()), + Frame::Primary(frame) => { + Geometry::Primary(frame.into_geometry()) + } + Frame::Secondary(frame) => { + Geometry::Secondary(frame.into_geometry()) + } } } } } -impl compositor::Default for Renderer +impl compositor::Default for Renderer where - L: compositor::Default, - R: compositor::Default, + A: compositor::Default, + B: compositor::Default, { - type Compositor = Compositor; + type Compositor = Compositor; } -- cgit From d922b478156488a7bc03c6e791e05c040d702634 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 8 Apr 2024 15:04:35 +0200 Subject: Reintroduce support for custom primitives in `iced_wgpu` --- renderer/src/fallback.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 2676ba87..975f4866 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -399,19 +399,19 @@ where } #[cfg(feature = "wgpu")] -impl iced_wgpu::primitive::pipeline::Renderer for Renderer +impl iced_wgpu::primitive::Renderer for Renderer where - A: iced_wgpu::primitive::pipeline::Renderer, + A: iced_wgpu::primitive::Renderer, B: core::Renderer, { - fn draw_pipeline_primitive( + fn draw_primitive( &mut self, bounds: Rectangle, - primitive: impl iced_wgpu::primitive::pipeline::Primitive, + primitive: impl iced_wgpu::Primitive, ) { match self { Self::Primary(renderer) => { - renderer.draw_pipeline_primitive(bounds, primitive); + renderer.draw_primitive(bounds, primitive); } Self::Secondary(_) => { log::warn!( -- cgit From 6ad5bb3597f640ac329801adf735d633bf0a512f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 9 Apr 2024 22:25:16 +0200 Subject: Port `iced_tiny_skia` to new layering architecture --- renderer/src/fallback.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 975f4866..c932de00 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -9,6 +9,8 @@ use crate::graphics; use crate::graphics::compositor; use crate::graphics::mesh; +use std::borrow::Cow; + /// A renderer `A` with a fallback strategy `B`. /// /// This type can be used to easily compose existing renderers and @@ -51,8 +53,8 @@ where delegate!(self, renderer, renderer.start_layer(bounds)); } - fn end_layer(&mut self, bounds: Rectangle) { - delegate!(self, renderer, renderer.end_layer(bounds)); + fn end_layer(&mut self) { + delegate!(self, renderer, renderer.end_layer()); } fn start_transformation(&mut self, transformation: Transformation) { @@ -63,8 +65,8 @@ where ); } - fn end_transformation(&mut self, transformation: Transformation) { - delegate!(self, renderer, renderer.end_transformation(transformation)); + fn end_transformation(&mut self) { + delegate!(self, renderer, renderer.end_transformation()); } } @@ -93,10 +95,6 @@ where delegate!(self, renderer, renderer.default_size()) } - fn load_font(&mut self, font: std::borrow::Cow<'static, [u8]>) { - delegate!(self, renderer, renderer.load_font(font)); - } - fn fill_paragraph( &mut self, text: &Self::Paragraph, @@ -323,6 +321,10 @@ where } } + fn load_font(&mut self, font: Cow<'static, [u8]>) { + delegate!(self, compositor, compositor.load_font(font)); + } + fn fetch_information(&self) -> compositor::Information { delegate!(self, compositor, compositor.fetch_information()) } -- cgit From b5b78d505e22cafccb4ecbf57dc61f536ca558ca Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 30 Apr 2024 07:57:54 +0200 Subject: Introduce `canvas::Cache` grouping Caches with the same `Group` will share their text atlas! --- renderer/src/fallback.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index c932de00..5f69b420 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -428,8 +428,8 @@ where mod geometry { use super::Renderer; use crate::core::{Point, Radians, Rectangle, Size, Vector}; + use crate::graphics::cache::{self, Cached}; use crate::graphics::geometry::{self, Fill, Path, Stroke, Text}; - use crate::graphics::Cached; impl geometry::Renderer for Renderer where @@ -483,21 +483,25 @@ mod geometry { } } - fn cache(self, previous: Option) -> Self::Cache { + fn cache( + self, + group: cache::Group, + previous: Option, + ) -> Self::Cache { match (self, previous) { ( Self::Primary(geometry), Some(Geometry::Primary(previous)), - ) => Geometry::Primary(geometry.cache(Some(previous))), + ) => Geometry::Primary(geometry.cache(group, Some(previous))), (Self::Primary(geometry), None) => { - Geometry::Primary(geometry.cache(None)) + Geometry::Primary(geometry.cache(group, None)) } ( Self::Secondary(geometry), Some(Geometry::Secondary(previous)), - ) => Geometry::Secondary(geometry.cache(Some(previous))), + ) => Geometry::Secondary(geometry.cache(group, Some(previous))), (Self::Secondary(geometry), None) => { - Geometry::Secondary(geometry.cache(None)) + Geometry::Secondary(geometry.cache(group, None)) } _ => unreachable!(), } -- cgit From 09a6bcfffc24f5abdc8709403bab7ae1e01563f1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 2 May 2024 13:15:17 +0200 Subject: Add `Image` rotation support Co-authored-by: DKolter <68352124+DKolter@users.noreply.github.com> --- renderer/src/fallback.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 5f69b420..37e6ac43 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -154,11 +154,13 @@ where handle: Self::Handle, filter_method: image::FilterMethod, bounds: Rectangle, + rotation: f32, + scale: Size, ) { delegate!( self, renderer, - renderer.draw_image(handle, filter_method, bounds) + renderer.draw_image(handle, filter_method, bounds, rotation, scale) ); } } @@ -177,8 +179,14 @@ where handle: svg::Handle, color: Option, bounds: Rectangle, + rotation: f32, + scale: Size, ) { - delegate!(self, renderer, renderer.draw_svg(handle, color, bounds)); + delegate!( + self, + renderer, + renderer.draw_svg(handle, color, bounds, rotation, scale) + ); } } -- cgit From a57313b23ecb9843856ca0ea08635b6121fcb2cb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 2 May 2024 15:21:22 +0200 Subject: Simplify image rotation API and its internals --- renderer/src/fallback.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index 37e6ac43..a077031b 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -3,7 +3,7 @@ use crate::core::image; use crate::core::renderer; use crate::core::svg; use crate::core::{ - self, Background, Color, Point, Rectangle, Size, Transformation, + self, Background, Color, Point, Radians, Rectangle, Size, Transformation, }; use crate::graphics; use crate::graphics::compositor; @@ -154,13 +154,12 @@ where handle: Self::Handle, filter_method: image::FilterMethod, bounds: Rectangle, - rotation: f32, - scale: Size, + rotation: Radians, ) { delegate!( self, renderer, - renderer.draw_image(handle, filter_method, bounds, rotation, scale) + renderer.draw_image(handle, filter_method, bounds, rotation) ); } } @@ -179,13 +178,12 @@ where handle: svg::Handle, color: Option, bounds: Rectangle, - rotation: f32, - scale: Size, + rotation: Radians, ) { delegate!( self, renderer, - renderer.draw_svg(handle, color, bounds, rotation, scale) + renderer.draw_svg(handle, color, bounds, rotation) ); } } -- cgit From fa9e1d96ea1924b51749b775ea0e67e69bc8a305 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 May 2024 13:25:58 +0200 Subject: Introduce dynamic `opacity` support for `Image` and `Svg` --- renderer/src/fallback.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'renderer/src/fallback.rs') diff --git a/renderer/src/fallback.rs b/renderer/src/fallback.rs index a077031b..6a169692 100644 --- a/renderer/src/fallback.rs +++ b/renderer/src/fallback.rs @@ -155,11 +155,18 @@ where filter_method: image::FilterMethod, bounds: Rectangle, rotation: Radians, + opacity: f32, ) { delegate!( self, renderer, - renderer.draw_image(handle, filter_method, bounds, rotation) + renderer.draw_image( + handle, + filter_method, + bounds, + rotation, + opacity + ) ); } } @@ -179,11 +186,12 @@ where color: Option, bounds: Rectangle, rotation: Radians, + opacity: f32, ) { delegate!( self, renderer, - renderer.draw_svg(handle, color, bounds, rotation) + renderer.draw_svg(handle, color, bounds, rotation, opacity) ); } } -- cgit