diff options
Diffstat (limited to 'tiny_skia/src/layer.rs')
-rw-r--r-- | tiny_skia/src/layer.rs | 144 |
1 files changed, 110 insertions, 34 deletions
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<Image>, } -#[derive(Debug, Clone)] -pub enum Item<T> { - Live(T), - Group(Vec<T>, Rectangle, Transformation), - Cached(Rc<[T]>, Rectangle, Transformation), -} - -impl<T> Item<T> { - 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<Rectangle> { + 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<T> { + Live(T), + Group(Vec<T>, Rectangle, Transformation), + Cached(Rc<[T]>, Rectangle, Transformation), +} + +impl<T> Item<T> { + 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, + } + } +} |