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

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: add test for contains; remove unused code 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
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 1088 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 {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
1172 bool skip_vert = ry >= halfH; 1172 bool skip_vert = ry >= halfH;
1173 1173
1174 if (skip_hori && skip_vert) { 1174 if (skip_hori && skip_vert) {
1175 this->addOval(rect, dir); 1175 this->addOval(rect, dir);
1176 return; 1176 return;
1177 } 1177 }
1178 1178
1179 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction; 1179 fDirection = this->hasOnlyMoveTos() ? dir : kUnknown_Direction;
1180 1180
1181 SkAutoPathBoundsUpdate apbu(this, rect); 1181 SkAutoPathBoundsUpdate apbu(this, rect);
1182 SkAutoDisableDirectionCheck(this); 1182 SkAutoDisableDirectionCheck addc(this);
1183 1183
1184 if (skip_hori) { 1184 if (skip_hori) {
1185 rx = halfW; 1185 rx = halfW;
1186 } else if (skip_vert) { 1186 } else if (skip_vert) {
1187 ry = halfH; 1187 ry = halfH;
1188 } 1188 }
1189 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR); 1189 SkScalar sx = SkScalarMul(rx, CUBIC_ARC_FACTOR);
1190 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR); 1190 SkScalar sy = SkScalarMul(ry, CUBIC_ARC_FACTOR);
1191 1191
1192 this->incReserve(17); 1192 this->incReserve(17);
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after
1504 2, // kConic 1504 2, // kConic
1505 3, // kCubic 1505 3, // kCubic
1506 0, // kClose 1506 0, // kClose
1507 0 // kDone 1507 0 // kDone
1508 }; 1508 };
1509 1509
1510 SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); 1510 SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb));
1511 return gPtsInVerb[verb]; 1511 return gPtsInVerb[verb];
1512 } 1512 }
1513 1513
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 1514 // ignore the last point of the 1st contour
1554 void SkPath::reversePathTo(const SkPath& path) { 1515 void SkPath::reversePathTo(const SkPath& path) {
1555 int i, vcount = path.fPathRef->countVerbs(); 1516 int i, vcount = path.fPathRef->countVerbs();
1556 // exit early if the path is empty, or just has a moveTo. 1517 // exit early if the path is empty, or just has a moveTo.
1557 if (vcount < 2) { 1518 if (vcount < 2) {
1558 return; 1519 return;
1559 } 1520 }
1560 1521
1561 SkPathRef::Editor(&fPathRef, vcount, path.countPoints()); 1522 SkPathRef::Editor(&fPathRef, vcount, path.countPoints());
1562 1523
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1748 dst->fDirection = kUnknown_Direction; 1709 dst->fDirection = kUnknown_Direction;
1749 } else { 1710 } else {
1750 SkScalar det2x2 = 1711 SkScalar det2x2 =
1751 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) - 1712 SkScalarMul(matrix.get(SkMatrix::kMScaleX), matrix.get(SkMatrix: :kMScaleY)) -
1752 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY)); 1713 SkScalarMul(matrix.get(SkMatrix::kMSkewX), matrix.get(SkMatrix:: kMSkewY));
1753 if (det2x2 < 0) { 1714 if (det2x2 < 0) {
1754 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection)); 1715 dst->fDirection = SkPath::OppositeDirection(static_cast<Directio n>(fDirection));
1755 } else if (det2x2 > 0) { 1716 } else if (det2x2 > 0) {
1756 dst->fDirection = fDirection; 1717 dst->fDirection = fDirection;
1757 } else { 1718 } else {
1719 dst->fConvexity = kUnknown_Convexity;
1758 dst->fDirection = kUnknown_Direction; 1720 dst->fDirection = kUnknown_Direction;
1759 } 1721 }
1760 } 1722 }
1761 1723
1762 // It's an oval only if it stays a rect. 1724 // It's an oval only if it stays a rect.
1763 dst->fIsOval = fIsOval && matrix.rectStaysRect(); 1725 dst->fIsOval = fIsOval && matrix.rectStaysRect();
1764 1726
1765 SkDEBUGCODE(dst->validate();) 1727 SkDEBUGCODE(dst->validate();)
1766 } 1728 }
1767 } 1729 }
(...skipping 544 matching lines...) Expand 10 before | Expand all | Expand 10 after
2312 #define kValueNeverReturnedBySign 2 2274 #define kValueNeverReturnedBySign 2
2313 2275
2314 static bool AlmostEqual(SkScalar compA, SkScalar compB) { 2276 static bool AlmostEqual(SkScalar compA, SkScalar compB) {
2315 // The error epsilon was empirically derived; worse case round rects 2277 // 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 2278 // with a mid point outset by 2x float epsilon in tests had an error
2317 // of 12. 2279 // of 12.
2318 const int epsilon = 16; 2280 const int epsilon = 16;
2319 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) { 2281 if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) {
2320 return false; 2282 return false;
2321 } 2283 }
2322 if (sk_float_abs(compA) <= FLT_EPSILON && sk_float_abs(compB) <= FLT_EPSILON ) { 2284 // no need to check for small numbers because SkPath::Iter has removed degen erate values
2323 return true;
2324 }
2325 int aBits = SkFloatAs2sCompliment(compA); 2285 int aBits = SkFloatAs2sCompliment(compA);
2326 int bBits = SkFloatAs2sCompliment(compB); 2286 int bBits = SkFloatAs2sCompliment(compB);
2327 return aBits < bBits + epsilon && bBits < aBits + epsilon; 2287 return aBits < bBits + epsilon && bBits < aBits + epsilon;
2328 } 2288 }
2329 2289
2330 // only valid for a single contour 2290 // only valid for a single contour
2331 struct Convexicator { 2291 struct Convexicator {
2332 Convexicator() 2292 Convexicator()
2333 : fPtCount(0) 2293 : fPtCount(0)
2334 , fConvexity(SkPath::kConvex_Convexity) 2294 , fConvexity(SkPath::kConvex_Convexity)
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after
2625 } else if (x > max) { 2585 } else if (x > max) {
2626 max = x; 2586 max = x;
2627 maxIndex = i; 2587 maxIndex = i;
2628 } 2588 }
2629 } 2589 }
2630 *maxIndexPtr = maxIndex; 2590 *maxIndexPtr = maxIndex;
2631 return minIndex; 2591 return minIndex;
2632 } 2592 }
2633 2593
2634 static void crossToDir(SkScalar cross, SkPath::Direction* dir) { 2594 static void crossToDir(SkScalar cross, SkPath::Direction* dir) {
2635 if (dir) { 2595 *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 } 2596 }
2694 2597
2695 /* 2598 /*
2696 * We loop through all contours, and keep the computed cross-product of the 2599 * 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 2600 * 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 2601 * 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 2602 * 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 2603 * that is outer most (or at least has the global y-max) before we can consider
2701 * its cross product. 2604 * its cross product.
2702 */ 2605 */
2703 bool SkPath::cheapComputeDirection(Direction* dir) const { 2606 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) { 2607 if (kUnknown_Direction != fDirection) {
2709 *dir = static_cast<Direction>(fDirection); 2608 *dir = static_cast<Direction>(fDirection);
2710 return true; 2609 return true;
2711 } 2610 }
2712 const Convexity conv = this->getConvexityOrUnknown(); 2611
2612 // don't want to pay the cost for computing this if it
2613 // is unknown, so we don't call isConvex()
2614 if (kConvex_Convexity == this->getConvexityOrUnknown()) {
2615 SkASSERT(kUnknown_Direction == fDirection);
2616 *dir = static_cast<Direction>(fDirection);
2617 return false;
2618 }
2713 2619
2714 ContourIter iter(*fPathRef.get()); 2620 ContourIter iter(*fPathRef.get());
2715 2621
2716 // initialize with our logical y-min 2622 // initialize with our logical y-min
2717 SkScalar ymax = this->getBounds().fTop; 2623 SkScalar ymax = this->getBounds().fTop;
2718 SkScalar ymaxCross = 0; 2624 SkScalar ymaxCross = 0;
2719 2625
2720 for (; !iter.done(); iter.next()) { 2626 for (; !iter.done(); iter.next()) {
2721 int n = iter.count(); 2627 int n = iter.count();
2722 if (n < 3) { 2628 if (n < 3) {
2723 continue; 2629 continue;
2724 } 2630 }
2725 2631
2726 const SkPoint* pts = iter.pts(); 2632 const SkPoint* pts = iter.pts();
2727 SkScalar cross = 0; 2633 SkScalar cross = 0;
2728 if (kConvex_Convexity == conv) { 2634 int index = find_max_y(pts, n);
2729 // We try first at scalar precision, and then again at double 2635 if (pts[index].fY < ymax) {
2730 // precision. This is because the vectors computed between distant 2636 continue;
2731 // points may lose too much precision. 2637 }
2732 if (convex_dir_test<SkScalar, toScalar>(n, pts, dir)) { 2638
2733 fDirection = *dir; 2639 // If there is more than 1 distinct point at the y-max, we take the
2734 return true; 2640 // x-min and x-max of them and just subtract to compute the dir.
2641 if (pts[(index + 1) % n].fY == pts[index].fY) {
2642 int maxIndex;
2643 int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex);
2644 if (minIndex == maxIndex) {
2645 goto TRY_CROSSPROD;
2735 } 2646 }
2736 if (convex_dir_test<double, toDouble>(n, pts, dir)) { 2647 SkASSERT(pts[minIndex].fY == pts[index].fY);
2737 fDirection = *dir; 2648 SkASSERT(pts[maxIndex].fY == pts[index].fY);
2738 return true; 2649 SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX);
2739 } else { 2650 // we just subtract the indices, and let that auto-convert to
2740 return false; 2651 // SkScalar, since we just want - or + to signal the direction.
2741 } 2652 cross = minIndex - maxIndex;
2742 } else { 2653 } else {
2743 int index = find_max_y(pts, n); 2654 TRY_CROSSPROD:
2744 if (pts[index].fY < ymax) { 2655 // Find a next and prev index to use for the cross-product test,
2656 // but we try to find pts that form non-zero vectors from pts[index]
2657 //
2658 // Its possible that we can't find two non-degenerate vectors, so
2659 // we have to guard our search (e.g. all the pts could be in the
2660 // same place).
2661
2662 // we pass n - 1 instead of -1 so we don't foul up % operator by
2663 // passing it a negative LH argument.
2664 int prev = find_diff_pt(pts, index, n, n - 1);
2665 if (prev == index) {
2666 // completely degenerate, skip to next contour
2745 continue; 2667 continue;
2746 } 2668 }
2669 int next = find_diff_pt(pts, index, n, 1);
2670 SkASSERT(next != index);
2671 cross = cross_prod(pts[prev], pts[index], pts[next]);
2672 // if we get a zero and the points are horizontal, then we look at t he spread in
2673 // x-direction. We really should continue to walk away from the dege neracy until
2674 // there is a divergence.
2675 if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == p ts[index].fY) {
2676 // construct the subtract so we get the correct Direction below
2677 cross = pts[index].fX - pts[next].fX;
2678 }
2679 }
2747 2680
2748 // If there is more than 1 distinct point at the y-max, we take the 2681 if (cross) {
2749 // x-min and x-max of them and just subtract to compute the dir. 2682 // record our best guess so far
2750 if (pts[(index + 1) % n].fY == pts[index].fY) { 2683 ymax = pts[index].fY;
2751 int maxIndex; 2684 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 } 2685 }
2796 } 2686 }
2797 if (ymaxCross) { 2687 if (ymaxCross) {
2798 crossToDir(ymaxCross, dir); 2688 crossToDir(ymaxCross, dir);
2799 fDirection = *dir; 2689 fDirection = *dir;
2800 return true; 2690 return true;
2801 } else { 2691 } else {
2802 return false; 2692 return false;
2803 } 2693 }
2804 } 2694 }
(...skipping 10 matching lines...) Expand all
2815 SkScalar A = c3 + 3*(c1 - c2) - c0; 2705 SkScalar A = c3 + 3*(c1 - c2) - c0;
2816 SkScalar B = 3*(c2 - c1 - c1 + c0); 2706 SkScalar B = 3*(c2 - c1 - c1 + c0);
2817 SkScalar C = 3*(c1 - c0); 2707 SkScalar C = 3*(c1 - c0);
2818 SkScalar D = c0; 2708 SkScalar D = c0;
2819 return eval_cubic_coeff(A, B, C, D, t); 2709 return eval_cubic_coeff(A, B, C, D, t);
2820 } 2710 }
2821 2711
2822 /* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the 2712 /* Given 4 cubic points (either Xs or Ys), and a target X or Y, compute the
2823 t value such that cubic(t) = target 2713 t value such that cubic(t) = target
2824 */ 2714 */
2825 static bool chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, 2715 static void chopMonoCubicAt(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3,
2826 SkScalar target, SkScalar* t) { 2716 SkScalar target, SkScalar* t) {
2827 // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3); 2717 // SkASSERT(c0 <= c1 && c1 <= c2 && c2 <= c3);
2828 SkASSERT(c0 < target && target < c3); 2718 SkASSERT(c0 < target && target < c3);
2829 2719
2830 SkScalar D = c0 - target; 2720 SkScalar D = c0 - target;
2831 SkScalar A = c3 + 3*(c1 - c2) - c0; 2721 SkScalar A = c3 + 3*(c1 - c2) - c0;
2832 SkScalar B = 3*(c2 - c1 - c1 + c0); 2722 SkScalar B = 3*(c2 - c1 - c1 + c0);
2833 SkScalar C = 3*(c1 - c0); 2723 SkScalar C = 3*(c1 - c0);
2834 2724
2835 const SkScalar TOLERANCE = SK_Scalar1 / 4096; 2725 const SkScalar TOLERANCE = SK_Scalar1 / 4096;
2836 SkScalar minT = 0; 2726 SkScalar minT = 0;
2837 SkScalar maxT = SK_Scalar1; 2727 SkScalar maxT = SK_Scalar1;
2838 SkScalar mid; 2728 SkScalar mid;
2839 int i; 2729 int i;
2840 for (i = 0; i < 16; i++) { 2730 for (i = 0; i < 16; i++) {
2841 mid = SkScalarAve(minT, maxT); 2731 mid = SkScalarAve(minT, maxT);
2842 SkScalar delta = eval_cubic_coeff(A, B, C, D, mid); 2732 SkScalar delta = eval_cubic_coeff(A, B, C, D, mid);
2843 if (delta < 0) { 2733 if (delta < 0) {
2844 minT = mid; 2734 minT = mid;
2845 delta = -delta; 2735 delta = -delta;
2846 } else { 2736 } else {
2847 maxT = mid; 2737 maxT = mid;
2848 } 2738 }
2849 if (delta < TOLERANCE) { 2739 if (delta < TOLERANCE) {
2850 break; 2740 break;
2851 } 2741 }
2852 } 2742 }
2853 *t = mid; 2743 *t = mid;
2854 return true;
2855 } 2744 }
2856 2745
2857 template <size_t N> static void find_minmax(const SkPoint pts[], 2746 template <size_t N> static void find_minmax(const SkPoint pts[],
2858 SkScalar* minPtr, SkScalar* maxPtr) { 2747 SkScalar* minPtr, SkScalar* maxPtr) {
2859 SkScalar min, max; 2748 SkScalar min, max;
2860 min = max = pts[0].fX; 2749 min = max = pts[0].fX;
2861 for (size_t i = 1; i < N; ++i) { 2750 for (size_t i = 1; i < N; ++i) {
2862 min = SkMinScalar(min, pts[i].fX); 2751 min = SkMinScalar(min, pts[i].fX);
2863 max = SkMaxScalar(max, pts[i].fX); 2752 max = SkMaxScalar(max, pts[i].fX);
2864 } 2753 }
(...skipping 21 matching lines...) Expand all
2886 SkScalar min, max; 2775 SkScalar min, max;
2887 find_minmax<4>(pts, &min, &max); 2776 find_minmax<4>(pts, &min, &max);
2888 if (x < min) { 2777 if (x < min) {
2889 return 0; 2778 return 0;
2890 } 2779 }
2891 if (x > max) { 2780 if (x > max) {
2892 return dir; 2781 return dir;
2893 } 2782 }
2894 2783
2895 // compute the actual x(t) value 2784 // compute the actual x(t) value
2896 SkScalar t, xt; 2785 SkScalar t;
2897 if (chopMonoCubicAt(pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY, y, &t)) { 2786 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); 2787 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; 2788 return xt < x ? dir : 0;
2904 } 2789 }
2905 2790
2906 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) { 2791 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y) {
2907 SkPoint dst[10]; 2792 SkPoint dst[10];
2908 int n = SkChopCubicAtYExtrema(pts, dst); 2793 int n = SkChopCubicAtYExtrema(pts, dst);
2909 int w = 0; 2794 int w = 0;
2910 for (int i = 0; i <= n; ++i) { 2795 for (int i = 0; i <= n; ++i) {
2911 w += winding_mono_cubic(&dst[i * 3], x, y); 2796 w += winding_mono_cubic(&dst[i * 3], x, y);
2912 } 2797 }
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
3052 switch (this->getFillType()) { 2937 switch (this->getFillType()) {
3053 case SkPath::kEvenOdd_FillType: 2938 case SkPath::kEvenOdd_FillType:
3054 case SkPath::kInverseEvenOdd_FillType: 2939 case SkPath::kInverseEvenOdd_FillType:
3055 w &= 1; 2940 w &= 1;
3056 break; 2941 break;
3057 default: 2942 default:
3058 break; 2943 break;
3059 } 2944 }
3060 return SkToBool(w); 2945 return SkToBool(w);
3061 } 2946 }
OLDNEW
« no previous file with comments | « include/core/SkPath.h ('k') | src/core/SkPathRef.cpp » ('j') | tests/PathTest.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698