~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/graphics/wince/PlatformPathWinCE.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
34
namespace WebCore {
 
35
 
 
36
// Implemented in GraphicsContextWinCE.cpp
 
37
void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y);
 
38
 
 
39
static 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
 
 
77
static 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
 
 
120
static 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
 
 
125
static 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
 
 
134
static void transformArcPoint(float& x, float& y, const FloatPoint& c)
 
135
{
 
136
    x += c.x();
 
137
    y += c.y();
 
138
}
 
139
 
 
140
static 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)
 
167
static 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
 
 
174
static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; }
 
175
static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; }
 
176
static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; }
 
177
static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; }
 
178
 
 
179
static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; }
 
180
static 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
 
 
188
struct 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
 
 
199
PathVector 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
 
 
204
static 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
 
 
213
static 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
 
 
235
static 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
 
 
279
int 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
 
 
296
int 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
 
 
313
void PathPolygon::move(const FloatSize& offset)
 
314
{
 
315
    for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i)
 
316
        i->move(offset);
 
317
}
 
318
 
 
319
void PathPolygon::transform(const AffineTransform& t)
 
320
{
 
321
    for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i)
 
322
        *i = t.mapPoint(*i);
 
323
}
 
324
 
 
325
bool 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
 
 
398
void 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
 
 
405
void 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
 
 
414
void 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
 
 
455
PathElementType 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
 
 
476
PlatformPath::PlatformPath()
 
477
    : m_penLifted(true)
 
478
{
 
479
    m_currentPoint.clear();
 
480
}
 
481
 
 
482
void 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
 
 
492
void 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
 
 
547
void PlatformPath::append(const PlatformPathElement& e)
 
548
{
 
549
    e.inflateRectToContainMe(m_boundingRect, lastPoint());
 
550
    addToSubpath(e);
 
551
    m_elements.append(e);
 
552
}
 
553
 
 
554
void 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
 
 
564
void 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
 
 
573
void PlatformPath::strokePath(HDC dc, const AffineTransform* transformation) const
 
574
{
 
575
    drawPolygons(dc, m_subpaths, false, transformation);
 
576
}
 
577
 
 
578
void 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
 
 
585
void 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
 
 
595
void 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
 
 
605
bool 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
 
 
619
void PlatformPath::moveTo(const FloatPoint& point)
 
620
{
 
621
    PlatformPathElement::MoveTo data = { { point.x(), point.y() } };
 
622
    PlatformPathElement pe(data);
 
623
    append(pe);
 
624
}
 
625
 
 
626
void PlatformPath::addLineTo(const FloatPoint& point)
 
627
{
 
628
    PlatformPathElement::LineTo data = { { point.x(), point.y() } };
 
629
    PlatformPathElement pe(data);
 
630
    append(pe);
 
631
}
 
632
 
 
633
void 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
 
 
640
void 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
 
 
647
void 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
 
 
710
void 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
 
717
void 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
 
 
739
void 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
 
 
751
void 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
 
 
757
void 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