1/*
2 *  Copyright (C) 2007-2009 Torch Mobile, Inc.
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Library General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2 of the License, or (at your option) any later version.
8 *
9 *  This library is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 *  Library General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Library General Public License
15 *  along with this library; see the file COPYING.LIB.  If not, write to
16 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 *  Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "PlatformPathWinCE.h"
22
23#include "AffineTransform.h"
24#include "FloatRect.h"
25#include "GraphicsContext.h"
26#include "Path.h"
27#include "WinCEGraphicsExtras.h"
28#include <wtf/MathExtras.h>
29#include <wtf/OwnPtr.h>
30#include <wtf/text/WTFString.h>
31
32#include <windows.h>
33
34namespace WebCore {
35
36// Implemented in GraphicsContextWinCE.cpp
37void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y);
38
39static void quadCurve(int segments, Vector<PathPoint>& pts, const PathPoint* control)
40{
41    const float step = 1.0 / segments;
42    register float tA = 0.0;
43    register float tB = 1.0;
44
45    float c1x = control[0].x();
46    float c1y = control[0].y();
47    float c2x = control[1].x();
48    float c2y = control[1].y();
49    float c3x = control[2].x();
50    float c3y = control[2].y();
51
52    const int offset = pts.size();
53    pts.resize(offset + segments);
54    PathPoint pp;
55    pp.m_x = c1x;
56    pp.m_y = c1y;
57
58    for (int i = 1; i < segments; ++i) {
59        tA += step;
60        tB -= step;
61
62        const float a = tB * tB;
63        const float b = 2.0 * tA * tB;
64        const float c = tA * tA;
65
66        pp.m_x = c1x * a + c2x * b + c3x * c;
67        pp.m_y = c1y * a + c2y * b + c3y * c;
68
69        pts[offset + i - 1] = pp;
70    }
71
72    pp.m_x = c3x;
73    pp.m_y = c3y;
74    pts[offset + segments - 1] = pp;
75}
76
77static inline void bezier(int segments, Vector<PathPoint>& pts, const PathPoint* control)
78{
79    const float step = 1.0 / segments;
80    register float tA = 0.0;
81    register float tB = 1.0;
82
83    float c1x = control[0].x();
84    float c1y = control[0].y();
85    float c2x = control[1].x();
86    float c2y = control[1].y();
87    float c3x = control[2].x();
88    float c3y = control[2].y();
89    float c4x = control[3].x();
90    float c4y = control[3].y();
91
92    const int offset = pts.size();
93    pts.resize(offset + segments);
94    PathPoint pp;
95    pp.m_x = c1x;
96    pp.m_y = c1y;
97
98    for (int i = 1; i < segments; ++i) {
99        tA += step;
100        tB -= step;
101        const float tAsq = tA * tA;
102        const float tBsq = tB * tB;
103
104        const float a = tBsq * tB;
105        const float b = 3.0 * tA * tBsq;
106        const float c = 3.0 * tB * tAsq;
107        const float d = tAsq * tA;
108
109        pp.m_x = c1x * a + c2x * b + c3x * c + c4x * d;
110        pp.m_y = c1y * a + c2y * b + c3y * c + c4y * d;
111
112        pts[offset + i - 1] = pp;
113    }
114
115    pp.m_x = c4x;
116    pp.m_y = c4y;
117    pts[offset + segments - 1] = pp;
118}
119
120static bool containsPoint(const FloatRect& r, const FloatPoint& p)
121{
122    return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.maxX() && p.y() < r.maxY();
123}
124
125static void normalizeAngle(float& angle)
126{
127    angle = fmod(angle, 2 * piFloat);
128    if (angle < 0)
129        angle += 2 * piFloat;
130    if (angle < 0.00001f)
131        angle = 0;
132}
133
134static void transformArcPoint(float& x, float& y, const FloatPoint& c)
135{
136    x += c.x();
137    y += c.y();
138}
139
140static void inflateRectToContainPoint(FloatRect& r, float x, float y)
141{
142    if (r.isEmpty()) {
143        r.setX(x);
144        r.setY(y);
145        r.setSize(FloatSize(1, 1));
146        return;
147    }
148    if (x < r.x()) {
149        r.setWidth(r.maxX() - x);
150        r.setX(x);
151    } else {
152        float w = x - r.x() + 1;
153        if (w > r.width())
154            r.setWidth(w);
155    }
156    if (y < r.y()) {
157        r.setHeight(r.maxY() - y);
158        r.setY(y);
159    } else {
160        float h =  y - r.y() + 1;
161        if (h > r.height())
162            r.setHeight(h);
163    }
164}
165
166// return 0-based value: 0 - first Quadrant ( 0 - 90 degree)
167static inline int quadrant(const PathPoint& point, const PathPoint& origin)
168{
169    return point.m_x < origin.m_x ?
170        (point.m_y < origin.m_y ? 2 : 1)
171        : (point.m_y < origin.m_y ? 3 : 0);
172}
173
174static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; }
175static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; }
176static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; }
177static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; }
178
179static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; }
180static inline int quadrantDiff(int q1, int q2)
181{
182    int d = q1 - q2;
183    while (d < 0)
184        d += 4;
185    return d;
186}
187
188struct PathVector {
189    float m_x;
190    float m_y;
191
192    PathVector() : m_x(0), m_y(0) {}
193    PathVector(float x, float y) : m_x(x), m_y(y) {}
194    double angle() const { return atan2(m_y, m_x); }
195    operator double () const { return angle(); }
196    double length() const { return _hypot(m_x, m_y); }
197};
198
199PathVector operator-(const PathPoint& p1, const PathPoint& p2)
200{
201    return PathVector(p1.m_x - p2.m_x, p1.m_y - p2.m_y);
202}
203
204static void addArcPoint(PathPolygon& poly, const PathPoint& center, const PathPoint& radius, double angle)
205{
206    PathPoint p;
207    getEllipsePointByAngle(angle, radius.m_x, radius.m_y, p.m_x, p.m_y);
208    transformArcPoint(p.m_x, p.m_y, center);
209    if (poly.isEmpty() || poly.last() != p)
210        poly.append(p);
211}
212
213static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& data)
214{
215    const PathPoint& startPoint = poly.last();
216    double curAngle = startPoint - data.m_center;
217    double endAngle = data.m_end - data.m_center;
218    double angleStep = 2. / std::max(data.m_radius.m_x, data.m_radius.m_y);
219    if (data.m_clockwise) {
220        if (endAngle <= curAngle || startPoint == data.m_end)
221            endAngle += 2 * piDouble;
222    } else {
223        angleStep = -angleStep;
224        if (endAngle >= curAngle || startPoint == data.m_end)
225            endAngle -= 2 * piDouble;
226    }
227
228    for (curAngle += angleStep; data.m_clockwise ? curAngle < endAngle : curAngle > endAngle; curAngle += angleStep)
229        addArcPoint(poly, data.m_center, data.m_radius, curAngle);
230
231    if (poly.isEmpty() || poly.last() != data.m_end)
232        poly.append(data.m_end);
233}
234
235static void drawPolygons(HDC dc, const Vector<PathPolygon>& polygons, bool fill, const AffineTransform* transformation)
236{
237    for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) {
238        int npoints = i->size();
239        if (!npoints)
240            continue;
241
242        POINT* winPoints = 0;
243        if (fill) {
244            if (npoints > 2)
245                winPoints = new POINT[npoints + 1];
246        } else
247            winPoints = new POINT[npoints];
248
249        if (winPoints) {
250            if (transformation) {
251                for (int i2 = 0; i2 < npoints; ++i2) {
252                    FloatPoint trPoint = transformation->mapPoint(i->at(i2));
253                    winPoints[i2].x = stableRound(trPoint.x());
254                    winPoints[i2].y = stableRound(trPoint.y());
255                }
256            } else {
257                for (int i2 = 0; i2 < npoints; ++i2) {
258                    winPoints[i2].x = stableRound(i->at(i2).x());
259                    winPoints[i2].y = stableRound(i->at(i2).y());
260                }
261            }
262
263            if (fill && winPoints[npoints - 1] != winPoints[0]) {
264                winPoints[npoints].x = winPoints[0].x;
265                winPoints[npoints].y = winPoints[0].y;
266                ++npoints;
267            }
268
269            if (fill)
270                ::Polygon(dc, winPoints, npoints);
271            else
272                ::Polyline(dc, winPoints, npoints);
273            delete[] winPoints;
274        }
275    }
276}
277
278
279int PlatformPathElement::numControlPoints() const
280{
281    switch (m_type) {
282    case PathMoveTo:
283    case PathLineTo:
284        return 1;
285    case PathQuadCurveTo:
286    case PathArcTo:
287        return 2;
288    case PathBezierCurveTo:
289        return 3;
290    default:
291        ASSERT(m_type == PathCloseSubpath);
292        return 0;
293    }
294}
295
296int PlatformPathElement::numPoints() const
297{
298    switch (m_type) {
299    case PathMoveTo:
300    case PathLineTo:
301    case PathArcTo:
302        return 1;
303    case PathQuadCurveTo:
304        return 2;
305    case PathBezierCurveTo:
306        return 3;
307    default:
308        ASSERT(m_type == PathCloseSubpath);
309        return 0;
310    }
311}
312
313void PathPolygon::move(const FloatSize& offset)
314{
315    for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i)
316        i->move(offset);
317}
318
319void PathPolygon::transform(const AffineTransform& t)
320{
321    for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i)
322        *i = t.mapPoint(*i);
323}
324
325bool PathPolygon::contains(const FloatPoint& point) const
326{
327    if (size() < 3)
328        return false;
329
330    // Test intersections between the polygon and the vertical line: x = point.x()
331
332    int intersected = 0;
333    const PathPoint* point1 = &last();
334    Vector<PathPoint>::const_iterator last = end();
335    // wasNegative: -1 means unknown, 0 means false, 1 means true.
336    int wasNegative = -1;
337    for (Vector<PathPoint>::const_iterator i = begin(); i != last; ++i) {
338        const PathPoint& point2 = *i;
339        if (point1->x() != point.x()) {
340            if (point2.x() == point.x()) {
341                // We are getting on the vertical line
342                wasNegative = point1->x() < point.x() ? 1 : 0;
343            } else if (point2.x() < point.x() != point1->x() < point.x()) {
344                float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y();
345                if (y >= point.y())
346                    ++intersected;
347            }
348        } else {
349            // We were on the vertical line
350
351            // handle special case
352            if (point1->y() == point.y())
353                return true;
354
355            if (point1->y() > point.y()) {
356                if (point2.x() == point.x()) {
357                    // see if the point is on this segment
358                    if (point2.y() <= point.y())
359                        return true;
360
361                    // We are still on the line
362                } else {
363                    // We are leaving the line now.
364                    // We have to get back to see which side we come from. If we come from
365                    // the same side we are leaving, no intersection should be counted
366                    if (wasNegative < 0) {
367                        Vector<PathPoint>::const_iterator jLast = i;
368                        Vector<PathPoint>::const_iterator j = i;
369                        do {
370                            if (j == begin())
371                                j = last;
372                            else
373                                --j;
374                            if (j->x() != point.x()) {
375                                if (j->x() > point.x())
376                                    wasNegative = 0;
377                                else
378                                    wasNegative = 1;
379                                break;
380                            }
381                        } while (j != jLast);
382
383                        if (wasNegative < 0)
384                            return false;
385                    }
386                    if (wasNegative ? point2.x() > point.x() : point2.x() < point.x())
387                        ++intersected;
388                }
389            } else if (point2.x() == point.x() && point2.y() >= point.y())
390                return true;
391        }
392        point1 = &point2;
393    }
394
395    return intersected & 1;
396}
397
398void PlatformPathElement::move(const FloatSize& offset)
399{
400    int n = numControlPoints();
401    for (int i = 0; i < n; ++i)
402        m_data.m_points[i].move(offset);
403}
404
405void PlatformPathElement::transform(const AffineTransform& t)
406{
407    int n = numControlPoints();
408    for (int i = 0; i < n; ++i) {
409        FloatPoint p = t.mapPoint(m_data.m_points[i]);
410        m_data.m_points[i].set(p.x(), p.y());
411    }
412}
413
414void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const
415{
416    if (m_type == PathArcTo) {
417        const ArcTo& data = m_data.m_arcToData;
418        PathPoint startPoint;
419        startPoint = lastPoint;
420        PathPoint endPoint = data.m_end;
421        if (!data.m_clockwise)
422            std::swap(startPoint, endPoint);
423
424        int q0 = quadrant(startPoint, data.m_center);
425        int q1 = quadrant(endPoint, data.m_center);
426        bool containsExtremes[4] = { false }; // bottom, left, top, right
427        static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } };
428        if (q0 == q1) {
429            if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) {
430                for (int i = 0; i < 4; ++i)
431                    containsExtremes[i] = true;
432            }
433        } else {
434            int extreme = q0;
435            int diff = quadrantDiff(q1, q0);
436            for (int i = 0; i < diff; ++i) {
437                containsExtremes[extreme] = true;
438                extreme = nextQuadrant(extreme);
439            }
440        }
441
442        inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y);
443        inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y);
444        for (int i = 0; i < 4; ++i) {
445            if (containsExtremes[i])
446                inflateRectToContainPoint(r, data.m_center.m_x + data.m_radius.m_x * extremeVectors[i].m_x, data.m_center.m_y + data.m_radius.m_y * extremeVectors[i].m_y);
447        }
448    } else {
449        int n = numPoints();
450        for (int i = 0; i < n; ++i)
451            inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y);
452    }
453}
454
455PathElementType PlatformPathElement::type() const
456{
457    switch (m_type) {
458    case PathMoveTo:
459        return PathElementMoveToPoint;
460    case PathLineTo:
461        return PathElementAddLineToPoint;
462    case PathArcTo:
463        // FIXME: there's no arcTo type for PathElement
464        return PathElementAddLineToPoint;
465        // return PathElementAddQuadCurveToPoint;
466    case PathQuadCurveTo:
467        return PathElementAddQuadCurveToPoint;
468    case PathBezierCurveTo:
469        return PathElementAddCurveToPoint;
470    default:
471        ASSERT(m_type == PathCloseSubpath);
472        return PathElementCloseSubpath;
473    }
474}
475
476PlatformPath::PlatformPath()
477    : m_penLifted(true)
478{
479    m_currentPoint.clear();
480}
481
482void PlatformPath::ensureSubpath()
483{
484    if (m_penLifted) {
485        m_penLifted = false;
486        m_subpaths.append(PathPolygon());
487        m_subpaths.last().append(m_currentPoint);
488    } else
489        ASSERT(!m_subpaths.isEmpty());
490}
491
492void PlatformPath::addToSubpath(const PlatformPathElement& e)
493{
494    if (e.platformType() == PlatformPathElement::PathMoveTo) {
495        m_penLifted = true;
496        m_currentPoint = e.pointAt(0);
497    } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) {
498        m_penLifted = true;
499        if (!m_subpaths.isEmpty()) {
500            if (m_currentPoint != m_subpaths.last()[0]) {
501                // According to W3C, we have to draw a line from current point to the initial point
502                m_subpaths.last().append(m_subpaths.last()[0]);
503                m_currentPoint = m_subpaths.last()[0];
504            }
505        } else
506            m_currentPoint.clear();
507    } else {
508        ensureSubpath();
509        switch (e.platformType()) {
510        case PlatformPathElement::PathLineTo:
511            m_subpaths.last().append(e.pointAt(0));
512            break;
513        case PlatformPathElement::PathArcTo:
514            addArcPoints(m_subpaths.last(), e.arcTo());
515            break;
516        case PlatformPathElement::PathQuadCurveTo:
517            {
518                PathPoint control[] = {
519                    m_currentPoint,
520                    e.pointAt(0),
521                    e.pointAt(1),
522                };
523                // FIXME: magic number?
524                quadCurve(50, m_subpaths.last(), control);
525            }
526            break;
527        case PlatformPathElement::PathBezierCurveTo:
528            {
529                PathPoint control[] = {
530                    m_currentPoint,
531                    e.pointAt(0),
532                    e.pointAt(1),
533                    e.pointAt(2),
534                };
535                // FIXME: magic number?
536                bezier(100, m_subpaths.last(), control);
537            }
538            break;
539        default:
540            ASSERT_NOT_REACHED();
541            break;
542        }
543        m_currentPoint = m_subpaths.last().last();
544    }
545}
546
547void PlatformPath::append(const PlatformPathElement& e)
548{
549    e.inflateRectToContainMe(m_boundingRect, lastPoint());
550    addToSubpath(e);
551    m_elements.append(e);
552}
553
554void PlatformPath::append(const PlatformPath& p)
555{
556    const PlatformPathElements& e = p.elements();
557    for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) {
558        addToSubpath(*it);
559        it->inflateRectToContainMe(m_boundingRect, lastPoint());
560        m_elements.append(*it);
561    }
562}
563
564void PlatformPath::clear()
565{
566    m_elements.clear();
567    m_boundingRect = FloatRect();
568    m_subpaths.clear();
569    m_currentPoint.clear();
570    m_penLifted = true;
571}
572
573void PlatformPath::strokePath(HDC dc, const AffineTransform* transformation) const
574{
575    drawPolygons(dc, m_subpaths, false, transformation);
576}
577
578void PlatformPath::fillPath(HDC dc, const AffineTransform* transformation) const
579{
580    HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN));
581    drawPolygons(dc, m_subpaths, true, transformation);
582    SelectObject(dc, oldPen);
583}
584
585void PlatformPath::translate(const FloatSize& size)
586{
587    for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it)
588        it->move(size);
589
590    m_boundingRect.move(size);
591    for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it)
592        it->move(size);
593}
594
595void PlatformPath::transform(const AffineTransform& t)
596{
597    for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it)
598        it->transform(t);
599
600    m_boundingRect = t.mapRect(m_boundingRect);
601    for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it)
602        it->transform(t);
603}
604
605bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const
606{
607    // optimization: check the bounding rect first
608    if (!containsPoint(m_boundingRect, point))
609        return false;
610
611    for (Vector<PathPolygon>::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) {
612        if (i->contains(point))
613            return true;
614    }
615
616    return false;
617}
618
619void PlatformPath::moveTo(const FloatPoint& point)
620{
621    PlatformPathElement::MoveTo data = { { point.x(), point.y() } };
622    PlatformPathElement pe(data);
623    append(pe);
624}
625
626void PlatformPath::addLineTo(const FloatPoint& point)
627{
628    PlatformPathElement::LineTo data = { { point.x(), point.y() } };
629    PlatformPathElement pe(data);
630    append(pe);
631}
632
633void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
634{
635    PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } };
636    PlatformPathElement pe(data);
637    append(pe);
638}
639
640void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
641{
642    PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } };
643    PlatformPathElement pe(data);
644    append(pe);
645}
646
647void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius)
648{
649    const PathPoint& p0 = m_currentPoint;
650    PathPoint p1;
651    p1 = fp1;
652    PathPoint p2;
653    p2 = fp2;
654    if (!radius || p0 == p1 || p1 == p2) {
655        addLineTo(p1);
656        return;
657    }
658
659    PathVector v01 = p0 - p1;
660    PathVector v21 = p2 - p1;
661
662    // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A)
663    double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x;
664
665    if (fabs(cross) < 1E-10) {
666        // on one line
667        addLineTo(p1);
668        return;
669    }
670
671    double d01 = v01.length();
672    double d21 = v21.length();
673    double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5;
674    double span = radius * tan(angle);
675    double rate = span / d01;
676    PathPoint startPoint;
677    startPoint.m_x = p1.m_x + v01.m_x * rate;
678    startPoint.m_y = p1.m_y + v01.m_y * rate;
679
680    addLineTo(startPoint);
681
682    PathPoint endPoint;
683    rate = span / d21;
684    endPoint.m_x = p1.m_x + v21.m_x * rate;
685    endPoint.m_y = p1.m_y + v21.m_y * rate;
686
687    PathPoint midPoint;
688    midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5;
689    midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5;
690
691    PathVector vm1 = midPoint - p1;
692    double dm1 = vm1.length();
693    double d = _hypot(radius, span);
694
695    PathPoint centerPoint;
696    rate = d / dm1;
697    centerPoint.m_x = p1.m_x + vm1.m_x * rate;
698    centerPoint.m_y = p1.m_y + vm1.m_y * rate;
699
700    PlatformPathElement::ArcTo data = {
701        endPoint,
702        centerPoint,
703        { radius, radius },
704        cross < 0
705    };
706    PlatformPathElement pe(data);
707    append(pe);
708}
709
710void PlatformPath::closeSubpath()
711{
712    PlatformPathElement pe;
713    append(pe);
714}
715
716// add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear
717void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise)
718{
719    float startX, startY, endX, endY;
720
721    normalizeAngle(sar);
722    normalizeAngle(ear);
723
724    getEllipsePointByAngle(sar, a, b, startX, startY);
725    getEllipsePointByAngle(ear, a, b, endX, endY);
726
727    transformArcPoint(startX, startY, p);
728    transformArcPoint(endX, endY, p);
729
730    FloatPoint start(startX, startY);
731    moveTo(start);
732
733    PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() },  { a, b }, !anticlockwise };
734    PlatformPathElement pe(data);
735    append(pe);
736}
737
738
739void PlatformPath::addRect(const FloatRect& r)
740{
741    moveTo(r.location());
742
743    float right = r.maxX() - 1;
744    float bottom = r.maxY() - 1;
745    addLineTo(FloatPoint(right, r.y()));
746    addLineTo(FloatPoint(right, bottom));
747    addLineTo(FloatPoint(r.x(), bottom));
748    addLineTo(r.location());
749}
750
751void PlatformPath::addEllipse(const FloatRect& r)
752{
753    FloatSize radius(r.width() * 0.5, r.height() * 0.5);
754    addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true);
755}
756
757void PlatformPath::apply(void* info, PathApplierFunction function) const
758{
759    PathElement pelement;
760    FloatPoint points[3];
761    pelement.points = points;
762
763    for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) {
764        pelement.type = it->type();
765        int n = it->numPoints();
766        for (int i = 0; i < n; ++i)
767            points[i] = it->pointAt(i);
768        function(info, &pelement);
769    }
770}
771
772} // namespace Webcore
773