diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index c06fb94f..6d63fea8 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -22,7 +22,7 @@ use pathfinder_geometry::vector::Vector2F; use pathfinder_geometry::rect::RectF; use pathfinder_geometry::transform2d::Transform2F; use pathfinder_renderer::paint::{Paint, PaintId}; -use pathfinder_renderer::scene::{DrawPath, Scene}; +use pathfinder_renderer::scene::{ClipPath, ClipPathId, DrawPath, Scene}; use std::borrow::Cow; use std::default::Default; use std::f32::consts::PI; @@ -199,17 +199,27 @@ impl CanvasRenderingContext2D { self.push_path(outline, paint_id); } + pub fn clip_path(&mut self, path: Path2D) { + let mut outline = path.into_outline(); + outline.transform(&self.current_state.transform); + + let clip_path_id = self.scene.push_clip_path(ClipPath::new(outline, String::new())); + self.current_state.clip_path = Some(clip_path_id); + } + fn push_path(&mut self, outline: Outline, paint_id: PaintId) { + let clip_path = self.current_state.clip_path; + if !self.current_state.shadow_paint.is_fully_transparent() { let paint = self.current_state.resolve_paint(&self.current_state.shadow_paint); let paint_id = self.scene.push_paint(&paint); let mut outline = outline.clone(); outline.transform(&Transform2F::from_translation(self.current_state.shadow_offset)); - self.scene.push_path(DrawPath::new(outline, paint_id, String::new())) + self.scene.push_path(DrawPath::new(outline, paint_id, clip_path, String::new())) } - self.scene.push_path(DrawPath::new(outline, paint_id, String::new())) + self.scene.push_path(DrawPath::new(outline, paint_id, clip_path, String::new())) } // Transformations @@ -273,6 +283,7 @@ struct State { shadow_offset: Vector2F, text_align: TextAlign, global_alpha: f32, + clip_path: Option, } impl State { @@ -293,6 +304,7 @@ impl State { shadow_offset: Vector2F::default(), text_align: TextAlign::Left, global_alpha: 1.0, + clip_path: None, } } diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index a6ba16c0..5fe239d6 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -24,6 +24,7 @@ use pathfinder_content::outline::Outline; #[derive(Clone)] pub struct Scene { pub(crate) paths: Vec, + pub(crate) clip_paths: Vec, palette: Palette, bounds: RectF, view_box: RectF, @@ -34,6 +35,7 @@ impl Scene { pub fn new() -> Scene { Scene { paths: vec![], + clip_paths: vec![], palette: Palette::new(), bounds: RectF::default(), view_box: RectF::default(), @@ -45,6 +47,13 @@ impl Scene { self.paths.push(path); } + pub fn push_clip_path(&mut self, clip_path: ClipPath) -> ClipPathId { + self.bounds = self.bounds.union_rect(clip_path.outline.bounds()); + let clip_path_id = ClipPathId(self.clip_paths.len() as u32); + self.clip_paths.push(clip_path); + clip_path_id + } + #[inline] pub fn build_paint_info(&self) -> PaintInfo { self.palette.build_paint_info(self.view_box.size().to_i32()) @@ -204,13 +213,24 @@ impl<'a> Iterator for PathIter<'a> { pub struct DrawPath { outline: Outline, paint: PaintId, + clip_path: Option, name: String, } +#[derive(Clone, Debug)] +pub struct ClipPath { + outline: Outline, + name: String, +} + +#[derive(Clone, Copy, Debug)] +pub struct ClipPathId(pub u32); + impl DrawPath { #[inline] - pub fn new(outline: Outline, paint: PaintId, name: String) -> DrawPath { - DrawPath { outline, paint, name } + pub fn new(outline: Outline, paint: PaintId, clip_path: Option, name: String) + -> DrawPath { + DrawPath { outline, paint, clip_path, name } } #[inline] @@ -218,8 +238,25 @@ impl DrawPath { &self.outline } + #[inline] + pub(crate) fn clip_path(&self) -> Option { + self.clip_path + } + #[inline] pub(crate) fn paint(&self) -> PaintId { self.paint } } + +impl ClipPath { + #[inline] + pub fn new(outline: Outline, name: String) -> ClipPath { + ClipPath { outline, name } + } + + #[inline] + pub fn outline(&self) -> &Outline { + &self.outline + } +} diff --git a/svg/src/lib.rs b/svg/src/lib.rs index e0e4f973..abc8073d 100644 --- a/svg/src/lib.rs +++ b/svg/src/lib.rs @@ -122,8 +122,9 @@ impl BuiltSVG { let path = Transform2FPathIter::new(path, &transform); let outline = Outline::from_segments(path); + // TODO(pcwalton): Clip paths. let name = format!("Fill({})", node.id()); - self.scene.push_path(DrawPath::new(outline, style, name)); + self.scene.push_path(DrawPath::new(outline, style, None, name)); } if let Some(ref stroke) = path.stroke { @@ -148,8 +149,9 @@ impl BuiltSVG { let mut outline = stroke_to_fill.into_outline(); outline.transform(&transform); + // TODO(pcwalton): Clip paths. let name = format!("Stroke({})", node.id()); - self.scene.push_path(DrawPath::new(outline, style, name)); + self.scene.push_path(DrawPath::new(outline, style, None, name)); } } NodeKind::Path(..) => {} diff --git a/swf/src/lib.rs b/swf/src/lib.rs index f8b10f27..b82889a8 100644 --- a/swf/src/lib.rs +++ b/swf/src/lib.rs @@ -197,6 +197,7 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) { scene.push_path(DrawPath::new( path, paint_id, + None, String::new() )); } diff --git a/text/src/lib.rs b/text/src/lib.rs index 366ca305..09fc3bd7 100644 --- a/text/src/lib.rs +++ b/text/src/lib.rs @@ -76,7 +76,7 @@ impl SceneExt for Scene { outline = stroke_to_fill.into_outline(); } - self.push_path(DrawPath::new(outline, paint_id, String::new())); + self.push_path(DrawPath::new(outline, paint_id, None, String::new())); Ok(()) }