servo: Merge #5414 - Canvas: added arcTo() support (from mmatyas:canvas_arcto); r=jdm

Based on the implementation in Firefox.

After comparing how `arcTo` works in different browsers, I've found the code in Firefox the cleanest implentation. It also performed better on some test, for example the one on [this site](http://flashcanvas.net/examples/dl.dropbox.com/u/1865210/mindcat/arcto.html). In (Linux) Firefox 36, it looks like [this](http://i59.tinypic.com/2ch5b2d.png), while in Chromium 41, [some features are missing](http://i58.tinypic.com/30u5w8z.png).

Source-Repo: https://github.com/servo/servo
Source-Revision: ae31d9d9e86eb90a1fe2858f10ca5e6e2e722c67
This commit is contained in:
Mátyás Mustoha 2015-04-01 15:00:43 -06:00
Родитель ace2c5ee02
Коммит f0707cb664
7 изменённых файлов: 81 добавлений и 4 удалений

Просмотреть файл

@ -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<f32>, Point2D<f32>),
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
Arc(Point2D<f32>, f32, f32, f32, bool),
ArcTo(Point2D<f32>, Point2D<f32>, f32),
SetFillStyle(FillOrStrokeStyle),
SetStrokeStyle(FillOrStrokeStyle),
SetTransform(Matrix2D<f32>),
@ -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<AzFloat>,
cp2: &Point2D<AzFloat>,
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::<AzFloat>(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::<AzFloat>(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::<AzFloat>(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)
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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()

Просмотреть файл

@ -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);

2
servo/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)",

2
servo/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)",

2
servo/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)",