Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Side by Side Diff: Source/core/platform/graphics/Path.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/platform/graphics/Path.h ('k') | Source/core/platform/graphics/Pattern.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
3 * 2006 Rob Buis <buis@kde.org>
4 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 * Copyright (C) 2013 Google Inc. All rights reserved.
6 * Copyright (C) 2013 Intel Corporation. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31 #include "core/platform/graphics/Path.h"
32
33 #include <math.h>
34 #include "core/platform/graphics/GraphicsContext.h"
35 #include "core/platform/graphics/skia/SkiaUtils.h"
36 #include "platform/geometry/FloatPoint.h"
37 #include "platform/geometry/FloatRect.h"
38 #include "platform/transforms/AffineTransform.h"
39 #include "third_party/skia/include/core/SkPathMeasure.h"
40 #include "third_party/skia/include/pathops/SkPathOps.h"
41 #include "wtf/MathExtras.h"
42
43 namespace WebCore {
44
45 Path::Path()
46 : m_path()
47 {
48 }
49
50 Path::Path(const Path& other)
51 {
52 m_path = SkPath(other.m_path);
53 }
54
55 Path::~Path()
56 {
57 }
58
59 Path& Path::operator=(const Path& other)
60 {
61 m_path = SkPath(other.m_path);
62 return *this;
63 }
64
65 bool Path::operator==(const Path& other) const
66 {
67 return m_path == other.m_path;
68 }
69
70 bool Path::contains(const FloatPoint& point, WindRule rule) const
71 {
72 return SkPathContainsPoint(m_path, point, rule == RULE_NONZERO ? SkPath::kWi nding_FillType : SkPath::kEvenOdd_FillType);
73 }
74
75 bool Path::strokeContains(const FloatPoint& point, const StrokeData& strokeData) const
76 {
77 SkPaint paint;
78 strokeData.setupPaint(&paint);
79 SkPath strokePath;
80 paint.getFillPath(m_path, &strokePath);
81
82 return SkPathContainsPoint(strokePath, point, SkPath::kWinding_FillType);
83 }
84
85 FloatRect Path::boundingRect() const
86 {
87 return m_path.getBounds();
88 }
89
90 FloatRect Path::strokeBoundingRect(const StrokeData& strokeData) const
91 {
92 SkPaint paint;
93 strokeData.setupPaint(&paint);
94 SkPath boundingPath;
95 paint.getFillPath(m_path, &boundingPath);
96
97 return boundingPath.getBounds();
98 }
99
100 static FloatPoint* convertPathPoints(FloatPoint dst[], const SkPoint src[], int count)
101 {
102 for (int i = 0; i < count; i++) {
103 dst[i].setX(SkScalarToFloat(src[i].fX));
104 dst[i].setY(SkScalarToFloat(src[i].fY));
105 }
106 return dst;
107 }
108
109 void Path::apply(void* info, PathApplierFunction function) const
110 {
111 SkPath::RawIter iter(m_path);
112 SkPoint pts[4];
113 PathElement pathElement;
114 FloatPoint pathPoints[3];
115
116 for (;;) {
117 switch (iter.next(pts)) {
118 case SkPath::kMove_Verb:
119 pathElement.type = PathElementMoveToPoint;
120 pathElement.points = convertPathPoints(pathPoints, &pts[0], 1);
121 break;
122 case SkPath::kLine_Verb:
123 pathElement.type = PathElementAddLineToPoint;
124 pathElement.points = convertPathPoints(pathPoints, &pts[1], 1);
125 break;
126 case SkPath::kQuad_Verb:
127 pathElement.type = PathElementAddQuadCurveToPoint;
128 pathElement.points = convertPathPoints(pathPoints, &pts[1], 2);
129 break;
130 case SkPath::kCubic_Verb:
131 pathElement.type = PathElementAddCurveToPoint;
132 pathElement.points = convertPathPoints(pathPoints, &pts[1], 3);
133 break;
134 case SkPath::kClose_Verb:
135 pathElement.type = PathElementCloseSubpath;
136 pathElement.points = convertPathPoints(pathPoints, 0, 0);
137 break;
138 case SkPath::kDone_Verb:
139 return;
140 default: // place-holder for kConic_Verb, when that lands from skia
141 break;
142 }
143 function(info, &pathElement);
144 }
145 }
146
147 void Path::transform(const AffineTransform& xform)
148 {
149 m_path.transform(affineTransformToSkMatrix(xform));
150 }
151
152 float Path::length() const
153 {
154 SkScalar length = 0;
155 SkPathMeasure measure(m_path, false);
156
157 do {
158 length += measure.getLength();
159 } while (measure.nextContour());
160
161 return SkScalarToFloat(length);
162 }
163
164 FloatPoint Path::pointAtLength(float length, bool& ok) const
165 {
166 FloatPoint point;
167 float normal;
168 ok = pointAndNormalAtLength(length, point, normal);
169 return point;
170 }
171
172 float Path::normalAngleAtLength(float length, bool& ok) const
173 {
174 FloatPoint point;
175 float normal;
176 ok = pointAndNormalAtLength(length, point, normal);
177 return normal;
178 }
179
180 bool Path::pointAndNormalAtLength(float length, FloatPoint& point, float& normal ) const
181 {
182 SkPathMeasure measure(m_path, false);
183
184 do {
185 SkScalar contourLength = measure.getLength();
186 if (length <= contourLength) {
187 SkVector tangent;
188 SkPoint position;
189
190 if (measure.getPosTan(length, &position, &tangent)) {
191 normal = rad2deg(SkScalarToFloat(SkScalarATan2(tangent.fY, tange nt.fX)));
192 point = FloatPoint(SkScalarToFloat(position.fX), SkScalarToFloat (position.fY));
193 return true;
194 }
195 }
196 length -= contourLength;
197 } while (measure.nextContour());
198
199 normal = 0;
200 point = FloatPoint(0, 0);
201 return false;
202 }
203
204 void Path::clear()
205 {
206 m_path.reset();
207 }
208
209 bool Path::isEmpty() const
210 {
211 return m_path.isEmpty();
212 }
213
214 bool Path::hasCurrentPoint() const
215 {
216 return m_path.getPoints(0, 0);
217 }
218
219 FloatPoint Path::currentPoint() const
220 {
221 if (m_path.countPoints() > 0) {
222 SkPoint skResult;
223 m_path.getLastPt(&skResult);
224 FloatPoint result;
225 result.setX(SkScalarToFloat(skResult.fX));
226 result.setY(SkScalarToFloat(skResult.fY));
227 return result;
228 }
229
230 // FIXME: Why does this return quietNaN? Other ports return 0,0.
231 float quietNaN = std::numeric_limits<float>::quiet_NaN();
232 return FloatPoint(quietNaN, quietNaN);
233 }
234
235 WindRule Path::windRule() const
236 {
237 return m_path.getFillType() == SkPath::kEvenOdd_FillType
238 ? RULE_EVENODD
239 : RULE_NONZERO;
240 }
241
242 void Path::setWindRule(const WindRule rule)
243 {
244 m_path.setFillType(rule == RULE_EVENODD
245 ? SkPath::kEvenOdd_FillType
246 : SkPath::kWinding_FillType);
247 }
248
249 void Path::moveTo(const FloatPoint& point)
250 {
251 m_path.moveTo(point);
252 }
253
254 void Path::addLineTo(const FloatPoint& point)
255 {
256 m_path.lineTo(point);
257 }
258
259 void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
260 {
261 m_path.quadTo(cp, ep);
262 }
263
264 void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const Fl oatPoint& ep)
265 {
266 m_path.cubicTo(p1, p2, ep);
267 }
268
269 void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
270 {
271 m_path.arcTo(p1, p2, WebCoreFloatToSkScalar(radius));
272 }
273
274 void Path::closeSubpath()
275 {
276 m_path.close();
277 }
278
279 void Path::addEllipse(const FloatPoint& p, float radiusX, float radiusY, float s tartAngle, float endAngle, bool anticlockwise)
280 {
281 ASSERT(std::abs(endAngle - startAngle) < 4 * piFloat);
282 ASSERT(startAngle >= 0 && startAngle < 2 * piFloat);
283 ASSERT((anticlockwise && (startAngle - endAngle) >= 0) || (!anticlockwise && (endAngle - startAngle) >= 0));
284
285 SkScalar cx = WebCoreFloatToSkScalar(p.x());
286 SkScalar cy = WebCoreFloatToSkScalar(p.y());
287 SkScalar radiusXScalar = WebCoreFloatToSkScalar(radiusX);
288 SkScalar radiusYScalar = WebCoreFloatToSkScalar(radiusY);
289 SkScalar s360 = SkIntToScalar(360);
290
291 SkRect oval;
292 oval.set(cx - radiusXScalar, cy - radiusYScalar, cx + radiusXScalar, cy + ra diusYScalar);
293
294 float sweep = endAngle - startAngle;
295 SkScalar startDegrees = WebCoreFloatToSkScalar(startAngle * 180 / piFloat);
296 SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
297
298 // We can't use SkPath::addOval(), because addOval() makes new sub-path. add Oval() calls moveTo() and close() internally.
299
300 // Use s180, not s360, because SkPath::arcTo(oval, angle, s360, false) draws nothing.
301 SkScalar s180 = SkIntToScalar(180);
302 if (sweepDegrees >= s360) {
303 // SkPath::arcTo can't handle the sweepAngle that is equal to or greater than 2Pi.
304 m_path.arcTo(oval, startDegrees, s180, false);
305 m_path.arcTo(oval, startDegrees + s180, s180, false);
306 m_path.arcTo(oval, startDegrees + s360, sweepDegrees - s360, false);
307 return;
308 }
309 if (sweepDegrees <= -s360) {
310 m_path.arcTo(oval, startDegrees, -s180, false);
311 m_path.arcTo(oval, startDegrees - s180, -s180, false);
312 m_path.arcTo(oval, startDegrees - s360, sweepDegrees + s360, false);
313 return;
314 }
315
316 m_path.arcTo(oval, startDegrees, sweepDegrees, false);
317 }
318
319 void Path::addArc(const FloatPoint& p, float radius, float startAngle, float end Angle, bool anticlockwise)
320 {
321 addEllipse(p, radius, radius, startAngle, endAngle, anticlockwise);
322 }
323
324 void Path::addRect(const FloatRect& rect)
325 {
326 m_path.addRect(rect);
327 }
328
329 void Path::addEllipse(const FloatPoint& p, float radiusX, float radiusY, float r otation, float startAngle, float endAngle, bool anticlockwise)
330 {
331 ASSERT(std::abs(endAngle - startAngle) < 4 * piFloat);
332 ASSERT(startAngle >= 0 && startAngle < 2 * piFloat);
333 ASSERT((anticlockwise && (startAngle - endAngle) >= 0) || (!anticlockwise && (endAngle - startAngle) >= 0));
334
335 if (!rotation) {
336 addEllipse(FloatPoint(p.x(), p.y()), radiusX, radiusY, startAngle, endAn gle, anticlockwise);
337 return;
338 }
339
340 // Add an arc after the relevant transform.
341 AffineTransform ellipseTransform = AffineTransform::translation(p.x(), p.y() ).rotate(rad2deg(rotation));
342 ASSERT(ellipseTransform.isInvertible());
343 AffineTransform inverseEllipseTransform = ellipseTransform.inverse();
344 transform(inverseEllipseTransform);
345 addEllipse(FloatPoint::zero(), radiusX, radiusY, startAngle, endAngle, antic lockwise);
346 transform(ellipseTransform);
347 }
348
349 void Path::addEllipse(const FloatRect& rect)
350 {
351 m_path.addOval(rect);
352 }
353
354 void Path::addRoundedRect(const RoundedRect& r)
355 {
356 addRoundedRect(r.rect(), r.radii().topLeft(), r.radii().topRight(), r.radii( ).bottomLeft(), r.radii().bottomRight());
357 }
358
359 void Path::addRoundedRect(const FloatRect& rect, const FloatSize& roundingRadii)
360 {
361 if (rect.isEmpty())
362 return;
363
364 FloatSize radius(roundingRadii);
365 FloatSize halfSize(rect.width() / 2, rect.height() / 2);
366
367 // Apply the SVG corner radius constraints, per the rect section of the SVG shapes spec: if
368 // one of rx,ry is negative, then the other corner radius value is used. If both values are
369 // negative then rx = ry = 0. If rx is greater than half of the width of the rectangle
370 // then set rx to half of the width; ry is handled similarly.
371
372 if (radius.width() < 0)
373 radius.setWidth((radius.height() < 0) ? 0 : radius.height());
374
375 if (radius.height() < 0)
376 radius.setHeight(radius.width());
377
378 if (radius.width() > halfSize.width())
379 radius.setWidth(halfSize.width());
380
381 if (radius.height() > halfSize.height())
382 radius.setHeight(halfSize.height());
383
384 addPathForRoundedRect(rect, radius, radius, radius, radius);
385 }
386
387 void Path::addRoundedRect(const FloatRect& rect, const FloatSize& topLeftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, const Float Size& bottomRightRadius)
388 {
389 if (rect.isEmpty())
390 return;
391
392 if (rect.width() < topLeftRadius.width() + topRightRadius.width()
393 || rect.width() < bottomLeftRadius.width() + bottomRightRadius.width ()
394 || rect.height() < topLeftRadius.height() + bottomLeftRadius.height( )
395 || rect.height() < topRightRadius.height() + bottomRightRadius.heigh t()) {
396 // If all the radii cannot be accommodated, return a rect.
397 addRect(rect);
398 return;
399 }
400
401 addPathForRoundedRect(rect, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
402 }
403
404 void Path::addPathForRoundedRect(const FloatRect& rect, const FloatSize& topLeft Radius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, cons t FloatSize& bottomRightRadius)
405 {
406 addBeziersForRoundedRect(rect, topLeftRadius, topRightRadius, bottomLeftRadi us, bottomRightRadius);
407 }
408
409 // Approximation of control point positions on a bezier to simulate a quarter of a circle.
410 // This is 1-kappa, where kappa = 4 * (sqrt(2) - 1) / 3
411 static const float gCircleControlPoint = 0.447715f;
412
413 void Path::addBeziersForRoundedRect(const FloatRect& rect, const FloatSize& topL eftRadius, const FloatSize& topRightRadius, const FloatSize& bottomLeftRadius, c onst FloatSize& bottomRightRadius)
414 {
415 moveTo(FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));
416
417 addLineTo(FloatPoint(rect.maxX() - topRightRadius.width(), rect.y()));
418 if (topRightRadius.width() > 0 || topRightRadius.height() > 0)
419 addBezierCurveTo(FloatPoint(rect.maxX() - topRightRadius.width() * gCirc leControlPoint, rect.y()),
420 FloatPoint(rect.maxX(), rect.y() + topRightRadius.height() * gCircle ControlPoint),
421 FloatPoint(rect.maxX(), rect.y() + topRightRadius.height()));
422 addLineTo(FloatPoint(rect.maxX(), rect.maxY() - bottomRightRadius.height())) ;
423 if (bottomRightRadius.width() > 0 || bottomRightRadius.height() > 0)
424 addBezierCurveTo(FloatPoint(rect.maxX(), rect.maxY() - bottomRightRadius .height() * gCircleControlPoint),
425 FloatPoint(rect.maxX() - bottomRightRadius.width() * gCircleControlP oint, rect.maxY()),
426 FloatPoint(rect.maxX() - bottomRightRadius.width(), rect.maxY()));
427 addLineTo(FloatPoint(rect.x() + bottomLeftRadius.width(), rect.maxY()));
428 if (bottomLeftRadius.width() > 0 || bottomLeftRadius.height() > 0)
429 addBezierCurveTo(FloatPoint(rect.x() + bottomLeftRadius.width() * gCircl eControlPoint, rect.maxY()),
430 FloatPoint(rect.x(), rect.maxY() - bottomLeftRadius.height() * gCirc leControlPoint),
431 FloatPoint(rect.x(), rect.maxY() - bottomLeftRadius.height()));
432 addLineTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height()));
433 if (topLeftRadius.width() > 0 || topLeftRadius.height() > 0)
434 addBezierCurveTo(FloatPoint(rect.x(), rect.y() + topLeftRadius.height() * gCircleControlPoint),
435 FloatPoint(rect.x() + topLeftRadius.width() * gCircleControlPoint, r ect.y()),
436 FloatPoint(rect.x() + topLeftRadius.width(), rect.y()));
437
438 closeSubpath();
439 }
440
441 void Path::translate(const FloatSize& size)
442 {
443 m_path.offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(s ize.height()));
444 }
445
446 bool Path::unionPath(const Path& other)
447 {
448 return Op(m_path, other.m_path, kUnion_PathOp, &m_path);
449 }
450
451 }
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/Path.h ('k') | Source/core/platform/graphics/Pattern.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698