diff --git a/crates/craft_renderer/src/render_command.rs b/crates/craft_renderer/src/render_command.rs index c9296de..e102e17 100644 --- a/crates/craft_renderer/src/render_command.rs +++ b/crates/craft_renderer/src/render_command.rs @@ -3,7 +3,7 @@ use std::rc::Weak; use peniko::Color; -use craft_primitives::geometry::{BezPath, Rectangle, Vec2}; +use craft_primitives::geometry::{Affine, BezPath, Rectangle, Vec2}; use craft_resource_manager::ResourceIdentifier; @@ -12,6 +12,7 @@ use crate::text_renderer_data::{TextData, TextScroll}; #[derive(Clone)] pub enum RenderCommand { + SetTransform(SetTransformCmd), DrawRect(DrawRectCmd), DrawRectOutline(DrawRectOutlineCmd), DrawImage(DrawImageCmd), @@ -25,6 +26,11 @@ pub enum RenderCommand { BoxShadowCmd(BoxShadowCmd), } +#[derive(Clone)] +pub struct SetTransformCmd { + pub transform: Affine, +} + #[derive(Clone)] pub struct DrawRectCmd { pub rect: Rectangle, diff --git a/crates/craft_renderer/src/render_list.rs b/crates/craft_renderer/src/render_list.rs index 448622c..c630604 100644 --- a/crates/craft_renderer/src/render_list.rs +++ b/crates/craft_renderer/src/render_list.rs @@ -3,10 +3,10 @@ use std::rc::Weak; use peniko::Color; -use craft_primitives::geometry::{BezPath, Rectangle, Shape}; +use craft_primitives::geometry::{Affine, BezPath, Rectangle, Shape}; use craft_resource_manager::ResourceIdentifier; -use crate::render_command::{BoxShadowCmd, DrawImageCmd, DrawRectCmd, DrawRectOutlineCmd, DrawTextCmd, DrawTinyVgCmd, FillBezPathCmd, PushLayerCmd}; +use crate::render_command::{BoxShadowCmd, DrawImageCmd, DrawRectCmd, DrawRectOutlineCmd, DrawTextCmd, DrawTinyVgCmd, FillBezPathCmd, PushLayerCmd, SetTransformCmd}; use crate::sort_commands::SortedCommands; use crate::text_renderer_data::{TextData, TextScroll}; use crate::{Brush, RenderCommand, TargetItem}; @@ -43,6 +43,11 @@ impl RenderList { self.overlay.children.clear(); } + #[inline(always)] + pub fn set_transform(&mut self, transform: Affine) { + self.commands.push(RenderCommand::SetTransform(SetTransformCmd { transform })); + } + #[inline(always)] pub fn draw_rect(&mut self, rect: Rectangle, color: Color) { if let Some(cull) = &self.cull diff --git a/crates/craft_renderer/src/sort_commands.rs b/crates/craft_renderer/src/sort_commands.rs index 80fd57c..9f74ae3 100644 --- a/crates/craft_renderer/src/sort_commands.rs +++ b/crates/craft_renderer/src/sort_commands.rs @@ -106,6 +106,12 @@ pub(crate) fn sort_and_cull_render_list_internal(surface_height: f32, render_lis } } + RenderCommand::SetTransform(_) => { + unsafe { + (*current).children.push(SortedItem::Other(index as u32)); + } + } + _ => { let bounding_rect = bounding_rect(command); if !should_cull(&bounding_rect, window_height) { diff --git a/crates/craft_renderer/src/vello/mod.rs b/crates/craft_renderer/src/vello/mod.rs index 386f705..be7a40f 100644 --- a/crates/craft_renderer/src/vello/mod.rs +++ b/crates/craft_renderer/src/vello/mod.rs @@ -52,6 +52,8 @@ pub struct VelloRenderer { scene: Scene, pub surface_clear_color: Color, pub render_into_texture: bool, + + transform: Affine } impl RenderSurface { @@ -240,18 +242,19 @@ impl VelloRenderer { scene: Scene::new(), surface_clear_color: Color::WHITE, render_into_texture, + transform: Default::default(), } } } -fn vello_draw_rect(scene: &mut Scene, rectangle: Rectangle, fill_color: Color) { +fn vello_draw_rect(scene: &mut Scene, rectangle: Rectangle, fill_color: Color, transform: &Affine) { let rect = Rect::new( rectangle.x as f64, rectangle.y as f64, (rectangle.x + rectangle.width) as f64, (rectangle.y + rectangle.height) as f64, ); - scene.fill(Fill::NonZero, Affine::IDENTITY, fill_color, None, &rect); + scene.fill(Fill::NonZero, *transform, fill_color, None, &rect); } impl Renderer for VelloRenderer { @@ -281,12 +284,17 @@ impl Renderer for VelloRenderer { resource_manager: Arc, window: Rectangle, ) { + self.transform = Affine::IDENTITY; + SortedCommands::draw(render_list, &render_list.overlay, &mut |command: &RenderCommand| { let scene = &mut self.scene; match command { + RenderCommand::SetTransform(cmd) => { + self.transform = cmd.transform; + } RenderCommand::DrawRect(cmd) => { - vello_draw_rect(scene, cmd.rect, cmd.color); + vello_draw_rect(scene, cmd.rect, cmd.color, &self.transform); } RenderCommand::DrawRectOutline(cmd) => { self.scene.stroke( @@ -312,23 +320,24 @@ impl Renderer for VelloRenderer { width: image.width(), height: image.height(), }; - let vello_image = vello::peniko::ImageBrush::new(vello_image); - let mut transform = Affine::IDENTITY; - transform = transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); - transform = transform.pre_scale_non_uniform( + let mut image_transform = Affine::IDENTITY; + image_transform = image_transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + image_transform = image_transform.pre_scale_non_uniform( cmd.rect.width as f64 / image.width() as f64, cmd.rect.height as f64 / image.height() as f64, ); - scene.draw_image(&vello_image, transform); + image_transform = self.transform * image_transform; + scene.draw_image(&vello_image, image_transform); } } RenderCommand::DrawText(cmd) => { let text_transform = Affine::default().with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); let scroll = cmd.text_scroll.unwrap_or(TextScroll::default()).scroll_y; - let text_transform = text_transform.then_translate(kurbo::Vec2::new(0.0, -scroll as f64)); + let mut text_transform = text_transform.then_translate(kurbo::Vec2::new(0.0, -scroll as f64)); + text_transform = self.transform * text_transform; let c = cmd.data.upgrade(); if c.is_none() { @@ -376,7 +385,7 @@ impl Renderer for VelloRenderer { width: background.width, height: background.height, }; - vello_draw_rect(scene, background_rect, *color); + vello_draw_rect(scene, background_rect, *color, &self.transform); } for (selection, selection_color) in &line.selections { @@ -386,7 +395,7 @@ impl Renderer for VelloRenderer { width: selection.width, height: selection.height, }; - vello_draw_rect(scene, selection_rect, *selection_color); + vello_draw_rect(scene, selection_rect, *selection_color, &self.transform); } }); @@ -433,7 +442,7 @@ impl Renderer for VelloRenderer { width: cursor.width, height: cursor.height, }; - vello_draw_rect(scene, cursor_rect, *cursor_color); + vello_draw_rect(scene, cursor_rect, *cursor_color, &self.transform); } } RenderCommand::DrawTinyVg(cmd) => { @@ -443,6 +452,7 @@ impl Renderer for VelloRenderer { resource_manager.clone(), cmd.resource_id.clone(), &cmd.override_color, + &self.transform ); } RenderCommand::PushLayer(cmd) => { @@ -465,7 +475,7 @@ impl Renderer for VelloRenderer { scene.pop_layer(); } RenderCommand::FillBezPath(cmd) => { - scene.fill(Fill::NonZero, Affine::IDENTITY, &cmd.brush, None, &cmd.path); + scene.fill(Fill::NonZero, self.transform, &cmd.brush, None, &cmd.path); } _ => {} } diff --git a/crates/craft_renderer/src/vello/tinyvg.rs b/crates/craft_renderer/src/vello/tinyvg.rs index bd0ea5b..37a527b 100644 --- a/crates/craft_renderer/src/vello/tinyvg.rs +++ b/crates/craft_renderer/src/vello/tinyvg.rs @@ -36,6 +36,7 @@ pub(crate) fn draw_tiny_vg( resource_manager: Arc, resource_identifier: ResourceIdentifier, override_color: &Option, + transform: &Affine ) { let resource = resource_manager.get(&resource_identifier); if let Some(resource) = resource @@ -46,7 +47,7 @@ pub(crate) fn draw_tiny_vg( } let tiny_vg = resource.tinyvg.as_ref().unwrap(); - let mut affine = Affine::IDENTITY; + let mut vg_transform = Affine::IDENTITY; let mut svg_width = tiny_vg.header.width as f32; let mut svg_height = tiny_vg.header.height as f32; @@ -58,12 +59,14 @@ pub(crate) fn draw_tiny_vg( svg_height = rectangle.height; } - affine = affine.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - affine = affine.pre_scale_non_uniform( + vg_transform = vg_transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + vg_transform = vg_transform.pre_scale_non_uniform( rectangle.width as f64 / svg_width as f64, rectangle.height as f64 / svg_height as f64, ); + vg_transform = *transform * vg_transform; + for command in &tiny_vg.draw_commands { match command { DrawCommand::FillPolygon(data) => { @@ -85,7 +88,7 @@ pub(crate) fn draw_tiny_vg( &data.style, None, &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } @@ -94,7 +97,7 @@ pub(crate) fn draw_tiny_vg( for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - scene.fill(Fill::EvenOdd, affine, &brush, None, &rectangle); + scene.fill(Fill::EvenOdd, vg_transform, &brush, None, &rectangle); } } DrawCommand::FillPath(data) => { @@ -104,7 +107,7 @@ pub(crate) fn draw_tiny_vg( &data.style, None, &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } @@ -116,7 +119,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(line.start), tinyvg_helpers::to_kurbo_point(line.end), ); - scene.stroke(&Stroke::new(data.line_width.0), affine, &brush, None, &line); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &brush, None, &line); } } DrawCommand::DrawLineLoop(data) => { @@ -128,7 +131,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point), ); - scene.stroke(&Stroke::new(data.line_width.0), affine, &brush, None, &line); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &brush, None, &line); start = *point; } } @@ -141,7 +144,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point), ); - scene.stroke(&Stroke::new(data.line_width.0), affine, &brush, None, &line); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &brush, None, &line); start = *point; } } @@ -152,7 +155,7 @@ pub(crate) fn draw_tiny_vg( &data.style, Some(&data.line_width), &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } @@ -175,7 +178,7 @@ pub(crate) fn draw_tiny_vg( &data.fill_style, None, &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); draw_path( @@ -184,7 +187,7 @@ pub(crate) fn draw_tiny_vg( &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } @@ -194,8 +197,8 @@ pub(crate) fn draw_tiny_vg( for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - scene.fill(Fill::EvenOdd, affine, &fill_brush, None, &rectangle); - scene.stroke(&Stroke::new(data.line_width.0), affine, &line_brush, None, &rectangle); + scene.fill(Fill::EvenOdd, vg_transform, &fill_brush, None, &rectangle); + scene.stroke(&Stroke::new(data.line_width.0), vg_transform, &line_brush, None, &rectangle); } } DrawCommand::OutlineFillPath(data) => { @@ -205,7 +208,7 @@ pub(crate) fn draw_tiny_vg( &data.fill_style, None, &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); draw_path( @@ -214,7 +217,7 @@ pub(crate) fn draw_tiny_vg( &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, + &vg_transform, override_color, ); } diff --git a/crates/craft_renderer/src/vello_cpu/mod.rs b/crates/craft_renderer/src/vello_cpu/mod.rs index cf3d500..bf56686 100644 --- a/crates/craft_renderer/src/vello_cpu/mod.rs +++ b/crates/craft_renderer/src/vello_cpu/mod.rs @@ -144,9 +144,9 @@ impl Renderer for VelloCpuRenderer { &'a mut self, render_list: &'a mut RenderList, resource_manager: Arc, - window: Rectangle, - //get_text_renderer: Box Option<&'a TextRender> + 'a>, + window: Rectangle ) { + vello_draw_rect( &mut self.render_context, Rectangle::new(0.0, 0.0, self.window_width as f32, self.window_height as f32), @@ -160,6 +160,9 @@ impl Renderer for VelloCpuRenderer { SortedCommands::draw(render_list, &render_list.overlay, &mut |command: &RenderCommand| { match command { + RenderCommand::SetTransform(cmd) => { + self.render_context.set_transform(cmd.transform); + } RenderCommand::DrawRect(cmd) => { self.render_context.set_paint(PaintType::Solid(cmd.color)); self.render_context.fill_rect(&cmd.rect.to_kurbo()); @@ -186,13 +189,14 @@ impl Renderer for VelloCpuRenderer { height: image.height(), }; - let mut transform = Affine::IDENTITY; - transform = transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); - transform = transform.pre_scale_non_uniform( + let scene_state = self.render_context.save_current_state(); + let mut image_transform = Affine::IDENTITY; + image_transform = image_transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); + image_transform = image_transform.pre_scale_non_uniform( cmd.rect.width as f64 / image.width() as f64, cmd.rect.height as f64 / image.height() as f64, ); - self.render_context.set_transform(transform); + self.render_context.set_transform(scene_state.transform * image_transform); let is = vello_common::paint::ImageSource::from_peniko_image_data(&id); @@ -209,7 +213,7 @@ impl Renderer for VelloCpuRenderer { image.width() as f64, image.height() as f64, )); - self.render_context.reset_transform(); + self.render_context.restore_state(scene_state); } } RenderCommand::DrawText(cmd) => { @@ -278,10 +282,11 @@ impl Renderer for VelloCpuRenderer { } }); + let scene_state = self.render_context.save_current_state(); + self.render_context.set_transform(scene_state.transform * text_transform); cull_and_process(&mut |line: &TextRenderLine| { for item in &line.items { if let Some(underline) = &item.underline { - self.render_context.set_transform(text_transform); self.render_context.set_stroke(Stroke::new(underline.width.into())); self.render_context.set_paint(PaintType::from(underline.brush.color)); self.render_context.stroke_path(&underline.line.to_path(0.1)); @@ -293,13 +298,11 @@ impl Renderer for VelloCpuRenderer { .map(|b| b.color) .unwrap_or_else(|| item.brush.color), )); - self.render_context.reset_transform(); let glyph_run_builder = self .render_context .glyph_run(&item.font) - .font_size(item.font_size) - .glyph_transform(text_transform); + .font_size(item.font_size); glyph_run_builder.fill_glyphs(item.glyphs.iter().map(|glyph| Glyph { id: glyph.id, x: glyph.x, @@ -307,6 +310,7 @@ impl Renderer for VelloCpuRenderer { })); } }); + self.render_context.restore_state(scene_state); if cmd.show_cursor && let Some((cursor, cursor_color)) = &text_render.cursor @@ -387,6 +391,7 @@ impl VelloCpuRenderer { } pub fn draw_box_shadow(&mut self, box_shadow: &BoxShadowCmd) { + let scene_state = self.render_context.save_current_state(); let radius = box_shadow.blur_radius / 2.0; let filter = Some(Filter::from_function(FilterFunction::Blur { radius: box_shadow.blur_radius as f32, @@ -413,12 +418,12 @@ impl VelloCpuRenderer { filter, ); - self.render_context.set_transform(Affine::translate(box_shadow.offset)); + self.render_context.set_transform(scene_state.transform * Affine::translate(box_shadow.offset)); self.render_context.set_paint(box_shadow.color); self.render_context.fill_path(&box_shadow.path); - self.render_context.set_transform(Affine::IDENTITY); + self.render_context.set_transform(scene_state.transform); self.render_context .set_blend_mode(BlendMode::new(Mix::Normal, Compose::DestOut)); @@ -429,6 +434,9 @@ impl VelloCpuRenderer { .set_blend_mode(BlendMode::new(Mix::Normal, Compose::SrcOver)); self.render_context.pop_layer(); + + + self.render_context.restore_state(scene_state); } } } diff --git a/crates/craft_renderer/src/vello_cpu/tinyvg.rs b/crates/craft_renderer/src/vello_cpu/tinyvg.rs index 0af9a40..94b5877 100644 --- a/crates/craft_renderer/src/vello_cpu/tinyvg.rs +++ b/crates/craft_renderer/src/vello_cpu/tinyvg.rs @@ -13,15 +13,13 @@ use vello_cpu::RenderContext; use crate::helpers::brush_to_paint; use crate::{Brush, tinyvg_helpers}; -fn stroke_path(scene: &mut RenderContext, bez_path: &BezPath, affine: &Affine, line_width: f64, brush: &Brush) { +fn stroke_path(scene: &mut RenderContext, bez_path: &BezPath, line_width: f64, brush: &Brush) { scene.set_stroke(Stroke::new(line_width)); - scene.set_transform(*affine); scene.set_paint(brush_to_paint(brush)); scene.stroke_path(bez_path); } -fn fill_path(scene: &mut RenderContext, bez_path: &BezPath, affine: &Affine, brush: &Brush) { - scene.set_transform(*affine); +fn fill_path(scene: &mut RenderContext, bez_path: &BezPath, brush: &Brush) { scene.set_paint(brush_to_paint(brush)); scene.set_fill_rule(Fill::EvenOdd); scene.fill_path(bez_path); @@ -33,15 +31,14 @@ pub(crate) fn draw_path( fill_style: &Style, line_width: Option<&Unit>, color_table: &ColorTable, - affine: &Affine, override_color: &Option, ) { let (bezier_path, brush) = tinyvg_helpers::assemble_path(path, fill_style, color_table, override_color); if let Some(line_width) = line_width { - stroke_path(scene, &bezier_path, affine, line_width.0, &brush); + stroke_path(scene, &bezier_path, line_width.0, &brush); } else { - fill_path(scene, &bezier_path, affine, &brush); + fill_path(scene, &bezier_path, &brush); } } @@ -64,7 +61,7 @@ pub(crate) fn draw_tiny_vg( } let tiny_vg = resource.tinyvg.as_ref().unwrap(); - let mut affine = Affine::IDENTITY; + let vg_transform = Affine::IDENTITY; let mut svg_width = tiny_vg.header.width as f32; let mut svg_height = tiny_vg.header.height as f32; @@ -76,12 +73,15 @@ pub(crate) fn draw_tiny_vg( svg_height = rectangle.height; } - affine = affine.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - affine = affine.pre_scale_non_uniform( + let vg_transform = vg_transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + let vg_transform = vg_transform.pre_scale_non_uniform( rectangle.width as f64 / svg_width as f64, rectangle.height as f64 / svg_height as f64, ); + let scene_state = scene.save_current_state(); + scene.set_transform(scene_state.transform * vg_transform); + for command in &tiny_vg.draw_commands { match command { DrawCommand::FillPolygon(data) => { @@ -103,7 +103,6 @@ pub(crate) fn draw_tiny_vg( &data.style, None, &tiny_vg.color_table, - &affine, override_color, ); } @@ -112,7 +111,7 @@ pub(crate) fn draw_tiny_vg( for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - fill_path(scene, &rectangle.into_path(0.1), &affine, &brush); + fill_path(scene, &rectangle.into_path(0.1), &brush); } } DrawCommand::FillPath(data) => { @@ -122,7 +121,6 @@ pub(crate) fn draw_tiny_vg( &data.style, None, &tiny_vg.color_table, - &affine, override_color, ); } @@ -134,7 +132,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(line.start), tinyvg_helpers::to_kurbo_point(line.end), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); } } DrawCommand::DrawLineLoop(data) => { @@ -146,7 +144,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -159,7 +157,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -170,7 +168,6 @@ pub(crate) fn draw_tiny_vg( &data.style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -193,7 +190,6 @@ pub(crate) fn draw_tiny_vg( &data.fill_style, None, &tiny_vg.color_table, - &affine, override_color, ); draw_path( @@ -202,7 +198,6 @@ pub(crate) fn draw_tiny_vg( &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -213,8 +208,8 @@ pub(crate) fn draw_tiny_vg( let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); let rec_bez_path = rectangle.into_path(0.1); - fill_path(scene, &rec_bez_path, &affine, &fill_brush); - stroke_path(scene, &rec_bez_path, &affine, data.line_width.0, &line_brush); + fill_path(scene, &rec_bez_path, &fill_brush); + stroke_path(scene, &rec_bez_path, data.line_width.0, &line_brush); } } DrawCommand::OutlineFillPath(data) => { @@ -224,7 +219,6 @@ pub(crate) fn draw_tiny_vg( &data.fill_style, None, &tiny_vg.color_table, - &affine, override_color, ); draw_path( @@ -233,7 +227,6 @@ pub(crate) fn draw_tiny_vg( &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -243,6 +236,7 @@ pub(crate) fn draw_tiny_vg( DrawCommand::TextHint(_data) => {} } } - scene.reset_transform(); + + scene.restore_state(scene_state); } } diff --git a/crates/craft_renderer/src/vello_hybrid/mod.rs b/crates/craft_renderer/src/vello_hybrid/mod.rs index 853e002..2402a12 100644 --- a/crates/craft_renderer/src/vello_hybrid/mod.rs +++ b/crates/craft_renderer/src/vello_hybrid/mod.rs @@ -131,6 +131,8 @@ fn vello_draw_rect(scene: &mut Scene, rectangle: Rectangle, fill_color: Color) { } fn draw_box_shadow(scene: &mut Scene, box_shadow: &BoxShadowCmd) { + let scene_state = scene.save_current_state(); + let radius = box_shadow.blur_radius / 2.0; let filter = Some(Filter::from_function(FilterFunction::Blur { radius: box_shadow.blur_radius as f32, @@ -156,12 +158,12 @@ fn draw_box_shadow(scene: &mut Scene, box_shadow: &BoxShadowCmd) { filter, ); - scene.set_transform(Affine::translate(box_shadow.offset)); + scene.set_transform(scene_state.transform * Affine::translate(box_shadow.offset)); scene.set_paint(box_shadow.color); scene.fill_path(&box_shadow.path); - scene.set_transform(Affine::IDENTITY); + scene.set_transform(scene_state.transform); scene.set_blend_mode(BlendMode::new(Mix::Normal, Compose::DestOut)); scene.set_paint(Color::WHITE); @@ -171,6 +173,8 @@ fn draw_box_shadow(scene: &mut Scene, box_shadow: &BoxShadowCmd) { scene.pop_layer(); } + + scene.restore_state(scene_state); } impl CraftRenderer for VelloHybridRenderer { @@ -226,6 +230,8 @@ impl CraftRenderer for VelloHybridRenderer { let width = surface.config.width; let height = surface.config.height; + self.scene.set_transform(Affine::IDENTITY); + vello_draw_rect( &mut self.scene, Rectangle::new(0.0, 0.0, width as f32, height as f32), @@ -248,6 +254,9 @@ impl CraftRenderer for VelloHybridRenderer { let scene = &mut self.scene; match command { + RenderCommand::SetTransform(cmd) => { + self.scene.set_transform(cmd.transform); + } RenderCommand::DrawRect(cmd) => { vello_draw_rect(scene, cmd.rect, cmd.color); } @@ -308,13 +317,14 @@ impl CraftRenderer for VelloHybridRenderer { }; seen_images.insert(image_id); + let scene_state = scene.save_current_state(); let mut transform = Affine::IDENTITY; transform = transform.with_translation(kurbo::Vec2::new(cmd.rect.x as f64, cmd.rect.y as f64)); transform = transform.pre_scale_non_uniform( cmd.rect.width as f64 / image.width() as f64, cmd.rect.height as f64 / image.height() as f64, ); - scene.set_transform(transform); + scene.set_transform(scene_state.transform * transform); scene.set_paint(PaintType::Image(vello_common::paint::Image { image: ImageSource::OpaqueId { @@ -325,7 +335,8 @@ impl CraftRenderer for VelloHybridRenderer { })); scene.fill_rect(&kurbo::Rect::new(0.0, 0.0, image.width() as f64, image.height() as f64)); - scene.reset_transform(); + + scene.restore_state(scene_state); } } RenderCommand::DrawText(cmd) => { @@ -394,10 +405,12 @@ impl CraftRenderer for VelloHybridRenderer { } }); + let scene_state = scene.save_current_state(); + scene.set_transform(scene_state.transform * text_transform); + cull_and_process(&mut |line: &TextRenderLine| { for item in &line.items { if let Some(underline) = &item.underline { - scene.set_transform(text_transform); scene.set_stroke(Stroke::new(underline.width.into())); scene.set_paint(PaintType::from(underline.brush.color)); scene.stroke_path(&underline.line.to_path(0.1)); @@ -409,12 +422,10 @@ impl CraftRenderer for VelloHybridRenderer { .map(|b| b.color) .unwrap_or_else(|| item.brush.color), )); - scene.reset_transform(); let glyph_run_builder = scene .glyph_run(&item.font) - .font_size(item.font_size) - .glyph_transform(text_transform); + .font_size(item.font_size); glyph_run_builder.fill_glyphs(item.glyphs.iter().map(|glyph| Glyph { id: glyph.id, x: glyph.x, @@ -423,6 +434,8 @@ impl CraftRenderer for VelloHybridRenderer { } }); + scene.restore_state(scene_state); + if cmd.show_cursor && let Some((cursor, cursor_color)) = &text_render.cursor { diff --git a/crates/craft_renderer/src/vello_hybrid/tinyvg.rs b/crates/craft_renderer/src/vello_hybrid/tinyvg.rs index f4ebd20..4a38ea6 100644 --- a/crates/craft_renderer/src/vello_hybrid/tinyvg.rs +++ b/crates/craft_renderer/src/vello_hybrid/tinyvg.rs @@ -14,15 +14,13 @@ use vello_hybrid::Scene; use crate::vello_hybrid::brush_to_paint; use crate::{Brush, tinyvg_helpers}; -fn stroke_path(scene: &mut Scene, bez_path: &BezPath, affine: &Affine, line_width: f64, brush: &Brush) { +fn stroke_path(scene: &mut Scene, bez_path: &BezPath, line_width: f64, brush: &Brush) { scene.set_stroke(Stroke::new(line_width)); - scene.set_transform(*affine); scene.set_paint(brush_to_paint(brush)); scene.stroke_path(bez_path); } -fn fill_path(scene: &mut Scene, bez_path: &BezPath, affine: &Affine, brush: &Brush) { - scene.set_transform(*affine); +fn fill_path(scene: &mut Scene, bez_path: &BezPath, brush: &Brush) { scene.set_paint(brush_to_paint(brush)); scene.set_fill_rule(Fill::EvenOdd); scene.fill_path(bez_path); @@ -34,15 +32,14 @@ pub(crate) fn draw_path( fill_style: &Style, line_width: Option<&Unit>, color_table: &ColorTable, - affine: &Affine, override_color: &Option, ) { let (bezier_path, brush) = tinyvg_helpers::assemble_path(path, fill_style, color_table, override_color); if let Some(line_width) = line_width { - stroke_path(scene, &bezier_path, affine, line_width.0, &brush); + stroke_path(scene, &bezier_path, line_width.0, &brush); } else { - fill_path(scene, &bezier_path, affine, &brush); + fill_path(scene, &bezier_path, &brush); } } @@ -65,7 +62,9 @@ pub(crate) fn draw_tiny_vg( } let tiny_vg = resource.tinyvg.as_ref().unwrap(); - let mut affine = Affine::IDENTITY; + let scene_state = scene.save_current_state(); + + let vg_transform = Affine::IDENTITY; let mut svg_width = tiny_vg.header.width as f32; let mut svg_height = tiny_vg.header.height as f32; @@ -77,12 +76,14 @@ pub(crate) fn draw_tiny_vg( svg_height = rectangle.height; } - affine = affine.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); - affine = affine.pre_scale_non_uniform( + let vg_transform = vg_transform.with_translation(kurbo::Vec2::new(rectangle.x as f64, rectangle.y as f64)); + let vg_transform = vg_transform.pre_scale_non_uniform( rectangle.width as f64 / svg_width as f64, rectangle.height as f64 / svg_height as f64, ); + scene.set_transform(scene_state.transform * vg_transform); + for command in &tiny_vg.draw_commands { match command { DrawCommand::FillPolygon(data) => { @@ -104,7 +105,6 @@ pub(crate) fn draw_tiny_vg( &data.style, None, &tiny_vg.color_table, - &affine, override_color, ); } @@ -113,7 +113,7 @@ pub(crate) fn draw_tiny_vg( for rectangle in &data.rectangles { let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); - fill_path(scene, &rectangle.into_path(0.1), &affine, &brush); + fill_path(scene, &rectangle.into_path(0.1), &brush); } } DrawCommand::FillPath(data) => { @@ -123,7 +123,6 @@ pub(crate) fn draw_tiny_vg( &data.style, None, &tiny_vg.color_table, - &affine, override_color, ); } @@ -135,7 +134,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(line.start), tinyvg_helpers::to_kurbo_point(line.end), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); } } DrawCommand::DrawLineLoop(data) => { @@ -147,7 +146,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -160,7 +159,7 @@ pub(crate) fn draw_tiny_vg( tinyvg_helpers::to_kurbo_point(start), tinyvg_helpers::to_kurbo_point(*point), ); - stroke_path(scene, &line.into_path(0.1), &affine, data.line_width.0, &brush); + stroke_path(scene, &line.into_path(0.1), data.line_width.0, &brush); start = *point; } } @@ -171,7 +170,6 @@ pub(crate) fn draw_tiny_vg( &data.style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -194,7 +192,6 @@ pub(crate) fn draw_tiny_vg( &data.fill_style, None, &tiny_vg.color_table, - &affine, override_color, ); draw_path( @@ -203,7 +200,6 @@ pub(crate) fn draw_tiny_vg( &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -214,8 +210,8 @@ pub(crate) fn draw_tiny_vg( let rectangle = kurbo::Rect::new(rectangle.x.0, rectangle.y.0, rectangle.height.0, rectangle.height.0); let rec_bez_path = rectangle.into_path(0.1); - fill_path(scene, &rec_bez_path, &affine, &fill_brush); - stroke_path(scene, &rec_bez_path, &affine, data.line_width.0, &line_brush); + fill_path(scene, &rec_bez_path, &fill_brush); + stroke_path(scene, &rec_bez_path, data.line_width.0, &line_brush); } } DrawCommand::OutlineFillPath(data) => { @@ -225,7 +221,6 @@ pub(crate) fn draw_tiny_vg( &data.fill_style, None, &tiny_vg.color_table, - &affine, override_color, ); draw_path( @@ -234,7 +229,6 @@ pub(crate) fn draw_tiny_vg( &data.line_style, Some(&data.line_width), &tiny_vg.color_table, - &affine, override_color, ); } @@ -245,6 +239,6 @@ pub(crate) fn draw_tiny_vg( } } - scene.reset_transform(); + scene.restore_state(scene_state); } } diff --git a/crates/craft_retained/src/elements/tinyvg.rs b/crates/craft_retained/src/elements/tinyvg.rs index 6a62872..a985aaa 100644 --- a/crates/craft_retained/src/elements/tinyvg.rs +++ b/crates/craft_retained/src/elements/tinyvg.rs @@ -3,7 +3,7 @@ use std::any::Any; use std::cell::RefCell; use std::rc::{Rc, Weak}; - +use peniko::Color; use craft_primitives::geometry::Rectangle; use craft_renderer::RenderList; @@ -129,6 +129,7 @@ impl TinyVg { }); let layout_context = Some(LayoutContext::TinyVg(TinyVgContext::new(resource_identifier.clone()))); inner.borrow_mut().element_data.create_layout_node(layout_context); + inner.borrow_mut().style_mut().set_color(Color::TRANSPARENT); PENDING_RESOURCES.with_borrow_mut(|pending_resources| { pending_resources.push_back((resource_identifier, ResourceType::TinyVg));