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