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

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

Issue 65493004: increase coverage of SkPath.cpp, remove unused code (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: increase coverage above 95%; add missing conic case Created 7 years, 1 month 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 | « include/core/SkPath.h ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkBuffer.h" 10 #include "SkBuffer.h"
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 SkPathRef::Editor(&fPathRef, inc, inc); 655 SkPathRef::Editor(&fPathRef, inc, inc);
656 SkDEBUGCODE(this->validate();) 656 SkDEBUGCODE(this->validate();)
657 } 657 }
658 658
659 void SkPath::moveTo(SkScalar x, SkScalar y) { 659 void SkPath::moveTo(SkScalar x, SkScalar y) {
660 SkDEBUGCODE(this->validate();) 660 SkDEBUGCODE(this->validate();)
661 661
662 SkPathRef::Editor ed(&fPathRef); 662 SkPathRef::Editor ed(&fPathRef);
663 663
664 // remember our index 664 // remember our index
665 fLastMoveToIndex = ed.pathRef()->countPoints(); 665 fLastMoveToIndex = fPathRef->countPoints();
666 666
667 ed.growForVerb(kMove_Verb)->set(x, y); 667 ed.growForVerb(kMove_Verb)->set(x, y);
668 } 668 }
669 669
670 void SkPath::rMoveTo(SkScalar x, SkScalar y) { 670 void SkPath::rMoveTo(SkScalar x, SkScalar y) {
671 SkPoint pt; 671 SkPoint pt;
672 this->getLastPt(&pt); 672 this->getLastPt(&pt);
673 this->moveTo(pt.fX + x, pt.fY + y); 673 this->moveTo(pt.fX + x, pt.fY + y);
674 } 674 }
675 675
(...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after
1099 this->addOval(bounds, dir); 1099 this->addOval(bounds, dir);
1100 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 1100 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT
1101 } else if (rrect.isSimple()) { 1101 } else if (rrect.isSimple()) {
1102 const SkVector& rad = rrect.getSimpleRadii(); 1102 const SkVector& rad = rrect.getSimpleRadii();
1103 this->addRoundRect(bounds, rad.x(), rad.y(), dir); 1103 this->addRoundRect(bounds, rad.x(), rad.y(), dir);
1104 #endif 1104 #endif
1105 } else { 1105 } else {
1106 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 1106 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
1107 1107
1108 SkAutoPathBoundsUpdate apbu(this, bounds); 1108 SkAutoPathBoundsUpdate apbu(this, bounds);
1109 SkAutoDisableDirectionCheck(this); 1109 SkAutoDisableDirectionCheck addc(this);
1110 1110
1111 this->incReserve(21); 1111 this->incReserve(21);
1112 if (kCW_Direction == dir) { 1112 if (kCW_Direction == dir) {
1113 this->moveTo(bounds.fLeft, 1113 this->moveTo(bounds.fLeft,
1114 bounds.fBottom - rrect.fRadii[SkRRect::kLowerLeft_Corne r].fY); 1114 bounds.fBottom - rrect.fRadii[SkRRect::kLowerLeft_Corne r].fY);
1115 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir); 1115 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir);
1116 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir); 1116 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir);
1117 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir); 1117 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir);
1118 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir); 1118 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir);
1119 } else { 1119 } else {
1120 this->moveTo(bounds.fLeft, 1120 this->moveTo(bounds.fLeft,
1121 bounds.fTop + rrect.fRadii[SkRRect::kUpperLeft_Corner]. fY); 1121 bounds.fTop + rrect.fRadii[SkRRect::kUpperLeft_Corner]. fY);
1122 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir); 1122 add_corner_quads(this, rrect, SkRRect::kLowerLeft_Corner, dir);
1123 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir); 1123 add_corner_quads(this, rrect, SkRRect::kLowerRight_Corner, dir);
1124 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir); 1124 add_corner_quads(this, rrect, SkRRect::kUpperRight_Corner, dir);
1125 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir); 1125 add_corner_quads(this, rrect, SkRRect::kUpperLeft_Corner, dir);
1126 } 1126 }
1127 this->close(); 1127 this->close();
1128 } 1128 }
1129 } 1129 }
1130 1130
1131 bool SkPath::hasOnlyMoveTos() const { 1131 bool SkPath::hasOnlyMoveTos() const {
1132 int count = fPathRef->countVerbs(); 1132 int count = fPathRef->countVerbs();
1133 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe mBegin(); 1133 const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMe mBegin();
1134 for (int i = 0; i < count; ++i) { 1134 for (int i = 0; i < count; ++i) {
1135 if (*verbs == kLine_Verb || 1135 if (*verbs == kLine_Verb ||
1136 *verbs == kQuad_Verb || 1136 *verbs == kQuad_Verb ||
1137 *verbs == kConic_Verb ||
1137 *verbs == kCubic_Verb) { 1138 *verbs == kCubic_Verb) {
1138 return false; 1139 return false;
1139 } 1140 }
1140 ++verbs; 1141 ++verbs;
1141 } 1142 }
1142 return true; 1143 return true;
1143 } 1144 }
1144 1145
1145 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT 1146 #ifdef SK_IGNORE_QUAD_RR_CORNERS_OPT
1146 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3) 1147 #define CUBIC_ARC_FACTOR ((SK_ScalarSqrt2 - SK_Scalar1) * 4 / 3)
(...skipping 25 matching lines...) Expand all
1172 bool skip_vert = ry >= halfH; 1173 bool skip_vert = ry >= halfH;
1173 1174
1174 if (skip_hori && skip_vert) { 1175 if (skip_hori && skip_vert) {
1175 this->addOval(rect, dir); 1176 this->addOval(rect, dir);
1176 return; 1177 return;
1177 } 1178 }
1178 1179
1179 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 1180 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
1180 1181
1181 SkAutoPathBoundsUpdate apbu(this, rect); 1182 SkAutoPathBoundsUpdate apbu(this, rect);
1182 SkAutoDisableDirectionCheck(this); 1183 SkAutoDisableDirectionCheck addc(this);
1183 1184
1184 if (skip_hori) { 1185 if (skip_hori) {
1185 rx = halfW; 1186 rx = halfW;
1186 } else if (skip_vert) { 1187 } else if (skip_vert) {
1187 ry = halfH; 1188 ry = halfH;
1188 } 1189 }
1189 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); 1190 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
1190 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); 1191 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
1191 1192
1192 this->incReserve(17); 1193 this->incReserve(17);
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after
1504 2, // kConic 1505 2, // kConic
1505 3, // kCubic 1506 3, // kCubic
1506 0, // kClose 1507 0, // kClose
1507 0 // kDone 1508 0 // kDone
1508 }; 1509 };
1509 1510
1510 SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); 1511 SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
1511 return gPtsInVerb[verb]; 1512 return gPtsInVerb[verb];
1512 } 1513 }
1513 1514
1514 // ignore the initial moveto, and stop when the 1st contour ends
1515 void SkPath::pathTo(const SkPath& path) {
1516 int i, vcount = path.fPathRef->countVerbs();
1517 // exit early if the path is empty, or just has a moveTo.
1518 if (vcount < 2) {
1519 return;
1520 }
1521
1522 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1523
1524 fIsOval = false;
1525
1526 const uint8_t* verbs = path.fPathRef->verbs();
1527 // skip the initial moveTo
1528 const SkPoint* pts = path.fPathRef->points() + 1;
1529 const SkScalar* conicWeight = path.fPathRef->conicWeights();
1530
1531 SkASSERT(verbs[~0] == kMove_Verb);
1532 for (i = 1; i < vcount; i++) {
1533 switch (verbs[~i]) {
1534 case kLine_Verb:
1535 this->lineTo(pts[0].fX, pts[0].fY);
1536 break;
1537 case kQuad_Verb:
1538 this->quadTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY);
1539 break;
1540 case kConic_Verb:
1541 this->conicTo(pts[0], pts[1], *conicWeight++);
1542 break;
1543 case kCubic_Verb:
1544 this->cubicTo(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, pts[2] .fX, pts[2].fY);
1545 break;
1546 case kClose_Verb:
1547 return;
1548 }
1549 pts += pts_in_verb(verbs[~i]);
1550 }
1551 }
1552
1553 // ignore the last point of the 1st contour 1515 // ignore the last point of the 1st contour
1554 void SkPath::reversePathTo(const SkPath& path) { 1516 void SkPath::reversePathTo(const SkPath& path) {
1555 int i, vcount = path.fPathRef->countVerbs(); 1517 int i, vcount = path.fPathRef->countVerbs();
1556 // exit early if the path is empty, or just has a moveTo. 1518 // exit early if the path is empty, or just has a moveTo.
1557 if (vcount < 2) { 1519 if (vcount < 2) {
1558 return; 1520 return;
1559 } 1521 }
1560 1522
1561 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1523 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1562 1524
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1748 dst->fDirection = kUnknown_Direction; 1710 dst->fDirection = kUnknown_Direction;
1749 } else { 1711 } else {
1750 SkScalar det2x2 = 1712 SkScalar det2x2 =
1751 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) - 1713 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) -
1752 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY)); 1714 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY));
1753 if (det2x2 < 0) { 1715 if (det2x2 < 0) {
1754 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection)); 1716 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection));
1755 } else if (det2x2 > 0) { 1717 } else if (det2x2 > 0) {
1756 dst->fDirection = fDirection; 1718 dst->fDirection = fDirection;
1757 } else { 1719 } else {
1720 dst->fConvexity = kUnknown_Convexity;
1758 dst->fDirection = kUnknown_Direction; 1721 dst->fDirection = kUnknown_Direction;
1759 } 1722 }
1760 } 1723 }
1761 1724
1762 // It's an oval only if it stays a rect. 1725 // It's an oval only if it stays a rect.
1763 dst->fIsOval = fIsOval && matrix.rectStaysRect(); 1726 dst->fIsOval = fIsOval && matrix.rectStaysRect();
1764 1727
1765 SkDEBUGCODE(dst->validate();) 1728 SkDEBUGCODE(dst->validate();)
1766 } 1729 }
1767 } 1730 }
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
2312 #define kValueNeverReturnedBySign 2 2275 #define kValueNeverReturnedBySign 2
2313 2276
2314 static bool AlmostEqual(SkScalar compA, SkScalar compB) { 2277 static bool AlmostEqual(SkScalar compA, SkScalar compB) {
2315 // The error epsilon was empirically derived; worse case round rects 2278 // The error epsilon was empirically derived; worse case round rects
2316 // with a mid point outset by 2x float epsilon in tests had an error 2279 // with a mid point outset by 2x float epsilon in tests had an error
2317 // of 12. 2280 // of 12.
2318 const int epsilon = 16; 2281 const int epsilon = 16;
2319 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) { 2282 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2320 return false; 2283 return false;
2321 } 2284 }
2322 if (sk_float_abs(compA) <= FLT_EPSILON && sk_float_abs(compB) <= FLT_EPSILON ) { 2285 // no need to check for small numbers because SkPath::Iter has removed degen erate values
2323 return true;
2324 }
2325 int aBits = SkFloatAs2sCompliment(compA); 2286 int aBits = SkFloatAs2sCompliment(compA);
2326 int bBits = SkFloatAs2sCompliment(compB); 2287 int bBits = SkFloatAs2sCompliment(compB);
2327 return aBits < bBits + epsilon && bBits < aBits + epsilon; 2288 return aBits < bBits + epsilon && bBits < aBits + epsilon;
2328 } 2289 }
2329 2290
2330 // only valid for a single contour 2291 // only valid for a single contour
2331 struct Convexicator { 2292 struct Convexicator {
2332 Convexicator() 2293 Convexicator()
2333 : fPtCount(0) 2294 : fPtCount(0)
2334 , fConvexity(SkPath::kConvex_Convexity) 2295 , fConvexity(SkPath::kConvex_Convexity)
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
2625 } else if (x > max) { 2586 } else if (x > max) {
2626 max = x; 2587 max = x;
2627 maxIndex = i; 2588 maxIndex = i;
2628 } 2589 }
2629 } 2590 }
2630 *maxIndexPtr = maxIndex; 2591 *maxIndexPtr = maxIndex;
2631 return minIndex; 2592 return minIndex;
2632 } 2593 }
2633 2594
2634 static void crossToDir(SkScalar cross, SkPath::Direction* dir) { 2595 static void crossToDir(SkScalar cross, SkPath::Direction* dir) {
2635 if (dir) { 2596 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2636 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2637 }
2638 }
2639
2640 #if 0
2641 #include "SkString.h"
2642 #include "../utils/SkParsePath.h"
2643 static void dumpPath(const SkPath& path) {
2644 SkString str;
2645 SkParsePath::ToSVGString(path, &str);
2646 SkDebugf("%s\n", str.c_str());
2647 }
2648 #endif
2649
2650 namespace {
2651 // for use with convex_dir_test
2652 double mul(double a, double b) { return a * b; }
2653 SkScalar mul(SkScalar a, SkScalar b) { return SkScalarMul(a, b); }
2654 double toDouble(SkScalar a) { return SkScalarToDouble(a); }
2655 SkScalar toScalar(SkScalar a) { return a; }
2656
2657 // determines the winding direction of a convex polygon with the precision
2658 // of T. CAST_SCALAR casts an SkScalar to T.
2659 template <typename T, T (CAST_SCALAR)(SkScalar)>
2660 bool convex_dir_test(int n, const SkPoint pts[], SkPath::Direction* dir) {
2661 // we find the first three points that form a non-degenerate
2662 // triangle. If there are no such points then the path is
2663 // degenerate. The first is always point 0. Now we find the second
2664 // point.
2665 int i = 0;
2666 enum { kX = 0, kY = 1 };
2667 T v0[2];
2668 while (1) {
2669 v0[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2670 v0[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2671 if (v0[kX] || v0[kY]) {
2672 break;
2673 }
2674 if (++i == n - 1) {
2675 return false;
2676 }
2677 }
2678 // now find a third point that is not colinear with the first two
2679 // points and check the orientation of the triangle (which will be
2680 // the same as the orientation of the path).
2681 for (++i; i < n; ++i) {
2682 T v1[2];
2683 v1[kX] = CAST_SCALAR(pts[i].fX) - CAST_SCALAR(pts[0].fX);
2684 v1[kY] = CAST_SCALAR(pts[i].fY) - CAST_SCALAR(pts[0].fY);
2685 T cross = mul(v0[kX], v1[kY]) - mul(v0[kY], v1[kX]);
2686 if (0 != cross) {
2687 *dir = cross > 0 ? SkPath::kCW_Direction : SkPath::kCCW_Direction;
2688 return true;
2689 }
2690 }
2691 return false;
2692 }
2693 } 2597 }
2694 2598
2695 /* 2599 /*
2696 * We loop through all contours, and keep the computed cross-product of the 2600 * We loop through all contours, and keep the computed cross-product of the
2697 * contour that contained the global y-max. If we just look at the first 2601 * contour that contained the global y-max. If we just look at the first
2698 * contour, we may find one that is wound the opposite way (correctly) since 2602 * contour, we may find one that is wound the opposite way (correctly) since
2699 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour 2603 * it is the interior of a hole (e.g. 'o'). Thus we must find the contour
2700 * that is outer most (or at least has the global y-max) before we can consider 2604 * that is outer most (or at least has the global y-max) before we can consider
2701 * its cross product. 2605 * its cross product.
2702 */ 2606 */
2703 bool SkPath::cheapComputeDirection(Direction* dir) const { 2607 bool SkPath::cheapComputeDirection(Direction* dir) const {
2704 // dumpPath(*this);
2705 // don't want to pay the cost for computing this if it
2706 // is unknown, so we don't call isConvex()
2707
2708 if (kUnknown_Direction != fDirection) { 2608 if (kUnknown_Direction != fDirection) {
2709 *dir = static_cast<Direction>(fDirection); 2609 *dir = static_cast<Direction>(fDirection);
2710 return true; 2610 return true;
2711 } 2611 }
2712 const Convexity conv = this->getConvexityOrUnknown(); 2612
2613 // don't want to pay the cost for computing this if it
2614 // is unknown, so we don't call isConvex()
2615 if (kConvex_Convexity == this->getConvexityOrUnknown()) {
2616 SkASSERT(kUnknown_Direction == fDirection);
2617 *dir = static_cast<Direction>(fDirection);
2618 return false;
2619 }
2713 2620
2714 ContourIter iter(*fPathRef.get()); 2621 ContourIter iter(*fPathRef.get());
2715 2622
2716 // initialize with our logical y-min 2623 // initialize with our logical y-min
2717 SkScalar ymax = this->getBounds().fTop; 2624 SkScalar ymax = this->getBounds().fTop;
2718 SkScalar ymaxCross = 0; 2625 SkScalar ymaxCross = 0;
2719 2626
2720 for (; !iter.done(); iter.next()) { 2627 for (; !iter.done(); iter.next()) {
2721 int n = iter.count(); 2628 int n = iter.count();
2722 if (n < 3) { 2629 if (n < 3) {
2723 continue; 2630 continue;
2724 } 2631 }
2725 2632
2726 const SkPoint* pts = iter.pts(); 2633 const SkPoint* pts = iter.pts();
2727 SkScalar cross = 0; 2634 SkScalar cross = 0;
2728 if (kConvex_Convexity == conv) { 2635 int index = find_max_y(pts, n);
2729 // We try first at scalar precision, and then again at double 2636 if (pts[index].fY < ymax) {
2730 // precision. This is because the vectors computed between distant 2637 continue;
2731 // points may lose too much precision. 2638 }
2732 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) { 2639
2733 fDirection = *dir; 2640 // If there is more than 1 distinct point at the y-max, we take the
2734 return true; 2641 // x-min and x-max of them and just subtract to compute the dir.
2642 if (pts[(index + 1) % n].fY == pts[index].fY) {
2643 int maxIndex;
2644 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2645 if (minIndex == maxIndex) {
2646 goto TRY_CROSSPROD;
2735 } 2647 }
2736 if (convex_dir_test<double, toDouble>(n, pts, dir)) { 2648 SkASSERT(pts[minIndex].fY == pts[index].fY);
2737 fDirection = *dir; 2649 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2738 return true; 2650 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2739 } else { 2651 // we just subtract the indices, and let that auto-convert to
2740 return false; 2652 // SkScalar, since we just want - or + to signal the direction.
2741 } 2653 cross = minIndex - maxIndex;
2742 } else { 2654 } else {
2743 int index = find_max_y(pts, n); 2655 TRY_CROSSPROD:
2744 if (pts[index].fY < ymax) { 2656 // Find a next and prev index to use for the cross-product test,
2657 // but we try to find pts that form non-zero vectors from pts[index]
2658 //
2659 // Its possible that we can't find two non-degenerate vectors, so
2660 // we have to guard our search (e.g. all the pts could be in the
2661 // same place).
2662
2663 // we pass n - 1 instead of -1 so we don't foul up % operator by
2664 // passing it a negative LH argument.
2665 int prev = find_diff_pt(pts, index, n, n - 1);
2666 if (prev == index) {
2667 // completely degenerate, skip to next contour
2745 continue; 2668 continue;
2746 } 2669 }
2670 int next = find_diff_pt(pts, index, n, 1);
2671 SkASSERT(next != index);
2672 cross = cross_prod(pts[prev], pts[index], pts[next]);
2673 // if we get a zero and the points are horizontal, then we look at t he spread in
2674 // x-direction. We really should continue to walk away from the dege neracy until
2675 // there is a divergence.
2676 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == p ts[index].fY) {
2677 // construct the subtract so we get the correct Direction below
2678 cross = pts[index].fX - pts[next].fX;
2679 }
2680 }
2747 2681
2748 // If there is more than 1 distinct point at the y-max, we take the 2682 if (cross) {
2749 // x-min and x-max of them and just subtract to compute the dir. 2683 // record our best guess so far
2750 if (pts[(index + 1) % n].fY == pts[index].fY) { 2684 ymax = pts[index].fY;
2751 int maxIndex; 2685 ymaxCross = cross;
2752 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2753 if (minIndex == maxIndex) {
2754 goto TRY_CROSSPROD;
2755 }
2756 SkASSERT(pts[minIndex].fY == pts[index].fY);
2757 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2758 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2759 // we just subtract the indices, and let that auto-convert to
2760 // SkScalar, since we just want - or + to signal the direction.
2761 cross = minIndex - maxIndex;
2762 } else {
2763 TRY_CROSSPROD:
2764 // Find a next and prev index to use for the cross-product test,
2765 // but we try to find pts that form non-zero vectors from pts[in dex]
2766 //
2767 // Its possible that we can't find two non-degenerate vectors, s o
2768 // we have to guard our search (e.g. all the pts could be in the
2769 // same place).
2770
2771 // we pass n - 1 instead of -1 so we don't foul up % operator by
2772 // passing it a negative LH argument.
2773 int prev = find_diff_pt(pts, index, n, n - 1);
2774 if (prev == index) {
2775 // completely degenerate, skip to next contour
2776 continue;
2777 }
2778 int next = find_diff_pt(pts, index, n, 1);
2779 SkASSERT(next != index);
2780 cross = cross_prod(pts[prev], pts[index], pts[next]);
2781 // if we get a zero and the points are horizontal, then we look at the spread in
2782 // x-direction. We really should continue to walk away from the degeneracy until
2783 // there is a divergence.
2784 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) {
2785 // construct the subtract so we get the correct Direction be low
2786 cross = pts[index].fX - pts[next].fX;
2787 }
2788 }
2789
2790 if (cross) {
2791 // record our best guess so far
2792 ymax = pts[index].fY;
2793 ymaxCross = cross;
2794 }
2795 } 2686 }
2796 } 2687 }
2797 if (ymaxCross) { 2688 if (ymaxCross) {
2798 crossToDir(ymaxCross, dir); 2689 crossToDir(ymaxCross, dir);
2799 fDirection = *dir; 2690 fDirection = *dir;
2800 return true; 2691 return true;
2801 } else { 2692 } else {
2802 return false; 2693 return false;
2803 } 2694 }
2804 } 2695 }
(...skipping 10 matching lines...) Expand all
2815 SkScalar A = c3 + 3*(c1 - c2) - c0; 2706 SkScalar A = c3 + 3*(c1 - c2) - c0;
2816 SkScalar B = 3*(c2 - c1 - c1 + c0); 2707 SkScalar B = 3*(c2 - c1 - c1 + c0);
2817 SkScalar C = 3*(c1 - c0); 2708 SkScalar C = 3*(c1 - c0);
2818 SkScalar D = c0; 2709 SkScalar D = c0;
2819 return eval_cubic_coeff(A, B, C, D, t); 2710 return eval_cubic_coeff(A, B, C, D, t);
2820 } 2711 }
2821 2712
2822 /* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the 2713 /* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
2823 t value such that cubic(t) = target 2714 t value such that cubic(t) = target
2824 */ 2715 */
2825 static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, 2716 static void chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
2826 SkScalar target, SkScalar* t) { 2717 SkScalar target, SkScalar* t) {
2827 // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3); 2718 // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
2828 SkASSERT(c0 < target && target < c3); 2719 SkASSERT(c0 < target && target < c3);
2829 2720
2830 SkScalar D = c0 - target; 2721 SkScalar D = c0 - target;
2831 SkScalar A = c3 + 3*(c1 - c2) - c0; 2722 SkScalar A = c3 + 3*(c1 - c2) - c0;
2832 SkScalar B = 3*(c2 - c1 - c1 + c0); 2723 SkScalar B = 3*(c2 - c1 - c1 + c0);
2833 SkScalar C = 3*(c1 - c0); 2724 SkScalar C = 3*(c1 - c0);
2834 2725
2835 const SkScalar TOLERANCE = SK_Scalar1 / 4096; 2726 const SkScalar TOLERANCE = SK_Scalar1 / 4096;
2836 SkScalar minT = 0; 2727 SkScalar minT = 0;
2837 SkScalar maxT = SK_Scalar1; 2728 SkScalar maxT = SK_Scalar1;
2838 SkScalar mid; 2729 SkScalar mid;
2839 int i; 2730 int i;
2840 for (i = 0; i < 16; i++) { 2731 for (i = 0; i < 16; i++) {
2841 mid = SkScalarAve(minT, maxT); 2732 mid = SkScalarAve(minT, maxT);
2842 SkScalar delta = eval_cubic_coeff(A, B, C, D, mid); 2733 SkScalar delta = eval_cubic_coeff(A, B, C, D, mid);
2843 if (delta < 0) { 2734 if (delta < 0) {
2844 minT = mid; 2735 minT = mid;
2845 delta = -delta; 2736 delta = -delta;
2846 } else { 2737 } else {
2847 maxT = mid; 2738 maxT = mid;
2848 } 2739 }
2849 if (delta < TOLERANCE) { 2740 if (delta < TOLERANCE) {
2850 break; 2741 break;
2851 } 2742 }
2852 } 2743 }
2853 *t = mid; 2744 *t = mid;
2854 return true;
2855 } 2745 }
2856 2746
2857 template <size_t N> static void find_minmax(const SkPoint pts[], 2747 template <size_t N> static void find_minmax(const SkPoint pts[],
2858 SkScalar* minPtr, SkScalar* maxPtr) { 2748 SkScalar* minPtr, SkScalar* maxPtr) {
2859 SkScalar min, max; 2749 SkScalar min, max;
2860 min = max = pts[0].fX; 2750 min = max = pts[0].fX;
2861 for (size_t i = 1; i < N; ++i) { 2751 for (size_t i = 1; i < N; ++i) {
2862 min = SkMinScalar(min, pts[i].fX); 2752 min = SkMinScalar(min, pts[i].fX);
2863 max = SkMaxScalar(max, pts[i].fX); 2753 max = SkMaxScalar(max, pts[i].fX);
2864 } 2754 }
(...skipping 21 matching lines...) Expand all
2886 SkScalar min, max; 2776 SkScalar min, max;
2887 find_minmax<4>(pts, &min, &max); 2777 find_minmax<4>(pts, &min, &max);
2888 if (x < min) { 2778 if (x < min) {
2889 return 0; 2779 return 0;
2890 } 2780 }
2891 if (x > max) { 2781 if (x > max) {
2892 return dir; 2782 return dir;
2893 } 2783 }
2894 2784
2895 // compute the actual x(t) value 2785 // compute the actual x(t) value
2896 SkScalar t, xt; 2786 SkScalar t;
2897 if (chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, &t)) { 2787 chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, &t);
2898 xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t); 2788 SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
2899 } else {
2900 SkScalar mid = SkScalarAve(pts[0].fY, pts[3].fY);
2901 xt = y < mid ? pts[0].fX : pts[3].fX;
2902 }
2903 return xt < x ? dir : 0; 2789 return xt < x ? dir : 0;
2904 } 2790 }
2905 2791
2906 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { 2792 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) {
2907 SkPoint dst[10]; 2793 SkPoint dst[10];
2908 int n = SkChopCubicAtYExtrema(pts, dst); 2794 int n = SkChopCubicAtYExtrema(pts, dst);
2909 int w = 0; 2795 int w = 0;
2910 for (int i = 0; i <= n; ++i) { 2796 for (int i = 0; i <= n; ++i) {
2911 w += winding_mono_cubic(&dst[i * 3], x, y); 2797 w += winding_mono_cubic(&dst[i * 3], x, y);
2912 } 2798 }
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
3052 switch (this->getFillType()) { 2938 switch (this->getFillType()) {
3053 case SkPath::kEvenOdd_FillType: 2939 case SkPath::kEvenOdd_FillType:
3054 case SkPath::kInverseEvenOdd_FillType: 2940 case SkPath::kInverseEvenOdd_FillType:
3055 w &= 1; 2941 w &= 1;
3056 break; 2942 break;
3057 default: 2943 default:
3058 break; 2944 break;
3059 } 2945 }
3060 return SkToBool(w); 2946 return SkToBool(w);
3061 } 2947 }
OLDNEW
« no previous file with comments | « include/core/SkPath.h ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698