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

Side by Side Diff: src/core/SkPath.cpp

Issue 455043002: use conics (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 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
OLDNEW
1
2 /* 1 /*
3 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
4 * 3 *
5 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 5 * found in the LICENSE file.
7 */ 6 */
8 7
9
10 #include "SkBuffer.h" 8 #include "SkBuffer.h"
11 #include "SkErrorInternals.h" 9 #include "SkErrorInternals.h"
10 #include "SkGeometry.h"
12 #include "SkMath.h" 11 #include "SkMath.h"
13 #include "SkPath.h" 12 #include "SkPath.h"
14 #include "SkPathRef.h" 13 #include "SkPathRef.h"
15 #include "SkRRect.h" 14 #include "SkRRect.h"
16 #include "SkThread.h" 15 #include "SkThread.h"
17 16
17 #define SK_SUPPORT_LEGACY_ADDOVAL
18
18 //////////////////////////////////////////////////////////////////////////// 19 ////////////////////////////////////////////////////////////////////////////
19 20
20 /** 21 /**
21 * Path.bounds is defined to be the bounds of all the control points. 22 * Path.bounds is defined to be the bounds of all the control points.
22 * If we called bounds.join(r) we would skip r if r was empty, which breaks 23 * If we called bounds.join(r) we would skip r if r was empty, which breaks
23 * our promise. Hence we have a custom joiner that doesn't look at emptiness 24 * our promise. Hence we have a custom joiner that doesn't look at emptiness
24 */ 25 */
25 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { 26 static void joinNoEmptyChecks(SkRect* dst, const SkRect& src) {
26 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); 27 dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft);
27 dst->fTop = SkMinScalar(dst->fTop, src.fTop); 28 dst->fTop = SkMinScalar(dst->fTop, src.fTop);
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
224 SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY); 225 SkScalar xT = SkScalarMul(v.fX, rect.fTop - edgeBegin->fY);
225 SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX); 226 SkScalar yR = SkScalarMul(v.fY, rect.fRight - edgeBegin->fX);
226 SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY); 227 SkScalar xB = SkScalarMul(v.fX, rect.fBottom - edgeBegin->fY);
227 if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) { 228 if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) {
228 return false; 229 return false;
229 } 230 }
230 } 231 }
231 return true; 232 return true;
232 } 233 }
233 234
235 // TODO: clean this up (e.g. add printing?) and add to SkTypes?
236 static inline void SkCheck(bool predicate) {
caryclark 2014/12/17 15:52:43 Is this different from SK_ALWAYSBREAK() ?
bsalomon 2014/12/17 16:00:26 Seems weird to have this one-off here. Can this be
reed1 2014/12/17 16:12:38 Will replace with ALWAYSBREAK, and propose the new
237 if (!predicate) {
238 sk_throw();
239 }
240 }
241
234 bool SkPath::conservativelyContainsRect(const SkRect& rect) const { 242 bool SkPath::conservativelyContainsRect(const SkRect& rect) const {
235 // This only handles non-degenerate convex paths currently. 243 // This only handles non-degenerate convex paths currently.
236 if (kConvex_Convexity != this->getConvexity()) { 244 if (kConvex_Convexity != this->getConvexity()) {
237 return false; 245 return false;
238 } 246 }
239 247
240 Direction direction; 248 Direction direction;
241 if (!this->cheapComputeDirection(&direction)) { 249 if (!this->cheapComputeDirection(&direction)) {
242 return false; 250 return false;
243 } 251 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 SkDEBUGCODE(++segmentCount); 283 SkDEBUGCODE(++segmentCount);
276 nextPt = 3; 284 nextPt = 3;
277 break; 285 break;
278 case kClose_Verb: 286 case kClose_Verb:
279 SkDEBUGCODE(++closeCount;) 287 SkDEBUGCODE(++closeCount;)
280 break; 288 break;
281 default: 289 default:
282 SkDEBUGFAIL("unknown verb"); 290 SkDEBUGFAIL("unknown verb");
283 } 291 }
284 if (-1 != nextPt) { 292 if (-1 != nextPt) {
285 if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) { 293 if (SkPath::kConic_Verb == verb) {
286 return false; 294 SkConic orig;
295 orig.set(pts, iter.conicWeight());
296 SkPoint quadPts[5];
297 int count = orig.chopIntoQuadsPOW2(quadPts, 1);
298 SkCheck(2 == count);
299
300 if (!check_edge_against_rect(quadPts[0], quadPts[2], rect, direc tion)) {
301 return false;
302 }
303 if (!check_edge_against_rect(quadPts[2], quadPts[4], rect, direc tion)) {
304 return false;
305 }
306 } else {
307 if (!check_edge_against_rect(prevPt, pts[nextPt], rect, directio n)) {
308 return false;
309 }
287 } 310 }
288 prevPt = pts[nextPt]; 311 prevPt = pts[nextPt];
289 } 312 }
290 } 313 }
291 314
292 return check_edge_against_rect(prevPt, firstPt, rect, direction); 315 return check_edge_against_rect(prevPt, firstPt, rect, direction);
293 } 316 }
294 317
295 uint32_t SkPath::getGenerationID() const { 318 uint32_t SkPath::getGenerationID() const {
296 uint32_t genID = fPathRef->genID(); 319 uint32_t genID = fPathRef->genID();
(...skipping 869 matching lines...) Expand 10 before | Expand all | Expand 10 after
1166 if (isOval) { 1189 if (isOval) {
1167 fDirection = dir; 1190 fDirection = dir;
1168 } else { 1191 } else {
1169 fDirection = kUnknown_Direction; 1192 fDirection = kUnknown_Direction;
1170 } 1193 }
1171 1194
1172 SkAutoDisableDirectionCheck addc(this); 1195 SkAutoDisableDirectionCheck addc(this);
1173 1196
1174 SkAutoPathBoundsUpdate apbu(this, oval); 1197 SkAutoPathBoundsUpdate apbu(this, oval);
1175 1198
1199 #ifdef SK_SUPPORT_LEGACY_ADDOVAL
1176 SkScalar cx = oval.centerX(); 1200 SkScalar cx = oval.centerX();
1177 SkScalar cy = oval.centerY(); 1201 SkScalar cy = oval.centerY();
1178 SkScalar rx = SkScalarHalf(oval.width()); 1202 SkScalar rx = SkScalarHalf(oval.width());
1179 SkScalar ry = SkScalarHalf(oval.height()); 1203 SkScalar ry = SkScalarHalf(oval.height());
1180 1204
1181 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8); 1205 SkScalar sx = SkScalarMul(rx, SK_ScalarTanPIOver8);
1182 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8); 1206 SkScalar sy = SkScalarMul(ry, SK_ScalarTanPIOver8);
1183 SkScalar mx = SkScalarMul(rx, SK_ScalarRoot2Over2); 1207 SkScalar mx = SkScalarMul(rx, SK_ScalarRoot2Over2);
1184 SkScalar my = SkScalarMul(ry, SK_ScalarRoot2Over2); 1208 SkScalar my = SkScalarMul(ry, SK_ScalarRoot2Over2);
1185 1209
1186 /* 1210 /*
1187 To handle imprecision in computing the center and radii, we revert to 1211 To handle imprecision in computing the center and radii, we revert to
1188 the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx) 1212 the provided bounds when we can (i.e. use oval.fLeft instead of cx-rx)
1189 to ensure that we don't exceed the oval's bounds *ever*, since we want 1213 to ensure that we don't exceed the oval's bounds *ever*, since we want
1190 to use oval for our fast-bounds, rather than have to recompute it. 1214 to use oval for our fast-bounds, rather than have to recompute it.
1191 */ 1215 */
1192 const SkScalar L = oval.fLeft; // cx - rx 1216 const SkScalar L = oval.fLeft; // cx - rx
1193 const SkScalar T = oval.fTop; // cy - ry 1217 const SkScalar T = oval.fTop; // cy - ry
1194 const SkScalar R = oval.fRight; // cx + rx 1218 const SkScalar R = oval.fRight; // cx + rx
1195 const SkScalar B = oval.fBottom; // cy + ry 1219 const SkScalar B = oval.fBottom; // cy + ry
1196 1220
1197 this->incReserve(17); // 8 quads + close 1221 this->incReserve(17); // 8 quads + close
1198 this->moveTo(R, cy); 1222 this->moveTo(R, cy);
1199 if (dir == kCCW_Direction) { 1223 if (dir == kCCW_Direction) {
1200 this->quadTo( R, cy - sy, cx + mx, cy - my); 1224 this->quadTo( R, cy - sy, cx + mx, cy - my);
1201 this->quadTo(cx + sx, T, cx , T); 1225 this->quadTo(cx + sx, T, cx , T);
1202 this->quadTo(cx - sx, T, cx - mx, cy - my); 1226 this->quadTo(cx - sx, T, cx - mx, cy - my);
1203 this->quadTo( L, cy - sy, L, cy ); 1227 this->quadTo( L, cy - sy, L, cy );
1204 this->quadTo( L, cy + sy, cx - mx, cy + my); 1228 this->quadTo( L, cy + sy, cx - mx, cy + my);
1205 this->quadTo(cx - sx, B, cx , B); 1229 this->quadTo(cx - sx, B, cx , B);
1206 this->quadTo(cx + sx, B, cx + mx, cy + my); 1230 this->quadTo(cx + sx, B, cx + mx, cy + my);
1207 this->quadTo( R, cy + sy, R, cy ); 1231 this->quadTo( R, cy + sy, R, cy );
1208 } else { 1232 } else {
1209 this->quadTo( R, cy + sy, cx + mx, cy + my); 1233 this->quadTo( R, cy + sy, cx + mx, cy + my);
1210 this->quadTo(cx + sx, B, cx , B); 1234 this->quadTo(cx + sx, B, cx , B);
1211 this->quadTo(cx - sx, B, cx - mx, cy + my); 1235 this->quadTo(cx - sx, B, cx - mx, cy + my);
1212 this->quadTo( L, cy + sy, L, cy ); 1236 this->quadTo( L, cy + sy, L, cy );
1213 this->quadTo( L, cy - sy, cx - mx, cy - my); 1237 this->quadTo( L, cy - sy, cx - mx, cy - my);
1214 this->quadTo(cx - sx, T, cx , T); 1238 this->quadTo(cx - sx, T, cx , T);
1215 this->quadTo(cx + sx, T, cx + mx, cy - my); 1239 this->quadTo(cx + sx, T, cx + mx, cy - my);
1216 this->quadTo( R, cy - sy, R, cy ); 1240 this->quadTo( R, cy - sy, R, cy );
1217 } 1241 }
1242 #else
1243 const SkScalar L = oval.fLeft;
1244 const SkScalar T = oval.fTop;
1245 const SkScalar R = oval.fRight;
1246 const SkScalar B = oval.fBottom;
1247 const SkScalar cx = oval.centerX();
1248 const SkScalar cy = oval.centerY();
1249 const SkScalar weight = SK_ScalarRoot2Over2;
1250
1251 this->incReserve(9); // move + 4 conics
1252 this->moveTo(R, cy);
1253 if (dir == kCCW_Direction) {
1254 this->conicTo(R, T, cx, T, weight);
1255 this->conicTo(L, T, L, cy, weight);
1256 this->conicTo(L, B, cx, B, weight);
1257 this->conicTo(R, B, R, cy, weight);
1258 } else {
1259 this->conicTo(R, B, cx, B, weight);
1260 this->conicTo(L, B, L, cy, weight);
1261 this->conicTo(L, T, cx, T, weight);
1262 this->conicTo(R, T, R, cy, weight);
1263 }
1264 #endif
1218 this->close(); 1265 this->close();
1219 1266
1220 SkPathRef::Editor ed(&fPathRef); 1267 SkPathRef::Editor ed(&fPathRef);
1221 1268
1222 ed.setIsOval(isOval); 1269 ed.setIsOval(isOval);
1223 } 1270 }
1224 1271
1225 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { 1272 void SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) {
1226 if (r > 0) { 1273 if (r > 0) {
1227 SkRect rect; 1274 SkRect rect;
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
1523 1570
1524 /////////////////////////////////////////////////////////////////////////////// 1571 ///////////////////////////////////////////////////////////////////////////////
1525 1572
1526 void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const { 1573 void SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const {
1527 SkMatrix matrix; 1574 SkMatrix matrix;
1528 1575
1529 matrix.setTranslate(dx, dy); 1576 matrix.setTranslate(dx, dy);
1530 this->transform(matrix, dst); 1577 this->transform(matrix, dst);
1531 } 1578 }
1532 1579
1533 #include "SkGeometry.h"
1534
1535 static void subdivide_quad_to(SkPath* path, const SkPoint pts[3],
1536 int level = 2) {
1537 if (--level >= 0) {
1538 SkPoint tmp[5];
1539
1540 SkChopQuadAtHalf(pts, tmp);
1541 subdivide_quad_to(path, &tmp[0], level);
1542 subdivide_quad_to(path, &tmp[2], level);
1543 } else {
1544 path->quadTo(pts[1], pts[2]);
1545 }
1546 }
1547
1548 static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4], 1580 static void subdivide_cubic_to(SkPath* path, const SkPoint pts[4],
1549 int level = 2) { 1581 int level = 2) {
1550 if (--level >= 0) { 1582 if (--level >= 0) {
1551 SkPoint tmp[7]; 1583 SkPoint tmp[7];
1552 1584
1553 SkChopCubicAtHalf(pts, tmp); 1585 SkChopCubicAtHalf(pts, tmp);
1554 subdivide_cubic_to(path, &tmp[0], level); 1586 subdivide_cubic_to(path, &tmp[0], level);
1555 subdivide_cubic_to(path, &tmp[3], level); 1587 subdivide_cubic_to(path, &tmp[3], level);
1556 } else { 1588 } else {
1557 path->cubicTo(pts[1], pts[2], pts[3]); 1589 path->cubicTo(pts[1], pts[2], pts[3]);
(...skipping 16 matching lines...) Expand all
1574 1606
1575 while ((verb = iter.next(pts, false)) != kDone_Verb) { 1607 while ((verb = iter.next(pts, false)) != kDone_Verb) {
1576 switch (verb) { 1608 switch (verb) {
1577 case kMove_Verb: 1609 case kMove_Verb:
1578 tmp.moveTo(pts[0]); 1610 tmp.moveTo(pts[0]);
1579 break; 1611 break;
1580 case kLine_Verb: 1612 case kLine_Verb:
1581 tmp.lineTo(pts[1]); 1613 tmp.lineTo(pts[1]);
1582 break; 1614 break;
1583 case kQuad_Verb: 1615 case kQuad_Verb:
1584 subdivide_quad_to(&tmp, pts); 1616 // promote the quad to a conic
1617 tmp.conicTo(pts[1], pts[2],
1618 SkConic::TransformW(pts, SK_Scalar1, matrix));
1585 break; 1619 break;
1586 case kConic_Verb: 1620 case kConic_Verb:
1587 SkDEBUGFAIL("TODO: compute new weight"); 1621 tmp.conicTo(pts[1], pts[2],
1588 tmp.conicTo(pts[1], pts[2], iter.conicWeight()); 1622 SkConic::TransformW(pts, iter.conicWeight(), mat rix));
1589 break; 1623 break;
1590 case kCubic_Verb: 1624 case kCubic_Verb:
1591 subdivide_cubic_to(&tmp, pts); 1625 subdivide_cubic_to(&tmp, pts);
1592 break; 1626 break;
1593 case kClose_Verb: 1627 case kClose_Verb:
1594 tmp.close(); 1628 tmp.close();
1595 break; 1629 break;
1596 default: 1630 default:
1597 SkDEBUGFAIL("unknown verb"); 1631 SkDEBUGFAIL("unknown verb");
1598 break; 1632 break;
(...skipping 1268 matching lines...) Expand 10 before | Expand all | Expand 10 after
2867 switch (this->getFillType()) { 2901 switch (this->getFillType()) {
2868 case SkPath::kEvenOdd_FillType: 2902 case SkPath::kEvenOdd_FillType:
2869 case SkPath::kInverseEvenOdd_FillType: 2903 case SkPath::kInverseEvenOdd_FillType:
2870 w &= 1; 2904 w &= 1;
2871 break; 2905 break;
2872 default: 2906 default:
2873 break; 2907 break;
2874 } 2908 }
2875 return SkToBool(w); 2909 return SkToBool(w);
2876 } 2910 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698