1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block/*
2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
3dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *
4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * This library is free software; you can redistribute it and/or
5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * modify it under the terms of the GNU Library General Public
6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * License as published by the Free Software Foundation; either
7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * version 2 of the License, or (at your option) any later version.
8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *
9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * This library is distributed in the hope that it will be useful,
10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * but WITHOUT ANY WARRANTY; without even the implied warranty of
11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Library General Public License for more details.
13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block *
14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * You should have received a copy of the GNU Library General Public License
15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * along with this library; see the file COPYING.LIB.  If not, write to
16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Boston, MA 02110-1301, USA.
18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block */
19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "config.h"
21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "Path.h"
22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
23dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "AffineTransform.h"
24dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "FloatRect.h"
25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "GraphicsContext.h"
26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "NotImplemented.h"
27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "PainterOpenVG.h"
28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "PlatformPathOpenVG.h"
29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "PlatformString.h"
30dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "StrokeStyleApplier.h"
31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "VGUtils.h"
32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <openvg.h>
34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <wtf/MathExtras.h>
35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
36dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#define WEBKIT_VG_PATH_CAPABILITIES VG_PATH_CAPABILITY_ALL
37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#define FUZZY_COMPARE(number, reference, delta) \
39dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    (number >= (reference - delta) && number <= (reference + delta))
40dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blocknamespace WebCore {
42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPlatformPathOpenVG::PlatformPathOpenVG()
44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    : SharedResourceOpenVG()
45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    createPath();
47dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPlatformPathOpenVG::PlatformPathOpenVG(const PlatformPathOpenVG& other)
50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    : SharedResourceOpenVG()
51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_currentPoint(other.m_currentPoint)
52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    , m_subpathStartPoint(other.m_subpathStartPoint)
53dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
54dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    createPath();
55dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // makeCompatibleContextCurrent() is called by createPath(), so not necessary here.
56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPath(m_vgPath, other.m_vgPath);
57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
59dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
60dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPlatformPathOpenVG& PlatformPathOpenVG::operator=(const PlatformPathOpenVG& other)
61dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
62dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (&other != this) {
63dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        clear();
64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // makeCompatibleContextCurrent() is called by clear(), so not necessary here.
65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        vgAppendPath(m_vgPath, other.m_vgPath);
66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        ASSERT_VG_NO_ERROR();
67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
68dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return *this;
69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
70dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
71dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPlatformPathOpenVG::~PlatformPathOpenVG()
72dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
73dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    makeCompatibleContextCurrent();
74dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
75dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgDestroyPath(m_vgPath);
76dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
77dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
78dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
79dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid PlatformPathOpenVG::clear()
80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    makeCompatibleContextCurrent();
82dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgClearPath(m_vgPath, WEBKIT_VG_PATH_CAPABILITIES);
84dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
85dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
86dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_subpathStartPoint.setX(0);
87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_subpathStartPoint.setY(0);
88dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_currentPoint = m_subpathStartPoint;
89dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
91dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid PlatformPathOpenVG::createPath()
92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    makeSharedContextCurrent();
94dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_vgPath = vgCreatePath(
96dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F,
97dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        1.0 /* scale */, 0.0 /* bias */,
98dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        0 /* expected number of segments */,
99dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        0 /* expected number of total coordinates */,
100dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        WEBKIT_VG_PATH_CAPABILITIES);
101dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
102dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
103dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
104dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPath::Path()
106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
107dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path = new PlatformPathOpenVG();
108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPath::~Path()
111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    delete m_path;
113dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPath::Path(const Path& other)
116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path = new PlatformPathOpenVG(*(other.m_path));
118dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
119dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPath& Path::operator=(const Path& other)
121dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
122dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    *m_path = *(other.m_path);
123dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return *this;
124dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
125dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
126967717af5423377c967781471ee106e2bb4e11c8Ben MurdochFloatPoint Path::currentPoint() const
127967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
128967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    // FIXME: is this the way to return the current point of the subpath?
129967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch    return m_currentPoint;
130967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
131967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
132967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool Path::contains(const FloatPoint& point, WindRule rule) const
134dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    notImplemented();
136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // OpenVG has no path-contains function, so for now we approximate by
138dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // using the bounding rect of the path.
139dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return boundingRect().contains(point);
140dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    notImplemented();
145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // OpenVG has no path-contains function, so for now we approximate by
147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // using the stroke bounding rect of the path.
148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return (const_cast<Path*>(this))->strokeBoundingRect().contains(point);
149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::translate(const FloatSize& size)
152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    AffineTransform transformation;
154dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    transformation.translate(size.width(), size.height());
155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    transform(transformation);
156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockFloatRect Path::boundingRect() const
159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat minX;
161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat minY;
162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat width;
163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat height;
164dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgPathBounds(m_path->vgPath(), &minX, &minY, &width, &height);
167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
169dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return FloatRect(FloatPoint(minX, minY), FloatSize(width, height));
170dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
171dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
1722bde8e466a4451c7319e3a072d118917957d6554Steve BlockFloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const
173dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
174dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    notImplemented();
175dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
176dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // vgPathBounds() ignores stroke parameters, and we don't currently have
177dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // an approximation that takes stroke parameters into account.
178dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return boundingRect();
179dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
180dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
181dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::moveTo(const FloatPoint& point)
182dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
183dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = { VG_MOVE_TO_ABS };
184dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = { point.x(), point.y() };
185dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
186dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
187dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
188dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
189dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
190dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = m_path->m_subpathStartPoint = point;
191dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
192dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
193dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addLineTo(const FloatPoint& point)
194dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
195dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = { VG_LINE_TO_ABS };
196dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = { point.x(), point.y() };
197dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
198dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
199dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
200dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
201dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
202dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = point;
203dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
204dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
205dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& endPoint)
206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
207dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = { VG_QUAD_TO_ABS };
208dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = { controlPoint.x(), controlPoint.y(), endPoint.x(), endPoint.y() };
209dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
210dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
211dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
213dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
214dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = endPoint;
215dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& endPoint)
218dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = { VG_CUBIC_TO_ABS };
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = { controlPoint1.x(), controlPoint1.y(), controlPoint2.x(), controlPoint2.y(), endPoint.x(), endPoint.y() };
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
223dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
225dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
226dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = endPoint;
227dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
228dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
229dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addArcTo(const FloatPoint& point1, const FloatPoint& point2, float radius)
230dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
231dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // See http://philip.html5.org/tests/canvas/suite/tests/spec.html#arcto.
232dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
233dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const FloatPoint& point0 = m_path->m_currentPoint;
234dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!radius || point0 == point1 || point1 == point2) {
235dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        addLineTo(point1);
236dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
237dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
238dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
239dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    FloatSize v01 = point0 - point1;
240dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    FloatSize v21 = point2 - point1;
241dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
242dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A)
243dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    double cross = v01.width() * v21.height() - v01.height() * v21.width();
244dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
245dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (fabs(cross) < 1E-10) {
246dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // on one line
247dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        addLineTo(point1);
248dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
249dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    }
250dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
251dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    double d01 = hypot(v01.width(), v01.height());
252dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    double d21 = hypot(v21.width(), v21.height());
253dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5;
254dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    double span = radius * tan(angle);
255dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    double rate = span / d01;
256dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    FloatPoint startPoint = FloatPoint(point1.x() + v01.width() * rate,
257dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                       point1.y() + v01.height() * rate);
258dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    rate = span / d21;
259dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    FloatPoint endPoint = FloatPoint(point1.x() + v21.width() * rate,
260dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                                     point1.y() + v21.height() * rate);
261dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
262dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO
263dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     respectively SCCWARC_TO and LCCWARC_TO arcs. We always use small
264dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     arcs for arcTo(), as the arc is defined as the "shortest arc" of the
265dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     circle specified in HTML 5.
266dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
267dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Fs: sweep flag, specifying whether the arc is drawn in increasing (true)
268dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     or decreasing (0) direction.
269dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const bool anticlockwise = cross < 0;
270dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
271dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Translate the large arc and sweep flags into an OpenVG segment command.
272dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGubyte segmentCommand = anticlockwise ? VG_SCCWARC_TO_ABS : VG_SCWARC_TO_ABS;
273dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
274dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGubyte pathSegments[] = {
275dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_LINE_TO_ABS,
276dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        segmentCommand
277dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
278dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = {
279dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        startPoint.x(), startPoint.y(),
280dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        radius, radius, 0, endPoint.x(), endPoint.y()
281dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
282dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
283dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
284dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData);
285dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
286dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
287dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = endPoint;
288dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
289dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
290dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::closeSubpath()
291dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
292dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = { VG_CLOSE_PATH };
293dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // pathData must not be 0, but certain compilers also don't create
294dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // zero-size arrays. So let's use a random aligned value (sizeof(VGfloat)),
295dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // it won't be accessed anyways as VG_CLOSE_PATH doesn't take coordinates.
296dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGfloat* pathData = reinterpret_cast<VGfloat*>(sizeof(VGfloat));
297dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
298dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
299dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 1, pathSegments, pathData);
300dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
301dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
302dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = m_path->m_subpathStartPoint;
303dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
304dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
305dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addArc(const FloatPoint& center, float radius, float startAngle, float endAngle, bool anticlockwise)
306dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
307dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // The OpenVG spec says nothing about inf as radius or start/end angle.
308dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // WebKit seems to pass those (e.g. https://bugs.webkit.org/show_bug.cgi?id=16449),
309dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // so abort instead of risking undefined behavior.
310dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!isfinite(radius) || !isfinite(startAngle) || !isfinite(endAngle))
311dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return;
312dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
313dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // For some reason, the HTML 5 spec defines the angle as going clockwise
314dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // from the positive X axis instead of going standard anticlockwise.
315dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // So let's make it a proper angle in order to keep sanity.
316dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    startAngle = fmod((2.0 * piDouble) - startAngle, 2.0 * piDouble);
317dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    endAngle = fmod((2.0 * piDouble) - endAngle, 2.0 * piDouble);
318dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
319dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Make it so that endAngle > startAngle. fmod() above takes care of
320dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // keeping the difference below 360 degrees.
321dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (endAngle <= startAngle)
322dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        endAngle += 2.0 * piDouble;
323dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
324dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat angleDelta = anticlockwise
325dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        ? (endAngle - startAngle)
326dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        : (startAngle - endAngle + (2.0 * piDouble));
327dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
328dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // OpenVG uses endpoint parameterization while this method receives its
329dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // values in center parameterization. It lacks an ellipse rotation
330dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // parameter so we use 0 for that, and also the radius is only a single
331dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // value which makes for rh == rv. In order to convert from endpoint to
332dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // center parameterization, we use the formulas from the OpenVG/SVG specs:
333dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
334dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // (x,y) = (cos rot, -sin rot; sin rot, -cos rot) * (rh * cos angle, rv * sin angle) + (center.x, center.y)
335dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // rot is 0, which simplifies this a bit:
336dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // (x,y) = (1, 0; 0, -1) * (rh * cos angle, rv * sin angle) + (center.x, center.y)
337dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //       = (1 * rh * cos angle + 0 * rv * sin angle, 0 * rh * cos angle + -1 * rv * sin angle) + (center.x, center.y)
338dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //       = (rh * cos angle, -rv * sin angle) + (center.x, center.y)
339dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // (Set angle = {startAngle, endAngle} to retrieve the respective endpoints.)
340dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
341dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat startX = radius * cos(startAngle) + center.x();
342dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat startY = -radius * sin(startAngle) + center.y();
343dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat endX = radius * cos(endAngle) + center.x();
344dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat endY = -radius * sin(endAngle) + center.y();
345dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
346dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Fa: large arc flag, makes the difference between SCWARC_TO and LCWARC_TO
347dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     respectively SCCWARC_TO and LCCWARC_TO arcs.
348dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const bool largeArc = (angleDelta > piDouble);
349dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
350dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Fs: sweep flag, specifying whether the arc is drawn in increasing (true)
351dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     or decreasing (0) direction. No need to calculate this value, as it
352dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    //     we already get it passed as a parameter (Fs == !anticlockwise).
353dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
354dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // Translate the large arc and sweep flags into an OpenVG segment command.
355dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // As OpenVG thinks of everything upside down, we need to reverse the
356dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // anticlockwise parameter in order to get the specified rotation.
357dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGubyte segmentCommand = !anticlockwise
358dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        ? (largeArc ? VG_LCCWARC_TO_ABS : VG_SCCWARC_TO_ABS)
359dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        : (largeArc ? VG_LCWARC_TO_ABS : VG_SCWARC_TO_ABS);
360dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
361dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // So now, we've got all the parameters in endpoint parameterization format
362dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // as OpenVG requires it. Which means we can just pass it like this.
363dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGubyte pathSegments[] = {
364dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        hasCurrentPoint() ? VG_LINE_TO_ABS : VG_MOVE_TO_ABS,
365dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        segmentCommand
366dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
367dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = {
368dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        startX, startY,
369dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        radius, radius, 0, endX, endY
370dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
371dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
372dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
373dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 2, pathSegments, pathData);
374dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
375dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
376dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint.setX(endX);
377dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint.setY(endY);
378dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
379dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
380dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addRect(const FloatRect& rect)
381dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
382dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = {
383dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_MOVE_TO_ABS,
384dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_HLINE_TO_REL,
385dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_VLINE_TO_REL,
386dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_HLINE_TO_REL,
387dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_CLOSE_PATH
388dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
389dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = {
390dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rect.x(), rect.y(),
391dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rect.width(),
392dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rect.height(),
393dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        -rect.width()
394dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
395dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
396dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
397dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 5, pathSegments, pathData);
398dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
399dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
400dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->m_currentPoint = m_path->m_subpathStartPoint = rect.location();
401dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
402dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
403dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::addEllipse(const FloatRect& rect)
404dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
405dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    static const VGubyte pathSegments[] = {
406dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_MOVE_TO_ABS,
407dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_SCCWARC_TO_REL,
408dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_SCCWARC_TO_REL,
409dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        VG_CLOSE_PATH
410dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
411dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const VGfloat pathData[] = {
412dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rect.x() + rect.width() / 2.0, rect.y(),
413dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rect.width() / 2.0, rect.height() / 2.0, 0, 0, rect.height(),
414dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        rect.width() / 2.0, rect.height() / 2.0, 0, 0, -rect.height()
415dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    };
416dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
417dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
418dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgAppendPathData(m_path->vgPath(), 4, pathSegments, pathData);
419dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
420dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
421dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
422dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::clear()
423dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
424dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->clear();
425dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
426dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
427dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool Path::isEmpty() const
428dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
429dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
430dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return !vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS);
431dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
432dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
433dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool Path::hasCurrentPoint() const
434dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
435dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
436dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS) > 0;
437dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
438dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
439dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::apply(void* info, PathApplierFunction function) const
440dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
441dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // OpenVG provides no means to retrieve path segment information.
442dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // This is *very* unfortunate, we might need to store the segments in
443dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // memory if we want to implement this function properly.
444dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // See http://www.khronos.org/message_boards/viewtopic.php?f=6&t=1887
445dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    notImplemented();
446dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
447dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
448dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockvoid Path::transform(const AffineTransform& transformation)
449dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
450dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    PlatformPathOpenVG* dst = new PlatformPathOpenVG();
451dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // dst->makeCompatibleContextCurrent() is called by the platform path
452dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // constructor, therefore not necessary to call it again here.
453dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    PainterOpenVG::transformPath(dst->vgPath(), m_path->vgPath(), transformation);
454dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    delete m_path;
455dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path = dst;
456dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
457e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    m_path->m_currentPoint = transformation.mapPoint(m_path->m_currentPoint);
458e78cbe89e6f337f2f1fe40315be88f742b547151Steve Block    m_path->m_subpathStartPoint = transformation.mapPoint(m_path->m_subpathStartPoint);
459dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
460dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
461dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
462dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// Path::length(), Path::pointAtLength() and Path::normalAngleAtLength() are
463dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// reimplemented here instead of in Path.cpp, because OpenVG has its own
464dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// functions and Path::apply() doesn't really work as long as we rely on VGPath
465dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block// as primary path storage.
466dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4672bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat Path::length() const
468dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
469dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
470dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat length = vgPathLength(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS));
471dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ASSERT_VG_NO_ERROR();
472dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return length;
473dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
474dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4752bde8e466a4451c7319e3a072d118917957d6554Steve BlockFloatPoint Path::pointAtLength(float length, bool& ok) const
476dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
477dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat x = 0, y = 0;
478dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
479dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
480dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgPointAlongPath(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS),
481dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                     length, &x, &y, 0, 0);
482dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ok = (vgGetError() == VG_NO_ERROR);
483dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return FloatPoint(x, y);
484dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
485dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
4862bde8e466a4451c7319e3a072d118917957d6554Steve Blockfloat Path::normalAngleAtLength(float length, bool& ok) const
487dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
488dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    VGfloat tangentX, tangentY;
489dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    m_path->makeCompatibleContextCurrent();
490dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
491dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    vgPointAlongPath(m_path->vgPath(), 0, vgGetParameteri(m_path->vgPath(), VG_PATH_NUM_SEGMENTS),
492dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                     length, 0, 0, &tangentX, &tangentY);
493dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    ok = (vgGetError() == VG_NO_ERROR);
494dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return atan2f(tangentY, tangentX) * 180.0 / piFloat; // convert to degrees
495dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
496dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
497dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
498