Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |