зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
ace2c5ee02
Коммит
f0707cb664
|
@ -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);
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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)",
|
||||
|
|
|
@ -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)",
|
||||
|
|
Загрузка…
Ссылка в новой задаче