canvas: Move current_default_path to script CanvasState (#38114)

This PR moves current path handling from canvas paint thread to script's
`CanvasState`. Because we used manual impl for arcto and some prechecks
for early fail before sending IPC we also needed to fix some bugs in
Path impl.

Testing: Existing WPT tests
work towards #38022
try run: https://github.com/sagudev/servo/actions/runs/16316090028

Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
sagudev 2025-07-18 07:45:53 +02:00 committed by GitHub
parent bbed6cddcd
commit a070f24450
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 82 additions and 594 deletions

View file

@ -10,6 +10,7 @@ use euclid::approxeq::ApproxEq;
use euclid::default::{Point2D, Rect, Size2D, Transform2D};
use ipc_channel::ipc::IpcSender;
use kurbo::{Affine, BezPath, ParamCurveNearest as _, PathEl, Point, Shape, Triangle};
use malloc_size_of::MallocSizeOf;
use malloc_size_of_derive::MallocSizeOf;
use pixels::IpcSnapshot;
use serde::{Deserialize, Serialize};
@ -20,6 +21,12 @@ use style::properties::style_structs::Font as FontStyleStruct;
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Path(pub BezPath);
impl MallocSizeOf for Path {
fn size_of(&self, _ops: &mut malloc_size_of::MallocSizeOfOps) -> usize {
std::mem::size_of_val(self.0.elements())
}
}
pub struct IndexSizeError;
impl Path {
@ -146,7 +153,7 @@ impl Path {
self.ensure_there_is_a_subpath(x1, y1);
// Step 3. If either radius is negative, then throw an "IndexSizeError" DOMException.
if radius.is_sign_negative() {
if radius < 0.0 {
return Err(IndexSizeError);
}
@ -166,7 +173,7 @@ impl Path {
// all lie on a single straight line, then add the point (x1, y1) to the subpath,
// and connect that point to the previous point (x0, y0) by a straight line.
let direction = Triangle::from_coords((x0, y0), (x1, y1), (x2, y2)).area();
if direction == 0.0 {
if direction.approx_eq(&0.0) {
self.0.line_to((x1, y1));
return Ok(());
}
@ -209,7 +216,7 @@ impl Path {
let angle_start = (tp1.y - cy).atan2(tp1.x - cx);
let angle_end = (tp2.y - cy).atan2(tp2.x - cx);
self.0.line_to((tp1.x, tp2.x));
self.0.line_to((tp1.x, tp1.y));
self.arc(cx, cy, radius, angle_start, angle_end, anticlockwise)
}
@ -280,7 +287,7 @@ impl Path {
}
// Step 2. If either radiusX or radiusY are negative, then throw an "IndexSizeError" DOMException.
if radius_x.is_sign_negative() || radius_y.is_sign_negative() {
if radius_x < 0.0 || radius_y < 0.0 {
return Err(IndexSizeError);
}
@ -419,34 +426,20 @@ pub enum CanvasMsg {
#[derive(Debug, Deserialize, Serialize)]
pub enum Canvas2dMsg {
Arc(Point2D<f32>, f32, f32, f32, bool),
ArcTo(Point2D<f32>, Point2D<f32>, f32),
DrawImage(IpcSnapshot, Rect<f64>, Rect<f64>, bool),
DrawEmptyImage(Size2D<u32>, Rect<f64>, Rect<f64>),
DrawImageInOther(CanvasId, Size2D<u32>, Rect<f64>, Rect<f64>, bool),
BeginPath,
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
ClearRect(Rect<f32>),
Clip,
ClipPath(Path),
ClosePath,
Ellipse(Point2D<f32>, f32, f32, f32, f32, f32, bool),
Fill(FillOrStrokeStyle),
FillPath(FillOrStrokeStyle, Path),
FillText(String, f64, f64, Option<f64>, FillOrStrokeStyle, bool),
FillRect(Rect<f32>, FillOrStrokeStyle),
GetImageData(Rect<u32>, Size2D<u32>, IpcSender<IpcSnapshot>),
IsPointInCurrentPath(f64, f64, FillRule, IpcSender<bool>),
LineTo(Point2D<f32>),
MoveTo(Point2D<f32>),
MeasureText(String, IpcSender<TextMetrics>),
PutImageData(Rect<u32>, IpcSnapshot),
QuadraticCurveTo(Point2D<f32>, Point2D<f32>),
Rect(Rect<f32>),
RestoreContext,
SaveContext,
StrokeRect(Rect<f32>, FillOrStrokeStyle),
Stroke(FillOrStrokeStyle),
StrokePath(FillOrStrokeStyle, Path),
SetLineWidth(f32),
SetLineCap(LineCapStyle),