diff options
author | 2023-06-22 00:38:36 +0200 | |
---|---|---|
committer | 2023-06-29 07:18:20 +0200 | |
commit | 0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2 (patch) | |
tree | 7f3d09dca8ea9fae96457d3f9266e014d1d25d80 /graphics | |
parent | 8d65e40a1174ecb8225ce9973575bced36e7aeb5 (diff) | |
download | iced-0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2.tar.gz iced-0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2.tar.bz2 iced-0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2.zip |
Introduce custom backend-specific primitives
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/Cargo.toml | 4 | ||||
-rw-r--r-- | graphics/src/backend.rs | 7 | ||||
-rw-r--r-- | graphics/src/damage.rs | 68 | ||||
-rw-r--r-- | graphics/src/geometry.rs | 16 | ||||
-rw-r--r-- | graphics/src/lib.rs | 9 | ||||
-rw-r--r-- | graphics/src/primitive.rs | 107 | ||||
-rw-r--r-- | graphics/src/renderer.rs | 70 |
7 files changed, 129 insertions, 152 deletions
diff --git a/graphics/Cargo.toml b/graphics/Cargo.toml index 02621695..7a9e6aee 100644 --- a/graphics/Cargo.toml +++ b/graphics/Cargo.toml @@ -32,10 +32,6 @@ features = ["derive"] version = "0.9" path = "../core" -[dependencies.tiny-skia] -version = "0.9" -optional = true - [dependencies.image] version = "0.24" optional = true diff --git a/graphics/src/backend.rs b/graphics/src/backend.rs index 70ccc664..3ff24335 100644 --- a/graphics/src/backend.rs +++ b/graphics/src/backend.rs @@ -6,6 +6,13 @@ use iced_core::{Font, Point, Size}; use std::borrow::Cow; +/// The graphics backend of a [`Renderer`]. +/// +/// [`Renderer`]: crate::Renderer +pub trait Backend { + type Primitive; +} + /// A graphics backend that supports text rendering. pub trait Text { /// The icon font of the backend. diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index c6b0f759..1add6707 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -1,11 +1,68 @@ //! Track and compute the damage of graphical primitives. +use crate::core::alignment; use crate::core::{Rectangle, Size}; use crate::Primitive; use std::sync::Arc; -/// Computes the damage regions between the two given primitives. -pub fn regions(a: &Primitive, b: &Primitive) -> Vec<Rectangle> { +pub trait Damage: PartialEq { + /// Returns the bounds of the [`Damage`]. + fn bounds(&self) -> Rectangle; +} + +impl<T: Damage> Damage for Primitive<T> { + fn bounds(&self) -> Rectangle { + match self { + Self::Text { + bounds, + horizontal_alignment, + vertical_alignment, + .. + } => { + let mut bounds = *bounds; + + bounds.x = match horizontal_alignment { + alignment::Horizontal::Left => bounds.x, + alignment::Horizontal::Center => { + bounds.x - bounds.width / 2.0 + } + alignment::Horizontal::Right => bounds.x - bounds.width, + }; + + bounds.y = match vertical_alignment { + alignment::Vertical::Top => bounds.y, + alignment::Vertical::Center => { + bounds.y - bounds.height / 2.0 + } + alignment::Vertical::Bottom => bounds.y - bounds.height, + }; + + bounds.expand(1.5) + } + Self::Quad { bounds, .. } + | Self::Image { bounds, .. } + | Self::Svg { bounds, .. } => bounds.expand(1.0), + Self::Clip { bounds, .. } => bounds.expand(1.0), + Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { + Rectangle::with_size(*size) + } + Self::Group { primitives } => primitives + .iter() + .map(Self::bounds) + .fold(Rectangle::with_size(Size::ZERO), |a, b| { + Rectangle::union(&a, &b) + }), + Self::Translate { + translation, + content, + } => content.bounds() + *translation, + Self::Cache { content } => content.bounds(), + Self::Custom(custom) => custom.bounds(), + } + } +} + +fn regions<T: Damage>(a: &Primitive<T>, b: &Primitive<T>) -> Vec<Rectangle> { match (a, b) { ( Primitive::Group { @@ -76,7 +133,10 @@ pub fn regions(a: &Primitive, b: &Primitive) -> Vec<Rectangle> { } /// Computes the damage regions between the two given lists of primitives. -pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec<Rectangle> { +pub fn list<T: Damage>( + previous: &[Primitive<T>], + current: &[Primitive<T>], +) -> Vec<Rectangle> { let damage = previous .iter() .zip(current) @@ -93,7 +153,7 @@ pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec<Rectangle> { // Extend damage by the added/removed primitives damage - .chain(bigger[smaller.len()..].iter().map(Primitive::bounds)) + .chain(bigger[smaller.len()..].iter().map(Damage::bounds)) .collect() } } diff --git a/graphics/src/geometry.rs b/graphics/src/geometry.rs index 729c3d44..5e547bae 100644 --- a/graphics/src/geometry.rs +++ b/graphics/src/geometry.rs @@ -14,20 +14,10 @@ pub use text::Text; pub use crate::gradient::{self, Gradient}; -use crate::Primitive; - -/// A bunch of shapes that can be drawn. -#[derive(Debug, Clone)] -pub struct Geometry(pub Primitive); - -impl From<Geometry> for Primitive { - fn from(geometry: Geometry) -> Self { - geometry.0 - } -} - /// A renderer capable of drawing some [`Geometry`]. pub trait Renderer: crate::core::Renderer { + type Geometry; + /// Draws the given layers of [`Geometry`]. - fn draw(&mut self, layers: Vec<Geometry>); + fn draw(&mut self, layers: Vec<Self::Geometry>); } diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 226b245b..055a9216 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -8,8 +8,8 @@ html_logo_url = "https://raw.githubusercontent.com/iced-rs/iced/9ab6923e943f784985e9ef9ca28b10278297225d/docs/logo.svg" )] #![deny( - missing_debug_implementations, - missing_docs, + //missing_debug_implementations, + //missing_docs, unsafe_code, unused_results, clippy::extra_unused_lifetimes, @@ -41,7 +41,9 @@ pub mod geometry; pub mod image; pub use antialiasing::Antialiasing; +pub use backend::Backend; pub use compositor::Compositor; +pub use damage::Damage; pub use error::Error; pub use gradient::Gradient; pub use primitive::Primitive; @@ -49,7 +51,4 @@ pub use renderer::Renderer; pub use transformation::Transformation; pub use viewport::Viewport; -#[cfg(feature = "geometry")] -pub use geometry::Geometry; - pub use iced_core as core; diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 187c6c6c..f8b005ad 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -12,8 +12,7 @@ use std::sync::Arc; /// A rendering primitive. #[derive(Debug, Clone, PartialEq)] -#[non_exhaustive] -pub enum Primitive { +pub enum Primitive<T> { /// A text primitive Text { /// The contents of the text @@ -90,41 +89,17 @@ pub enum Primitive { /// Any geometry that falls out of this region will be clipped. size: Size, }, - /// A [`tiny_skia`] path filled with some paint. - #[cfg(feature = "tiny-skia")] - Fill { - /// The path to fill. - path: tiny_skia::Path, - /// The paint to use. - paint: tiny_skia::Paint<'static>, - /// The fill rule to follow. - rule: tiny_skia::FillRule, - /// The transform to apply to the path. - transform: tiny_skia::Transform, - }, - /// A [`tiny_skia`] path stroked with some paint. - #[cfg(feature = "tiny-skia")] - Stroke { - /// The path to stroke. - path: tiny_skia::Path, - /// The paint to use. - paint: tiny_skia::Paint<'static>, - /// The stroke settings. - stroke: tiny_skia::Stroke, - /// The transform to apply to the path. - transform: tiny_skia::Transform, - }, /// A group of primitives Group { /// The primitives of the group - primitives: Vec<Primitive>, + primitives: Vec<Primitive<T>>, }, /// A clip primitive Clip { /// The bounds of the clip bounds: Rectangle, /// The content of the clip - content: Box<Primitive>, + content: Box<Primitive<T>>, }, /// A primitive that applies a translation Translate { @@ -132,7 +107,7 @@ pub enum Primitive { translation: Vector, /// The primitive to translate - content: Box<Primitive>, + content: Box<Primitive<T>>, }, /// A cached primitive. /// @@ -140,11 +115,13 @@ pub enum Primitive { /// generation is expensive. Cache { /// The cached primitive - content: Arc<Primitive>, + content: Arc<Primitive<T>>, }, + /// A backend-specific primitive. + Custom(T), } -impl Primitive { +impl<T> Primitive<T> { /// Creates a [`Primitive::Group`]. pub fn group(primitives: Vec<Self>) -> Self { Self::Group { primitives } @@ -165,68 +142,6 @@ impl Primitive { content: Box::new(self), } } - - /// Returns the bounds of the [`Primitive`]. - pub fn bounds(&self) -> Rectangle { - match self { - Self::Text { - bounds, - horizontal_alignment, - vertical_alignment, - .. - } => { - let mut bounds = *bounds; - - bounds.x = match horizontal_alignment { - alignment::Horizontal::Left => bounds.x, - alignment::Horizontal::Center => { - bounds.x - bounds.width / 2.0 - } - alignment::Horizontal::Right => bounds.x - bounds.width, - }; - - bounds.y = match vertical_alignment { - alignment::Vertical::Top => bounds.y, - alignment::Vertical::Center => { - bounds.y - bounds.height / 2.0 - } - alignment::Vertical::Bottom => bounds.y - bounds.height, - }; - - bounds.expand(1.5) - } - Self::Quad { bounds, .. } - | Self::Image { bounds, .. } - | Self::Svg { bounds, .. } => bounds.expand(1.0), - Self::Clip { bounds, .. } => bounds.expand(1.0), - Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { - Rectangle::with_size(*size) - } - #[cfg(feature = "tiny-skia")] - Self::Fill { path, .. } | Self::Stroke { path, .. } => { - let bounds = path.bounds(); - - Rectangle { - x: bounds.x(), - y: bounds.y(), - width: bounds.width(), - height: bounds.height(), - } - .expand(1.0) - } - Self::Group { primitives } => primitives - .iter() - .map(Self::bounds) - .fold(Rectangle::with_size(Size::ZERO), |a, b| { - Rectangle::union(&a, &b) - }), - Self::Translate { - translation, - content, - } => content.bounds() + *translation, - Self::Cache { content } => content.bounds(), - } - } } /// A set of [`Vertex2D`] and indices representing a list of triangles. @@ -268,9 +183,3 @@ unsafe impl Zeroable for GradientVertex2D {} #[allow(unsafe_code)] unsafe impl Pod for GradientVertex2D {} - -impl From<()> for Primitive { - fn from(_: ()) -> Self { - Self::Group { primitives: vec![] } - } -} diff --git a/graphics/src/renderer.rs b/graphics/src/renderer.rs index 7e70a766..9acfc2b7 100644 --- a/graphics/src/renderer.rs +++ b/graphics/src/renderer.rs @@ -1,5 +1,5 @@ //! Create a renderer from a [`Backend`]. -use crate::backend; +use crate::backend::{self, Backend}; use crate::Primitive; use iced_core::image; @@ -16,13 +16,13 @@ use std::marker::PhantomData; /// A backend-agnostic renderer that supports all the built-in widgets. #[derive(Debug)] -pub struct Renderer<B, Theme> { +pub struct Renderer<B: Backend, Theme> { backend: B, - primitives: Vec<Primitive>, + primitives: Vec<Primitive<B::Primitive>>, theme: PhantomData<Theme>, } -impl<B, T> Renderer<B, T> { +impl<B: Backend, T> Renderer<B, T> { /// Creates a new [`Renderer`] from the given [`Backend`]. pub fn new(backend: B) -> Self { Self { @@ -38,7 +38,7 @@ impl<B, T> Renderer<B, T> { } /// Enqueues the given [`Primitive`] in the [`Renderer`] for drawing. - pub fn draw_primitive(&mut self, primitive: Primitive) { + pub fn draw_primitive(&mut self, primitive: Primitive<B::Primitive>) { self.primitives.push(primitive); } @@ -46,13 +46,42 @@ impl<B, T> Renderer<B, T> { /// of the [`Renderer`]. pub fn with_primitives<O>( &mut self, - f: impl FnOnce(&mut B, &[Primitive]) -> O, + f: impl FnOnce(&mut B, &[Primitive<B::Primitive>]) -> O, ) -> O { f(&mut self.backend, &self.primitives) } + + pub fn start_layer(&mut self) -> Vec<Primitive<B::Primitive>> { + std::mem::take(&mut self.primitives) + } + + pub fn end_layer( + &mut self, + primitives: Vec<Primitive<B::Primitive>>, + bounds: Rectangle, + ) { + let layer = std::mem::replace(&mut self.primitives, primitives); + + self.primitives.push(Primitive::group(layer).clip(bounds)); + } + + pub fn start_translation(&mut self) -> Vec<Primitive<B::Primitive>> { + std::mem::take(&mut self.primitives) + } + + pub fn end_translation( + &mut self, + primitives: Vec<Primitive<B::Primitive>>, + translation: Vector, + ) { + let layer = std::mem::replace(&mut self.primitives, primitives); + + self.primitives + .push(Primitive::group(layer).translate(translation)); + } } -impl<B, T> iced_core::Renderer for Renderer<B, T> { +impl<B: Backend, T> iced_core::Renderer for Renderer<B, T> { type Theme = T; fn layout<Message>( @@ -64,13 +93,11 @@ impl<B, T> iced_core::Renderer for Renderer<B, T> { } fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) { - let current = std::mem::take(&mut self.primitives); + let current = self.start_layer(); f(self); - let layer = std::mem::replace(&mut self.primitives, current); - - self.primitives.push(Primitive::group(layer).clip(bounds)); + self.end_layer(current, bounds); } fn with_translation( @@ -78,14 +105,11 @@ impl<B, T> iced_core::Renderer for Renderer<B, T> { translation: Vector, f: impl FnOnce(&mut Self), ) { - let current = std::mem::take(&mut self.primitives); + let current = self.start_translation(); f(self); - let layer = std::mem::replace(&mut self.primitives, current); - - self.primitives - .push(Primitive::group(layer).translate(translation)); + self.end_translation(current, translation); } fn fill_quad( @@ -109,7 +133,7 @@ impl<B, T> iced_core::Renderer for Renderer<B, T> { impl<B, T> text::Renderer for Renderer<B, T> where - B: backend::Text, + B: Backend + backend::Text, { type Font = Font; @@ -188,7 +212,7 @@ where impl<B, T> image::Renderer for Renderer<B, T> where - B: backend::Image, + B: Backend + backend::Image, { type Handle = image::Handle; @@ -203,7 +227,7 @@ where impl<B, T> svg::Renderer for Renderer<B, T> where - B: backend::Svg, + B: Backend + backend::Svg, { fn dimensions(&self, handle: &svg::Handle) -> Size<u32> { self.backend().viewport_dimensions(handle) @@ -222,11 +246,3 @@ where }) } } - -#[cfg(feature = "geometry")] -impl<B, T> crate::geometry::Renderer for Renderer<B, T> { - fn draw(&mut self, layers: Vec<crate::Geometry>) { - self.primitives - .extend(layers.into_iter().map(crate::Geometry::into)); - } -} |