2008-12-29 Dirk Schulze <krit@webkit.org>
[WebKit-https.git] / WebCore / platform / graphics / cairo / PathCairo.cpp
index 4ba0b6e..c61f2ac 100644 (file)
@@ -4,6 +4,7 @@
                   2004, 2005, 2006 Rob Buis <buis@kde.org>
                   2005, 2007 Apple Inc. All Rights reserved.
                   2007 Alp Toker <alp@atoker.com>
+                  2008 Dirk Schulze <krit@webkit.org>
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -155,9 +156,78 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlo
 
 void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
 {
-    // FIXME: cairo_arc_to not yet in cairo see cairo.h
-    // cairo_arc_to(m_cr, p1.x(), p1.y(), p2.x(), p2.y());
-    notImplemented();
+    if (isEmpty())
+        return;
+
+    cairo_t* cr = platformPath()->m_cr;
+
+    double x0, y0;
+    cairo_get_current_point(cr, &x0, &y0);
+    FloatPoint p0(x0, y0);
+    if ((p1.x() == p0.x() && p1.y() == p0.y()) || (p1.x() == p2.x() && p1.y() == p2.y()) || radius == 0.f) {
+        cairo_line_to(cr, p1.x(), p1.y());
+        return;
+    }
+
+    FloatPoint p1p0((p0.x() - p1.x()),(p0.y() - p1.y()));
+    FloatPoint p1p2((p2.x() - p1.x()),(p2.y() - p1.y()));
+    float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+    float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+    double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+    // all points on a line logic
+    if (cos_phi == -1) {
+        cairo_line_to(cr, p1.x(), p1.y());
+        return;
+    }
+    if (cos_phi == 1) {
+        // add infinite far away point
+        unsigned int max_length = 65535;
+        double factor_max = max_length / p1p0_length;
+        FloatPoint ep((p0.x() + factor_max * p1p0.x()), (p0.y() + factor_max * p1p0.y()));
+        cairo_line_to(cr, ep.x(), ep.y());
+        return;
+    }
+
+    float tangent = radius / tan(acos(cos_phi) / 2);
+    float factor_p1p0 = tangent / p1p0_length;
+    FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+    FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+    float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+    float factor_ra = radius / orth_p1p0_length;
+
+    // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+    double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+    if (cos_alpha < 0.f)
+        orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+    FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+    // calculate angles for addArc
+    orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+    float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+    if (orth_p1p0.y() < 0.f)
+        sa = 2 * piDouble - sa;
+
+    // anticlockwise logic
+    bool anticlockwise = false;
+
+    float factor_p1p2 = tangent / p1p2_length;
+    FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+    FloatPoint orth_p1p2((t_p1p2.x() - p.x()),(t_p1p2.y() - p.y()));
+    float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+    float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+    if (orth_p1p2.y() < 0)
+        ea = 2 * piDouble - ea;
+    if ((sa > ea) && ((sa - ea) < piDouble))
+        anticlockwise = true;
+    if ((sa < ea) && ((ea - sa) > piDouble))
+        anticlockwise = true;
+
+    cairo_line_to(cr, t_p1p0.x(), t_p1p0.y());
+
+    addArc(p, radius, sa, ea, anticlockwise);
 }
 
 void Path::addEllipse(const FloatRect& rect)