diff options
Diffstat (limited to 'tiny_skia/src/layer.rs')
-rw-r--r-- | tiny_skia/src/layer.rs | 243 |
1 files changed, 243 insertions, 0 deletions
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<Layer>; + +#[derive(Debug, Clone)] +pub struct Layer { + pub bounds: Rectangle, + pub quads: Vec<(Quad, Background)>, + pub primitives: Vec<Item<Primitive>>, + pub text: Vec<Item<Text>>, + 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, + 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<Text>, + 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<Color>, + 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<Primitive>, + 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(); + } +} |