From c87a35e4d5f3db206a512f953cc8fb4627b24c72 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Thu, 12 Jul 2018 15:59:21 -0400 Subject: [PATCH] Ensure canvas path stroking and filling use the same paths. --- components/canvas/canvas_data.rs | 42 +++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 04540c8a495..2b3e7e1e091 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -8,7 +8,7 @@ use azure::azure_hl::{AntialiasMode, CapStyle, CompositionOp, JoinStyle}; use azure::azure_hl::{ BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptions, SurfaceFormat, }; -use azure::azure_hl::{Color, ColorPattern, DrawSurfaceOptions, Filter, PathBuilder}; +use azure::azure_hl::{Color, ColorPattern, DrawSurfaceOptions, Filter, PathBuilder, Path}; use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern}; use canvas_traits::canvas::*; use cssparser::RGBA; @@ -23,6 +23,7 @@ pub struct CanvasData<'a> { drawtarget: DrawTarget, /// TODO(pcwalton): Support multiple paths. path_builder: PathBuilder, + path: Option, state: CanvasPaintState<'a>, saved_states: Vec>, webrender_api: webrender_api::RenderApi, @@ -47,6 +48,7 @@ impl<'a> CanvasData<'a> { CanvasData { drawtarget: draw_target, path_builder: path_builder, + path: None, state: CanvasPaintState::new(antialias), saved_states: vec![], webrender_api: webrender_api, @@ -206,40 +208,54 @@ impl<'a> CanvasData<'a> { } pub fn begin_path(&mut self) { - self.path_builder = self.drawtarget.create_path_builder() + self.path_builder = self.drawtarget.create_path_builder(); + self.path = None; } pub fn close_path(&self) { self.path_builder.close() } - pub fn fill(&self) { + fn ensure_path(&mut self) { + if self.path.is_none() { + self.path = Some(self.path_builder.finish()); + } + } + + fn path(&self) -> &Path { + self.path.as_ref().expect("Should have called ensure_path()") + } + + pub fn fill(&mut self) { if is_zero_size_gradient(&self.state.fill_style) { return; // Paint nothing if gradient size is zero. } + self.ensure_path(); self.drawtarget.fill( - &self.path_builder.finish(), + &self.path(), self.state.fill_style.to_pattern_ref(), &self.state.draw_options, ); } - pub fn stroke(&self) { + pub fn stroke(&mut self) { if is_zero_size_gradient(&self.state.stroke_style) { return; // Paint nothing if gradient size is zero. } + self.ensure_path(); self.drawtarget.stroke( - &self.path_builder.finish(), + &self.path(), self.state.stroke_style.to_pattern_ref(), &self.state.stroke_opts, &self.state.draw_options, ); } - pub fn clip(&self) { - self.drawtarget.push_clip(&self.path_builder.finish()); + pub fn clip(&mut self) { + self.ensure_path(); + self.drawtarget.push_clip(&self.path()); } pub fn is_point_in_path( @@ -249,9 +265,13 @@ impl<'a> CanvasData<'a> { _fill_rule: FillRule, chan: IpcSender, ) { - let path = self.path_builder.finish(); - let result = path.contains_point(x, y, &self.state.transform); - self.path_builder = path.copy_to_builder(); + self.ensure_path(); + let (path_builder, result) = { + let path = self.path(); + let result = path.contains_point(x, y, &self.state.transform); + (path.copy_to_builder(), result) + }; + self.path_builder = path_builder; chan.send(result).unwrap(); }