1 // Copyright (c) 2008, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "config.h"
31 #include "Path.h"
32
33 #include "AffineTransform.h"
34 #include "FloatRect.h"
35 #include "ImageBuffer.h"
36 #include "StrokeStyleApplier.h"
37
38 #include "SkPath.h"
39 #include "SkRegion.h"
40 #include "SkiaUtils.h"
41
42 #include <wtf/MathExtras.h>
43
44 namespace WebCore {
45
Path()46 Path::Path()
47 {
48 m_path = new SkPath;
49 }
50
Path(const Path & other)51 Path::Path(const Path& other)
52 {
53 m_path = new SkPath(*other.m_path);
54 }
55
~Path()56 Path::~Path()
57 {
58 delete m_path;
59 }
60
operator =(const Path & other)61 Path& Path::operator=(const Path& other)
62 {
63 *m_path = *other.m_path;
64 return *this;
65 }
66
isEmpty() const67 bool Path::isEmpty() const
68 {
69 return m_path->isEmpty();
70 }
71
hasCurrentPoint() const72 bool Path::hasCurrentPoint() const
73 {
74 return m_path->getPoints(NULL, 0) != 0;
75 }
76
currentPoint() const77 FloatPoint Path::currentPoint() const
78 {
79 // FIXME: return current point of subpath.
80 float quietNaN = std::numeric_limits<float>::quiet_NaN();
81 return FloatPoint(quietNaN, quietNaN);
82 }
83
contains(const FloatPoint & point,WindRule rule) const84 bool Path::contains(const FloatPoint& point, WindRule rule) const
85 {
86 return SkPathContainsPoint(m_path, point,
87 rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
88 }
89
translate(const FloatSize & size)90 void Path::translate(const FloatSize& size)
91 {
92 m_path->offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height()));
93 }
94
boundingRect() const95 FloatRect Path::boundingRect() const
96 {
97 return m_path->getBounds();
98 }
99
moveTo(const FloatPoint & point)100 void Path::moveTo(const FloatPoint& point)
101 {
102 m_path->moveTo(point);
103 }
104
addLineTo(const FloatPoint & point)105 void Path::addLineTo(const FloatPoint& point)
106 {
107 m_path->lineTo(point);
108 }
109
addQuadCurveTo(const FloatPoint & cp,const FloatPoint & ep)110 void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
111 {
112 m_path->quadTo(cp, ep);
113 }
114
addBezierCurveTo(const FloatPoint & p1,const FloatPoint & p2,const FloatPoint & ep)115 void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
116 {
117 m_path->cubicTo(p1, p2, ep);
118 }
119
addArcTo(const FloatPoint & p1,const FloatPoint & p2,float radius)120 void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
121 {
122 m_path->arcTo(p1, p2, WebCoreFloatToSkScalar(radius));
123 }
124
closeSubpath()125 void Path::closeSubpath()
126 {
127 m_path->close();
128 }
129
addArc(const FloatPoint & p,float r,float sa,float ea,bool anticlockwise)130 void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise) {
131 SkScalar cx = WebCoreFloatToSkScalar(p.x());
132 SkScalar cy = WebCoreFloatToSkScalar(p.y());
133 SkScalar radius = WebCoreFloatToSkScalar(r);
134 SkScalar s360 = SkIntToScalar(360);
135
136 SkRect oval;
137 oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
138
139 float sweep = ea - sa;
140 SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat);
141 SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
142 // Check for a circle.
143 if (sweepDegrees >= s360 || sweepDegrees <= -s360) {
144 // Move to the start position (0 sweep means we add a single point).
145 m_path->arcTo(oval, startDegrees, 0, false);
146 // Draw the circle.
147 m_path->addOval(oval, anticlockwise ?
148 SkPath::kCCW_Direction : SkPath::kCW_Direction);
149 // Force a moveTo the end position.
150 m_path->arcTo(oval, startDegrees + sweepDegrees, 0, true);
151 } else {
152 // Counterclockwise arcs should be drawn with negative sweeps, while
153 // clockwise arcs should be drawn with positive sweeps. Check to see
154 // if the situation is reversed and correct it by adding or subtracting
155 // a full circle
156 if (anticlockwise && sweepDegrees > 0) {
157 sweepDegrees -= s360;
158 } else if (!anticlockwise && sweepDegrees < 0) {
159 sweepDegrees += s360;
160 }
161
162 m_path->arcTo(oval, startDegrees, sweepDegrees, false);
163 }
164 }
165
addRect(const FloatRect & rect)166 void Path::addRect(const FloatRect& rect)
167 {
168 m_path->addRect(rect);
169 }
170
addEllipse(const FloatRect & rect)171 void Path::addEllipse(const FloatRect& rect)
172 {
173 m_path->addOval(rect);
174 }
175
clear()176 void Path::clear()
177 {
178 m_path->reset();
179 }
180
convertPathPoints(FloatPoint dst[],const SkPoint src[],int count)181 static FloatPoint* convertPathPoints(FloatPoint dst[], const SkPoint src[], int count)
182 {
183 for (int i = 0; i < count; i++) {
184 dst[i].setX(SkScalarToFloat(src[i].fX));
185 dst[i].setY(SkScalarToFloat(src[i].fY));
186 }
187 return dst;
188 }
189
apply(void * info,PathApplierFunction function) const190 void Path::apply(void* info, PathApplierFunction function) const
191 {
192 SkPath::Iter iter(*m_path, false);
193 SkPoint pts[4];
194 PathElement pathElement;
195 FloatPoint pathPoints[3];
196
197 for (;;) {
198 switch (iter.next(pts)) {
199 case SkPath::kMove_Verb:
200 pathElement.type = PathElementMoveToPoint;
201 pathElement.points = convertPathPoints(pathPoints, &pts[0], 1);
202 break;
203 case SkPath::kLine_Verb:
204 pathElement.type = PathElementAddLineToPoint;
205 pathElement.points = convertPathPoints(pathPoints, &pts[1], 1);
206 break;
207 case SkPath::kQuad_Verb:
208 pathElement.type = PathElementAddQuadCurveToPoint;
209 pathElement.points = convertPathPoints(pathPoints, &pts[1], 2);
210 break;
211 case SkPath::kCubic_Verb:
212 pathElement.type = PathElementAddCurveToPoint;
213 pathElement.points = convertPathPoints(pathPoints, &pts[1], 3);
214 break;
215 case SkPath::kClose_Verb:
216 pathElement.type = PathElementCloseSubpath;
217 pathElement.points = convertPathPoints(pathPoints, 0, 0);
218 break;
219 case SkPath::kDone_Verb:
220 return;
221 }
222 function(info, &pathElement);
223 }
224 }
225
transform(const AffineTransform & xform)226 void Path::transform(const AffineTransform& xform)
227 {
228 m_path->transform(xform);
229 }
230
strokeBoundingRect(StrokeStyleApplier * applier) const231 FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const
232 {
233 GraphicsContext* scratch = scratchContext();
234 scratch->save();
235
236 if (applier)
237 applier->strokeStyle(scratch);
238
239 SkPaint paint;
240 scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
241 SkPath boundingPath;
242 paint.getFillPath(*platformPath(), &boundingPath);
243
244 FloatRect r = boundingPath.getBounds();
245 scratch->restore();
246 return r;
247 }
248
strokeContains(StrokeStyleApplier * applier,const FloatPoint & point) const249 bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
250 {
251 ASSERT(applier);
252 GraphicsContext* scratch = scratchContext();
253 scratch->save();
254
255 applier->strokeStyle(scratch);
256
257 SkPaint paint;
258 scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
259 SkPath strokePath;
260 paint.getFillPath(*platformPath(), &strokePath);
261 bool contains = SkPathContainsPoint(&strokePath, point,
262 SkPath::kWinding_FillType);
263
264 scratch->restore();
265 return contains;
266 }
267 } // namespace WebCore
268