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 |