canvas: Join Path and PathBuilder into Path (#37842)

Dealing with both path and builder makes code complicated and this is
backend internal specific anyway (we often do conversions between the
two just so we get specific functionality). Now I joined both into
single abstractions `Path`, that has all what one needs and let raqote
backend deal with path/pathbuilder coversions.

Motivation: Simplification and in Vello there is only
[BezPath](https://docs.rs/kurbo/0.11.2/kurbo/struct.BezPath.html) so we
use it as both path and pathbuilder.

Reviewable per commit.

Testing: Existing WPT tests

---------

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
sagudev 2025-07-04 18:32:20 +02:00 committed by GitHub
parent 940eff9497
commit b57c9acc65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 197 additions and 230 deletions

View file

@ -5,14 +5,14 @@
use std::borrow::Cow;
use canvas_traits::canvas::{
CompositionOrBlending, FillOrStrokeStyle, LineCapStyle, LineJoinStyle,
CompositionOrBlending, FillOrStrokeStyle, LineCapStyle, LineJoinStyle, PathSegment,
};
use euclid::Angle;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use lyon_geom::Arc;
use style::color::AbsoluteColor;
use crate::canvas_data::{CanvasPaintState, Filter, TextRun};
use crate::canvas_data::{CanvasPaintState, Filter, PathBuilderRef, TextRun};
pub(crate) trait Backend: Clone + Sized {
type Pattern<'a>: PatternHelpers + Clone;
@ -21,9 +21,8 @@ pub(crate) trait Backend: Clone + Sized {
type DrawOptions: DrawOptionsHelpers + Clone;
type CompositionOp;
type DrawTarget: GenericDrawTarget<Self>;
type PathBuilder: GenericPathBuilder<Self>;
type Path: GenericPath<Self> + Clone;
type SourceSurface;
type Path: PathHelpers<Self> + Clone;
type GradientStop;
type GradientStops;
@ -61,7 +60,6 @@ pub(crate) trait GenericDrawTarget<B: Backend> {
source: Rect<i32>,
destination: Point2D<i32>,
);
fn create_path_builder(&self) -> B::PathBuilder;
fn create_similar_draw_target(&self, size: &Size2D<i32>) -> Self;
fn create_source_surface_from_data(&self, data: &[u8]) -> Option<B::SourceSurface>;
fn draw_surface(
@ -118,8 +116,10 @@ pub(crate) trait GenericDrawTarget<B: Backend> {
fn bytes(&self) -> Cow<[u8]>;
}
/// A generic PathBuilder that abstracts the interface for azure's and raqote's PathBuilder.
pub(crate) trait GenericPathBuilder<B: Backend> {
/// A generic Path that abstracts the interface for raqote's PathBuilder/Path.
pub(crate) trait GenericPath<B: Backend<Path = Self>> {
fn new() -> Self;
fn transform(&mut self, transform: &Transform2D<f32>);
fn arc(
&mut self,
origin: Point2D<f32>,
@ -237,7 +237,76 @@ pub(crate) trait GenericPathBuilder<B: Backend> {
self.quadratic_curve_to(&q.ctrl, &q.to);
});
}
fn finish(&mut self) -> B::Path;
fn contains_point(&self, x: f64, y: f64, path_transform: &Transform2D<f32>) -> bool;
fn add_segments(&mut self, path: &[PathSegment]) {
let mut build_ref = PathBuilderRef::<B> {
builder: self,
transform: Transform2D::identity(),
};
for &seg in path {
match seg {
PathSegment::ClosePath => build_ref.close(),
PathSegment::MoveTo { x, y } => build_ref.move_to(&Point2D::new(x, y)),
PathSegment::LineTo { x, y } => build_ref.line_to(&Point2D::new(x, y)),
PathSegment::Quadratic { cpx, cpy, x, y } => {
build_ref.quadratic_curve_to(&Point2D::new(cpx, cpy), &Point2D::new(x, y))
},
PathSegment::Bezier {
cp1x,
cp1y,
cp2x,
cp2y,
x,
y,
} => build_ref.bezier_curve_to(
&Point2D::new(cp1x, cp1y),
&Point2D::new(cp2x, cp2y),
&Point2D::new(x, y),
),
PathSegment::ArcTo {
cp1x,
cp1y,
cp2x,
cp2y,
radius,
} => build_ref.arc_to(&Point2D::new(cp1x, cp1y), &Point2D::new(cp2x, cp2y), radius),
PathSegment::Ellipse {
x,
y,
radius_x,
radius_y,
rotation,
start_angle,
end_angle,
anticlockwise,
} => build_ref.ellipse(
&Point2D::new(x, y),
radius_x,
radius_y,
rotation,
start_angle,
end_angle,
anticlockwise,
),
PathSegment::SvgArc {
radius_x,
radius_y,
rotation,
large_arc,
sweep,
x,
y,
} => build_ref.svg_arc(
radius_x,
radius_y,
rotation,
large_arc,
sweep,
&Point2D::new(x, y),
),
}
}
}
}
pub(crate) trait PatternHelpers {
@ -257,11 +326,3 @@ pub(crate) trait StrokeOptionsHelpers {
pub(crate) trait DrawOptionsHelpers {
fn set_alpha(&mut self, val: f32);
}
pub(crate) trait PathHelpers<B: Backend> {
fn transformed_copy_to_builder(&self, transform: &Transform2D<f32>) -> B::PathBuilder;
fn contains_point(&self, x: f64, y: f64, path_transform: &Transform2D<f32>) -> bool;
fn copy_to_builder(&self) -> B::PathBuilder;
}