diff options
author | Steven Novaryo <65610990+stevennovaryo@users.noreply.github.com> | 2025-04-01 19:22:00 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-01 11:22:00 +0000 |
commit | a77592e281aad3df23e38fcc574059a31c37f30c (patch) | |
tree | 29864dca24b1e8f699400b0264a4a7d199fa1d0e | |
parent | bc6926d1feea04b41879d43507509636db29b377 (diff) | |
download | servo-a77592e281aad3df23e38fcc574059a31c37f30c.tar.gz servo-a77592e281aad3df23e38fcc574059a31c37f30c.zip |
canvas: Implement line dash setters and getters (#36257)
Implement `setLineDash`, `getLineDash`, and `lineDashOffset` from
`CanvasPathDrawingStyles` mixin, according to the spec
https://html.spec.whatwg.org/multipage/canvas.html#canvaspathdrawingstyles.
Testing: Existing WPT.
---------
Signed-off-by: stevennovaryo <steven.novaryo@gmail.com>
21 files changed, 144 insertions, 92 deletions
diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs index 5462098abf5..34942388c23 100644 --- a/components/canvas/canvas_data.rs +++ b/components/canvas/canvas_data.rs @@ -1366,6 +1366,14 @@ impl<'a> CanvasData<'a> { self.state.stroke_opts.set_miter_limit(limit); } + pub fn set_line_dash(&mut self, items: Vec<f32>) { + self.state.stroke_opts.set_line_dash(items); + } + + pub fn set_line_dash_offset(&mut self, offset: f32) { + self.state.stroke_opts.set_line_dash_offset(offset); + } + pub fn get_transform(&self) -> Transform2D<f32> { self.drawtarget.get_transform() } diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 09d670d5274..1c6877772d3 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -230,6 +230,10 @@ impl<'a> CanvasPaintThread<'a> { Canvas2dMsg::SetLineCap(cap) => self.canvas(canvas_id).set_line_cap(cap), Canvas2dMsg::SetLineJoin(join) => self.canvas(canvas_id).set_line_join(join), Canvas2dMsg::SetMiterLimit(limit) => self.canvas(canvas_id).set_miter_limit(limit), + Canvas2dMsg::SetLineDash(items) => self.canvas(canvas_id).set_line_dash(items), + Canvas2dMsg::SetLineDashOffset(offset) => { + self.canvas(canvas_id).set_line_dash_offset(offset) + }, Canvas2dMsg::GetTransform(sender) => { let transform = self.canvas(canvas_id).get_transform(); sender.send(transform).unwrap(); diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs index bc8d20e9dcf..e40367a4ee8 100644 --- a/components/canvas/raqote_backend.rs +++ b/components/canvas/raqote_backend.rs @@ -298,6 +298,16 @@ impl StrokeOptions { StrokeOptions::Raqote(options) => options.cap = val.to_raqote_style(), } } + pub fn set_line_dash(&mut self, items: Vec<f32>) { + match self { + StrokeOptions::Raqote(options) => options.dash_array = items, + } + } + pub fn set_line_dash_offset(&mut self, offset: f32) { + match self { + StrokeOptions::Raqote(options) => options.dash_offset = offset, + } + } pub fn as_raqote(&self) -> &raqote::StrokeStyle { match self { StrokeOptions::Raqote(options) => options, diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs index b82f682b29f..fac9bee800d 100644 --- a/components/script/canvas_state.rs +++ b/components/script/canvas_state.rs @@ -94,6 +94,8 @@ pub(crate) struct CanvasContextState { #[no_trace] line_join: LineJoinStyle, miter_limit: f64, + line_dash: Vec<f64>, + line_dash_offset: f64, #[no_trace] transform: Transform2D<f32>, shadow_offset_x: f64, @@ -134,6 +136,8 @@ impl CanvasContextState { text_align: Default::default(), text_baseline: Default::default(), direction: Default::default(), + line_dash: Vec::new(), + line_dash_offset: 0.0, } } } @@ -1286,6 +1290,59 @@ impl CanvasState { self.send_canvas_2d_msg(Canvas2dMsg::SetMiterLimit(limit as f32)) } + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getlinedash> + pub(crate) fn line_dash(&self) -> Vec<f64> { + // > return a sequence whose values are the values of + // > the object's dash list, in the same order. + self.state.borrow().line_dash.clone() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-setlinedash> + pub(crate) fn set_line_dash(&self, segments: Vec<f64>) { + // > If any value in segments is not finite (e.g. an Infinity or a NaN value), + // > or if any value is negative (less than zero), then return (without throwing + // > an exception; user agents could show a message on a developer console, + // > though, as that would be helpful for debugging). + if segments + .iter() + .any(|segment| !segment.is_finite() || *segment < 0.0) + { + return; + } + + // > If the number of elements in segments is odd, then let segments + // > be the concatenation of two copies of segments. + let mut line_dash: Vec<_> = segments.clone(); + if segments.len() & 1 == 1 { + line_dash.extend(line_dash.clone()); + } + + // > Let the object's dash list be segments. + self.state.borrow_mut().line_dash = line_dash.clone(); + self.send_canvas_2d_msg(Canvas2dMsg::SetLineDash( + line_dash.into_iter().map(|dash| dash as f32).collect(), + )) + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + pub(crate) fn line_dash_offset(&self) -> f64 { + // > On getting, it must return the current value. + self.state.borrow().line_dash_offset + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset? + pub(crate) fn set_line_dash_offset(&self, offset: f64) { + // > On setting, infinite and NaN values must be ignored, + // > leaving the value unchanged; + if !offset.is_finite() { + return; + } + + // > other values must change the current value to the new value. + self.state.borrow_mut().line_dash_offset = offset; + self.send_canvas_2d_msg(Canvas2dMsg::SetLineDashOffset(offset as f32)); + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata pub(crate) fn create_image_data( &self, diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index cc8215fd335..f6bf432de69 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -642,6 +642,26 @@ impl CanvasRenderingContext2DMethods<crate::DomTypeHolder> for CanvasRenderingCo self.canvas_state.set_miter_limit(limit) } + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-setlinedash> + fn SetLineDash(&self, segments: Vec<f64>) { + self.canvas_state.set_line_dash(segments); + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getlinedash> + fn GetLineDash(&self) -> Vec<f64> { + self.canvas_state.line_dash() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + fn LineDashOffset(&self) -> f64 { + self.canvas_state.line_dash_offset() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + fn SetLineDashOffset(&self, offset: f64) { + self.canvas_state.set_line_dash_offset(offset); + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsetx fn ShadowOffsetX(&self) -> f64 { self.canvas_state.shadow_offset_x() diff --git a/components/script/dom/offscreencanvasrenderingcontext2d.rs b/components/script/dom/offscreencanvasrenderingcontext2d.rs index 731ef6d008a..69a1d41af2e 100644 --- a/components/script/dom/offscreencanvasrenderingcontext2d.rs +++ b/components/script/dom/offscreencanvasrenderingcontext2d.rs @@ -340,6 +340,26 @@ impl OffscreenCanvasRenderingContext2DMethods<crate::DomTypeHolder> self.context.SetMiterLimit(limit) } + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-setlinedash> + fn SetLineDash(&self, segments: Vec<f64>) { + self.context.SetLineDash(segments) + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getlinedash> + fn GetLineDash(&self) -> Vec<f64> { + self.context.GetLineDash() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + fn LineDashOffset(&self) -> f64 { + self.context.LineDashOffset() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + fn SetLineDashOffset(&self, offset: f64) { + self.context.SetLineDashOffset(offset) + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-createimagedata fn CreateImageData(&self, sw: i32, sh: i32, can_gc: CanGc) -> Fallible<DomRoot<ImageData>> { self.context.CreateImageData(sw, sh, can_gc) diff --git a/components/script/dom/paintrenderingcontext2d.rs b/components/script/dom/paintrenderingcontext2d.rs index 0babe77da97..04660e56a6b 100644 --- a/components/script/dom/paintrenderingcontext2d.rs +++ b/components/script/dom/paintrenderingcontext2d.rs @@ -430,6 +430,26 @@ impl PaintRenderingContext2DMethods<crate::DomTypeHolder> for PaintRenderingCont self.canvas_state.set_miter_limit(limit) } + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-setlinedash> + fn SetLineDash(&self, segments: Vec<f64>) { + self.canvas_state.set_line_dash(segments); + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-getlinedash> + fn GetLineDash(&self) -> Vec<f64> { + self.canvas_state.line_dash() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + fn LineDashOffset(&self) -> f64 { + self.canvas_state.line_dash_offset() + } + + /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-linedashoffset> + fn SetLineDashOffset(&self, offset: f64) { + self.canvas_state.set_line_dash_offset(offset); + } + // https://html.spec.whatwg.org/multipage/#dom-context-2d-shadowoffsetx fn ShadowOffsetX(&self) -> f64 { self.canvas_state.shadow_offset_x() diff --git a/components/script_bindings/webidls/CanvasRenderingContext2D.webidl b/components/script_bindings/webidls/CanvasRenderingContext2D.webidl index 92f61126859..f47de4efd29 100644 --- a/components/script_bindings/webidls/CanvasRenderingContext2D.webidl +++ b/components/script_bindings/webidls/CanvasRenderingContext2D.webidl @@ -191,9 +191,9 @@ interface mixin CanvasPathDrawingStyles { attribute unrestricted double miterLimit; // (default 10) // dashed lines - //void setLineDash(sequence<unrestricted double> segments); // default empty - //sequence<unrestricted double> getLineDash(); - //attribute unrestricted double lineDashOffset; + undefined setLineDash(sequence<unrestricted double> segments); // default empty + sequence<unrestricted double> getLineDash(); + attribute unrestricted double lineDashOffset; }; interface mixin CanvasTextDrawingStyles { diff --git a/components/shared/canvas/canvas.rs b/components/shared/canvas/canvas.rs index b01246bf9c1..90ba569b5eb 100644 --- a/components/shared/canvas/canvas.rs +++ b/components/shared/canvas/canvas.rs @@ -120,6 +120,8 @@ pub enum Canvas2dMsg { SetLineCap(LineCapStyle), SetLineJoin(LineJoinStyle), SetMiterLimit(f32), + SetLineDash(Vec<f32>), + SetLineDashOffset(f32), SetGlobalAlpha(f32), SetGlobalComposition(CompositionOrBlending), SetTransform(Transform2D<f32>), diff --git a/tests/wpt/meta/html/canvas/element/manual/line-styles/setLineDash.html.ini b/tests/wpt/meta/html/canvas/element/manual/line-styles/setLineDash.html.ini deleted file mode 100644 index ec4caf8e050..00000000000 --- a/tests/wpt/meta/html/canvas/element/manual/line-styles/setLineDash.html.ini +++ /dev/null @@ -1,7 +0,0 @@ -[setLineDash.html] - [Invalid arguments to setLineDash()] - expected: FAIL - - [setLineDash] - expected: FAIL - diff --git a/tests/wpt/meta/html/canvas/element/reset/2d.reset.render.line.html.ini b/tests/wpt/meta/html/canvas/element/reset/2d.reset.render.line.html.ini deleted file mode 100644 index 46b6c887ca4..00000000000 --- a/tests/wpt/meta/html/canvas/element/reset/2d.reset.render.line.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[2d.reset.render.line.html] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/element/reset/2d.reset.state.line_dash.html.ini b/tests/wpt/meta/html/canvas/element/reset/2d.reset.state.line_dash.html.ini deleted file mode 100644 index 61f771ded91..00000000000 --- a/tests/wpt/meta/html/canvas/element/reset/2d.reset.state.line_dash.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[2d.reset.state.line_dash.html] - [check that the line dash is reset] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/element/reset/2d.reset.state.line_dash_offset.html.ini b/tests/wpt/meta/html/canvas/element/reset/2d.reset.state.line_dash_offset.html.ini deleted file mode 100644 index 7a60aa8737e..00000000000 --- a/tests/wpt/meta/html/canvas/element/reset/2d.reset.state.line_dash_offset.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[2d.reset.state.line_dash_offset.html] - [check that the state is reset] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.render.line.html.ini b/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.render.line.html.ini deleted file mode 100644 index 46b6c887ca4..00000000000 --- a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.render.line.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[2d.reset.render.line.html] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash.html.ini b/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash.html.ini deleted file mode 100644 index 61f771ded91..00000000000 --- a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[2d.reset.state.line_dash.html] - [check that the line dash is reset] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash.worker.js.ini deleted file mode 100644 index e68cc6f1ea1..00000000000 --- a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash.worker.js.ini +++ /dev/null @@ -1,3 +0,0 @@ -[2d.reset.state.line_dash.worker.html] - [check that the line dash is reset] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash_offset.html.ini b/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash_offset.html.ini deleted file mode 100644 index 7a60aa8737e..00000000000 --- a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash_offset.html.ini +++ /dev/null @@ -1,3 +0,0 @@ -[2d.reset.state.line_dash_offset.html] - [check that the state is reset] - expected: FAIL diff --git a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash_offset.worker.js.ini b/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash_offset.worker.js.ini deleted file mode 100644 index a550b617421..00000000000 --- a/tests/wpt/meta/html/canvas/offscreen/reset/2d.reset.state.line_dash_offset.worker.js.ini +++ /dev/null @@ -1,3 +0,0 @@ -[2d.reset.state.line_dash_offset.worker.html] - [check that the state is reset] - expected: FAIL diff --git a/tests/wpt/meta/html/dom/idlharness.any.js.ini b/tests/wpt/meta/html/dom/idlharness.any.js.ini index 1ffefa4d7d9..3603be6f694 100644 --- a/tests/wpt/meta/html/dom/idlharness.any.js.ini +++ b/tests/wpt/meta/html/dom/idlharness.any.js.ini @@ -71,15 +71,6 @@ [OffscreenCanvasRenderingContext2D interface: operation strokeText(DOMString, unrestricted double, unrestricted double, optional unrestricted double)] expected: FAIL - [OffscreenCanvasRenderingContext2D interface: operation setLineDash(sequence<unrestricted double>)] - expected: FAIL - - [OffscreenCanvasRenderingContext2D interface: operation getLineDash()] - expected: FAIL - - [OffscreenCanvasRenderingContext2D interface: attribute lineDashOffset] - expected: FAIL - [OffscreenCanvasRenderingContext2D interface: attribute letterSpacing] expected: FAIL diff --git a/tests/wpt/meta/html/dom/idlharness.https.html.ini b/tests/wpt/meta/html/dom/idlharness.https.html.ini index 92bcad853c6..12044351c9e 100644 --- a/tests/wpt/meta/html/dom/idlharness.https.html.ini +++ b/tests/wpt/meta/html/dom/idlharness.https.html.ini @@ -146,9 +146,6 @@ [OffscreenCanvasRenderingContext2D interface: operation commit()] expected: FAIL - [CanvasRenderingContext2D interface: operation setLineDash(sequence<unrestricted double>)] - expected: FAIL - [DataTransferItemList interface object name] expected: FAIL @@ -4613,15 +4610,6 @@ [CanvasRenderingContext2D interface: operation strokeText(DOMString, unrestricted double, unrestricted double, optional unrestricted double)] expected: FAIL - [CanvasRenderingContext2D interface: operation setLineDash(sequence<unrestricted double>)] - expected: FAIL - - [CanvasRenderingContext2D interface: operation getLineDash()] - expected: FAIL - - [CanvasRenderingContext2D interface: attribute lineDashOffset] - expected: FAIL - [CanvasRenderingContext2D interface: attribute letterSpacing] expected: FAIL @@ -4691,18 +4679,6 @@ [CanvasRenderingContext2D interface: calling strokeText(DOMString, unrestricted double, unrestricted double, optional unrestricted double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "setLineDash(sequence<unrestricted double>)" with the proper type] - expected: FAIL - - [CanvasRenderingContext2D interface: calling setLineDash(sequence<unrestricted double>) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] - expected: FAIL - - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "getLineDash()" with the proper type] - expected: FAIL - - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "lineDashOffset" with the proper type] - expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "letterSpacing" with the proper type] expected: FAIL @@ -4802,15 +4778,6 @@ [OffscreenCanvasRenderingContext2D interface: operation strokeText(DOMString, unrestricted double, unrestricted double, optional unrestricted double)] expected: FAIL - [OffscreenCanvasRenderingContext2D interface: operation setLineDash(sequence<unrestricted double>)] - expected: FAIL - - [OffscreenCanvasRenderingContext2D interface: operation getLineDash()] - expected: FAIL - - [OffscreenCanvasRenderingContext2D interface: attribute lineDashOffset] - expected: FAIL - [OffscreenCanvasRenderingContext2D interface: attribute letterSpacing] expected: FAIL diff --git a/tests/wpt/meta/webidl/ecmascript-binding/sequence-conversion.html.ini b/tests/wpt/meta/webidl/ecmascript-binding/sequence-conversion.html.ini deleted file mode 100644 index 059896ad46b..00000000000 --- a/tests/wpt/meta/webidl/ecmascript-binding/sequence-conversion.html.ini +++ /dev/null @@ -1,18 +0,0 @@ -[sequence-conversion.html] - [An array] - expected: FAIL - - [A generator] - expected: FAIL - - [An array with an overridden Symbol.iterator] - expected: FAIL - - [An array with an overridden Symbol.iterator on the prototype] - expected: FAIL - - [An array with an overridden %ArrayIterator%.prototype.next] - expected: FAIL - - [A holey array with fallback to an accessor on the prototype] - expected: FAIL |