diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 58f132982..f787de9ad 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -154,24 +154,23 @@ impl RenderState { } pub fn reset_canvas(&mut self) { - self.surfaces.canvas(SurfaceId::Shape).restore_to_count(1); + self.surfaces.canvas(SurfaceId::Fills).restore_to_count(1); + self.surfaces.canvas(SurfaceId::Strokes).restore_to_count(1); self.surfaces.canvas(SurfaceId::Current).restore_to_count(1); - self.surfaces - .canvas(SurfaceId::Shape) - .clear(self.background_color) - .reset_matrix(); - self.surfaces - .canvas(SurfaceId::Current) - .clear(self.background_color) - .reset_matrix(); - self.surfaces - .canvas(SurfaceId::Shadow) - .clear(self.background_color) - .reset_matrix(); - self.surfaces - .canvas(SurfaceId::Overlay) - .clear(self.background_color) - .reset_matrix(); + + self.surfaces.apply_mut( + &[ + SurfaceId::Fills, + SurfaceId::Strokes, + SurfaceId::Current, + SurfaceId::Shadow, + SurfaceId::Overlay, + ], + |s| { + s.canvas().clear(self.background_color).reset_matrix(); + }, + ); + self.surfaces .canvas(SurfaceId::Debug) .clear(skia::Color::TRANSPARENT) @@ -179,15 +178,28 @@ impl RenderState { } pub fn apply_render_to_final_canvas(&mut self) { - self.surfaces - .draw_into(SurfaceId::Current, SurfaceId::Target, None); + self.surfaces.draw_into( + SurfaceId::Current, + SurfaceId::Target, + Some(&skia::Paint::default()), + ); } pub fn apply_drawing_to_render_canvas(&mut self) { self.surfaces - .flush_and_submit(&mut self.gpu_state, SurfaceId::Shape); + .flush_and_submit(&mut self.gpu_state, SurfaceId::Fills); + self.surfaces.draw_into( + SurfaceId::Fills, + SurfaceId::Current, + Some(&skia::Paint::default()), + ); self.surfaces - .draw_into(SurfaceId::Shape, SurfaceId::Current, None); + .flush_and_submit(&mut self.gpu_state, SurfaceId::Strokes); + self.surfaces.draw_into( + SurfaceId::Strokes, + SurfaceId::Current, + Some(&skia::Paint::default()), + ); self.surfaces .flush_and_submit(&mut self.gpu_state, SurfaceId::Current); @@ -196,17 +208,17 @@ impl RenderState { self.surfaces .draw_into(SurfaceId::Overlay, SurfaceId::Current, None); - self.surfaces - .canvas(SurfaceId::Shadow) - .clear(skia::Color::TRANSPARENT); - - self.surfaces - .canvas(SurfaceId::Overlay) - .clear(skia::Color::TRANSPARENT); - - self.surfaces - .canvas(SurfaceId::Shape) - .clear(skia::Color::TRANSPARENT); + self.surfaces.apply_mut( + &[ + SurfaceId::Shadow, + SurfaceId::Overlay, + SurfaceId::Fills, + SurfaceId::Strokes, + ], + |s| { + s.canvas().clear(skia::Color::TRANSPARENT); + }, + ); } pub fn invalidate_cache_if_needed(&mut self) { @@ -221,22 +233,27 @@ impl RenderState { modifiers: Option<&Matrix>, clip_bounds: Option<(Rect, Option, Matrix)>, ) { - self.surfaces.canvas(SurfaceId::Shape).save(); + let surface_ids = &[SurfaceId::Fills, SurfaceId::Strokes]; + self.surfaces.apply_mut(surface_ids, |s| { + s.canvas().save(); + }); + + // set clipping if let Some((bounds, corners, transform)) = clip_bounds { - self.surfaces.canvas(SurfaceId::Shape).concat(&transform); + self.surfaces + .apply_mut(&[SurfaceId::Fills, SurfaceId::Strokes], |s| { + s.canvas().concat(&transform); + }); + if let Some(corners) = corners { let rrect = RRect::new_rect_radii(bounds, &corners); - self.surfaces.canvas(SurfaceId::Shape).clip_rrect( - rrect, - skia::ClipOp::Intersect, - true, - ); + self.surfaces.apply_mut(surface_ids, |s| { + s.canvas().clip_rrect(rrect, skia::ClipOp::Intersect, true); + }); } else { - self.surfaces.canvas(SurfaceId::Shape).clip_rect( - bounds, - skia::ClipOp::Intersect, - true, - ); + self.surfaces.apply_mut(surface_ids, |s| { + s.canvas().clip_rect(bounds, skia::ClipOp::Intersect, true); + }); } if self.options.is_debug_visible() { @@ -245,13 +262,14 @@ impl RenderState { paint.set_color(skia::Color::from_argb(255, 255, 0, 0)); paint.set_stroke_width(4.); self.surfaces - .canvas(SurfaceId::Shape) + .canvas(SurfaceId::Fills) .draw_rect(bounds, &paint); } - self.surfaces - .canvas(SurfaceId::Shape) - .concat(&transform.invert().unwrap_or(Matrix::default())); + self.surfaces.apply_mut(surface_ids, |s| { + s.canvas() + .concat(&transform.invert().unwrap_or(Matrix::default())); + }); } // Clone so we don't change the value in the global state @@ -262,7 +280,6 @@ impl RenderState { } let center = shape.center(); - let mut matrix = shape.transform; matrix.post_translate(center); matrix.pre_translate(-center); @@ -270,17 +287,17 @@ impl RenderState { match &shape.shape_type { Type::SVGRaw(sr) => { if let Some(modifiers) = modifiers { - self.surfaces.canvas(SurfaceId::Shape).concat(&modifiers); + self.surfaces.canvas(SurfaceId::Fills).concat(&modifiers); } - self.surfaces.canvas(SurfaceId::Shape).concat(&matrix); + self.surfaces.canvas(SurfaceId::Fills).concat(&matrix); if let Some(svg) = shape.svg.as_ref() { - svg.render(self.surfaces.canvas(SurfaceId::Shape)) + svg.render(self.surfaces.canvas(SurfaceId::Fills)) } else { let font_manager = skia::FontMgr::from(self.font_provider.clone()); let dom_result = skia::svg::Dom::from_str(sr.content.to_string(), font_manager); match dom_result { Ok(dom) => { - dom.render(self.surfaces.canvas(SurfaceId::Shape)); + dom.render(self.surfaces.canvas(SurfaceId::Fills)); shape.set_svg(dom); } Err(e) => { @@ -290,7 +307,10 @@ impl RenderState { } } _ => { - self.surfaces.canvas(SurfaceId::Shape).concat(&matrix); + self.surfaces + .apply_mut(&[SurfaceId::Fills, SurfaceId::Strokes], |s| { + s.canvas().concat(&matrix); + }); for fill in shape.fills().rev() { fills::render(self, &shape, fill); @@ -319,7 +339,10 @@ impl RenderState { }; self.apply_drawing_to_render_canvas(); - self.surfaces.canvas(SurfaceId::Shape).restore(); + self.surfaces + .apply_mut(&[SurfaceId::Fills, SurfaceId::Strokes], |s| { + s.canvas().restore(); + }); } pub fn start_render_loop( @@ -328,20 +351,23 @@ impl RenderState { modifiers: &HashMap, timestamp: i32, ) -> Result<(), String> { + let surface_ids = &[SurfaceId::Fills, SurfaceId::Strokes]; + if self.render_in_progress { if let Some(frame_id) = self.render_request_id { self.cancel_animation_frame(frame_id); } } self.reset_canvas(); - self.surfaces.canvas(SurfaceId::Shape).scale(( - self.viewbox.zoom * self.options.dpr(), - self.viewbox.zoom * self.options.dpr(), - )); - self.surfaces - .canvas(SurfaceId::Shape) - .translate((self.viewbox.pan_x, self.viewbox.pan_y)); - // + self.surfaces.apply_mut(surface_ids, |s| { + s.canvas().scale(( + self.viewbox.zoom * self.options.dpr(), + self.viewbox.zoom * self.options.dpr(), + )); + s.canvas() + .translate((self.viewbox.pan_x, self.viewbox.pan_y)); + }); + self.pending_nodes = vec![NodeRenderState { id: Uuid::nil(), visited_children: false, @@ -430,7 +456,8 @@ impl RenderState { let image = &cached.image; let paint = skia::Paint::default(); self.surfaces.canvas(SurfaceId::Target).save(); - self.surfaces.canvas(SurfaceId::Shape).save(); + self.surfaces.canvas(SurfaceId::Fills).save(); + self.surfaces.canvas(SurfaceId::Strokes).save(); let navigate_zoom = self.viewbox.zoom / cached.viewbox.zoom; let navigate_x = cached.viewbox.zoom * (self.viewbox.pan_x - cached.viewbox.pan_x); @@ -451,7 +478,8 @@ impl RenderState { .draw_image(image, (0, 0), Some(&paint)); self.surfaces.canvas(SurfaceId::Target).restore(); - self.surfaces.canvas(SurfaceId::Shape).restore(); + self.surfaces.canvas(SurfaceId::Fills).restore(); + self.surfaces.canvas(SurfaceId::Strokes).restore(); self.flush(); diff --git a/render-wasm/src/render/debug.rs b/render-wasm/src/render/debug.rs index 033f7c90e..8e13ce6bc 100644 --- a/render-wasm/src/render/debug.rs +++ b/render-wasm/src/render/debug.rs @@ -64,7 +64,9 @@ pub fn render_debug_shape(render_state: &mut RenderState, element: &Shape, inter pub fn render(render_state: &mut RenderState) { render_debug_view(render_state); - render_state - .surfaces - .draw_into(SurfaceId::Debug, SurfaceId::Current, None); + render_state.surfaces.draw_into( + SurfaceId::Debug, + SurfaceId::Current, + Some(&skia::Paint::default()), + ); } diff --git a/render-wasm/src/render/fills.rs b/render-wasm/src/render/fills.rs index e182e8473..12cce0cd3 100644 --- a/render-wasm/src/render/fills.rs +++ b/render-wasm/src/render/fills.rs @@ -16,7 +16,7 @@ fn draw_image_fill_in_container( } let size = image_fill.size(); - let canvas = render_state.surfaces.canvas(SurfaceId::Shape); + let canvas = render_state.surfaces.canvas(SurfaceId::Fills); let container = &shape.selrect; let path_transform = shape.to_path_transform(); let paint = fill.to_paint(container); @@ -96,7 +96,7 @@ fn draw_image_fill_in_container( * This SHOULD be the only public function in this module. */ pub fn render(render_state: &mut RenderState, shape: &Shape, fill: &Fill) { - let canvas = render_state.surfaces.canvas(SurfaceId::Shape); + let canvas = render_state.surfaces.canvas(SurfaceId::Fills); let selrect = shape.selrect; let path_transform = shape.to_path_transform(); diff --git a/render-wasm/src/render/shadows.rs b/render-wasm/src/render/shadows.rs index f0af52698..fbc98ff7a 100644 --- a/render-wasm/src/render/shadows.rs +++ b/render-wasm/src/render/shadows.rs @@ -7,11 +7,16 @@ pub fn render_drop_shadow(render_state: &mut RenderState, shadow: &Shadow, scale let shadow_paint = shadow.to_paint(scale); render_state .surfaces - .draw_into(SurfaceId::Shape, SurfaceId::Shadow, Some(&shadow_paint)); - + .draw_into(SurfaceId::Fills, SurfaceId::Shadow, Some(&shadow_paint)); render_state .surfaces - .draw_into(SurfaceId::Shadow, SurfaceId::Current, None); + .draw_into(SurfaceId::Strokes, SurfaceId::Shadow, Some(&shadow_paint)); + + render_state.surfaces.draw_into( + SurfaceId::Shadow, + SurfaceId::Current, + Some(&skia::Paint::default()), + ); render_state .surfaces @@ -24,7 +29,7 @@ pub fn render_inner_shadow(render_state: &mut RenderState, shadow: &Shadow, scal render_state .surfaces - .draw_into(SurfaceId::Shape, SurfaceId::Shadow, Some(&shadow_paint)); // , ShadowPaint + .draw_into(SurfaceId::Fills, SurfaceId::Shadow, Some(&shadow_paint)); render_state .surfaces diff --git a/render-wasm/src/render/strokes.rs b/render-wasm/src/render/strokes.rs index 69121a01d..48665ccdd 100644 --- a/render-wasm/src/render/strokes.rs +++ b/render-wasm/src/render/strokes.rs @@ -330,7 +330,7 @@ fn draw_image_stroke_in_container( } let size = image_fill.size(); - let canvas = render_state.surfaces.canvas(SurfaceId::Shape); + let canvas = render_state.surfaces.canvas(SurfaceId::Fills); let container = &shape.selrect; let path_transform = shape.to_path_transform(); let svg_attrs = &shape.svg_attrs; @@ -432,7 +432,7 @@ fn draw_image_stroke_in_container( * This SHOULD be the only public function in this module. */ pub fn render(render_state: &mut RenderState, shape: &Shape, stroke: &Stroke) { - let canvas = render_state.surfaces.canvas(SurfaceId::Shape); + let canvas = render_state.surfaces.canvas(SurfaceId::Strokes); let dpr_scale = render_state.viewbox.zoom * render_state.options.dpr(); let selrect = shape.selrect; let path_transform = shape.to_path_transform(); diff --git a/render-wasm/src/render/surfaces.rs b/render-wasm/src/render/surfaces.rs index 3d7f10126..1e7c9e0e2 100644 --- a/render-wasm/src/render/surfaces.rs +++ b/render-wasm/src/render/surfaces.rs @@ -1,10 +1,12 @@ use super::gpu_state::GpuState; use skia_safe as skia; +#[derive(Debug, PartialEq, Clone, Copy)] pub enum SurfaceId { Target, Current, - Shape, + Fills, + Strokes, Shadow, Overlay, Debug, @@ -15,8 +17,10 @@ pub struct Surfaces { target: skia::Surface, // keeps the current render current: skia::Surface, - // keeps the current shape - shape: skia::Surface, + // keeps the current shape's fills + shape_fills: skia::Surface, + // keeps the current shape's strokes + shape_strokes: skia::Surface, // used for rendering shadows shadow: skia::Surface, // for drawing the things that are over shadows. @@ -37,7 +41,8 @@ impl Surfaces { let current = target.new_surface_with_dimensions((width, height)).unwrap(); let shadow = target.new_surface_with_dimensions((width, height)).unwrap(); let overlay = target.new_surface_with_dimensions((width, height)).unwrap(); - let shape = target.new_surface_with_dimensions((width, height)).unwrap(); + let shape_fills = target.new_surface_with_dimensions((width, height)).unwrap(); + let shape_strokes = target.new_surface_with_dimensions((width, height)).unwrap(); let debug = target.new_surface_with_dimensions((width, height)).unwrap(); Surfaces { @@ -45,7 +50,8 @@ impl Surfaces { current, shadow, overlay, - shape, + shape_fills, + shape_strokes, debug, sampling_options, } @@ -76,13 +82,21 @@ impl Surfaces { .draw(self.canvas(to), (0.0, 0.0), sampling_options, paint); } + pub fn apply_mut(&mut self, ids: &[SurfaceId], mut f: impl FnMut(&mut skia::Surface) -> ()) { + for id in ids { + let surface = self.get_mut(*id); + f(surface); + } + } + fn get_mut(&mut self, id: SurfaceId) -> &mut skia::Surface { match id { SurfaceId::Target => &mut self.target, SurfaceId::Current => &mut self.current, SurfaceId::Shadow => &mut self.shadow, SurfaceId::Overlay => &mut self.overlay, - SurfaceId::Shape => &mut self.shape, + SurfaceId::Fills => &mut self.shape_fills, + SurfaceId::Strokes => &mut self.shape_strokes, SurfaceId::Debug => &mut self.debug, } } @@ -93,7 +107,7 @@ impl Surfaces { self.current = self.target.new_surface_with_dimensions(dim).unwrap(); self.overlay = self.target.new_surface_with_dimensions(dim).unwrap(); self.shadow = self.target.new_surface_with_dimensions(dim).unwrap(); - self.shape = self.target.new_surface_with_dimensions(dim).unwrap(); + self.shape_fills = self.target.new_surface_with_dimensions(dim).unwrap(); self.debug = self.target.new_surface_with_dimensions(dim).unwrap(); } }