diff options
author | 2023-02-26 00:38:46 +0100 | |
---|---|---|
committer | 2023-02-26 00:38:46 +0100 | |
commit | df5d66423de141a009bbed993d99d491ed6373c9 (patch) | |
tree | 22d1c2a42dff13b180aa5e40b786627eb57d820d | |
parent | 445b31c6c5f16ecc9f07bd072f246e827aa5b854 (diff) | |
download | iced-df5d66423de141a009bbed993d99d491ed6373c9.tar.gz iced-df5d66423de141a009bbed993d99d491ed6373c9.tar.bz2 iced-df5d66423de141a009bbed993d99d491ed6373c9.zip |
Draft support for `Quad` and `Clip` primitives in `iced_tiny_skia`
-rw-r--r-- | tiny_skia/src/backend.rs | 153 |
1 files changed, 150 insertions, 3 deletions
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<T: AsRef<str>>( &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 |