Ensure canvas path stroking and filling use the same paths.

This commit is contained in:
Josh Matthews 2018-07-12 15:59:21 -04:00
parent a34c8f952e
commit c87a35e4d5

View file

@ -8,7 +8,7 @@ use azure::azure_hl::{AntialiasMode, CapStyle, CompositionOp, JoinStyle};
use azure::azure_hl::{ use azure::azure_hl::{
BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptions, SurfaceFormat, 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 azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern};
use canvas_traits::canvas::*; use canvas_traits::canvas::*;
use cssparser::RGBA; use cssparser::RGBA;
@ -23,6 +23,7 @@ pub struct CanvasData<'a> {
drawtarget: DrawTarget, drawtarget: DrawTarget,
/// TODO(pcwalton): Support multiple paths. /// TODO(pcwalton): Support multiple paths.
path_builder: PathBuilder, path_builder: PathBuilder,
path: Option<Path>,
state: CanvasPaintState<'a>, state: CanvasPaintState<'a>,
saved_states: Vec<CanvasPaintState<'a>>, saved_states: Vec<CanvasPaintState<'a>>,
webrender_api: webrender_api::RenderApi, webrender_api: webrender_api::RenderApi,
@ -47,6 +48,7 @@ impl<'a> CanvasData<'a> {
CanvasData { CanvasData {
drawtarget: draw_target, drawtarget: draw_target,
path_builder: path_builder, path_builder: path_builder,
path: None,
state: CanvasPaintState::new(antialias), state: CanvasPaintState::new(antialias),
saved_states: vec![], saved_states: vec![],
webrender_api: webrender_api, webrender_api: webrender_api,
@ -206,40 +208,54 @@ impl<'a> CanvasData<'a> {
} }
pub fn begin_path(&mut self) { 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) { pub fn close_path(&self) {
self.path_builder.close() 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) { if is_zero_size_gradient(&self.state.fill_style) {
return; // Paint nothing if gradient size is zero. return; // Paint nothing if gradient size is zero.
} }
self.ensure_path();
self.drawtarget.fill( self.drawtarget.fill(
&self.path_builder.finish(), &self.path(),
self.state.fill_style.to_pattern_ref(), self.state.fill_style.to_pattern_ref(),
&self.state.draw_options, &self.state.draw_options,
); );
} }
pub fn stroke(&self) { pub fn stroke(&mut self) {
if is_zero_size_gradient(&self.state.stroke_style) { if is_zero_size_gradient(&self.state.stroke_style) {
return; // Paint nothing if gradient size is zero. return; // Paint nothing if gradient size is zero.
} }
self.ensure_path();
self.drawtarget.stroke( self.drawtarget.stroke(
&self.path_builder.finish(), &self.path(),
self.state.stroke_style.to_pattern_ref(), self.state.stroke_style.to_pattern_ref(),
&self.state.stroke_opts, &self.state.stroke_opts,
&self.state.draw_options, &self.state.draw_options,
); );
} }
pub fn clip(&self) { pub fn clip(&mut self) {
self.drawtarget.push_clip(&self.path_builder.finish()); self.ensure_path();
self.drawtarget.push_clip(&self.path());
} }
pub fn is_point_in_path( pub fn is_point_in_path(
@ -249,9 +265,13 @@ impl<'a> CanvasData<'a> {
_fill_rule: FillRule, _fill_rule: FillRule,
chan: IpcSender<bool>, chan: IpcSender<bool>,
) { ) {
let path = self.path_builder.finish(); self.ensure_path();
let result = path.contains_point(x, y, &self.state.transform); let (path_builder, result) = {
self.path_builder = path.copy_to_builder(); 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(); chan.send(result).unwrap();
} }