From 8c373cd497e370d356b480380482779397bdb510 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 25 Feb 2023 15:38:25 +0100 Subject: Scaffold `iced_tiny_skia` and connect it to `iced_renderer` --- tiny_skia/src/backend.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 tiny_skia/src/backend.rs (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs new file mode 100644 index 00000000..4282a745 --- /dev/null +++ b/tiny_skia/src/backend.rs @@ -0,0 +1,87 @@ +use crate::{Font, Settings, Size}; + +use iced_graphics::backend; +use iced_graphics::text; + +use std::borrow::Cow; + +pub struct Backend { + default_font: Font, + default_text_size: f32, +} + +impl Backend { + pub fn new(settings: Settings) -> Self { + Self { + default_font: settings.default_font, + default_text_size: settings.default_text_size, + } + } +} + +impl iced_graphics::Backend for Backend { + fn trim_measurements(&mut self) { + // TODO + } +} + +impl backend::Text for Backend { + const ICON_FONT: Font = Font::Name("Iced-Icons"); + const CHECKMARK_ICON: char = '\u{f00c}'; + const ARROW_DOWN_ICON: char = '\u{e800}'; + + fn default_font(&self) -> Font { + self.default_font + } + + fn default_size(&self) -> f32 { + self.default_text_size + } + + fn measure( + &self, + _contents: &str, + _size: f32, + _font: Font, + _bounds: Size, + ) -> (f32, f32) { + // TODO + (0.0, 0.0) + } + + fn hit_test( + &self, + _contents: &str, + _size: f32, + _font: Font, + _bounds: Size, + _point: iced_native::Point, + _nearest_only: bool, + ) -> Option { + // TODO + None + } + + fn load_font(&mut self, _font: Cow<'static, [u8]>) { + // TODO + } +} + +#[cfg(feature = "image")] +impl backend::Image for Backend { + fn dimensions(&self, _handle: &iced_native::image::Handle) -> Size { + // TODO + Size::new(0, 0) + } +} + +#[cfg(feature = "svg")] +impl backend::Svg for Backend { + fn viewport_dimensions( + &self, + _handle: &iced_native::svg::Handle, + ) -> Size { + // TODO + Size::new(0, 0) + } +} -- cgit From 535d7a4d57e131e661587b36e41820dd6ccccc3e Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 25 Feb 2023 16:05:42 +0100 Subject: Implement basic presentation with `softbuffer` for `iced_tiny_skia` --- tiny_skia/src/backend.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 4282a745..62373ec7 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,7 +1,8 @@ -use crate::{Font, Settings, Size}; +use crate::{Color, Font, Settings, Size, Viewport}; use iced_graphics::backend; use iced_graphics::text; +use iced_graphics::Primitive; use std::borrow::Cow; @@ -17,6 +18,22 @@ impl Backend { default_text_size: settings.default_text_size, } } + + pub fn draw>( + &mut self, + pixels: &mut tiny_skia::Pixmap, + _primitives: &[Primitive], + _viewport: &Viewport, + background_color: Color, + _overlay: &[T], + ) { + pixels.fill(into_color(background_color)); + } +} + +fn into_color(color: Color) -> tiny_skia::Color { + tiny_skia::Color::from_rgba(color.r, color.g, color.b, color.a) + .expect("Convert color from iced to tiny_skia") } impl iced_graphics::Backend for Backend { -- cgit From df5d66423de141a009bbed993d99d491ed6373c9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 26 Feb 2023 00:38:46 +0100 Subject: Draft support for `Quad` and `Clip` primitives in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 3 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 62373ec7..54752a21 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -2,7 +2,7 @@ use crate::{Color, Font, Settings, Size, Viewport}; use iced_graphics::backend; use iced_graphics::text; -use iced_graphics::Primitive; +use iced_graphics::{Background, Primitive, Rectangle, Vector}; use std::borrow::Cow; @@ -22,12 +22,133 @@ impl Backend { pub fn draw>( &mut self, pixels: &mut tiny_skia::Pixmap, - _primitives: &[Primitive], - _viewport: &Viewport, + primitives: &[Primitive], + viewport: &Viewport, background_color: Color, _overlay: &[T], ) { pixels.fill(into_color(background_color)); + + let scale_factor = viewport.scale_factor() as f32; + + for primitive in primitives { + draw_primitive(primitive, pixels, None, scale_factor, Vector::ZERO); + } + } +} + +fn draw_primitive( + primitive: &Primitive, + pixels: &mut tiny_skia::Pixmap, + clip_mask: Option<&tiny_skia::ClipMask>, + scale_factor: f32, + translation: Vector, +) { + match primitive { + Primitive::None => {} + Primitive::Quad { + bounds, + background, + border_radius: _, // TODO + border_width, + border_color, + } => { + let transform = tiny_skia::Transform::from_translate( + translation.x, + translation.y, + ) + .post_scale(scale_factor, scale_factor); + + let path = tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ) + .expect("Create quad rectangle"), + ); + + pixels.fill_path( + &path, + &tiny_skia::Paint { + shader: match background { + Background::Color(color) => { + tiny_skia::Shader::SolidColor(into_color(*color)) + } + }, + anti_alias: true, + ..tiny_skia::Paint::default() + }, + tiny_skia::FillRule::EvenOdd, + transform, + clip_mask, + ); + + if *border_width > 0.0 { + pixels.stroke_path( + &path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + *border_color, + )), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: *border_width, + ..tiny_skia::Stroke::default() + }, + transform, + clip_mask, + ); + } + } + Primitive::Text { .. } => { + // TODO + } + Primitive::Image { .. } => { + // TODO + } + Primitive::Svg { .. } => { + // TODO + } + Primitive::Group { primitives } => { + for primitive in primitives { + draw_primitive( + primitive, + pixels, + clip_mask, + scale_factor, + translation, + ); + } + } + Primitive::Translate { + translation: offset, + content, + } => { + draw_primitive( + content, + pixels, + clip_mask, + scale_factor, + translation + *offset, + ); + } + Primitive::Clip { bounds, content } => { + draw_primitive( + content, + pixels, + Some(&rectangular_clip_mask(pixels, *bounds * scale_factor)), + scale_factor, + translation, + ); + } + Primitive::Cached { cache } => { + draw_primitive(cache, pixels, clip_mask, scale_factor, translation); + } + Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {} } } @@ -36,6 +157,32 @@ fn into_color(color: Color) -> tiny_skia::Color { .expect("Convert color from iced to tiny_skia") } +fn rectangular_clip_mask( + pixels: &tiny_skia::Pixmap, + bounds: Rectangle, +) -> tiny_skia::ClipMask { + let mut clip_mask = tiny_skia::ClipMask::new(); + + let path = { + let mut builder = tiny_skia::PathBuilder::new(); + builder.push_rect(bounds.x, bounds.y, bounds.width, bounds.height); + + builder.finish().unwrap() + }; + + clip_mask + .set_path( + pixels.width(), + pixels.height(), + &path, + tiny_skia::FillRule::EvenOdd, + true, + ) + .expect("Set path of clipping area"); + + clip_mask +} + impl iced_graphics::Backend for Backend { fn trim_measurements(&mut self) { // TODO -- cgit From 744f3028f484c44899fed56d9190387569828a95 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 26 Feb 2023 00:49:27 +0100 Subject: Use `Surface::buffer` directly for drawing in `iced_tiny_skia` ... with a nice little color trick :^) --- tiny_skia/src/backend.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 54752a21..9eea1a32 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -21,7 +21,7 @@ impl Backend { pub fn draw>( &mut self, - pixels: &mut tiny_skia::Pixmap, + pixels: &mut tiny_skia::PixmapMut<'_>, primitives: &[Primitive], viewport: &Viewport, background_color: Color, @@ -39,7 +39,7 @@ impl Backend { fn draw_primitive( primitive: &Primitive, - pixels: &mut tiny_skia::Pixmap, + pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: Option<&tiny_skia::ClipMask>, scale_factor: f32, translation: Vector, @@ -153,12 +153,12 @@ fn draw_primitive( } fn into_color(color: Color) -> tiny_skia::Color { - tiny_skia::Color::from_rgba(color.r, color.g, color.b, color.a) + tiny_skia::Color::from_rgba(color.b, color.g, color.r, color.a) .expect("Convert color from iced to tiny_skia") } fn rectangular_clip_mask( - pixels: &tiny_skia::Pixmap, + pixels: &tiny_skia::PixmapMut<'_>, bounds: Rectangle, ) -> tiny_skia::ClipMask { let mut clip_mask = tiny_skia::ClipMask::new(); -- cgit From 64fb722dfe8769d4a92edb0133f1863383ecfd86 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 26 Feb 2023 23:40:17 +0100 Subject: Draft text support in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 269 +++++++++++++++++++++++++++-------------------- 1 file changed, 157 insertions(+), 112 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 9eea1a32..5e743479 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -9,6 +9,7 @@ use std::borrow::Cow; pub struct Backend { default_font: Font, default_text_size: f32, + text_pipeline: crate::text::Pipeline, } impl Backend { @@ -16,6 +17,7 @@ impl Backend { Self { default_font: settings.default_font, default_text_size: settings.default_text_size, + text_pipeline: crate::text::Pipeline::new(), } } @@ -32,123 +34,161 @@ impl Backend { let scale_factor = viewport.scale_factor() as f32; for primitive in primitives { - draw_primitive(primitive, pixels, None, scale_factor, Vector::ZERO); + self.draw_primitive( + primitive, + pixels, + None, + scale_factor, + Vector::ZERO, + ); } + + self.text_pipeline.end_frame(); } -} -fn draw_primitive( - primitive: &Primitive, - pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: Option<&tiny_skia::ClipMask>, - scale_factor: f32, - translation: Vector, -) { - match primitive { - Primitive::None => {} - Primitive::Quad { - bounds, - background, - border_radius: _, // TODO - border_width, - border_color, - } => { - let transform = tiny_skia::Transform::from_translate( - translation.x, - translation.y, - ) - .post_scale(scale_factor, scale_factor); - - let path = tiny_skia::PathBuilder::from_rect( - tiny_skia::Rect::from_xywh( - bounds.x, - bounds.y, - bounds.width, - bounds.height, + fn draw_primitive( + &mut self, + primitive: &Primitive, + pixels: &mut tiny_skia::PixmapMut<'_>, + clip_mask: Option<&tiny_skia::ClipMask>, + scale_factor: f32, + translation: Vector, + ) { + match primitive { + Primitive::None => {} + Primitive::Quad { + bounds, + background, + border_radius: _, // TODO + border_width, + border_color, + } => { + let transform = tiny_skia::Transform::from_translate( + translation.x, + translation.y, ) - .expect("Create quad rectangle"), - ); + .post_scale(scale_factor, scale_factor); - pixels.fill_path( - &path, - &tiny_skia::Paint { - shader: match background { - Background::Color(color) => { - tiny_skia::Shader::SolidColor(into_color(*color)) - } - }, - anti_alias: true, - ..tiny_skia::Paint::default() - }, - tiny_skia::FillRule::EvenOdd, - transform, - clip_mask, - ); + let path = tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ) + .expect("Create quad rectangle"), + ); - if *border_width > 0.0 { - pixels.stroke_path( + pixels.fill_path( &path, &tiny_skia::Paint { - shader: tiny_skia::Shader::SolidColor(into_color( - *border_color, - )), + shader: match background { + Background::Color(color) => { + tiny_skia::Shader::SolidColor(into_color( + *color, + )) + } + }, anti_alias: true, ..tiny_skia::Paint::default() }, - &tiny_skia::Stroke { - width: *border_width, - ..tiny_skia::Stroke::default() - }, + tiny_skia::FillRule::EvenOdd, transform, clip_mask, ); + + if *border_width > 0.0 { + pixels.stroke_path( + &path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + *border_color, + )), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: *border_width, + ..tiny_skia::Stroke::default() + }, + transform, + clip_mask, + ); + } } - } - Primitive::Text { .. } => { - // TODO - } - Primitive::Image { .. } => { - // TODO - } - Primitive::Svg { .. } => { - // TODO - } - Primitive::Group { primitives } => { - for primitive in primitives { - draw_primitive( - primitive, + Primitive::Text { + content, + bounds, + color, + size, + font, + horizontal_alignment, + vertical_alignment, + } => { + self.text_pipeline.draw( + content, + (*bounds + translation) * scale_factor, + *color, + *size * scale_factor, + *font, + *horizontal_alignment, + *vertical_alignment, + pixels, + clip_mask, + ); + } + Primitive::Image { .. } => { + // TODO + } + Primitive::Svg { .. } => { + // TODO + } + Primitive::Group { primitives } => { + for primitive in primitives { + self.draw_primitive( + primitive, + pixels, + clip_mask, + scale_factor, + translation, + ); + } + } + Primitive::Translate { + translation: offset, + content, + } => { + self.draw_primitive( + content, pixels, clip_mask, scale_factor, + translation + *offset, + ); + } + Primitive::Clip { bounds, content } => { + self.draw_primitive( + content, + pixels, + Some(&rectangular_clip_mask( + pixels, + *bounds * scale_factor, + )), + scale_factor, translation, ); } + Primitive::Cached { cache } => { + self.draw_primitive( + cache, + pixels, + clip_mask, + scale_factor, + translation, + ); + } + Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {} } - Primitive::Translate { - translation: offset, - content, - } => { - draw_primitive( - content, - pixels, - clip_mask, - scale_factor, - translation + *offset, - ); - } - Primitive::Clip { bounds, content } => { - draw_primitive( - content, - pixels, - Some(&rectangular_clip_mask(pixels, *bounds * scale_factor)), - scale_factor, - translation, - ); - } - Primitive::Cached { cache } => { - draw_primitive(cache, pixels, clip_mask, scale_factor, translation); - } - Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {} } } @@ -185,7 +225,7 @@ fn rectangular_clip_mask( impl iced_graphics::Backend for Backend { fn trim_measurements(&mut self) { - // TODO + self.text_pipeline.trim_measurement_cache(); } } @@ -204,30 +244,35 @@ impl backend::Text for Backend { fn measure( &self, - _contents: &str, - _size: f32, - _font: Font, - _bounds: Size, + contents: &str, + size: f32, + font: Font, + bounds: Size, ) -> (f32, f32) { - // TODO - (0.0, 0.0) + self.text_pipeline.measure(contents, size, font, bounds) } fn hit_test( &self, - _contents: &str, - _size: f32, - _font: Font, - _bounds: Size, - _point: iced_native::Point, - _nearest_only: bool, + contents: &str, + size: f32, + font: Font, + bounds: Size, + point: iced_native::Point, + nearest_only: bool, ) -> Option { - // TODO - None + self.text_pipeline.hit_test( + contents, + size, + font, + bounds, + point, + nearest_only, + ) } - fn load_font(&mut self, _font: Cow<'static, [u8]>) { - // TODO + fn load_font(&mut self, font: Cow<'static, [u8]>) { + self.text_pipeline.load_font(font); } } -- cgit From 53573cf7cfd48f9bfd97d9e8b82308a0290d2b9d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 26 Feb 2023 23:59:00 +0100 Subject: Draw debug overlay in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 5e743479..cefed71f 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,5 +1,6 @@ use crate::{Color, Font, Settings, Size, Viewport}; +use iced_graphics::alignment; use iced_graphics::backend; use iced_graphics::text; use iced_graphics::{Background, Primitive, Rectangle, Vector}; @@ -27,7 +28,7 @@ impl Backend { primitives: &[Primitive], viewport: &Viewport, background_color: Color, - _overlay: &[T], + overlay: &[T], ) { pixels.fill(into_color(background_color)); @@ -43,6 +44,31 @@ impl Backend { ); } + for (i, text) in overlay.iter().enumerate() { + const OVERLAY_TEXT_SIZE: f32 = 20.0; + + self.draw_primitive( + &Primitive::Text { + content: text.as_ref().to_owned(), + size: OVERLAY_TEXT_SIZE, + bounds: Rectangle { + x: 10.0, + y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + width: f32::INFINITY, + height: f32::INFINITY, + }, + color: Color::BLACK, + font: Font::Monospace, + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + }, + pixels, + None, + scale_factor, + Vector::ZERO, + ); + } + self.text_pipeline.end_frame(); } -- cgit From fbb14bf9b879d3d154618fa8d6a81bac018fee69 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 27 Feb 2023 00:47:53 +0100 Subject: Implement `border_radius` support for quads in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 80 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 10 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index cefed71f..b1dd6a46 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -85,7 +85,7 @@ impl Backend { Primitive::Quad { bounds, background, - border_radius: _, // TODO + border_radius, border_width, border_color, } => { @@ -95,15 +95,7 @@ impl Backend { ) .post_scale(scale_factor, scale_factor); - let path = tiny_skia::PathBuilder::from_rect( - tiny_skia::Rect::from_xywh( - bounds.x, - bounds.y, - bounds.width, - bounds.height, - ) - .expect("Create quad rectangle"), - ); + let path = rounded_rectangle(*bounds, *border_radius); pixels.fill_path( &path, @@ -223,6 +215,74 @@ fn into_color(color: Color) -> tiny_skia::Color { .expect("Convert color from iced to tiny_skia") } +fn rounded_rectangle( + bounds: Rectangle, + border_radius: [f32; 4], +) -> tiny_skia::Path { + let [top_left, top_right, bottom_right, bottom_left] = border_radius; + + if top_left == top_right + && top_left == bottom_right + && top_left == bottom_left + && top_left == bounds.width / 2.0 + && top_left == bounds.height / 2.0 + { + return tiny_skia::PathBuilder::from_circle( + bounds.x + bounds.width / 2.0, + bounds.y + bounds.height / 2.0, + top_left, + ) + .expect("Build circle path"); + } + + let mut builder = tiny_skia::PathBuilder::new(); + + builder.move_to(bounds.x + top_left, bounds.y); + builder.line_to(bounds.x + bounds.width - top_right, bounds.y); + + if top_right > 0.0 { + builder.quad_to( + bounds.x + bounds.width, + bounds.y, + bounds.x + bounds.width, + bounds.y + top_right, + ); + } + + builder.line_to( + bounds.x + bounds.width, + bounds.y + bounds.height - bottom_right, + ); + + if bottom_right > 0.0 { + builder.quad_to( + bounds.x + bounds.width, + bounds.y + bounds.height, + bounds.x + bounds.width - bottom_right, + bounds.y + bounds.height, + ); + } + + builder.line_to(bounds.x + bottom_left, bounds.y + bounds.height); + + if bottom_right > 0.0 { + builder.quad_to( + bounds.x, + bounds.y + bounds.height, + bounds.x, + bounds.y + bounds.height - bottom_left, + ); + } + + builder.line_to(bounds.x, bounds.y + top_left); + + if top_left > 0.0 { + builder.quad_to(bounds.x, bounds.y, bounds.x + top_left, bounds.y); + } + + builder.finish().expect("Build rounded rectangle path") +} + fn rectangular_clip_mask( pixels: &tiny_skia::PixmapMut<'_>, bounds: Rectangle, -- cgit From 37ce30f360ce7cba9ad05654e1faf26276a1dc17 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 27 Feb 2023 02:58:02 +0100 Subject: Use `kurbo` to approximate arcs in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 80 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 10 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index b1dd6a46..38a6c51d 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -241,48 +241,108 @@ fn rounded_rectangle( builder.line_to(bounds.x + bounds.width - top_right, bounds.y); if top_right > 0.0 { - builder.quad_to( - bounds.x + bounds.width, + arc_to( + &mut builder, + bounds.x + bounds.width - top_right, bounds.y, bounds.x + bounds.width, bounds.y + top_right, + top_right, ); } - builder.line_to( + maybe_line_to( + &mut builder, bounds.x + bounds.width, bounds.y + bounds.height - bottom_right, ); if bottom_right > 0.0 { - builder.quad_to( + arc_to( + &mut builder, bounds.x + bounds.width, - bounds.y + bounds.height, + bounds.y + bounds.height - bottom_right, bounds.x + bounds.width - bottom_right, bounds.y + bounds.height, + bottom_right, ); } - builder.line_to(bounds.x + bottom_left, bounds.y + bounds.height); + maybe_line_to( + &mut builder, + bounds.x + bottom_left, + bounds.y + bounds.height, + ); if bottom_right > 0.0 { - builder.quad_to( - bounds.x, + arc_to( + &mut builder, + bounds.x + bottom_left, bounds.y + bounds.height, bounds.x, bounds.y + bounds.height - bottom_left, + bottom_left, ); } - builder.line_to(bounds.x, bounds.y + top_left); + maybe_line_to(&mut builder, bounds.x, bounds.y + top_left); if top_left > 0.0 { - builder.quad_to(bounds.x, bounds.y, bounds.x + top_left, bounds.y); + arc_to( + &mut builder, + bounds.x, + bounds.y + top_left, + bounds.x + top_left, + bounds.y, + top_left, + ); } builder.finish().expect("Build rounded rectangle path") } +fn maybe_line_to(path: &mut tiny_skia::PathBuilder, x: f32, y: f32) { + if path.last_point() != Some(tiny_skia::Point { x, y }) { + path.line_to(x, y); + } +} + +fn arc_to( + path: &mut tiny_skia::PathBuilder, + x_from: f32, + y_from: f32, + x_to: f32, + y_to: f32, + radius: f32, +) { + let svg_arc = kurbo::SvgArc { + from: kurbo::Point::new(f64::from(x_from), f64::from(y_from)), + to: kurbo::Point::new(f64::from(x_to), f64::from(y_to)), + radii: kurbo::Vec2::new(f64::from(radius), f64::from(radius)), + x_rotation: 0.0, + large_arc: false, + sweep: true, + }; + + match kurbo::Arc::from_svg_arc(&svg_arc) { + Some(arc) => { + arc.to_cubic_beziers(0.1, |p1, p2, p| { + path.cubic_to( + p1.x as f32, + p1.y as f32, + p2.x as f32, + p2.y as f32, + p.x as f32, + p.y as f32, + ); + }); + } + None => { + path.line_to(x_to as f32, y_to as f32); + } + } +} + fn rectangular_clip_mask( pixels: &tiny_skia::PixmapMut<'_>, bounds: Rectangle, -- cgit From 8750d83337041f1d0fac8c2c0f4c40fd3a051a2c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 27 Feb 2023 03:02:13 +0100 Subject: Short-circuit rectangle path building in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 38a6c51d..d0977462 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -221,6 +221,22 @@ fn rounded_rectangle( ) -> tiny_skia::Path { let [top_left, top_right, bottom_right, bottom_left] = border_radius; + if top_left == 0.0 + && top_right == 0.0 + && bottom_right == 0.0 + && bottom_left == 0.0 + { + return tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ) + .expect("Build quad rectangle"), + ); + } + if top_left == top_right && top_left == bottom_right && top_left == bottom_left -- cgit From 3105ad2e0036e101e66b5e6ab437b570f2d923a3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 27 Feb 2023 03:04:05 +0100 Subject: Remove useless `f32` conversion in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d0977462..66d83221 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -354,7 +354,7 @@ fn arc_to( }); } None => { - path.line_to(x_to as f32, y_to as f32); + path.line_to(x_to, y_to); } } } -- cgit From 5fd5d1cdf8e5354788dc40729c4565ef377d3bba Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Mar 2023 21:34:26 +0100 Subject: Implement `Canvas` support for `iced_tiny_skia` --- tiny_skia/src/backend.rs | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 66d83221..e08cede7 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,9 +1,9 @@ -use crate::{Color, Font, Settings, Size, Viewport}; +use crate::{Color, Font, Primitive, Settings, Size, Viewport}; use iced_graphics::alignment; use iced_graphics::backend; use iced_graphics::text; -use iced_graphics::{Background, Primitive, Rectangle, Vector}; +use iced_graphics::{Background, Rectangle, Vector}; use std::borrow::Cow; @@ -81,7 +81,6 @@ impl Backend { translation: Vector, ) { match primitive { - Primitive::None => {} Primitive::Quad { bounds, background, @@ -161,6 +160,38 @@ impl Backend { Primitive::Svg { .. } => { // TODO } + Primitive::Fill { + path, + paint, + rule, + transform, + } => { + pixels.fill_path( + path, + paint, + *rule, + transform + .post_translate(translation.x, translation.y) + .post_scale(scale_factor, scale_factor), + clip_mask, + ); + } + Primitive::Stroke { + path, + paint, + stroke, + transform, + } => { + pixels.stroke_path( + path, + paint, + stroke, + transform + .post_translate(translation.x, translation.y) + .post_scale(scale_factor, scale_factor), + clip_mask, + ); + } Primitive::Group { primitives } => { for primitive in primitives { self.draw_primitive( @@ -196,16 +227,19 @@ impl Backend { translation, ); } - Primitive::Cached { cache } => { + Primitive::Cache { content } => { self.draw_primitive( - cache, + content, pixels, clip_mask, scale_factor, translation, ); } - Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => {} + Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { + // Not supported! + // TODO: Draw a placeholder (?) / Log it (?) + } } } } @@ -386,6 +420,8 @@ fn rectangular_clip_mask( } impl iced_graphics::Backend for Backend { + type Geometry = (); + fn trim_measurements(&mut self) { self.text_pipeline.trim_measurement_cache(); } -- cgit From 5c0427edbb4358896412c736af2f441c12601d1b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Mar 2023 21:41:32 +0100 Subject: Fix `Clip` primitive translation in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index e08cede7..838426f5 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -221,7 +221,7 @@ impl Backend { pixels, Some(&rectangular_clip_mask( pixels, - *bounds * scale_factor, + (*bounds + translation) * scale_factor, )), scale_factor, translation, -- cgit From 868f79d22e2be82e98b06d66da3b4cbc6139d7c7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 2 Mar 2023 00:40:36 +0100 Subject: Reuse `ClipMask` in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 838426f5..2e4663ea 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -25,6 +25,7 @@ impl Backend { pub fn draw>( &mut self, pixels: &mut tiny_skia::PixmapMut<'_>, + clip_mask: &mut tiny_skia::ClipMask, primitives: &[Primitive], viewport: &Viewport, background_color: Color, @@ -38,6 +39,7 @@ impl Backend { self.draw_primitive( primitive, pixels, + clip_mask, None, scale_factor, Vector::ZERO, @@ -63,6 +65,7 @@ impl Backend { vertical_alignment: alignment::Vertical::Top, }, pixels, + clip_mask, None, scale_factor, Vector::ZERO, @@ -76,7 +79,8 @@ impl Backend { &mut self, primitive: &Primitive, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: Option<&tiny_skia::ClipMask>, + clip_mask: &mut tiny_skia::ClipMask, + clip_bounds: Option, scale_factor: f32, translation: Vector, ) { @@ -95,6 +99,7 @@ impl Backend { .post_scale(scale_factor, scale_factor); let path = rounded_rectangle(*bounds, *border_radius); + let clip_mask = clip_bounds.map(|_| clip_mask as &_); pixels.fill_path( &path, @@ -151,7 +156,7 @@ impl Backend { *horizontal_alignment, *vertical_alignment, pixels, - clip_mask, + clip_bounds.map(|_| clip_mask as &_), ); } Primitive::Image { .. } => { @@ -173,7 +178,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - clip_mask, + clip_bounds.map(|_| clip_mask as &_), ); } Primitive::Stroke { @@ -189,7 +194,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - clip_mask, + clip_bounds.map(|_| clip_mask as &_), ); } Primitive::Group { primitives } => { @@ -198,6 +203,7 @@ impl Backend { primitive, pixels, clip_mask, + clip_bounds, scale_factor, translation, ); @@ -211,27 +217,37 @@ impl Backend { content, pixels, clip_mask, + clip_bounds, scale_factor, translation + *offset, ); } Primitive::Clip { bounds, content } => { + let bounds = (*bounds + translation) * scale_factor; + + adjust_clip_mask(clip_mask, pixels, bounds); + self.draw_primitive( content, pixels, - Some(&rectangular_clip_mask( - pixels, - (*bounds + translation) * scale_factor, - )), + clip_mask, + Some(bounds), scale_factor, translation, ); + + if let Some(bounds) = clip_bounds { + adjust_clip_mask(clip_mask, pixels, bounds); + } else { + clip_mask.clear(); + } } Primitive::Cache { content } => { self.draw_primitive( content, pixels, clip_mask, + clip_bounds, scale_factor, translation, ); @@ -393,12 +409,11 @@ fn arc_to( } } -fn rectangular_clip_mask( +fn adjust_clip_mask( + clip_mask: &mut tiny_skia::ClipMask, pixels: &tiny_skia::PixmapMut<'_>, bounds: Rectangle, -) -> tiny_skia::ClipMask { - let mut clip_mask = tiny_skia::ClipMask::new(); - +) { let path = { let mut builder = tiny_skia::PathBuilder::new(); builder.push_rect(bounds.x, bounds.y, bounds.width, bounds.height); @@ -415,8 +430,6 @@ fn rectangular_clip_mask( true, ) .expect("Set path of clipping area"); - - clip_mask } impl iced_graphics::Backend for Backend { -- cgit From d13d19ba3569560edd67f20b48f37548d10ceee9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 Mar 2023 04:00:44 +0100 Subject: Rename `canvas::frame` to `canvas` in `iced_wgpu` --- tiny_skia/src/backend.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 2e4663ea..6883a953 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -256,6 +256,9 @@ impl Backend { // Not supported! // TODO: Draw a placeholder (?) / Log it (?) } + _ => { + // Not supported! + } } } } -- cgit From 6cc48b5c62bac287b8f9f1c79c1fb7486c51b18f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 Mar 2023 04:57:55 +0100 Subject: Move `Canvas` and `QRCode` to `iced` crate Rename `canvas` modules to `geometry` in graphics subcrates --- tiny_skia/src/backend.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 6883a953..050c6c75 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -436,8 +436,6 @@ fn adjust_clip_mask( } impl iced_graphics::Backend for Backend { - type Geometry = (); - fn trim_measurements(&mut self) { self.text_pipeline.trim_measurement_cache(); } -- cgit From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- tiny_skia/src/backend.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 050c6c75..d364e36a 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,9 +1,9 @@ -use crate::{Color, Font, Primitive, Settings, Size, Viewport}; - -use iced_graphics::alignment; -use iced_graphics::backend; -use iced_graphics::text; -use iced_graphics::{Background, Rectangle, Vector}; +use crate::core::alignment; +use crate::core::text; +use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; +use crate::graphics::backend; +use crate::graphics::{Primitive, Viewport}; +use crate::Settings; use std::borrow::Cow; @@ -470,7 +470,7 @@ impl backend::Text for Backend { size: f32, font: Font, bounds: Size, - point: iced_native::Point, + point: Point, nearest_only: bool, ) -> Option { self.text_pipeline.hit_test( @@ -490,7 +490,7 @@ impl backend::Text for Backend { #[cfg(feature = "image")] impl backend::Image for Backend { - fn dimensions(&self, _handle: &iced_native::image::Handle) -> Size { + fn dimensions(&self, _handle: &crate::core::image::Handle) -> Size { // TODO Size::new(0, 0) } @@ -500,7 +500,7 @@ impl backend::Image for Backend { impl backend::Svg for Backend { fn viewport_dimensions( &self, - _handle: &iced_native::svg::Handle, + _handle: &crate::core::svg::Handle, ) -> Size { // TODO Size::new(0, 0) -- cgit From bb49e17cabd45f3a21af98b4c5ecdddd507fd427 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Mar 2023 05:06:26 +0100 Subject: Implement `raster` pipeline in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d364e36a..d894ab95 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -11,6 +11,9 @@ pub struct Backend { default_font: Font, default_text_size: f32, text_pipeline: crate::text::Pipeline, + + #[cfg(feature = "image")] + raster_pipeline: crate::raster::Pipeline, } impl Backend { @@ -19,6 +22,9 @@ impl Backend { default_font: settings.default_font, default_text_size: settings.default_text_size, text_pipeline: crate::text::Pipeline::new(), + + #[cfg(feature = "image")] + raster_pipeline: crate::raster::Pipeline::new(), } } @@ -159,8 +165,21 @@ impl Backend { clip_bounds.map(|_| clip_mask as &_), ); } - Primitive::Image { .. } => { - // TODO + #[cfg(feature = "image")] + Primitive::Image { handle, bounds } => { + let transform = tiny_skia::Transform::from_translate( + translation.x, + translation.y, + ) + .post_scale(scale_factor, scale_factor); + + self.raster_pipeline.draw( + handle, + *bounds, + pixels, + transform, + clip_bounds.map(|_| clip_mask as &_), + ); } Primitive::Svg { .. } => { // TODO @@ -490,9 +509,8 @@ impl backend::Text for Backend { #[cfg(feature = "image")] impl backend::Image for Backend { - fn dimensions(&self, _handle: &crate::core::image::Handle) -> Size { - // TODO - Size::new(0, 0) + fn dimensions(&self, handle: &crate::core::image::Handle) -> Size { + self.raster_pipeline.dimensions(handle) } } -- cgit From 5b3977daf6df624ca5d5e1a21ce282161234b22d Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Mar 2023 06:09:51 +0100 Subject: Implement `vector` pipeline in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d894ab95..3c2a97b9 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -14,6 +14,9 @@ pub struct Backend { #[cfg(feature = "image")] raster_pipeline: crate::raster::Pipeline, + + #[cfg(feature = "svg")] + vector_pipeline: crate::vector::Pipeline, } impl Backend { @@ -25,6 +28,9 @@ impl Backend { #[cfg(feature = "image")] raster_pipeline: crate::raster::Pipeline::new(), + + #[cfg(feature = "svg")] + vector_pipeline: crate::vector::Pipeline::new(), } } @@ -78,7 +84,10 @@ impl Backend { ); } - self.text_pipeline.end_frame(); + self.text_pipeline.trim_cache(); + + #[cfg(feature = "svg")] + self.vector_pipeline.trim_cache(); } fn draw_primitive( @@ -181,8 +190,18 @@ impl Backend { clip_bounds.map(|_| clip_mask as &_), ); } - Primitive::Svg { .. } => { - // TODO + #[cfg(feature = "svg")] + Primitive::Svg { + handle, + bounds, + color: _, // TODO: Implement color filter + } => { + self.vector_pipeline.draw( + handle, + (*bounds + translation) * scale_factor, + pixels, + clip_bounds.map(|_| clip_mask as &_), + ); } Primitive::Fill { path, @@ -518,9 +537,8 @@ impl backend::Image for Backend { impl backend::Svg for Backend { fn viewport_dimensions( &self, - _handle: &crate::core::svg::Handle, + handle: &crate::core::svg::Handle, ) -> Size { - // TODO - Size::new(0, 0) + self.vector_pipeline.viewport_dimensions(handle) } } -- cgit From a8d55ceb829377725b4e7632702894fed6867eda Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 7 Mar 2023 06:15:05 +0100 Subject: Trim `raster` cache in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 3c2a97b9..b3c7d2bc 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -86,6 +86,9 @@ impl Backend { self.text_pipeline.trim_cache(); + #[cfg(feature = "image")] + self.raster_pipeline.trim_cache(); + #[cfg(feature = "svg")] self.vector_pipeline.trim_cache(); } -- cgit From 424ac8177309440bbd8efe0dd9f7622cb10807ce Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 9 Mar 2023 04:48:35 +0100 Subject: Implement color filter support for `Primitive::Svg` in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index b3c7d2bc..ba063f4e 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -197,10 +197,11 @@ impl Backend { Primitive::Svg { handle, bounds, - color: _, // TODO: Implement color filter + color, } => { self.vector_pipeline.draw( handle, + *color, (*bounds + translation) * scale_factor, pixels, clip_bounds.map(|_| clip_mask as &_), -- cgit From c8f637fc16099c70836574425a6df20a3e2fa801 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 17 Mar 2023 19:35:57 +0100 Subject: Fix panic rendering an out of bounds clip in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index ba063f4e..271d026f 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -267,6 +267,14 @@ impl Backend { Primitive::Clip { bounds, content } => { let bounds = (*bounds + translation) * scale_factor; + if bounds.x + bounds.width <= 0.0 + || bounds.y + bounds.height <= 0.0 + || bounds.x as u32 >= pixels.width() + || bounds.y as u32 >= pixels.height() + { + return; + } + adjust_clip_mask(clip_mask, pixels, bounds); self.draw_primitive( -- cgit From 707de9d788dc3c49d4ac57a19afac1bb938b78d9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 30 Mar 2023 00:56:00 +0200 Subject: Introduce support for `Font` attributes --- tiny_skia/src/backend.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 271d026f..58076b84 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -72,7 +72,7 @@ impl Backend { height: f32::INFINITY, }, color: Color::BLACK, - font: Font::Monospace, + font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, }, @@ -492,7 +492,7 @@ impl iced_graphics::Backend for Backend { } impl backend::Text for Backend { - const ICON_FONT: Font = Font::Name("Iced-Icons"); + const ICON_FONT: Font = Font::with_name("Iced-Icons"); const CHECKMARK_ICON: char = '\u{f00c}'; const ARROW_DOWN_ICON: char = '\u{e800}'; -- cgit From 0f7abffc0e94b4bb9f8117db633bfd07d900eb93 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 22 Mar 2023 00:36:57 +0100 Subject: Draft (very) basic incremental rendering for `iced_tiny_skia` --- tiny_skia/src/backend.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 58076b84..fe84f83b 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -17,6 +17,9 @@ pub struct Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline, + + last_primitives: Vec, + last_background_color: Color, } impl Backend { @@ -31,6 +34,9 @@ impl Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline::new(), + + last_primitives: Vec::new(), + last_background_color: Color::BLACK, } } @@ -43,10 +49,48 @@ impl Backend { background_color: Color, overlay: &[T], ) { - pixels.fill(into_color(background_color)); + let damage = if self.last_background_color == background_color { + Primitive::damage_list(&self.last_primitives, primitives) + } else { + vec![Rectangle::with_size(viewport.logical_size())] + }; + + if damage.is_empty() { + return; + } + + self.last_primitives = primitives.to_vec(); + self.last_background_color = background_color; let scale_factor = viewport.scale_factor() as f32; + dbg!(&damage); + + for region in &damage { + let region = *region * scale_factor; + + pixels.fill_path( + &tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + region.x, + region.y, + region.width.min(viewport.physical_width() as f32), + region.height.min(viewport.physical_height() as f32), + ) + .expect("Create damage rectangle"), + ), + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + background_color, + )), + ..Default::default() + }, + tiny_skia::FillRule::default(), + tiny_skia::Transform::identity(), + None, + ); + } + for primitive in primitives { self.draw_primitive( primitive, @@ -55,6 +99,7 @@ impl Backend { None, scale_factor, Vector::ZERO, + &damage, ); } @@ -81,6 +126,7 @@ impl Backend { None, scale_factor, Vector::ZERO, + &[], ); } @@ -101,6 +147,7 @@ impl Backend { clip_bounds: Option, scale_factor: f32, translation: Vector, + damage: &[Rectangle], ) { match primitive { Primitive::Quad { @@ -110,6 +157,10 @@ impl Backend { border_width, border_color, } => { + if !damage.iter().any(|damage| damage.intersects(bounds)) { + return; + } + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, @@ -165,6 +216,13 @@ impl Backend { horizontal_alignment, vertical_alignment, } => { + if !damage + .iter() + .any(|damage| damage.intersects(&primitive.bounds())) + { + return; + } + self.text_pipeline.draw( content, (*bounds + translation) * scale_factor, @@ -179,6 +237,10 @@ impl Backend { } #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { + if !damage.iter().any(|damage| damage.intersects(bounds)) { + return; + } + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, @@ -248,6 +310,7 @@ impl Backend { clip_bounds, scale_factor, translation, + damage, ); } } @@ -262,6 +325,7 @@ impl Backend { clip_bounds, scale_factor, translation + *offset, + damage, ); } Primitive::Clip { bounds, content } => { @@ -284,6 +348,7 @@ impl Backend { Some(bounds), scale_factor, translation, + damage, ); if let Some(bounds) = clip_bounds { @@ -300,6 +365,7 @@ impl Backend { clip_bounds, scale_factor, translation, + damage, ); } Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { -- cgit From 6270c33ed9823c67f6b6e6dac8fd32521e4ac5a9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 4 Apr 2023 20:47:53 +0200 Subject: Keep playing with incremental rendering (still very slow) --- tiny_skia/src/backend.rs | 232 ++++++++++++++++++++++++++++++----------------- 1 file changed, 150 insertions(+), 82 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index fe84f83b..8101082a 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -20,6 +20,7 @@ pub struct Backend { last_primitives: Vec, last_background_color: Color, + last_size: Size, } impl Backend { @@ -37,6 +38,7 @@ impl Backend { last_primitives: Vec::new(), last_background_color: Color::BLACK, + last_size: Size::new(0, 0), } } @@ -47,9 +49,13 @@ impl Backend { primitives: &[Primitive], viewport: &Viewport, background_color: Color, - overlay: &[T], + _overlay: &[T], ) { - let damage = if self.last_background_color == background_color { + let physical_size = viewport.physical_size(); + + let damage = if self.last_background_color == background_color + && self.last_size == physical_size + { Primitive::damage_list(&self.last_primitives, primitives) } else { vec![Rectangle::with_size(viewport.logical_size())] @@ -61,24 +67,46 @@ impl Backend { self.last_primitives = primitives.to_vec(); self.last_background_color = background_color; + self.last_size = physical_size; let scale_factor = viewport.scale_factor() as f32; + let physical_bounds = Rectangle { + x: 0.0, + y: 0.0, + width: physical_size.width as f32, + height: physical_size.height as f32, + }; - dbg!(&damage); + dbg!(damage.len()); + + 'draw_regions: for (i, region) in damage.iter().enumerate() { + for previous in damage.iter().take(i) { + if previous.contains(region.position()) + && previous.contains( + region.position() + + Vector::new(region.width, region.height), + ) + { + continue 'draw_regions; + } + } - for region in &damage { let region = *region * scale_factor; + let Some(region) = physical_bounds.intersection(®ion) else { continue }; + + let path = tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + region.x, + region.y, + region.width.min(viewport.physical_width() as f32), + region.height.min(viewport.physical_height() as f32), + ) + .expect("Create damage rectangle"), + ); + pixels.fill_path( - &tiny_skia::PathBuilder::from_rect( - tiny_skia::Rect::from_xywh( - region.x, - region.y, - region.width.min(viewport.physical_width() as f32), - region.height.min(viewport.physical_height() as f32), - ) - .expect("Create damage rectangle"), - ), + &path, &tiny_skia::Paint { shader: tiny_skia::Shader::SolidColor(into_color( background_color, @@ -89,47 +117,64 @@ impl Backend { tiny_skia::Transform::identity(), None, ); - } - for primitive in primitives { - self.draw_primitive( - primitive, - pixels, - clip_mask, - None, - scale_factor, - Vector::ZERO, - &damage, - ); - } + adjust_clip_mask(clip_mask, pixels, region); - for (i, text) in overlay.iter().enumerate() { - const OVERLAY_TEXT_SIZE: f32 = 20.0; - - self.draw_primitive( - &Primitive::Text { - content: text.as_ref().to_owned(), - size: OVERLAY_TEXT_SIZE, - bounds: Rectangle { - x: 10.0, - y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - width: f32::INFINITY, - height: f32::INFINITY, - }, - color: Color::BLACK, - font: Font::MONOSPACE, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, - }, - pixels, - clip_mask, - None, - scale_factor, - Vector::ZERO, - &[], - ); + for primitive in primitives { + self.draw_primitive( + primitive, + pixels, + clip_mask, + region, + scale_factor, + Vector::ZERO, + ); + } + + //pixels.stroke_path( + // &path, + // &tiny_skia::Paint { + // shader: tiny_skia::Shader::SolidColor(into_color( + // Color::from_rgb(1.0, 0.0, 0.0), + // )), + // anti_alias: true, + // ..tiny_skia::Paint::default() + // }, + // &tiny_skia::Stroke { + // width: 1.0, + // ..tiny_skia::Stroke::default() + // }, + // tiny_skia::Transform::identity(), + // None, + //); } + //for (i, text) in overlay.iter().enumerate() { + // const OVERLAY_TEXT_SIZE: f32 = 20.0; + + // self.draw_primitive( + // &Primitive::Text { + // content: text.as_ref().to_owned(), + // size: OVERLAY_TEXT_SIZE, + // bounds: Rectangle { + // x: 10.0, + // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + // width: f32::INFINITY, + // height: f32::INFINITY, + // }, + // color: Color::BLACK, + // font: Font::MONOSPACE, + // horizontal_alignment: alignment::Horizontal::Left, + // vertical_alignment: alignment::Vertical::Top, + // }, + // pixels, + // clip_mask, + // Rectangle::EMPTY, + // scale_factor, + // Vector::ZERO, + // ); + //} + self.text_pipeline.trim_cache(); #[cfg(feature = "image")] @@ -144,10 +189,9 @@ impl Backend { primitive: &Primitive, pixels: &mut tiny_skia::PixmapMut<'_>, clip_mask: &mut tiny_skia::ClipMask, - clip_bounds: Option, + clip_bounds: Rectangle, scale_factor: f32, translation: Vector, - damage: &[Rectangle], ) { match primitive { Primitive::Quad { @@ -157,7 +201,9 @@ impl Backend { border_width, border_color, } => { - if !damage.iter().any(|damage| damage.intersects(bounds)) { + if !clip_bounds + .intersects(&((*bounds + translation) * scale_factor)) + { return; } @@ -168,7 +214,6 @@ impl Backend { .post_scale(scale_factor, scale_factor); let path = rounded_rectangle(*bounds, *border_radius); - let clip_mask = clip_bounds.map(|_| clip_mask as &_); pixels.fill_path( &path, @@ -185,7 +230,7 @@ impl Backend { }, tiny_skia::FillRule::EvenOdd, transform, - clip_mask, + Some(clip_mask), ); if *border_width > 0.0 { @@ -203,7 +248,7 @@ impl Backend { ..tiny_skia::Stroke::default() }, transform, - clip_mask, + Some(clip_mask), ); } } @@ -216,10 +261,9 @@ impl Backend { horizontal_alignment, vertical_alignment, } => { - if !damage - .iter() - .any(|damage| damage.intersects(&primitive.bounds())) - { + if !clip_bounds.intersects( + &((primitive.bounds() + translation) * scale_factor), + ) { return; } @@ -232,12 +276,14 @@ impl Backend { *horizontal_alignment, *vertical_alignment, pixels, - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { - if !damage.iter().any(|damage| damage.intersects(bounds)) { + if !clip_bounds + .intersects(&((*bounds + translation) * scale_factor)) + { return; } @@ -252,7 +298,7 @@ impl Backend { *bounds, pixels, transform, - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } #[cfg(feature = "svg")] @@ -275,6 +321,20 @@ impl Backend { rule, transform, } => { + let bounds = path.bounds(); + + if !clip_bounds.intersects( + &((Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor), + ) { + return; + } + pixels.fill_path( path, paint, @@ -282,7 +342,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } Primitive::Stroke { @@ -291,6 +351,20 @@ impl Backend { stroke, transform, } => { + let bounds = path.bounds(); + + if !clip_bounds.intersects( + &((Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor), + ) { + return; + } + pixels.stroke_path( path, paint, @@ -298,7 +372,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - clip_bounds.map(|_| clip_mask as &_), + Some(clip_mask), ); } Primitive::Group { primitives } => { @@ -310,7 +384,6 @@ impl Backend { clip_bounds, scale_factor, translation, - damage, ); } } @@ -325,7 +398,6 @@ impl Backend { clip_bounds, scale_factor, translation + *offset, - damage, ); } Primitive::Clip { bounds, content } => { @@ -339,22 +411,19 @@ impl Backend { return; } - adjust_clip_mask(clip_mask, pixels, bounds); + if let Some(bounds) = clip_bounds.intersection(&bounds) { + adjust_clip_mask(clip_mask, pixels, bounds); - self.draw_primitive( - content, - pixels, - clip_mask, - Some(bounds), - scale_factor, - translation, - damage, - ); + self.draw_primitive( + content, + pixels, + clip_mask, + bounds, + scale_factor, + translation, + ); - if let Some(bounds) = clip_bounds { - adjust_clip_mask(clip_mask, pixels, bounds); - } else { - clip_mask.clear(); + adjust_clip_mask(clip_mask, pixels, clip_bounds); } } Primitive::Cache { content } => { @@ -365,7 +434,6 @@ impl Backend { clip_bounds, scale_factor, translation, - damage, ); } Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { -- cgit From f8cd1faa286daaf34cc532bf6d34b932b32eb35a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 04:10:00 +0200 Subject: Group damage regions by area increase --- tiny_skia/src/backend.rs | 275 +++++++++++++++++++++++++++++------------------ 1 file changed, 171 insertions(+), 104 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 8101082a..b1417409 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -49,7 +49,7 @@ impl Backend { primitives: &[Primitive], viewport: &Viewport, background_color: Color, - _overlay: &[T], + overlay: &[T], ) { let physical_size = viewport.physical_size(); @@ -70,37 +70,20 @@ impl Backend { self.last_size = physical_size; let scale_factor = viewport.scale_factor() as f32; - let physical_bounds = Rectangle { - x: 0.0, - y: 0.0, - width: physical_size.width as f32, - height: physical_size.height as f32, - }; - - dbg!(damage.len()); - 'draw_regions: for (i, region) in damage.iter().enumerate() { - for previous in damage.iter().take(i) { - if previous.contains(region.position()) - && previous.contains( - region.position() - + Vector::new(region.width, region.height), - ) - { - continue 'draw_regions; - } - } + let damage = group_damage(damage, scale_factor, physical_size); - let region = *region * scale_factor; - - let Some(region) = physical_bounds.intersection(®ion) else { continue }; + if !overlay.is_empty() { + pixels.fill(into_color(background_color)); + } + for region in damage { let path = tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh( region.x, region.y, - region.width.min(viewport.physical_width() as f32), - region.height.min(viewport.physical_height() as f32), + region.width, + region.height, ) .expect("Create damage rectangle"), ); @@ -111,6 +94,7 @@ impl Backend { shader: tiny_skia::Shader::SolidColor(into_color( background_color, )), + anti_alias: false, ..Default::default() }, tiny_skia::FillRule::default(), @@ -131,49 +115,62 @@ impl Backend { ); } - //pixels.stroke_path( - // &path, - // &tiny_skia::Paint { - // shader: tiny_skia::Shader::SolidColor(into_color( - // Color::from_rgb(1.0, 0.0, 0.0), - // )), - // anti_alias: true, - // ..tiny_skia::Paint::default() - // }, - // &tiny_skia::Stroke { - // width: 1.0, - // ..tiny_skia::Stroke::default() - // }, - // tiny_skia::Transform::identity(), - // None, - //); + if !overlay.is_empty() { + pixels.stroke_path( + &path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + Color::from_rgb(1.0, 0.0, 0.0), + )), + anti_alias: false, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: 1.0, + ..tiny_skia::Stroke::default() + }, + tiny_skia::Transform::identity(), + None, + ); + } } - //for (i, text) in overlay.iter().enumerate() { - // const OVERLAY_TEXT_SIZE: f32 = 20.0; - - // self.draw_primitive( - // &Primitive::Text { - // content: text.as_ref().to_owned(), - // size: OVERLAY_TEXT_SIZE, - // bounds: Rectangle { - // x: 10.0, - // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - // width: f32::INFINITY, - // height: f32::INFINITY, - // }, - // color: Color::BLACK, - // font: Font::MONOSPACE, - // horizontal_alignment: alignment::Horizontal::Left, - // vertical_alignment: alignment::Vertical::Top, - // }, - // pixels, - // clip_mask, - // Rectangle::EMPTY, - // scale_factor, - // Vector::ZERO, - // ); - //} + if !overlay.is_empty() { + let bounds = Rectangle { + x: 0.0, + y: 0.0, + width: viewport.physical_width() as f32, + height: viewport.physical_height() as f32, + }; + + adjust_clip_mask(clip_mask, pixels, bounds); + + for (i, text) in overlay.iter().enumerate() { + const OVERLAY_TEXT_SIZE: f32 = 20.0; + + self.draw_primitive( + &Primitive::Text { + content: text.as_ref().to_owned(), + size: OVERLAY_TEXT_SIZE, + bounds: Rectangle { + x: 10.0, + y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + width: bounds.width - 1.0, + height: bounds.height - 1.0, + }, + color: Color::BLACK, + font: Font::MONOSPACE, + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + }, + pixels, + clip_mask, + bounds, + scale_factor, + Vector::ZERO, + ); + } + } self.text_pipeline.trim_cache(); @@ -201,12 +198,15 @@ impl Backend { border_width, border_color, } => { - if !clip_bounds - .intersects(&((*bounds + translation) * scale_factor)) - { + let physical_bounds = (*bounds + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, @@ -230,7 +230,7 @@ impl Backend { }, tiny_skia::FillRule::EvenOdd, transform, - Some(clip_mask), + clip_mask, ); if *border_width > 0.0 { @@ -248,7 +248,7 @@ impl Backend { ..tiny_skia::Stroke::default() }, transform, - Some(clip_mask), + clip_mask, ); } } @@ -261,12 +261,16 @@ impl Backend { horizontal_alignment, vertical_alignment, } => { - if !clip_bounds.intersects( - &((primitive.bounds() + translation) * scale_factor), - ) { + let physical_bounds = + (primitive.bounds() + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + self.text_pipeline.draw( content, (*bounds + translation) * scale_factor, @@ -276,7 +280,7 @@ impl Backend { *horizontal_alignment, *vertical_alignment, pixels, - Some(clip_mask), + clip_mask, ); } #[cfg(feature = "image")] @@ -323,18 +327,21 @@ impl Backend { } => { let bounds = path.bounds(); - if !clip_bounds.intersects( - &((Rectangle { - x: bounds.x(), - y: bounds.y(), - width: bounds.width(), - height: bounds.height(), - } + translation) - * scale_factor), - ) { + let physical_bounds = (Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + pixels.fill_path( path, paint, @@ -342,7 +349,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - Some(clip_mask), + clip_mask, ); } Primitive::Stroke { @@ -353,18 +360,21 @@ impl Backend { } => { let bounds = path.bounds(); - if !clip_bounds.intersects( - &((Rectangle { - x: bounds.x(), - y: bounds.y(), - width: bounds.width(), - height: bounds.height(), - } + translation) - * scale_factor), - ) { + let physical_bounds = (Rectangle { + x: bounds.x(), + y: bounds.y(), + width: bounds.width(), + height: bounds.height(), + } + translation) + * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then(|| clip_mask as &_); + pixels.stroke_path( path, paint, @@ -372,7 +382,7 @@ impl Backend { transform .post_translate(translation.x, translation.y) .post_scale(scale_factor, scale_factor), - Some(clip_mask), + clip_mask, ); } Primitive::Group { primitives } => { @@ -403,15 +413,26 @@ impl Backend { Primitive::Clip { bounds, content } => { let bounds = (*bounds + translation) * scale_factor; - if bounds.x + bounds.width <= 0.0 - || bounds.y + bounds.height <= 0.0 - || bounds.x as u32 >= pixels.width() - || bounds.y as u32 >= pixels.height() - { - return; - } + if bounds == clip_bounds { + self.draw_primitive( + content, + pixels, + clip_mask, + bounds, + scale_factor, + translation, + ); + } else if let Some(bounds) = clip_bounds.intersection(&bounds) { + if bounds.x + bounds.width <= 0.0 + || bounds.y + bounds.height <= 0.0 + || bounds.x as u32 >= pixels.width() + || bounds.y as u32 >= pixels.height() + || bounds.width <= 1.0 + || bounds.height <= 1.0 + { + return; + } - if let Some(bounds) = clip_bounds.intersection(&bounds) { adjust_clip_mask(clip_mask, pixels, bounds); self.draw_primitive( @@ -614,11 +635,57 @@ fn adjust_clip_mask( pixels.height(), &path, tiny_skia::FillRule::EvenOdd, - true, + false, ) .expect("Set path of clipping area"); } +fn group_damage( + mut damage: Vec, + scale_factor: f32, + bounds: Size, +) -> Vec { + use std::cmp::Ordering; + + const AREA_THRESHOLD: f32 = 20_000.0; + + let bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width as f32, + height: bounds.height as f32, + }; + + damage.sort_by(|a, b| { + a.x.partial_cmp(&b.x) + .unwrap_or(Ordering::Equal) + .then_with(|| a.y.partial_cmp(&b.y).unwrap_or(Ordering::Equal)) + }); + + let mut output = Vec::new(); + let mut scaled = damage + .into_iter() + .filter_map(|region| (region * scale_factor).intersection(&bounds)) + .filter(|region| region.width >= 1.0 && region.height >= 1.0); + + if let Some(mut current) = scaled.next() { + for region in scaled { + let union = current.union(®ion); + + if union.area() - current.area() - region.area() <= AREA_THRESHOLD { + current = union; + } else { + output.push(current); + current = region; + } + } + + output.push(current); + } + + output +} + impl iced_graphics::Backend for Backend { fn trim_measurements(&mut self) { self.text_pipeline.trim_measurement_cache(); -- cgit From 1bba9a080f796276d5da87bf8decd2ed89ef218a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 05:49:30 +0200 Subject: Fix `Svg` and `Image` primitives in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index b1417409..8bc2321c 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -205,7 +205,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); let transform = tiny_skia::Transform::from_translate( translation.x, @@ -269,7 +269,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); self.text_pipeline.draw( content, @@ -285,25 +285,23 @@ impl Backend { } #[cfg(feature = "image")] Primitive::Image { handle, bounds } => { - if !clip_bounds - .intersects(&((*bounds + translation) * scale_factor)) - { + let physical_bounds = (*bounds + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { return; } + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then_some(clip_mask as &_); + let transform = tiny_skia::Transform::from_translate( translation.x, translation.y, ) .post_scale(scale_factor, scale_factor); - self.raster_pipeline.draw( - handle, - *bounds, - pixels, - transform, - Some(clip_mask), - ); + self.raster_pipeline + .draw(handle, *bounds, pixels, transform, clip_mask); } #[cfg(feature = "svg")] Primitive::Svg { @@ -311,12 +309,21 @@ impl Backend { bounds, color, } => { + let physical_bounds = (*bounds + translation) * scale_factor; + + if !clip_bounds.intersects(&physical_bounds) { + return; + } + + let clip_mask = (!physical_bounds.is_within(&clip_bounds)) + .then_some(clip_mask as &_); + self.vector_pipeline.draw( handle, *color, (*bounds + translation) * scale_factor, pixels, - clip_bounds.map(|_| clip_mask as &_), + clip_mask, ); } Primitive::Fill { @@ -340,7 +347,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); pixels.fill_path( path, @@ -373,7 +380,7 @@ impl Backend { } let clip_mask = (!physical_bounds.is_within(&clip_bounds)) - .then(|| clip_mask as &_); + .then_some(clip_mask as &_); pixels.stroke_path( path, -- cgit From 4ede482ab5ff6364237f5f4626784075045d5dfb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 18:41:40 +0200 Subject: Present new frame only when damaged in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 8bc2321c..0b534bba 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -50,7 +50,7 @@ impl Backend { viewport: &Viewport, background_color: Color, overlay: &[T], - ) { + ) -> bool { let physical_size = viewport.physical_size(); let damage = if self.last_background_color == background_color @@ -62,7 +62,7 @@ impl Backend { }; if damage.is_empty() { - return; + return false; } self.last_primitives = primitives.to_vec(); @@ -179,6 +179,8 @@ impl Backend { #[cfg(feature = "svg")] self.vector_pipeline.trim_cache(); + + true } fn draw_primitive( -- cgit From e134a82f4ca67346fc9095a0d488122737cfb0d8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 5 Apr 2023 18:42:27 +0200 Subject: Switch debug mode to fade old primitives and display damage in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 97 ++++++++++++++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 37 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 0b534bba..974faa74 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -74,7 +74,30 @@ impl Backend { let damage = group_damage(damage, scale_factor, physical_size); if !overlay.is_empty() { - pixels.fill(into_color(background_color)); + let path = tiny_skia::PathBuilder::from_rect( + tiny_skia::Rect::from_xywh( + 0.0, + 0.0, + physical_size.width as f32, + physical_size.height as f32, + ) + .expect("Create damage rectangle"), + ); + + pixels.fill_path( + &path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color(Color { + a: 0.1, + ..background_color + })), + anti_alias: false, + ..Default::default() + }, + tiny_skia::FillRule::default(), + tiny_skia::Transform::identity(), + None, + ); } for region in damage { @@ -135,42 +158,42 @@ impl Backend { } } - if !overlay.is_empty() { - let bounds = Rectangle { - x: 0.0, - y: 0.0, - width: viewport.physical_width() as f32, - height: viewport.physical_height() as f32, - }; - - adjust_clip_mask(clip_mask, pixels, bounds); - - for (i, text) in overlay.iter().enumerate() { - const OVERLAY_TEXT_SIZE: f32 = 20.0; - - self.draw_primitive( - &Primitive::Text { - content: text.as_ref().to_owned(), - size: OVERLAY_TEXT_SIZE, - bounds: Rectangle { - x: 10.0, - y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - width: bounds.width - 1.0, - height: bounds.height - 1.0, - }, - color: Color::BLACK, - font: Font::MONOSPACE, - horizontal_alignment: alignment::Horizontal::Left, - vertical_alignment: alignment::Vertical::Top, - }, - pixels, - clip_mask, - bounds, - scale_factor, - Vector::ZERO, - ); - } - } + //if !overlay.is_empty() { + // let bounds = Rectangle { + // x: 0.0, + // y: 0.0, + // width: viewport.physical_width() as f32, + // height: viewport.physical_height() as f32, + // }; + + // adjust_clip_mask(clip_mask, pixels, bounds); + + // for (i, text) in overlay.iter().enumerate() { + // const OVERLAY_TEXT_SIZE: f32 = 20.0; + + // self.draw_primitive( + // &Primitive::Text { + // content: text.as_ref().to_owned(), + // size: OVERLAY_TEXT_SIZE, + // bounds: Rectangle { + // x: 10.0, + // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, + // width: bounds.width - 1.0, + // height: bounds.height - 1.0, + // }, + // color: Color::BLACK, + // font: Font::MONOSPACE, + // horizontal_alignment: alignment::Horizontal::Left, + // vertical_alignment: alignment::Vertical::Top, + // }, + // pixels, + // clip_mask, + // bounds, + // scale_factor, + // Vector::ZERO, + // ); + // } + //} self.text_pipeline.trim_cache(); -- cgit From f0fa5f76cb0b0e451b3fc86b1678403c103867e4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 26 Apr 2023 16:15:53 +0200 Subject: Remove `debug` overlay from `iced_tiny_skia` for now --- tiny_skia/src/backend.rs | 38 -------------------------------------- 1 file changed, 38 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 974faa74..756e46b3 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,4 +1,3 @@ -use crate::core::alignment; use crate::core::text; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; @@ -158,43 +157,6 @@ impl Backend { } } - //if !overlay.is_empty() { - // let bounds = Rectangle { - // x: 0.0, - // y: 0.0, - // width: viewport.physical_width() as f32, - // height: viewport.physical_height() as f32, - // }; - - // adjust_clip_mask(clip_mask, pixels, bounds); - - // for (i, text) in overlay.iter().enumerate() { - // const OVERLAY_TEXT_SIZE: f32 = 20.0; - - // self.draw_primitive( - // &Primitive::Text { - // content: text.as_ref().to_owned(), - // size: OVERLAY_TEXT_SIZE, - // bounds: Rectangle { - // x: 10.0, - // y: 10.0 + i as f32 * OVERLAY_TEXT_SIZE * 1.2, - // width: bounds.width - 1.0, - // height: bounds.height - 1.0, - // }, - // color: Color::BLACK, - // font: Font::MONOSPACE, - // horizontal_alignment: alignment::Horizontal::Left, - // vertical_alignment: alignment::Vertical::Top, - // }, - // pixels, - // clip_mask, - // bounds, - // scale_factor, - // Vector::ZERO, - // ); - // } - //} - self.text_pipeline.trim_cache(); #[cfg(feature = "image")] -- cgit From 9c63eb7df559e58b14188b4096e9bd206444bbf3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 26 Apr 2023 16:46:27 +0200 Subject: Update `tiny-skia` and `resvg` --- tiny_skia/src/backend.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 756e46b3..16a7f9b8 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -44,7 +44,7 @@ impl Backend { pub fn draw>( &mut self, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: &mut tiny_skia::ClipMask, + clip_mask: &mut tiny_skia::Mask, primitives: &[Primitive], viewport: &Viewport, background_color: Color, @@ -124,7 +124,7 @@ impl Backend { None, ); - adjust_clip_mask(clip_mask, pixels, region); + adjust_clip_mask(clip_mask, region); for primitive in primitives { self.draw_primitive( @@ -172,7 +172,7 @@ impl Backend { &mut self, primitive: &Primitive, pixels: &mut tiny_skia::PixmapMut<'_>, - clip_mask: &mut tiny_skia::ClipMask, + clip_mask: &mut tiny_skia::Mask, clip_bounds: Rectangle, scale_factor: f32, translation: Vector, @@ -427,7 +427,7 @@ impl Backend { return; } - adjust_clip_mask(clip_mask, pixels, bounds); + adjust_clip_mask(clip_mask, bounds); self.draw_primitive( content, @@ -438,7 +438,7 @@ impl Backend { translation, ); - adjust_clip_mask(clip_mask, pixels, clip_bounds); + adjust_clip_mask(clip_mask, clip_bounds); } } Primitive::Cache { content } => { @@ -611,11 +611,9 @@ fn arc_to( } } -fn adjust_clip_mask( - clip_mask: &mut tiny_skia::ClipMask, - pixels: &tiny_skia::PixmapMut<'_>, - bounds: Rectangle, -) { +fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { + clip_mask.clear(); + let path = { let mut builder = tiny_skia::PathBuilder::new(); builder.push_rect(bounds.x, bounds.y, bounds.width, bounds.height); @@ -623,15 +621,12 @@ fn adjust_clip_mask( builder.finish().unwrap() }; - clip_mask - .set_path( - pixels.width(), - pixels.height(), - &path, - tiny_skia::FillRule::EvenOdd, - false, - ) - .expect("Set path of clipping area"); + clip_mask.fill_path( + &path, + tiny_skia::FillRule::EvenOdd, + false, + tiny_skia::Transform::default(), + ); } fn group_damage( -- cgit From af0303f95e27737d9de8915f939b60a2bc3282ae Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:10:41 +0200 Subject: Move damage tracking logic to `compositor` in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 80 ++---------------------------------------------- 1 file changed, 3 insertions(+), 77 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 16a7f9b8..9c69e1d2 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -16,10 +16,6 @@ pub struct Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline, - - last_primitives: Vec, - last_background_color: Color, - last_size: Size, } impl Backend { @@ -34,10 +30,6 @@ impl Backend { #[cfg(feature = "svg")] vector_pipeline: crate::vector::Pipeline::new(), - - last_primitives: Vec::new(), - last_background_color: Color::BLACK, - last_size: Size::new(0, 0), } } @@ -47,31 +39,13 @@ impl Backend { clip_mask: &mut tiny_skia::Mask, primitives: &[Primitive], viewport: &Viewport, + damage: &[Rectangle], background_color: Color, overlay: &[T], - ) -> bool { + ) { let physical_size = viewport.physical_size(); - - let damage = if self.last_background_color == background_color - && self.last_size == physical_size - { - Primitive::damage_list(&self.last_primitives, primitives) - } else { - vec![Rectangle::with_size(viewport.logical_size())] - }; - - if damage.is_empty() { - return false; - } - - self.last_primitives = primitives.to_vec(); - self.last_background_color = background_color; - self.last_size = physical_size; - let scale_factor = viewport.scale_factor() as f32; - let damage = group_damage(damage, scale_factor, physical_size); - if !overlay.is_empty() { let path = tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh( @@ -99,7 +73,7 @@ impl Backend { ); } - for region in damage { + for ®ion in damage { let path = tiny_skia::PathBuilder::from_rect( tiny_skia::Rect::from_xywh( region.x, @@ -164,8 +138,6 @@ impl Backend { #[cfg(feature = "svg")] self.vector_pipeline.trim_cache(); - - true } fn draw_primitive( @@ -629,52 +601,6 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { ); } -fn group_damage( - mut damage: Vec, - scale_factor: f32, - bounds: Size, -) -> Vec { - use std::cmp::Ordering; - - const AREA_THRESHOLD: f32 = 20_000.0; - - let bounds = Rectangle { - x: 0.0, - y: 0.0, - width: bounds.width as f32, - height: bounds.height as f32, - }; - - damage.sort_by(|a, b| { - a.x.partial_cmp(&b.x) - .unwrap_or(Ordering::Equal) - .then_with(|| a.y.partial_cmp(&b.y).unwrap_or(Ordering::Equal)) - }); - - let mut output = Vec::new(); - let mut scaled = damage - .into_iter() - .filter_map(|region| (region * scale_factor).intersection(&bounds)) - .filter(|region| region.width >= 1.0 && region.height >= 1.0); - - if let Some(mut current) = scaled.next() { - for region in scaled { - let union = current.union(®ion); - - if union.area() - current.area() - region.area() <= AREA_THRESHOLD { - current = union; - } else { - output.push(current); - current = region; - } - } - - output.push(current); - } - - output -} - impl iced_graphics::Backend for Backend { fn trim_measurements(&mut self) { self.text_pipeline.trim_measurement_cache(); -- cgit From 33b5a900197e2798a393d6d9a0834039666eddbb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 01:19:56 +0200 Subject: Make basic text shaping the default shaping strategy --- tiny_skia/src/backend.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 9c69e1d2..0a06f8c9 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -219,6 +219,7 @@ impl Backend { font, horizontal_alignment, vertical_alignment, + advanced_shape, } => { let physical_bounds = (primitive.bounds() + translation) * scale_factor; @@ -238,6 +239,7 @@ impl Backend { *font, *horizontal_alignment, *vertical_alignment, + *advanced_shape, pixels, clip_mask, ); @@ -626,8 +628,10 @@ impl backend::Text for Backend { size: f32, font: Font, bounds: Size, + advanced_shape: bool, ) -> (f32, f32) { - self.text_pipeline.measure(contents, size, font, bounds) + self.text_pipeline + .measure(contents, size, font, bounds, advanced_shape) } fn hit_test( @@ -638,6 +642,7 @@ impl backend::Text for Backend { bounds: Size, point: Point, nearest_only: bool, + advanced_shape: bool, ) -> Option { self.text_pipeline.hit_test( contents, @@ -646,6 +651,7 @@ impl backend::Text for Backend { bounds, point, nearest_only, + advanced_shape, ) } -- cgit From 4bd290afe7d81d9aaf7467b3ce91491f6600261a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 02:00:45 +0200 Subject: Introduce `text::Shaping` enum and replace magic boolean --- tiny_skia/src/backend.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 0a06f8c9..3ef7e717 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -219,7 +219,7 @@ impl Backend { font, horizontal_alignment, vertical_alignment, - advanced_shape, + shaping, } => { let physical_bounds = (primitive.bounds() + translation) * scale_factor; @@ -239,7 +239,7 @@ impl Backend { *font, *horizontal_alignment, *vertical_alignment, - *advanced_shape, + *shaping, pixels, clip_mask, ); @@ -628,10 +628,10 @@ impl backend::Text for Backend { size: f32, font: Font, bounds: Size, - advanced_shape: bool, + shaping: text::Shaping, ) -> (f32, f32) { self.text_pipeline - .measure(contents, size, font, bounds, advanced_shape) + .measure(contents, size, font, bounds, shaping) } fn hit_test( @@ -640,18 +640,18 @@ impl backend::Text for Backend { size: f32, font: Font, bounds: Size, + shaping: text::Shaping, point: Point, nearest_only: bool, - advanced_shape: bool, ) -> Option { self.text_pipeline.hit_test( contents, size, font, bounds, + shaping, point, nearest_only, - advanced_shape, ) } -- cgit From 9499a8f9e6f9971dedfae563cb133232aa3cebc2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 May 2023 13:00:16 +0200 Subject: Support configurable `LineHeight` in text widgets --- tiny_skia/src/backend.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 3ef7e717..99230a2f 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -216,6 +216,7 @@ impl Backend { bounds, color, size, + line_height, font, horizontal_alignment, vertical_alignment, @@ -233,13 +234,15 @@ impl Backend { self.text_pipeline.draw( content, - (*bounds + translation) * scale_factor, + *bounds + translation, *color, - *size * scale_factor, + *size, + *line_height, *font, *horizontal_alignment, *vertical_alignment, *shaping, + scale_factor, pixels, clip_mask, ); @@ -626,18 +629,26 @@ impl backend::Text for Backend { &self, contents: &str, size: f32, + line_height: text::LineHeight, font: Font, bounds: Size, shaping: text::Shaping, ) -> (f32, f32) { - self.text_pipeline - .measure(contents, size, font, bounds, shaping) + self.text_pipeline.measure( + contents, + size, + line_height, + font, + bounds, + shaping, + ) } fn hit_test( &self, contents: &str, size: f32, + line_height: text::LineHeight, font: Font, bounds: Size, shaping: text::Shaping, @@ -647,6 +658,7 @@ impl backend::Text for Backend { self.text_pipeline.hit_test( contents, size, + line_height, font, bounds, shaping, -- cgit From 2bc4880d0031dca86851cd10b30c197261847e1b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 8 May 2023 14:51:06 +0200 Subject: Warn about unsupported primitives in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 99230a2f..b6adb8ce 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -430,10 +430,18 @@ impl Backend { } Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { // Not supported! - // TODO: Draw a placeholder (?) / Log it (?) + // TODO: Draw a placeholder (?) + log::warn!( + "Unsupported primitive in `iced_tiny_skia`: {:?}", + primitive + ); } _ => { // Not supported! + log::warn!( + "Unsupported primitive in `iced_tiny_skia`: {:?}", + primitive + ); } } } -- cgit From 75439ff96e11fd38b7800f8af65428aacd279a2e Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 9 May 2023 16:23:17 -0400 Subject: fix: border radius typo --- tiny_skia/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index b6adb8ce..d481bacd 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -527,7 +527,7 @@ fn rounded_rectangle( bounds.y + bounds.height, ); - if bottom_right > 0.0 { + if bottom_left > 0.0 { arc_to( &mut builder, bounds.x + bottom_left, -- cgit From 46fc5a7992001ca8de6966d182ab9dba33d6742e Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 10 May 2023 17:48:21 -0400 Subject: fix: quad rendering including border only inside of the bounds --- tiny_skia/src/backend.rs | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d481bacd..58721a80 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -157,6 +157,7 @@ impl Backend { border_width, border_color, } => { + // XXX border seems to be contained by the bounds of the primitive in wgpu and for damage regions, so we do the same here let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -172,7 +173,26 @@ impl Backend { ) .post_scale(scale_factor, scale_factor); - let path = rounded_rectangle(*bounds, *border_radius); + // Make sure the border radius is not larger than the bounds + let border_width = border_width + .min(bounds.width / 2.0) + .min(bounds.height / 2.0); + + // Offset the fill by the border width + let path_bounds = Rectangle { + x: bounds.x + border_width, + y: bounds.y + border_width, + width: bounds.width - 2.0 * border_width, + height: bounds.height - 2.0 * border_width, + }; + // fill border radius is the border radius minus the border width + let mut fill_border_radius = *border_radius; + for radius in &mut fill_border_radius { + *radius = (*radius - border_width / 2.0) + .min(path_bounds.width / 2.0) + .min(path_bounds.height / 2.0); + } + let path = rounded_rectangle(path_bounds, fill_border_radius); pixels.fill_path( &path, @@ -192,9 +212,27 @@ impl Backend { clip_mask, ); - if *border_width > 0.0 { + // border path is offset by half the border width + let path_bounds = Rectangle { + x: bounds.x + border_width / 2.0, + y: bounds.y + border_width / 2.0, + width: bounds.width - border_width, + height: bounds.height - border_width, + }; + + let mut border_radius = *border_radius; + for radius in &mut border_radius { + *radius = radius + .min(path_bounds.width / 2.0) + .min(path_bounds.height / 2.0); + } + + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); + + if border_width > 0.0 { pixels.stroke_path( - &path, + &border_radius_path, &tiny_skia::Paint { shader: tiny_skia::Shader::SolidColor(into_color( *border_color, @@ -203,7 +241,7 @@ impl Backend { ..tiny_skia::Paint::default() }, &tiny_skia::Stroke { - width: *border_width, + width: border_width, ..tiny_skia::Stroke::default() }, transform, -- cgit From 5ee26cc8ec1a49c78d1f3f99ebf6696f827ea5d1 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 11 May 2023 12:25:43 -0400 Subject: fix: don't offset fill of quad --- tiny_skia/src/backend.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 58721a80..583b8dac 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -178,21 +178,13 @@ impl Backend { .min(bounds.width / 2.0) .min(bounds.height / 2.0); - // Offset the fill by the border width - let path_bounds = Rectangle { - x: bounds.x + border_width, - y: bounds.y + border_width, - width: bounds.width - 2.0 * border_width, - height: bounds.height - 2.0 * border_width, - }; - // fill border radius is the border radius minus the border width let mut fill_border_radius = *border_radius; for radius in &mut fill_border_radius { - *radius = (*radius - border_width / 2.0) - .min(path_bounds.width / 2.0) - .min(path_bounds.height / 2.0); + *radius = (*radius) + .min(bounds.width / 2.0) + .min(bounds.height / 2.0); } - let path = rounded_rectangle(path_bounds, fill_border_radius); + let path = rounded_rectangle(*bounds, fill_border_radius); pixels.fill_path( &path, -- cgit From 6551a0b2ab6c831dd1d3646ecf55180339275e22 Mon Sep 17 00:00:00 2001 From: Bingus Date: Thu, 11 May 2023 09:12:06 -0700 Subject: Added support for gradients as background variants + other optimizations. --- tiny_skia/src/backend.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d481bacd..dd1adbd8 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,4 +1,5 @@ use crate::core::text; +use crate::core::Gradient; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; use crate::graphics::{Primitive, Viewport}; @@ -183,6 +184,9 @@ impl Backend { *color, )) } + Background::Gradient(gradient) => { + into_gradient(*gradient, *bounds) + } }, anti_alias: true, ..tiny_skia::Paint::default() @@ -452,6 +456,47 @@ fn into_color(color: Color) -> tiny_skia::Color { .expect("Convert color from iced to tiny_skia") } +fn into_gradient<'a>( + gradient: Gradient, + bounds: Rectangle, +) -> tiny_skia::Shader<'a> { + let Gradient::Linear(linear) = gradient; + let (start, end) = linear.angle.to_distance(&bounds); + let stops: Vec = linear + .color_stops + .into_iter() + .flatten() + .map(|stop| { + tiny_skia::GradientStop::new( + stop.offset, + tiny_skia::Color::from_rgba( + stop.color.b, + stop.color.g, + stop.color.r, + stop.color.a, + ) + .expect("Create color"), + ) + }) + .collect(); + + tiny_skia::LinearGradient::new( + tiny_skia::Point { + x: start.x, + y: start.y, + }, + tiny_skia::Point { x: end.x, y: end.y }, + if stops.is_empty() { + vec![tiny_skia::GradientStop::new(0.0, tiny_skia::Color::BLACK)] + } else { + stops + }, + tiny_skia::SpreadMode::Pad, + tiny_skia::Transform::identity(), + ) + .expect("Create linear gradient") +} + fn rounded_rectangle( bounds: Rectangle, border_radius: [f32; 4], -- cgit From 102c78abd8085d06b72da8edfa83a15ff9df89f2 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 11 May 2023 19:21:36 -0400 Subject: fix: tiny-skia quad handle case where border_radius < border_width / 2.0 --- tiny_skia/src/backend.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 7 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 583b8dac..d0d24b23 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,3 +1,5 @@ +use tiny_skia::{Mask, Pixmap, PixmapPaint}; + use crate::core::text; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; @@ -212,17 +214,29 @@ impl Backend { height: bounds.height - border_width, }; + // Make sure the border radius is correct let mut border_radius = *border_radius; - for radius in &mut border_radius { - *radius = radius - .min(path_bounds.width / 2.0) - .min(path_bounds.height / 2.0); + let mut border_radius_gt_half_border_width = + [true, true, true, true]; + for (i, radius) in &mut border_radius.iter_mut().enumerate() { + *radius = if *radius == 0.0 { + // Path should handle this fine + 0.0 + } else if *radius > border_width / 2.0 { + *radius - border_width / 2.0 + } else { + border_radius_gt_half_border_width[i] = false; + 0.0 + } + .min(path_bounds.width / 2.0) + .min(path_bounds.height / 2.0); } - let border_radius_path = - rounded_rectangle(path_bounds, border_radius); + // Stroking a path works well in this case. + if border_radius_gt_half_border_width.iter().all(|b| *b) { + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); - if border_width > 0.0 { pixels.stroke_path( &border_radius_path, &tiny_skia::Paint { @@ -239,6 +253,68 @@ impl Backend { transform, clip_mask, ); + } else { + // Draw corners that have to small border radii as having no border radius, + // but mask them with the rounded rectangle with the correct border radius. + + let mut temp_pixmap = + Pixmap::new(bounds.width as u32, bounds.height as u32) + .unwrap(); + + let mut quad_mask = + Mask::new(bounds.width as u32, bounds.height as u32) + .unwrap(); + + let zero_bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width, + height: bounds.height, + }; + let path = + rounded_rectangle(zero_bounds, fill_border_radius); + + quad_mask.fill_path( + &path, + tiny_skia::FillRule::EvenOdd, + true, + transform, + ); + let path_bounds = Rectangle { + x: border_width / 2.0, + y: border_width / 2.0, + width: bounds.width - border_width, + height: bounds.height - border_width, + }; + + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); + + temp_pixmap.stroke_path( + &border_radius_path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(into_color( + *border_color, + )), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: border_width, + ..tiny_skia::Stroke::default() + }, + transform, + Some(&quad_mask), + ); + + pixels.draw_pixmap( + bounds.x as i32, + bounds.y as i32, + temp_pixmap.as_ref(), + &PixmapPaint::default(), + transform, + clip_mask, + ); } } Primitive::Text { -- cgit From a3f32ad201c8f3aaa9efd849c917e5e106d31a9b Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Mon, 15 May 2023 13:40:52 -0400 Subject: fix: when clearing damaged surface with background color blend mode should be Source only --- tiny_skia/src/backend.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d481bacd..39bed555 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -91,6 +91,7 @@ impl Backend { background_color, )), anti_alias: false, + blend_mode: tiny_skia::BlendMode::Source, ..Default::default() }, tiny_skia::FillRule::default(), -- cgit From 4c1a082f0468a59099bbf8aa8991420a41234948 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 19 May 2023 03:32:21 +0200 Subject: Remove `Builder` abstractions for gradients --- tiny_skia/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index dd1adbd8..9495d2fc 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -463,7 +463,7 @@ fn into_gradient<'a>( let Gradient::Linear(linear) = gradient; let (start, end) = linear.angle.to_distance(&bounds); let stops: Vec = linear - .color_stops + .stops .into_iter() .flatten() .map(|stop| { -- cgit From 49353bc4ea2e93e5d70f026e7eda169987b7c1c7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 19 May 2023 03:53:23 +0200 Subject: Inline `into_gradient` in `tiny_skia::backend` ... since it's not really reused anywhere else. --- tiny_skia/src/backend.rs | 84 +++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 43 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 9495d2fc..d55b9dab 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -184,8 +184,47 @@ impl Backend { *color, )) } - Background::Gradient(gradient) => { - into_gradient(*gradient, *bounds) + Background::Gradient(Gradient::Linear(linear)) => { + let (start, end) = + linear.angle.to_distance(&bounds); + + let stops: Vec = + linear + .stops + .into_iter() + .flatten() + .map(|stop| { + tiny_skia::GradientStop::new( + stop.offset, + tiny_skia::Color::from_rgba( + stop.color.b, + stop.color.g, + stop.color.r, + stop.color.a, + ) + .expect("Create color"), + ) + }) + .collect(); + + tiny_skia::LinearGradient::new( + tiny_skia::Point { + x: start.x, + y: start.y, + }, + tiny_skia::Point { x: end.x, y: end.y }, + if stops.is_empty() { + vec![tiny_skia::GradientStop::new( + 0.0, + tiny_skia::Color::BLACK, + )] + } else { + stops + }, + tiny_skia::SpreadMode::Pad, + tiny_skia::Transform::identity(), + ) + .expect("Create linear gradient") } }, anti_alias: true, @@ -456,47 +495,6 @@ fn into_color(color: Color) -> tiny_skia::Color { .expect("Convert color from iced to tiny_skia") } -fn into_gradient<'a>( - gradient: Gradient, - bounds: Rectangle, -) -> tiny_skia::Shader<'a> { - let Gradient::Linear(linear) = gradient; - let (start, end) = linear.angle.to_distance(&bounds); - let stops: Vec = linear - .stops - .into_iter() - .flatten() - .map(|stop| { - tiny_skia::GradientStop::new( - stop.offset, - tiny_skia::Color::from_rgba( - stop.color.b, - stop.color.g, - stop.color.r, - stop.color.a, - ) - .expect("Create color"), - ) - }) - .collect(); - - tiny_skia::LinearGradient::new( - tiny_skia::Point { - x: start.x, - y: start.y, - }, - tiny_skia::Point { x: end.x, y: end.y }, - if stops.is_empty() { - vec![tiny_skia::GradientStop::new(0.0, tiny_skia::Color::BLACK)] - } else { - stops - }, - tiny_skia::SpreadMode::Pad, - tiny_skia::Transform::identity(), - ) - .expect("Create linear gradient") -} - fn rounded_rectangle( bounds: Rectangle, border_radius: [f32; 4], -- cgit From ccf7d1994fd1856a32fe8a9afe3a6474aa4e6dc8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 19 May 2023 04:05:31 +0200 Subject: Fix needless borrow in `tiny_skia::backend` --- tiny_skia/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d55b9dab..491e80c9 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -186,7 +186,7 @@ impl Backend { } Background::Gradient(Gradient::Linear(linear)) => { let (start, end) = - linear.angle.to_distance(&bounds); + linear.angle.to_distance(bounds); let stops: Vec = linear -- cgit From 5bc7cbf5bca039ec3a4cbe82b161c087a4b39680 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 20 Jun 2023 06:22:17 +0200 Subject: Use subpixel glyph positioning and layout linearity ... for offsetting and scaling text --- tiny_skia/src/backend.rs | 6 ------ 1 file changed, 6 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 9d0fc527..bcc667f9 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -658,12 +658,6 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { ); } -impl iced_graphics::Backend for Backend { - fn trim_measurements(&mut self) { - self.text_pipeline.trim_measurement_cache(); - } -} - impl backend::Text for Backend { const ICON_FONT: Font = Font::with_name("Iced-Icons"); const CHECKMARK_ICON: char = '\u{f00c}'; -- cgit From bf7d636ebf90b6eba3ab6e4c718439e382ce9ec0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 27 Jun 2023 22:05:49 +0200 Subject: Draw border path for `quad` only if it has a border in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 214 ++++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 105 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index d0d24b23..86eccdda 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -159,7 +159,6 @@ impl Backend { border_width, border_color, } => { - // XXX border seems to be contained by the bounds of the primitive in wgpu and for damage regions, so we do the same here let physical_bounds = (*bounds + translation) * scale_factor; if !clip_bounds.intersects(&physical_bounds) { @@ -206,115 +205,120 @@ impl Backend { clip_mask, ); - // border path is offset by half the border width - let path_bounds = Rectangle { - x: bounds.x + border_width / 2.0, - y: bounds.y + border_width / 2.0, - width: bounds.width - border_width, - height: bounds.height - border_width, - }; - - // Make sure the border radius is correct - let mut border_radius = *border_radius; - let mut border_radius_gt_half_border_width = - [true, true, true, true]; - for (i, radius) in &mut border_radius.iter_mut().enumerate() { - *radius = if *radius == 0.0 { - // Path should handle this fine - 0.0 - } else if *radius > border_width / 2.0 { - *radius - border_width / 2.0 - } else { - border_radius_gt_half_border_width[i] = false; - 0.0 - } - .min(path_bounds.width / 2.0) - .min(path_bounds.height / 2.0); - } - - // Stroking a path works well in this case. - if border_radius_gt_half_border_width.iter().all(|b| *b) { - let border_radius_path = - rounded_rectangle(path_bounds, border_radius); - - pixels.stroke_path( - &border_radius_path, - &tiny_skia::Paint { - shader: tiny_skia::Shader::SolidColor(into_color( - *border_color, - )), - anti_alias: true, - ..tiny_skia::Paint::default() - }, - &tiny_skia::Stroke { - width: border_width, - ..tiny_skia::Stroke::default() - }, - transform, - clip_mask, - ); - } else { - // Draw corners that have to small border radii as having no border radius, - // but mask them with the rounded rectangle with the correct border radius. - - let mut temp_pixmap = - Pixmap::new(bounds.width as u32, bounds.height as u32) - .unwrap(); - - let mut quad_mask = - Mask::new(bounds.width as u32, bounds.height as u32) - .unwrap(); - - let zero_bounds = Rectangle { - x: 0.0, - y: 0.0, - width: bounds.width, - height: bounds.height, - }; - let path = - rounded_rectangle(zero_bounds, fill_border_radius); - - quad_mask.fill_path( - &path, - tiny_skia::FillRule::EvenOdd, - true, - transform, - ); - let path_bounds = Rectangle { - x: border_width / 2.0, - y: border_width / 2.0, + if border_width > 0.0 { + // Border path is offset by half the border width + let border_bounds = Rectangle { + x: bounds.x + border_width / 2.0, + y: bounds.y + border_width / 2.0, width: bounds.width - border_width, height: bounds.height - border_width, }; - let border_radius_path = - rounded_rectangle(path_bounds, border_radius); - - temp_pixmap.stroke_path( - &border_radius_path, - &tiny_skia::Paint { - shader: tiny_skia::Shader::SolidColor(into_color( - *border_color, - )), - anti_alias: true, - ..tiny_skia::Paint::default() - }, - &tiny_skia::Stroke { - width: border_width, - ..tiny_skia::Stroke::default() - }, - transform, - Some(&quad_mask), - ); + // Make sure the border radius is correct + let mut border_radius = *border_radius; + let mut is_simple_border = true; + + for radius in &mut border_radius { + *radius = if *radius == 0.0 { + // Path should handle this fine + 0.0 + } else if *radius > border_width / 2.0 { + *radius - border_width / 2.0 + } else { + is_simple_border = false; + 0.0 + } + .min(border_bounds.width / 2.0) + .min(border_bounds.height / 2.0); + } - pixels.draw_pixmap( - bounds.x as i32, - bounds.y as i32, - temp_pixmap.as_ref(), - &PixmapPaint::default(), - transform, - clip_mask, - ); + // Stroking a path works well in this case + if is_simple_border { + let border_path = + rounded_rectangle(border_bounds, border_radius); + + pixels.stroke_path( + &border_path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor( + into_color(*border_color), + ), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: border_width, + ..tiny_skia::Stroke::default() + }, + transform, + clip_mask, + ); + } else { + // Draw corners that have too small border radii as having no border radius, + // but mask them with the rounded rectangle with the correct border radius. + let mut temp_pixmap = Pixmap::new( + bounds.width as u32, + bounds.height as u32, + ) + .unwrap(); + + let mut quad_mask = Mask::new( + bounds.width as u32, + bounds.height as u32, + ) + .unwrap(); + + let zero_bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width, + height: bounds.height, + }; + let path = + rounded_rectangle(zero_bounds, fill_border_radius); + + quad_mask.fill_path( + &path, + tiny_skia::FillRule::EvenOdd, + true, + transform, + ); + let path_bounds = Rectangle { + x: border_width / 2.0, + y: border_width / 2.0, + width: bounds.width - border_width, + height: bounds.height - border_width, + }; + + let border_radius_path = + rounded_rectangle(path_bounds, border_radius); + + temp_pixmap.stroke_path( + &border_radius_path, + &tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor( + into_color(*border_color), + ), + anti_alias: true, + ..tiny_skia::Paint::default() + }, + &tiny_skia::Stroke { + width: border_width, + ..tiny_skia::Stroke::default() + }, + transform, + Some(&quad_mask), + ); + + pixels.draw_pixmap( + bounds.x as i32, + bounds.y as i32, + temp_pixmap.as_ref(), + &PixmapPaint::default(), + transform, + clip_mask, + ); + } } } Primitive::Text { -- cgit From 2f886b0e4e1927ead031b1256026d53f48d5f8eb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 27 Jun 2023 22:06:32 +0200 Subject: Fix import consistency in `iced_tiny_skia` --- tiny_skia/src/backend.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 86eccdda..87738174 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -1,5 +1,3 @@ -use tiny_skia::{Mask, Pixmap, PixmapPaint}; - use crate::core::text; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; @@ -256,13 +254,13 @@ impl Backend { } else { // Draw corners that have too small border radii as having no border radius, // but mask them with the rounded rectangle with the correct border radius. - let mut temp_pixmap = Pixmap::new( + let mut temp_pixmap = tiny_skia::Pixmap::new( bounds.width as u32, bounds.height as u32, ) .unwrap(); - let mut quad_mask = Mask::new( + let mut quad_mask = tiny_skia::Mask::new( bounds.width as u32, bounds.height as u32, ) @@ -314,7 +312,7 @@ impl Backend { bounds.x as i32, bounds.y as i32, temp_pixmap.as_ref(), - &PixmapPaint::default(), + &tiny_skia::PixmapPaint::default(), transform, clip_mask, ); -- cgit From 78ad365db232e53cbdf12105e40c1dbe87a3238c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 28 Jun 2023 00:35:37 +0200 Subject: Reuse entries in `text::Cache` in `iced_wgpu` --- tiny_skia/src/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index ba038052..c8999561 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -787,7 +787,7 @@ impl backend::Text for Backend { font: Font, bounds: Size, shaping: text::Shaping, - ) -> (f32, f32) { + ) -> Size { self.text_pipeline.measure( contents, size, -- cgit From 0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 22 Jun 2023 00:38:36 +0200 Subject: Introduce custom backend-specific primitives --- tiny_skia/src/backend.rs | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index c8999561..0d06ef70 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -2,7 +2,8 @@ use crate::core::text; use crate::core::Gradient; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::backend; -use crate::graphics::{Primitive, Viewport}; +use crate::graphics::{Damage, Viewport}; +use crate::primitive::{self, Primitive}; use crate::Settings; use std::borrow::Cow; @@ -419,6 +420,13 @@ impl Backend { self.raster_pipeline .draw(handle, *bounds, pixels, transform, clip_mask); } + #[cfg(not(feature = "image"))] + Primitive::Image { .. } => { + log::warn!( + "Unsupported primitive in `iced_tiny_skia`: {:?}", + primitive + ); + } #[cfg(feature = "svg")] Primitive::Svg { handle, @@ -442,12 +450,19 @@ impl Backend { clip_mask, ); } - Primitive::Fill { + #[cfg(not(feature = "svg"))] + Primitive::Svg { .. } => { + log::warn!( + "Unsupported primitive in `iced_tiny_skia`: {:?}", + primitive + ); + } + Primitive::Custom(primitive::Custom::Fill { path, paint, rule, transform, - } => { + }) => { let bounds = path.bounds(); let physical_bounds = (Rectangle { @@ -475,12 +490,12 @@ impl Backend { clip_mask, ); } - Primitive::Stroke { + Primitive::Custom(primitive::Custom::Stroke { path, paint, stroke, transform, - } => { + }) => { let bounds = path.bounds(); let physical_bounds = (Rectangle { @@ -588,13 +603,6 @@ impl Backend { primitive ); } - _ => { - // Not supported! - log::warn!( - "Unsupported primitive in `iced_tiny_skia`: {:?}", - primitive - ); - } } } } @@ -766,6 +774,10 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { ); } +impl iced_graphics::Backend for Backend { + type Primitive = primitive::Custom; +} + impl backend::Text for Backend { const ICON_FONT: Font = Font::with_name("Iced-Icons"); const CHECKMARK_ICON: char = '\u{f00c}'; -- cgit From fa5650cfd1115e6ccec2ad795cf58fd970d5b43c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 29 Jun 2023 07:48:03 +0200 Subject: Decouple `Mesh` primitives from main `Primitive` type --- tiny_skia/src/backend.rs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index 0d06ef70..e0134220 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -595,14 +595,6 @@ impl Backend { translation, ); } - Primitive::SolidMesh { .. } | Primitive::GradientMesh { .. } => { - // Not supported! - // TODO: Draw a placeholder (?) - log::warn!( - "Unsupported primitive in `iced_tiny_skia`: {:?}", - primitive - ); - } } } } -- cgit From af386fd0a3de432337ee9cdaa4d3661e98bd4105 Mon Sep 17 00:00:00 2001 From: Alec Deason Date: Sat, 10 Jun 2023 13:18:42 -0700 Subject: Upgrade resvg to 0.34 and tiny_skia to 0.10 --- tiny_skia/src/backend.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tiny_skia/src/backend.rs') diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs index e0134220..a8add70b 100644 --- a/tiny_skia/src/backend.rs +++ b/tiny_skia/src/backend.rs @@ -753,7 +753,15 @@ fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) { let path = { let mut builder = tiny_skia::PathBuilder::new(); - builder.push_rect(bounds.x, bounds.y, bounds.width, bounds.height); + builder.push_rect( + tiny_skia::Rect::from_xywh( + bounds.x, + bounds.y, + bounds.width, + bounds.height, + ) + .unwrap(), + ); builder.finish().unwrap() }; -- cgit