diff options
Diffstat (limited to 'tiny_skia')
-rw-r--r-- | tiny_skia/Cargo.toml | 2 | ||||
-rw-r--r-- | tiny_skia/src/engine.rs | 42 | ||||
-rw-r--r-- | tiny_skia/src/geometry.rs | 74 | ||||
-rw-r--r-- | tiny_skia/src/layer.rs | 47 | ||||
-rw-r--r-- | tiny_skia/src/lib.rs | 65 | ||||
-rw-r--r-- | tiny_skia/src/text.rs | 8 | ||||
-rw-r--r-- | tiny_skia/src/vector.rs | 34 |
7 files changed, 151 insertions, 121 deletions
diff --git a/tiny_skia/Cargo.toml b/tiny_skia/Cargo.toml index 32ead3e0..323233f0 100644 --- a/tiny_skia/Cargo.toml +++ b/tiny_skia/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [features] image = ["iced_graphics/image"] -svg = ["resvg"] +svg = ["iced_graphics/svg", "resvg"] geometry = ["iced_graphics/geometry"] [dependencies] diff --git a/tiny_skia/src/engine.rs b/tiny_skia/src/engine.rs index 028b304f..196c36cf 100644 --- a/tiny_skia/src/engine.rs +++ b/tiny_skia/src/engine.rs @@ -439,9 +439,13 @@ impl Engine { let transformation = transformation * *local_transformation; let (width, height) = buffer.size(); - let physical_bounds = - Rectangle::new(raw.position, Size::new(width, height)) - * transformation; + let physical_bounds = Rectangle::new( + raw.position, + Size::new( + width.unwrap_or(clip_bounds.width), + height.unwrap_or(clip_bounds.height), + ), + ) * transformation; if !clip_bounds.intersects(&physical_bounds) { return; @@ -546,13 +550,7 @@ impl Engine { ) { match image { #[cfg(feature = "image")] - Image::Raster { - handle, - filter_method, - bounds, - rotation, - opacity, - } => { + Image::Raster(raster, bounds) => { let physical_bounds = *bounds * _transformation; if !_clip_bounds.intersects(&physical_bounds) { @@ -563,7 +561,7 @@ impl Engine { .then_some(_clip_mask as &_); let center = physical_bounds.center(); - let radians = f32::from(*rotation); + let radians = f32::from(raster.rotation); let transform = into_transform(_transformation).post_rotate_at( radians.to_degrees(), @@ -572,23 +570,17 @@ impl Engine { ); self.raster_pipeline.draw( - handle, - *filter_method, + &raster.handle, + raster.filter_method, *bounds, - *opacity, + raster.opacity, _pixels, transform, clip_mask, ); } #[cfg(feature = "svg")] - Image::Vector { - handle, - color, - bounds, - rotation, - opacity, - } => { + Image::Vector(svg, bounds) => { let physical_bounds = *bounds * _transformation; if !_clip_bounds.intersects(&physical_bounds) { @@ -599,7 +591,7 @@ impl Engine { .then_some(_clip_mask as &_); let center = physical_bounds.center(); - let radians = f32::from(*rotation); + let radians = f32::from(svg.rotation); let transform = into_transform(_transformation).post_rotate_at( radians.to_degrees(), @@ -608,10 +600,10 @@ impl Engine { ); self.vector_pipeline.draw( - handle, - *color, + &svg.handle, + svg.color, physical_bounds, - *opacity, + svg.opacity, _pixels, transform, clip_mask, diff --git a/tiny_skia/src/geometry.rs b/tiny_skia/src/geometry.rs index 02b6e1b9..0d5fff62 100644 --- a/tiny_skia/src/geometry.rs +++ b/tiny_skia/src/geometry.rs @@ -1,10 +1,10 @@ use crate::core::text::LineHeight; -use crate::core::{Pixels, Point, Radians, Rectangle, Size, Vector}; +use crate::core::{self, Pixels, Point, Radians, Rectangle, Size, Svg, Vector}; use crate::graphics::cache::{self, Cached}; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::stroke::{self, Stroke}; use crate::graphics::geometry::{self, Path, Style}; -use crate::graphics::{Gradient, Text}; +use crate::graphics::{self, Gradient, Image, Text}; use crate::Primitive; use std::rc::Rc; @@ -13,6 +13,7 @@ use std::rc::Rc; pub enum Geometry { Live { text: Vec<Text>, + images: Vec<graphics::Image>, primitives: Vec<Primitive>, clip_bounds: Rectangle, }, @@ -22,6 +23,7 @@ pub enum Geometry { #[derive(Debug, Clone)] pub struct Cache { pub text: Rc<[Text]>, + pub images: Rc<[graphics::Image]>, pub primitives: Rc<[Primitive]>, pub clip_bounds: Rectangle, } @@ -37,10 +39,12 @@ impl Cached for Geometry { match self { Self::Live { primitives, + images, text, clip_bounds, } => Cache { primitives: Rc::from(primitives), + images: Rc::from(images), text: Rc::from(text), clip_bounds, }, @@ -55,6 +59,7 @@ pub struct Frame { transform: tiny_skia::Transform, stack: Vec<tiny_skia::Transform>, primitives: Vec<Primitive>, + images: Vec<graphics::Image>, text: Vec<Text>, } @@ -68,6 +73,7 @@ impl Frame { clip_bounds, stack: Vec::new(), primitives: Vec::new(), + images: Vec::new(), text: Vec::new(), transform: tiny_skia::Transform::from_translate( clip_bounds.x, @@ -162,6 +168,15 @@ impl geometry::frame::Backend for Frame { }); } + fn stroke_rectangle<'a>( + &mut self, + top_left: Point, + size: Size, + stroke: impl Into<Stroke<'a>>, + ) { + self.stroke(&Path::rectangle(top_left, size), stroke); + } + fn fill_text(&mut self, text: impl Into<geometry::Text>) { let text = text.into(); @@ -238,7 +253,7 @@ impl geometry::frame::Backend for Frame { Self::with_clip(clip_bounds) } - fn paste(&mut self, frame: Self, _at: Point) { + fn paste(&mut self, frame: Self) { self.primitives.extend(frame.primitives); self.text.extend(frame.text); } @@ -269,10 +284,63 @@ impl geometry::frame::Backend for Frame { fn into_geometry(self) -> Geometry { Geometry::Live { primitives: self.primitives, + images: self.images, text: self.text, clip_bounds: self.clip_bounds, } } + + fn draw_image(&mut self, bounds: Rectangle, image: impl Into<core::Image>) { + let mut image = image.into(); + + let (bounds, external_rotation) = + transform_rectangle(bounds, self.transform); + + image.rotation += external_rotation; + + self.images.push(graphics::Image::Raster(image, bounds)); + } + + fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) { + let mut svg = svg.into(); + + let (bounds, external_rotation) = + transform_rectangle(bounds, self.transform); + + svg.rotation += external_rotation; + + self.images.push(Image::Vector(svg, bounds)); + } +} + +fn transform_rectangle( + rectangle: Rectangle, + transform: tiny_skia::Transform, +) -> (Rectangle, Radians) { + let mut top_left = tiny_skia::Point { + x: rectangle.x, + y: rectangle.y, + }; + + let mut top_right = tiny_skia::Point { + x: rectangle.x + rectangle.width, + y: rectangle.y, + }; + + let mut bottom_left = tiny_skia::Point { + x: rectangle.x, + y: rectangle.y + rectangle.height, + }; + + transform.map_point(&mut top_left); + transform.map_point(&mut top_right); + transform.map_point(&mut bottom_left); + + Rectangle::with_vertices( + Point::new(top_left.x, top_left.y), + Point::new(top_right.x, top_right.y), + Point::new(bottom_left.x, bottom_left.y), + ) } fn convert_path(path: &Path) -> Option<tiny_skia::Path> { diff --git a/tiny_skia/src/layer.rs b/tiny_skia/src/layer.rs index 48fca1d8..bdfd4d38 100644 --- a/tiny_skia/src/layer.rs +++ b/tiny_skia/src/layer.rs @@ -1,6 +1,6 @@ +use crate::core::renderer::Quad; use crate::core::{ - image, renderer::Quad, svg, Background, Color, Point, Radians, Rectangle, - Transformation, + self, Background, Color, Point, Rectangle, Svg, Transformation, }; use crate::graphics::damage; use crate::graphics::layer; @@ -72,7 +72,7 @@ impl Layer { pub fn draw_text( &mut self, - text: crate::core::Text, + text: core::Text, position: Point, color: Color, clip_bounds: Rectangle, @@ -115,42 +115,35 @@ impl Layer { .push(Item::Cached(text, clip_bounds, transformation)); } - pub fn draw_image( + pub fn draw_image(&mut self, image: Image, transformation: Transformation) { + match image { + Image::Raster(raster, bounds) => { + self.draw_raster(raster, bounds, transformation); + } + Image::Vector(svg, bounds) => { + self.draw_svg(svg, bounds, transformation); + } + } + } + + pub fn draw_raster( &mut self, - handle: image::Handle, - filter_method: image::FilterMethod, + image: core::Image, bounds: Rectangle, transformation: Transformation, - rotation: Radians, - opacity: f32, ) { - let image = Image::Raster { - handle, - filter_method, - bounds: bounds * transformation, - rotation, - opacity, - }; + let image = Image::Raster(image, bounds * transformation); self.images.push(image); } pub fn draw_svg( &mut self, - handle: svg::Handle, - color: Option<Color>, + svg: Svg, bounds: Rectangle, transformation: Transformation, - rotation: Radians, - opacity: f32, ) { - let svg = Image::Vector { - handle, - color, - bounds: bounds * transformation, - rotation, - opacity, - }; + let svg = Image::Vector(svg, bounds * transformation); self.images.push(svg); } @@ -293,7 +286,7 @@ impl graphics::Layer for Layer { fn flush(&mut self) {} - fn resize(&mut self, bounds: graphics::core::Rectangle) { + fn resize(&mut self, bounds: Rectangle) { self.bounds = bounds; } diff --git a/tiny_skia/src/lib.rs b/tiny_skia/src/lib.rs index 1aabff00..758921d4 100644 --- a/tiny_skia/src/lib.rs +++ b/tiny_skia/src/lib.rs @@ -178,6 +178,16 @@ impl Renderer { engine::adjust_clip_mask(clip_mask, clip_bounds); } + for image in &layer.images { + self.engine.draw_image( + image, + Transformation::scale(scale_factor), + pixels, + clip_mask, + clip_bounds, + ); + } + for group in &layer.text { for text in group.as_slice() { self.engine.draw_text( @@ -190,16 +200,6 @@ impl Renderer { ); } } - - for image in &layer.images { - self.engine.draw_image( - image, - Transformation::scale(scale_factor), - pixels, - clip_mask, - clip_bounds, - ); - } } if !overlay.is_empty() { @@ -330,6 +330,7 @@ impl graphics::geometry::Renderer for Renderer { match geometry { Geometry::Live { primitives, + images, text, clip_bounds, } => { @@ -339,6 +340,10 @@ impl graphics::geometry::Renderer for Renderer { transformation, ); + for image in images { + layer.draw_image(image, transformation); + } + layer.draw_text_group(text, clip_bounds, transformation); } Geometry::Cache(cache) => { @@ -348,6 +353,10 @@ impl graphics::geometry::Renderer for Renderer { transformation, ); + for image in cache.images.iter() { + layer.draw_image(image.clone(), transformation); + } + layer.draw_text_cache( cache.text, cache.clip_bounds, @@ -372,23 +381,9 @@ impl core::image::Renderer for Renderer { self.engine.raster_pipeline.dimensions(handle) } - fn draw_image( - &mut self, - handle: Self::Handle, - filter_method: core::image::FilterMethod, - bounds: Rectangle, - rotation: core::Radians, - opacity: f32, - ) { + fn draw_image(&mut self, image: core::Image, bounds: Rectangle) { let (layer, transformation) = self.layers.current_mut(); - layer.draw_image( - handle, - filter_method, - bounds, - transformation, - rotation, - opacity, - ); + layer.draw_raster(image, bounds, transformation); } } @@ -401,23 +396,9 @@ impl core::svg::Renderer for Renderer { self.engine.vector_pipeline.viewport_dimensions(handle) } - fn draw_svg( - &mut self, - handle: core::svg::Handle, - color: Option<Color>, - bounds: Rectangle, - rotation: core::Radians, - opacity: f32, - ) { + fn draw_svg(&mut self, svg: core::Svg, bounds: Rectangle) { let (layer, transformation) = self.layers.current_mut(); - layer.draw_svg( - handle, - color, - bounds, - transformation, - rotation, - opacity, - ); + layer.draw_svg(svg, bounds, transformation); } } diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs index c71deb10..0fc3d1f7 100644 --- a/tiny_skia/src/text.rs +++ b/tiny_skia/src/text.rs @@ -169,7 +169,13 @@ impl Pipeline { font_system.raw(), &mut self.glyph_cache, buffer, - Rectangle::new(position, Size::new(width, height)), + Rectangle::new( + position, + Size::new( + width.unwrap_or(pixels.width() as f32), + height.unwrap_or(pixels.height() as f32), + ), + ), color, alignment::Horizontal::Left, alignment::Vertical::Top, diff --git a/tiny_skia/src/vector.rs b/tiny_skia/src/vector.rs index bbe08cb8..8a15f47f 100644 --- a/tiny_skia/src/vector.rs +++ b/tiny_skia/src/vector.rs @@ -1,8 +1,7 @@ use crate::core::svg::{Data, Handle}; use crate::core::{Color, Rectangle, Size}; -use crate::graphics::text; -use resvg::usvg::{self, TreeTextToPath}; +use resvg::usvg; use rustc_hash::{FxHashMap, FxHashSet}; use tiny_skia::Transform; @@ -80,35 +79,28 @@ struct RasterKey { impl Cache { fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> { - use usvg::TreeParsing; - let id = handle.id(); if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) { - let mut svg = match handle.data() { + let svg = match handle.data() { Data::Path(path) => { fs::read_to_string(path).ok().and_then(|contents| { usvg::Tree::from_str( &contents, - &usvg::Options::default(), + &usvg::Options::default(), // TODO: Set usvg::Options::fontdb ) .ok() }) } Data::Bytes(bytes) => { - usvg::Tree::from_data(bytes, &usvg::Options::default()).ok() + usvg::Tree::from_data( + bytes, + &usvg::Options::default(), // TODO: Set usvg::Options::fontdb + ) + .ok() } }; - if let Some(svg) = &mut svg { - if svg.has_text_nodes() { - let mut font_system = - text::font_system().write().expect("Write font system"); - - svg.convert_text(font_system.raw().db_mut()); - } - } - let _ = entry.insert(svg); } @@ -118,11 +110,9 @@ impl Cache { fn viewport_dimensions(&mut self, handle: &Handle) -> Option<Size<u32>> { let tree = self.load(handle)?; + let size = tree.size(); - Some(Size::new( - tree.size.width() as u32, - tree.size.height() as u32, - )) + Some(Size::new(size.width() as u32, size.height() as u32)) } fn draw( @@ -147,7 +137,7 @@ impl Cache { let mut image = tiny_skia::Pixmap::new(size.width, size.height)?; - let tree_size = tree.size.to_int_size(); + let tree_size = tree.size().to_int_size(); let target_size = if size.width > size.height { tree_size.scale_to_width(size.width) @@ -167,7 +157,7 @@ impl Cache { tiny_skia::Transform::default() }; - resvg::Tree::from_usvg(tree).render(transform, &mut image.as_mut()); + resvg::render(tree, transform, &mut image.as_mut()); if let Some([r, g, b, _]) = key.color { // Apply color filter |