From 56303e21ccb22313498584cdeb08544398a08c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1ty=C3=A1s=20Mustoha?= Date: Thu, 26 Mar 2015 16:43:34 +0100 Subject: [PATCH] Canvas: added arcTo() support. --- components/canvas/canvas_paint_task.rs | 60 +++++++++++++++++++ components/canvas/lib.rs | 1 + .../script/dom/canvasrenderingcontext2d.rs | 13 ++++ .../webidls/CanvasRenderingContext2D.webidl | 5 +- components/servo/Cargo.lock | 2 +- ports/cef/Cargo.lock | 2 +- ports/gonk/Cargo.lock | 2 +- .../2d.path.arcTo.coincide.2.html.ini | 5 -- .../2d.path.arcTo.collinear.1.html.ini | 5 -- .../2d.path.arcTo.collinear.2.html.ini | 5 -- .../2d.path.arcTo.collinear.3.html.ini | 5 -- .../2d.path.arcTo.ensuresubpath.1.html.ini | 5 -- .../2d.path.arcTo.ensuresubpath.2.html.ini | 5 -- .../2d.path.arcTo.negative.html.ini | 5 -- .../2d.path.arcTo.nonfinite.html.ini | 5 -- .../2d.path.arcTo.shape.end.html.ini | 5 -- .../2d.path.arcTo.zero.1.html.ini | 5 -- .../2d.path.arcTo.zero.2.html.ini | 5 -- .../2d.path.stroke.prune.arc.html.ini | 5 -- .../wpt/metadata/html/dom/interfaces.html.ini | 12 ---- 20 files changed, 81 insertions(+), 76 deletions(-) delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.coincide.2.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.1.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.2.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.3.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.1.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.2.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.negative.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.nonfinite.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.shape.end.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.1.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.2.html.ini delete mode 100644 tests/wpt/metadata/2dcontext/path-objects/2d.path.stroke.prune.arc.html.ini diff --git a/components/canvas/canvas_paint_task.rs b/components/canvas/canvas_paint_task.rs index 522f5104aa3..403e4b2a3c7 100644 --- a/components/canvas/canvas_paint_task.rs +++ b/components/canvas/canvas_paint_task.rs @@ -16,6 +16,7 @@ use util::vec::byte_swap; use cssparser::RGBA; use std::borrow::ToOwned; +use std::num::Float; use std::sync::mpsc::{channel, Sender}; #[derive(Clone)] @@ -34,6 +35,7 @@ pub enum CanvasMsg { QuadraticCurveTo(Point2D, Point2D), BezierCurveTo(Point2D, Point2D, Point2D), Arc(Point2D, f32, f32, f32, bool), + ArcTo(Point2D, Point2D, f32), SetFillStyle(FillOrStrokeStyle), SetStrokeStyle(FillOrStrokeStyle), SetTransform(Matrix2D), @@ -230,6 +232,9 @@ impl<'a> CanvasPaintTask<'a> { CanvasMsg::Arc(ref center, radius, start, end, ccw) => { painter.arc(center, radius, start, end, ccw) } + CanvasMsg::ArcTo(ref cp1, ref cp2, radius) => { + painter.arc_to(cp1, cp2, radius) + } CanvasMsg::SetFillStyle(style) => painter.set_fill_style(style), CanvasMsg::SetStrokeStyle(style) => painter.set_stroke_style(style), CanvasMsg::SetTransform(ref matrix) => painter.set_transform(matrix), @@ -344,6 +349,61 @@ impl<'a> CanvasPaintTask<'a> { self.path_builder.arc(*center, radius, start_angle, end_angle, ccw) } + fn arc_to(&self, + cp1: &Point2D, + cp2: &Point2D, + radius: AzFloat) { + let cp0 = self.path_builder.get_current_point(); + let cp1 = *cp1; + let cp2 = *cp2; + + if (cp0.x == cp1.x && cp0.y == cp1.y) || cp1 == cp2 || radius == 0.0 { + self.line_to(&cp1); + return; + } + + // if all three control points lie on a single straight line, + // connect the first two by a straight line + let direction = (cp2.x - cp1.x) * (cp0.y - cp1.y) + (cp2.y - cp1.y) * (cp1.x - cp0.x); + if direction == 0.0 { + self.line_to(&cp1); + return; + } + + // otherwise, draw the Arc + let a2 = (cp0.x - cp1.x).powi(2) + (cp0.y - cp1.y).powi(2); + let b2 = (cp1.x - cp2.x).powi(2) + (cp1.y - cp2.y).powi(2); + let d = { + let c2 = (cp0.x - cp2.x).powi(2) + (cp0.y - cp2.y).powi(2); + let cosx = (a2 + b2 - c2) / (2.0 * (a2 * b2).sqrt()); + let sinx = (1.0 - cosx.powi(2)).sqrt(); + radius / ((1.0 - cosx) / sinx) + }; + + // first tangent point + let anx = (cp1.x - cp0.x) / a2.sqrt(); + let any = (cp1.y - cp0.y) / a2.sqrt(); + let tp1 = Point2D::(cp1.x - anx * d, cp1.y - any * d); + + // second tangent point + let bnx = (cp1.x - cp2.x) / b2.sqrt(); + let bny = (cp1.y - cp2.y) / b2.sqrt(); + let tp2 = Point2D::(cp1.x - bnx * d, cp1.y - bny * d); + + // arc center and angles + let anticlockwise = direction < 0.0; + let cx = tp1.x + any * radius * if anticlockwise { 1.0 } else { -1.0 }; + let cy = tp1.y - anx * radius * if anticlockwise { 1.0 } else { -1.0 }; + let angle_start = (tp1.y - cy).atan2(tp1.x - cx); + let angle_end = (tp2.y - cy).atan2(tp2.x - cx); + + self.line_to(&tp1); + if [cx, cy, angle_start, angle_end].iter().all(|x| x.is_finite()) { + self.arc(&Point2D::(cx, cy), radius, + angle_start, angle_end, anticlockwise); + } + } + fn set_fill_style(&mut self, style: FillOrStrokeStyle) { self.fill_style = style.to_azure_pattern(&self.drawtarget) } diff --git a/components/canvas/lib.rs b/components/canvas/lib.rs index 7118b76af00..dba859dc9df 100644 --- a/components/canvas/lib.rs +++ b/components/canvas/lib.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #![feature(collections)] +#![feature(std_misc)] extern crate azure; extern crate cssparser; diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 4145c8e28cc..c2316dd44db 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -477,6 +477,19 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> Ok(()) } + fn ArcTo(self, cp1x: f64, cp1y: f64, cp2x: f64, cp2y: f64, r: f64) -> Fallible<()> { + if !([cp1x, cp1y, cp2x, cp2y, r].iter().all(|x| x.is_finite())) { + return Ok(()); + } + if r < 0.0 { + return Err(IndexSize); + } + self.renderer.send(CanvasMsg::ArcTo(Point2D(cp1x as f32, cp1y as f32), + Point2D(cp2x as f32, cp2y as f32), + r as f32)).unwrap(); + Ok(()) + } + // https://html.spec.whatwg.org/#dom-context-2d-imagesmoothingenabled fn ImageSmoothingEnabled(self) -> bool { self.image_smoothing_enabled.get() diff --git a/components/script/dom/webidls/CanvasRenderingContext2D.webidl b/components/script/dom/webidls/CanvasRenderingContext2D.webidl index 96624deb0fa..511a26ae66b 100644 --- a/components/script/dom/webidls/CanvasRenderingContext2D.webidl +++ b/components/script/dom/webidls/CanvasRenderingContext2D.webidl @@ -145,7 +145,10 @@ interface CanvasPathMethods { unrestricted double x, unrestricted double y); - //void arcTo(double x1, double y1, double x2, double y2, double radius); + [Throws] + void arcTo(unrestricted double x1, unrestricted double y1, + unrestricted double x2, unrestricted double y2, + unrestricted double radius); // NOT IMPLEMENTED [LenientFloat] void arcTo(double x1, double y1, double x2, double y2, double radiusX, double radiusY, double rotation); //void rect(double x, double y, double w, double h); diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 4183d8627e9..4ed7d0fee11 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -31,7 +31,7 @@ source = "git+https://github.com/tomaka/android-rs-glue#5a68056599fb498b0cf3715f [[package]] name = "azure" version = "0.1.0" -source = "git+https://github.com/servo/rust-azure#9aae2113fb19a34a67a82b7ec6a5e0b34e290d29" +source = "git+https://github.com/servo/rust-azure#c71473d94ae24fb195987660698207d5088a4042" dependencies = [ "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 30adc00a7b4..0fbbade1a28 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -36,7 +36,7 @@ source = "git+https://github.com/tomaka/android-rs-glue#5a68056599fb498b0cf3715f [[package]] name = "azure" version = "0.1.0" -source = "git+https://github.com/servo/rust-azure#9aae2113fb19a34a67a82b7ec6a5e0b34e290d29" +source = "git+https://github.com/servo/rust-azure#c71473d94ae24fb195987660698207d5088a4042" dependencies = [ "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index 0ee174dbc67..49e49ef1338 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -24,7 +24,7 @@ dependencies = [ [[package]] name = "azure" version = "0.1.0" -source = "git+https://github.com/servo/rust-azure#9aae2113fb19a34a67a82b7ec6a5e0b34e290d29" +source = "git+https://github.com/servo/rust-azure#c71473d94ae24fb195987660698207d5088a4042" dependencies = [ "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.coincide.2.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.coincide.2.html.ini deleted file mode 100644 index 916ac446886..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.coincide.2.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.coincide.2.html] - type: testharness - [arcTo() draws a straight line to P1 if P1 = P2] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.1.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.1.html.ini deleted file mode 100644 index 6196beb9176..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.1.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.collinear.1.html] - type: testharness - [arcTo() with all points on a line, and P1 between P0/P2, draws a straight line to P1] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.2.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.2.html.ini deleted file mode 100644 index 85fbca77e84..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.2.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.collinear.2.html] - type: testharness - [arcTo() with all points on a line, and P2 between P0/P1, draws a straight line to P1] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.3.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.3.html.ini deleted file mode 100644 index f1faf63dde5..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.collinear.3.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.collinear.3.html] - type: testharness - [arcTo() with all points on a line, and P0 between P1/P2, draws a straight line to P1] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.1.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.1.html.ini deleted file mode 100644 index 1f530b60b13..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.1.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.ensuresubpath.1.html] - type: testharness - [If there is no subpath, the first control point is added (and nothing is drawn up to it)] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.2.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.2.html.ini deleted file mode 100644 index a0dd9521cd8..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.ensuresubpath.2.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.ensuresubpath.2.html] - type: testharness - [If there is no subpath, the first control point is added] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.negative.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.negative.html.ini deleted file mode 100644 index a95f562affc..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.negative.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.negative.html] - type: testharness - [arcTo() with negative radius throws an exception] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.nonfinite.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.nonfinite.html.ini deleted file mode 100644 index 9edb4bf29ef..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.nonfinite.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.nonfinite.html] - type: testharness - [arcTo() with Infinity/NaN is ignored] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.shape.end.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.shape.end.html.ini deleted file mode 100644 index 019012629ca..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.shape.end.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.shape.end.html] - type: testharness - [arcTo() does not draw anything from P1 to P2] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.1.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.1.html.ini deleted file mode 100644 index 4bea8f4b115..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.1.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.zero.1.html] - type: testharness - [arcTo() with zero radius draws a straight line from P0 to P1] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.2.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.2.html.ini deleted file mode 100644 index 7570e15e03a..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.arcTo.zero.2.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.arcTo.zero.2.html] - type: testharness - [arcTo() with zero radius draws a straight line from P0 to P1, even when all points are collinear] - expected: FAIL - diff --git a/tests/wpt/metadata/2dcontext/path-objects/2d.path.stroke.prune.arc.html.ini b/tests/wpt/metadata/2dcontext/path-objects/2d.path.stroke.prune.arc.html.ini deleted file mode 100644 index d0d5286768b..00000000000 --- a/tests/wpt/metadata/2dcontext/path-objects/2d.path.stroke.prune.arc.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[2d.path.stroke.prune.arc.html] - type: testharness - [Zero-length line segments from arcTo and arc are removed before stroking] - expected: FAIL - diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index 9ae1cc788db..474c32309fd 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -7083,9 +7083,6 @@ [CanvasRenderingContext2D interface: attribute direction] expected: FAIL - [CanvasRenderingContext2D interface: operation arcTo(unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double)] - expected: FAIL - [CanvasRenderingContext2D interface: operation arcTo(unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double)] expected: FAIL @@ -7305,15 +7302,6 @@ [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "direction" with the proper type (69)] expected: FAIL - [CanvasRenderingContext2D interface: document.createElement("canvas").getContext("2d") must inherit property "arcTo" with the proper type (75)] - expected: FAIL - - [CanvasRenderingContext2D interface: calling arcTo(unrestricted double,unrestricted double,unrestricted double,unrestricted double,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 "arcTo" with the proper type (76)] - expected: FAIL - [CanvasRenderingContext2D interface: calling arcTo(unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double,unrestricted double) on document.createElement("canvas").getContext("2d") with too few arguments must throw TypeError] expected: FAIL