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 --- tiny_skia/src/layer.rs | 243 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 tiny_skia/src/layer.rs (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs new file mode 100644 index 00000000..1f5c8b46 --- /dev/null +++ b/tiny_skia/src/layer.rs @@ -0,0 +1,243 @@ +use crate::core::image; +use crate::core::renderer::Quad; +use crate::core::svg; +use crate::core::{Background, Color, Point, Rectangle, Transformation}; +use crate::graphics::layer; +use crate::graphics::text::{Editor, Paragraph, Text}; +use crate::graphics::{self, Image}; +use crate::Primitive; + +use std::rc::Rc; + +pub type Stack = layer::Stack; + +#[derive(Debug, Clone)] +pub struct Layer { + pub bounds: Rectangle, + pub quads: Vec<(Quad, Background)>, + pub primitives: Vec>, + pub text: Vec>, + pub images: Vec, +} + +#[derive(Debug, Clone)] +pub enum Item { + Live(T), + Group(Vec, Rectangle, Transformation), + Cached(Rc<[T]>, Rectangle, Transformation), +} + +impl Item { + pub fn transformation(&self) -> Transformation { + match self { + Item::Live(_) => Transformation::IDENTITY, + Item::Group(_, _, transformation) + | Item::Cached(_, _, transformation) => *transformation, + } + } + + pub fn clip_bounds(&self) -> Rectangle { + match self { + Item::Live(_) => Rectangle::INFINITE, + Item::Group(_, clip_bounds, _) + | Item::Cached(_, clip_bounds, _) => *clip_bounds, + } + } + + pub fn as_slice(&self) -> &[T] { + match self { + Item::Live(item) => std::slice::from_ref(item), + Item::Group(group, _, _) => group.as_slice(), + Item::Cached(cache, _, _) => cache, + } + } +} + +impl Layer { + pub fn draw_quad( + &mut self, + mut quad: Quad, + background: Background, + transformation: Transformation, + ) { + quad.bounds = quad.bounds * transformation; + self.quads.push((quad, background)); + } + + pub fn draw_paragraph( + &mut self, + paragraph: &Paragraph, + position: Point, + color: Color, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + let paragraph = Text::Paragraph { + paragraph: paragraph.downgrade(), + position, + color, + clip_bounds, + transformation, + }; + + self.text.push(Item::Live(paragraph)); + } + + pub fn draw_editor( + &mut self, + editor: &Editor, + position: Point, + color: Color, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + let editor = Text::Editor { + editor: editor.downgrade(), + position, + color, + clip_bounds, + transformation, + }; + + self.text.push(Item::Live(editor)); + } + + pub fn draw_text( + &mut self, + text: crate::core::Text, + position: Point, + color: Color, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + let text = Text::Cached { + content: text.content, + bounds: Rectangle::new(position, text.bounds) * transformation, + color, + size: text.size * transformation.scale_factor(), + line_height: text.line_height.to_absolute(text.size) + * transformation.scale_factor(), + font: text.font, + horizontal_alignment: text.horizontal_alignment, + vertical_alignment: text.vertical_alignment, + shaping: text.shaping, + clip_bounds: clip_bounds * transformation, + }; + + self.text.push(Item::Live(text)); + } + + pub fn draw_text_group( + &mut self, + text: Vec, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + self.text + .push(Item::Group(text, clip_bounds, transformation)); + } + + pub fn draw_text_cache( + &mut self, + text: Rc<[Text]>, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + self.text + .push(Item::Cached(text, clip_bounds, transformation)); + } + + pub fn draw_image( + &mut self, + handle: image::Handle, + filter_method: image::FilterMethod, + bounds: Rectangle, + transformation: Transformation, + ) { + let image = Image::Raster { + handle, + filter_method, + bounds: bounds * transformation, + }; + + self.images.push(image); + } + + pub fn draw_svg( + &mut self, + handle: svg::Handle, + color: Option, + bounds: Rectangle, + transformation: Transformation, + ) { + let svg = Image::Vector { + handle, + color, + bounds: bounds * transformation, + }; + + self.images.push(svg); + } + + pub fn draw_primitive_group( + &mut self, + primitives: Vec, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + self.primitives.push(Item::Group( + primitives, + clip_bounds, + transformation, + )); + } + + pub fn draw_primitive_cache( + &mut self, + primitives: Rc<[Primitive]>, + clip_bounds: Rectangle, + transformation: Transformation, + ) { + self.primitives.push(Item::Cached( + primitives, + clip_bounds, + transformation, + )); + } +} + +impl Default for Layer { + fn default() -> Self { + Self { + bounds: Rectangle::INFINITE, + quads: Vec::new(), + primitives: Vec::new(), + text: Vec::new(), + images: Vec::new(), + } + } +} + +impl graphics::Layer for Layer { + fn with_bounds(bounds: Rectangle) -> Self { + Self { + bounds, + ..Self::default() + } + } + + fn flush(&mut self) {} + + fn resize(&mut self, bounds: graphics::core::Rectangle) { + self.bounds = bounds; + } + + fn reset(&mut self) { + self.bounds = Rectangle::INFINITE; + + self.quads.clear(); + self.text.clear(); + self.primitives.clear(); + self.images.clear(); + } +} -- cgit From 1e802e776cb591f3860d1bfbaa1423d356fc8456 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 Apr 2024 15:21:42 +0200 Subject: Reintroduce damage tracking for `iced_tiny_skia` --- tiny_skia/src/layer.rs | 144 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 110 insertions(+), 34 deletions(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index 1f5c8b46..0d770d81 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -2,6 +2,7 @@ use crate::core::image; use crate::core::renderer::Quad; use crate::core::svg; use crate::core::{Background, Color, Point, Rectangle, Transformation}; +use crate::graphics::damage; use crate::graphics::layer; use crate::graphics::text::{Editor, Paragraph, Text}; use crate::graphics::{self, Image}; @@ -20,39 +21,6 @@ pub struct Layer { pub images: Vec, } -#[derive(Debug, Clone)] -pub enum Item { - Live(T), - Group(Vec, Rectangle, Transformation), - Cached(Rc<[T]>, Rectangle, Transformation), -} - -impl Item { - pub fn transformation(&self) -> Transformation { - match self { - Item::Live(_) => Transformation::IDENTITY, - Item::Group(_, _, transformation) - | Item::Cached(_, _, transformation) => *transformation, - } - } - - pub fn clip_bounds(&self) -> Rectangle { - match self { - Item::Live(_) => Rectangle::INFINITE, - Item::Group(_, clip_bounds, _) - | Item::Cached(_, clip_bounds, _) => *clip_bounds, - } - } - - pub fn as_slice(&self) -> &[T] { - match self { - Item::Live(item) => std::slice::from_ref(item), - Item::Group(group, _, _) => group.as_slice(), - Item::Cached(cache, _, _) => cache, - } - } -} - impl Layer { pub fn draw_quad( &mut self, @@ -204,6 +172,81 @@ impl Layer { transformation, )); } + + pub fn damage(previous: &Self, current: &Self) -> Vec { + let mut damage = damage::list( + &previous.quads, + ¤t.quads, + |(quad, _)| vec![quad.bounds.expand(1.0)], + |(quad_a, background_a), (quad_b, background_b)| { + quad_a == quad_b && background_a == background_b + }, + ); + + let text = damage::diff( + &previous.text, + ¤t.text, + |item| { + item.as_slice() + .iter() + .filter_map(Text::visible_bounds) + .map(|bounds| bounds * item.transformation()) + .collect() + }, + |text_a, text_b| { + damage::list( + text_a.as_slice(), + text_b.as_slice(), + |text| { + text.visible_bounds() + .into_iter() + .filter_map(|bounds| { + bounds.intersection(&text_a.clip_bounds()) + }) + .collect() + }, + |text_a, text_b| text_a == text_b, + ) + }, + ); + + let primitives = damage::list( + &previous.primitives, + ¤t.primitives, + |item| match item { + Item::Live(primitive) => vec![primitive.visible_bounds()], + Item::Group(primitives, bounds, transformation) => { + damage::group( + primitives + .as_slice() + .iter() + .map(Primitive::visible_bounds) + .map(|bounds| bounds * *transformation) + .collect(), + *bounds, + ) + } + Item::Cached(_, bounds, _) => { + vec![*bounds] + } + }, + |primitive_a, primitive_b| match (primitive_a, primitive_b) { + ( + Item::Cached(cache_a, bounds_a, transformation_a), + Item::Cached(cache_b, bounds_b, transformation_b), + ) => { + Rc::ptr_eq(cache_a, cache_b) + && bounds_a == bounds_b + && transformation_a == transformation_b + } + _ => false, + }, + ); + + damage.extend(text); + damage.extend(primitives); + damage + } } impl Default for Layer { @@ -236,8 +279,41 @@ impl graphics::Layer for Layer { self.bounds = Rectangle::INFINITE; self.quads.clear(); - self.text.clear(); self.primitives.clear(); + self.text.clear(); self.images.clear(); } } + +#[derive(Debug, Clone)] +pub enum Item { + Live(T), + Group(Vec, Rectangle, Transformation), + Cached(Rc<[T]>, Rectangle, Transformation), +} + +impl Item { + pub fn transformation(&self) -> Transformation { + match self { + Item::Live(_) => Transformation::IDENTITY, + Item::Group(_, _, transformation) + | Item::Cached(_, _, transformation) => *transformation, + } + } + + pub fn clip_bounds(&self) -> Rectangle { + match self { + Item::Live(_) => Rectangle::INFINITE, + Item::Group(_, clip_bounds, _) + | Item::Cached(_, clip_bounds, _) => *clip_bounds, + } + } + + pub fn as_slice(&self) -> &[T] { + match self { + Item::Live(item) => std::slice::from_ref(item), + Item::Group(group, _, _) => group.as_slice(), + Item::Cached(cache, _, _) => cache, + } + } +} -- cgit From 32cd456fb936117307c178b4d47ae89124c8329a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 Apr 2024 16:26:55 +0200 Subject: Account for `transformation` in `Text::visible_bounds` --- tiny_skia/src/layer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index 0d770d81..17e6ac13 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -200,9 +200,7 @@ impl Layer { |text| { text.visible_bounds() .into_iter() - .filter_map(|bounds| { - bounds.intersection(&text_a.clip_bounds()) - }) + .map(|bounds| bounds * text_a.transformation()) .collect() }, |text_a, text_b| text_a == text_b, -- cgit From fdd9896dc5f727f4c659ad6252f1ab36cca77762 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 Apr 2024 19:55:27 +0200 Subject: Track image damage in `iced_tiny_skia` --- tiny_skia/src/layer.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index 17e6ac13..d3d8b988 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -241,8 +241,16 @@ impl Layer { }, ); + let images = damage::list( + &previous.images, + ¤t.images, + |image| vec![image.bounds().expand(1.0)], + Image::eq, + ); + damage.extend(text); damage.extend(primitives); + damage.extend(images); damage } } -- cgit From 1e8554bf02f366b18b31b9ea1dfb150f7935ca06 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 Apr 2024 20:23:07 +0200 Subject: Sort damage by distance from origin in `iced_graphics::damage` --- tiny_skia/src/layer.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index d3d8b988..ec87c2bf 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -213,16 +213,14 @@ impl Layer { ¤t.primitives, |item| match item { Item::Live(primitive) => vec![primitive.visible_bounds()], - Item::Group(primitives, bounds, transformation) => { - damage::group( - primitives - .as_slice() - .iter() - .map(Primitive::visible_bounds) - .map(|bounds| bounds * *transformation) - .collect(), - *bounds, - ) + Item::Group(primitives, group_bounds, transformation) => { + primitives + .as_slice() + .iter() + .map(Primitive::visible_bounds) + .map(|bounds| bounds * *transformation) + .filter_map(|bounds| bounds.intersection(group_bounds)) + .collect() } Item::Cached(_, bounds, _) => { vec![*bounds] -- cgit From 43aafb7b79d51106c05f2494e6adc4a7a51d947e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 10 Apr 2024 20:31:44 +0200 Subject: Clip quad damage with layer bounds in `iced_tiny_skia` --- tiny_skia/src/layer.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index ec87c2bf..3e42e4aa 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -174,10 +174,20 @@ impl Layer { } pub fn damage(previous: &Self, current: &Self) -> Vec { + if previous.bounds != current.bounds { + return vec![previous.bounds, current.bounds]; + } + let mut damage = damage::list( &previous.quads, ¤t.quads, - |(quad, _)| vec![quad.bounds.expand(1.0)], + |(quad, _)| { + quad.bounds + .expand(1.0) + .intersection(¤t.bounds) + .into_iter() + .collect() + }, |(quad_a, background_a), (quad_b, background_b)| { quad_a == quad_b && background_a == background_b }, -- 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> --- tiny_skia/src/layer.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index 3e42e4aa..e9651814 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -1,7 +1,7 @@ -use crate::core::image; -use crate::core::renderer::Quad; -use crate::core::svg; -use crate::core::{Background, Color, Point, Rectangle, Transformation}; +use crate::core::{ + image, renderer::Quad, svg, Background, Color, Point, Rectangle, Size, + Transformation, +}; use crate::graphics::damage; use crate::graphics::layer; use crate::graphics::text::{Editor, Paragraph, Text}; @@ -121,11 +121,15 @@ impl Layer { filter_method: image::FilterMethod, bounds: Rectangle, transformation: Transformation, + rotation: f32, + scale: Size, ) { let image = Image::Raster { handle, filter_method, bounds: bounds * transformation, + rotation, + scale, }; self.images.push(image); @@ -137,11 +141,15 @@ impl Layer { color: Option, bounds: Rectangle, transformation: Transformation, + rotation: f32, + scale: Size, ) { let svg = Image::Vector { handle, color, bounds: bounds * transformation, + rotation, + scale, }; self.images.push(svg); @@ -256,6 +264,22 @@ impl Layer { Image::eq, ); + // let center = bounds.center(); + // let rotated_size = RotationLayout::Change + // .apply_to_size(bounds.size(), *rotation); + // + // let scaled_size = Size::new( + // rotated_size.width * scale.width, + // rotated_size.height * scale.height, + // ); + // + // let top_left = Point::new( + // center.x - scaled_size.width / 2.0, + // center.y - scaled_size.height / 2.0, + // ); + // + // Rectangle::new(top_left, scaled_size).expand(1.0) + damage.extend(text); damage.extend(primitives); damage.extend(images); -- 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 --- tiny_skia/src/layer.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index e9651814..c8a31ba3 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -1,5 +1,5 @@ use crate::core::{ - image, renderer::Quad, svg, Background, Color, Point, Rectangle, Size, + image, renderer::Quad, svg, Background, Color, Point, Radians, Rectangle, Transformation, }; use crate::graphics::damage; @@ -121,15 +121,13 @@ impl Layer { filter_method: image::FilterMethod, bounds: Rectangle, transformation: Transformation, - rotation: f32, - scale: Size, + rotation: Radians, ) { let image = Image::Raster { handle, filter_method, bounds: bounds * transformation, rotation, - scale, }; self.images.push(image); @@ -141,15 +139,13 @@ impl Layer { color: Option, bounds: Rectangle, transformation: Transformation, - rotation: f32, - scale: Size, + rotation: Radians, ) { let svg = Image::Vector { handle, color, bounds: bounds * transformation, rotation, - scale, }; self.images.push(svg); -- cgit From 568ac66486937a294f2a79cefea277e4eb46b81e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 2 May 2024 17:15:26 +0200 Subject: Remove commented code in `tiny_skia::layer` --- tiny_skia/src/layer.rs | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index c8a31ba3..c907c93c 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -260,22 +260,6 @@ impl Layer { Image::eq, ); - // let center = bounds.center(); - // let rotated_size = RotationLayout::Change - // .apply_to_size(bounds.size(), *rotation); - // - // let scaled_size = Size::new( - // rotated_size.width * scale.width, - // rotated_size.height * scale.height, - // ); - // - // let top_left = Point::new( - // center.x - scaled_size.width / 2.0, - // center.y - scaled_size.height / 2.0, - // ); - // - // Rectangle::new(top_left, scaled_size).expand(1.0) - damage.extend(text); damage.extend(primitives); damage.extend(images); -- 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` --- tiny_skia/src/layer.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tiny_skia/src/layer.rs') diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index c907c93c..48fca1d8 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -122,12 +122,14 @@ impl Layer { bounds: Rectangle, transformation: Transformation, rotation: Radians, + opacity: f32, ) { let image = Image::Raster { handle, filter_method, bounds: bounds * transformation, rotation, + opacity, }; self.images.push(image); @@ -140,12 +142,14 @@ impl Layer { bounds: Rectangle, transformation: Transformation, rotation: Radians, + opacity: f32, ) { let svg = Image::Vector { handle, color, bounds: bounds * transformation, rotation, + opacity, }; self.images.push(svg); -- cgit