Chromium Code Reviews| Index: src/core/SkPath.cpp |
| diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp |
| index d7e047e343be097586be739808dcedc934f8cc0d..37592ddc3c875fb28c263d144baa8d888988040f 100644 |
| --- a/src/core/SkPath.cpp |
| +++ b/src/core/SkPath.cpp |
| @@ -2621,19 +2621,34 @@ template <size_t N> static void find_minmax(const SkPoint pts[], |
| *maxPtr = max; |
| } |
| +static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) { |
| + if (start.fY == end.fY) { |
| + return between(start.fX, x, end.fX) && x != end.fX; |
| + } else { |
| + return x == start.fX && y == start.fY; |
| + } |
| +} |
| + |
| static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { |
| - if (!between(pts[0].fY, y, pts[3].fY)) { |
| + SkScalar y0 = pts[0].fY; |
| + SkScalar y3 = pts[3].fY; |
| + |
| + int dir = 1; |
| + if (y0 > y3) { |
| + SkTSwap(y0, y3); |
| + dir = -1; |
| + } |
| + if (y < y0 || y > y3) { |
| return 0; |
| } |
| - if (y == pts[3].fY) { |
| - // if the cubic is a horizontal line, check if the point is on it |
| - // but don't check the last point, because that point is shared with the next curve |
| - if (pts[0].fY == pts[3].fY && between(pts[0].fX, x, pts[3].fX) && x != pts[3].fX) { |
| - *onCurveCount += 1; |
| - } |
| + if (checkOnCurve(x, y, pts[0], pts[3])) { |
| + *onCurveCount += 1; |
| + return 0; |
| + } |
| + if (y == y3) { |
| return 0; |
| } |
| - int dir = pts[0].fY > pts[3].fY ? -1 : 1; |
| + |
| // quickreject or quickaccept |
| SkScalar min, max; |
| find_minmax<4>(pts, &min, &max); |
| @@ -2651,6 +2666,7 @@ static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* |
| if (SkScalarNearlyEqual(xt, x)) { |
| if (x != pts[3].fX || y != pts[3].fY) { // don't test end points; they're start points |
| *onCurveCount += 1; |
| + return 0; |
| } |
| } |
| return xt < x ? dir : 0; |
| @@ -2697,10 +2713,11 @@ static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* |
| if (y < y0 || y > y2) { |
| return 0; |
| } |
| + if (checkOnCurve(x, y, pts[0], pts[2])) { |
| + *onCurveCount += 1; |
| + return 0; |
| + } |
| if (y == y2) { |
| - if (y0 == y2 && between(pts[0].fX, x, pts[2].fX) && x != pts[2].fX) { // check horizontal |
| - *onCurveCount += 1; |
| - } |
| return 0; |
| } |
| @@ -2715,10 +2732,10 @@ static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* |
| SkASSERT(n <= 1); |
| SkScalar xt; |
| if (0 == n) { |
| - SkScalar mid = SkScalarAve(y0, y2); |
| - // Need [0] and [2] if dir == 1 |
| - // and [2] and [0] if dir == -1 |
| - xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX; |
| + // zero roots are returned only when y0 == y |
| + // Need [0] if dir == 1 |
| + // and [2] if dir == -1 |
| + xt = pts[1 - dir].fX; |
| } else { |
| SkScalar t = roots[0]; |
| xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t); |
| @@ -2726,6 +2743,7 @@ static int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* |
| if (SkScalarNearlyEqual(xt, x)) { |
| if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points |
| *onCurveCount += 1; |
| + return 0; |
| } |
| } |
| return xt < x ? dir : 0; |
| @@ -2773,10 +2791,11 @@ static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* o |
| if (y < y0 || y > y2) { |
| return 0; |
| } |
| + if (checkOnCurve(x, y, pts[0], pts[2])) { |
| + *onCurveCount += 1; |
| + return 0; |
| + } |
| if (y == y2) { |
| - if (y0 == y2 && between(pts[0].fX, x, pts[2].fX) && x != pts[2].fX) { // check horizontal |
| - *onCurveCount += 1; |
| - } |
| return 0; |
| } |
| // bounds check on X (not required. is it faster?) |
| @@ -2794,10 +2813,10 @@ static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* o |
| SkASSERT(n <= 1); |
| SkScalar xt; |
| if (0 == n) { |
| - SkScalar mid = SkScalarAve(y0, y2); |
| - // Need [0] and [2] if dir == 1 |
| - // and [2] and [0] if dir == -1 |
| - xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX; |
| + // zero roots are returned only when y0 == y |
| + // Need [0] if dir == 1 |
| + // and [2] if dir == -1 |
| + xt = pts[1 - dir].fX; |
| } else { |
| SkScalar t = roots[0]; |
| SkScalar C = pts[0].fX; |
| @@ -2808,6 +2827,7 @@ static int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* o |
| if (SkScalarNearlyEqual(xt, x)) { |
| if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points |
| *onCurveCount += 1; |
| + return 0; |
| } |
| } |
| return xt < x ? dir : 0; |
| @@ -2844,10 +2864,11 @@ static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurv |
| if (y < y0 || y > y1) { |
| return 0; |
| } |
| - if (y == pts[1].fY) { |
| - if (y0 == y1 && between(x0, x, x1) && x != x1) { // check if on horizontal line |
| - *onCurveCount += 1; |
| - } |
| + if (checkOnCurve(x, y, pts[0], pts[1])) { |
| + *onCurveCount += 1; |
| + return 0; |
| + } |
| + if (y == y1) { |
| return 0; |
| } |
| SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x0); |
| @@ -2856,7 +2877,9 @@ static int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurv |
| // zero cross means the point is on the line, and since the case where |
| // y of the query point is at the end point is handled above, we can be |
| // sure that we're on the line (excluding the end point) here |
| - *onCurveCount += 1; |
| + if (x != x1 || y != pts[1].fY) { |
|
fs
2015/12/18 10:18:34
Nit: Maybe you should use pts[1].fX rather than x1
|
| + *onCurveCount += 1; |
| + } |
| dir = 0; |
| } else if (SkScalarSignAsInt(cross) == dir) { |
| dir = 0; |
| @@ -3023,6 +3046,7 @@ bool SkPath::contains(SkScalar x, SkScalar y) const { |
| // If the point touches an even number of curves, and the fill is winding, check for |
| // coincidence. Count coincidence as places where the on curve points have identical tangents. |
| iter.setPath(*this, true); |
| + done = false; |
| SkTDArray<SkVector> tangents; |
| do { |
| SkPoint pts[4]; |
| @@ -3056,8 +3080,8 @@ bool SkPath::contains(SkScalar x, SkScalar y) const { |
| for (int index = 0; index < last; ++index) { |
| const SkVector& test = tangents[index]; |
| if (SkScalarNearlyZero(test.cross(tangent)) |
| - && SkScalarSignAsInt(tangent.fX - test.fX) <= 0 |
| - && SkScalarSignAsInt(tangent.fY - test.fY) <= 0) { |
| + && SkScalarSignAsInt(tangent.fX * test.fX) <= 0 |
| + && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) { |
| tangents.remove(last); |
| tangents.removeShuffle(index); |
| break; |