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

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

Issue 1532003004: fix bugs in path contains (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years 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
« no previous file with comments | « no previous file | tests/PathTest.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 * Copyright 2006 The Android Open Source Project 2 * Copyright 2006 The Android Open Source Project
3 * 3 *
4 * 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
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBuffer.h" 8 #include "SkBuffer.h"
9 #include "SkCubicClipper.h" 9 #include "SkCubicClipper.h"
10 #include "SkErrorInternals.h" 10 #include "SkErrorInternals.h"
(...skipping 2603 matching lines...) Expand 10 before | Expand all | Expand 10 after
2614 SkScalar min, max; 2614 SkScalar min, max;
2615 min = max = pts[0].fX; 2615 min = max = pts[0].fX;
2616 for (size_t i = 1; i < N; ++i) { 2616 for (size_t i = 1; i < N; ++i) {
2617 min = SkMinScalar(min, pts[i].fX); 2617 min = SkMinScalar(min, pts[i].fX);
2618 max = SkMaxScalar(max, pts[i].fX); 2618 max = SkMaxScalar(max, pts[i].fX);
2619 } 2619 }
2620 *minPtr = min; 2620 *minPtr = min;
2621 *maxPtr = max; 2621 *maxPtr = max;
2622 } 2622 }
2623 2623
2624 static bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkP oint& end) {
2625 if (start.fY == end.fY) {
2626 return between(start.fX, x, end.fX) && x != end.fX;
2627 } else {
2628 return x == start.fX && y == start.fY;
2629 }
2630 }
2631
2624 static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { 2632 static int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) {
2625 if (!between(pts[0].fY, y, pts[3].fY)) { 2633 SkScalar y0 = pts[0].fY;
2634 SkScalar y3 = pts[3].fY;
2635
2636 int dir = 1;
2637 if (y0 > y3) {
2638 SkTSwap(y0, y3);
2639 dir = -1;
2640 }
2641 if (y < y0 || y > y3) {
2626 return 0; 2642 return 0;
2627 } 2643 }
2628 if (y == pts[3].fY) { 2644 if (checkOnCurve(x, y, pts[0], pts[3])) {
2629 // if the cubic is a horizontal line, check if the point is on it 2645 *onCurveCount += 1;
2630 // but don't check the last point, because that point is shared with the next curve
2631 if (pts[0].fY == pts[3].fY && between(pts[0].fX, x, pts[3].fX) && x != p ts[3].fX) {
2632 *onCurveCount += 1;
2633 }
2634 return 0; 2646 return 0;
2635 } 2647 }
2636 int dir = pts[0].fY > pts[3].fY ? -1 : 1; 2648 if (y == y3) {
2649 return 0;
2650 }
2651
2637 // quickreject or quickaccept 2652 // quickreject or quickaccept
2638 SkScalar min, max; 2653 SkScalar min, max;
2639 find_minmax<4>(pts, &min, &max); 2654 find_minmax<4>(pts, &min, &max);
2640 if (x < min) { 2655 if (x < min) {
2641 return 0; 2656 return 0;
2642 } 2657 }
2643 if (x > max) { 2658 if (x > max) {
2644 return dir; 2659 return dir;
2645 } 2660 }
2646 2661
2647 // compute the actual x(t) value 2662 // compute the actual x(t) value
2648 SkScalar t; 2663 SkScalar t;
2649 SkAssertResult(SkCubicClipper::ChopMonoAtY(pts, y, &t)); 2664 SkAssertResult(SkCubicClipper::ChopMonoAtY(pts, y, &t));
2650 SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t); 2665 SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t);
2651 if (SkScalarNearlyEqual(xt, x)) { 2666 if (SkScalarNearlyEqual(xt, x)) {
2652 if (x != pts[3].fX || y != pts[3].fY) { // don't test end points; they' re start points 2667 if (x != pts[3].fX || y != pts[3].fY) { // don't test end points; they' re start points
2653 *onCurveCount += 1; 2668 *onCurveCount += 1;
2669 return 0;
2654 } 2670 }
2655 } 2671 }
2656 return xt < x ? dir : 0; 2672 return xt < x ? dir : 0;
2657 } 2673 }
2658 2674
2659 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCur veCount) { 2675 static int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCur veCount) {
2660 SkPoint dst[10]; 2676 SkPoint dst[10];
2661 int n = SkChopCubicAtYExtrema(pts, dst); 2677 int n = SkChopCubicAtYExtrema(pts, dst);
2662 int w = 0; 2678 int w = 0;
2663 for (int i = 0; i <= n; ++i) { 2679 for (int i = 0; i <= n; ++i) {
(...skipping 26 matching lines...) Expand all
2690 SkScalar y2 = pts[2].fY; 2706 SkScalar y2 = pts[2].fY;
2691 2707
2692 int dir = 1; 2708 int dir = 1;
2693 if (y0 > y2) { 2709 if (y0 > y2) {
2694 SkTSwap(y0, y2); 2710 SkTSwap(y0, y2);
2695 dir = -1; 2711 dir = -1;
2696 } 2712 }
2697 if (y < y0 || y > y2) { 2713 if (y < y0 || y > y2) {
2698 return 0; 2714 return 0;
2699 } 2715 }
2716 if (checkOnCurve(x, y, pts[0], pts[2])) {
2717 *onCurveCount += 1;
2718 return 0;
2719 }
2700 if (y == y2) { 2720 if (y == y2) {
2701 if (y0 == y2 && between(pts[0].fX, x, pts[2].fX) && x != pts[2].fX) { / / check horizontal
2702 *onCurveCount += 1;
2703 }
2704 return 0; 2721 return 0;
2705 } 2722 }
2706 2723
2707 SkScalar roots[2]; 2724 SkScalar roots[2];
2708 SkScalar A = pts[2].fY; 2725 SkScalar A = pts[2].fY;
2709 SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y; 2726 SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y;
2710 SkScalar C = pts[0].fY; 2727 SkScalar C = pts[0].fY;
2711 A += C - 2 * B; // A = a + c - 2*(b*w - yCept*w + yCept) 2728 A += C - 2 * B; // A = a + c - 2*(b*w - yCept*w + yCept)
2712 B -= C; // B = b*w - w * yCept + yCept - a 2729 B -= C; // B = b*w - w * yCept + yCept - a
2713 C -= y; 2730 C -= y;
2714 int n = SkFindUnitQuadRoots(A, 2 * B, C, roots); 2731 int n = SkFindUnitQuadRoots(A, 2 * B, C, roots);
2715 SkASSERT(n <= 1); 2732 SkASSERT(n <= 1);
2716 SkScalar xt; 2733 SkScalar xt;
2717 if (0 == n) { 2734 if (0 == n) {
2718 SkScalar mid = SkScalarAve(y0, y2); 2735 // zero roots are returned only when y0 == y
2719 // Need [0] and [2] if dir == 1 2736 // Need [0] if dir == 1
2720 // and [2] and [0] if dir == -1 2737 // and [2] if dir == -1
2721 xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX; 2738 xt = pts[1 - dir].fX;
2722 } else { 2739 } else {
2723 SkScalar t = roots[0]; 2740 SkScalar t = roots[0];
2724 xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denomina tor(conic.fW, t); 2741 xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denomina tor(conic.fW, t);
2725 } 2742 }
2726 if (SkScalarNearlyEqual(xt, x)) { 2743 if (SkScalarNearlyEqual(xt, x)) {
2727 if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they' re start points 2744 if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they' re start points
2728 *onCurveCount += 1; 2745 *onCurveCount += 1;
2746 return 0;
2729 } 2747 }
2730 } 2748 }
2731 return xt < x ? dir : 0; 2749 return xt < x ? dir : 0;
2732 } 2750 }
2733 2751
2734 static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) { 2752 static bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) {
2735 // return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0; 2753 // return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0;
2736 if (y0 == y1) { 2754 if (y0 == y1) {
2737 return true; 2755 return true;
2738 } 2756 }
(...skipping 27 matching lines...) Expand all
2766 SkScalar y2 = pts[2].fY; 2784 SkScalar y2 = pts[2].fY;
2767 2785
2768 int dir = 1; 2786 int dir = 1;
2769 if (y0 > y2) { 2787 if (y0 > y2) {
2770 SkTSwap(y0, y2); 2788 SkTSwap(y0, y2);
2771 dir = -1; 2789 dir = -1;
2772 } 2790 }
2773 if (y < y0 || y > y2) { 2791 if (y < y0 || y > y2) {
2774 return 0; 2792 return 0;
2775 } 2793 }
2794 if (checkOnCurve(x, y, pts[0], pts[2])) {
2795 *onCurveCount += 1;
2796 return 0;
2797 }
2776 if (y == y2) { 2798 if (y == y2) {
2777 if (y0 == y2 && between(pts[0].fX, x, pts[2].fX) && x != pts[2].fX) { / / check horizontal
2778 *onCurveCount += 1;
2779 }
2780 return 0; 2799 return 0;
2781 } 2800 }
2782 // bounds check on X (not required. is it faster?) 2801 // bounds check on X (not required. is it faster?)
2783 #if 0 2802 #if 0
2784 if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) { 2803 if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) {
2785 return 0; 2804 return 0;
2786 } 2805 }
2787 #endif 2806 #endif
2788 2807
2789 SkScalar roots[2]; 2808 SkScalar roots[2];
2790 int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, 2809 int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY,
2791 2 * (pts[1].fY - pts[0].fY), 2810 2 * (pts[1].fY - pts[0].fY),
2792 pts[0].fY - y, 2811 pts[0].fY - y,
2793 roots); 2812 roots);
2794 SkASSERT(n <= 1); 2813 SkASSERT(n <= 1);
2795 SkScalar xt; 2814 SkScalar xt;
2796 if (0 == n) { 2815 if (0 == n) {
2797 SkScalar mid = SkScalarAve(y0, y2); 2816 // zero roots are returned only when y0 == y
2798 // Need [0] and [2] if dir == 1 2817 // Need [0] if dir == 1
2799 // and [2] and [0] if dir == -1 2818 // and [2] if dir == -1
2800 xt = y < mid ? pts[1 - dir].fX : pts[dir - 1].fX; 2819 xt = pts[1 - dir].fX;
2801 } else { 2820 } else {
2802 SkScalar t = roots[0]; 2821 SkScalar t = roots[0];
2803 SkScalar C = pts[0].fX; 2822 SkScalar C = pts[0].fX;
2804 SkScalar A = pts[2].fX - 2 * pts[1].fX + C; 2823 SkScalar A = pts[2].fX - 2 * pts[1].fX + C;
2805 SkScalar B = 2 * (pts[1].fX - C); 2824 SkScalar B = 2 * (pts[1].fX - C);
2806 xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C); 2825 xt = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
2807 } 2826 }
2808 if (SkScalarNearlyEqual(xt, x)) { 2827 if (SkScalarNearlyEqual(xt, x)) {
2809 if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they' re start points 2828 if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they' re start points
2810 *onCurveCount += 1; 2829 *onCurveCount += 1;
2830 return 0;
2811 } 2831 }
2812 } 2832 }
2813 return xt < x ? dir : 0; 2833 return xt < x ? dir : 0;
2814 } 2834 }
2815 2835
2816 static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurv eCount) { 2836 static int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurv eCount) {
2817 SkPoint dst[5]; 2837 SkPoint dst[5];
2818 int n = 0; 2838 int n = 0;
2819 2839
2820 if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) { 2840 if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) {
(...skipping 16 matching lines...) Expand all
2837 SkScalar dy = y1 - y0; 2857 SkScalar dy = y1 - y0;
2838 2858
2839 int dir = 1; 2859 int dir = 1;
2840 if (y0 > y1) { 2860 if (y0 > y1) {
2841 SkTSwap(y0, y1); 2861 SkTSwap(y0, y1);
2842 dir = -1; 2862 dir = -1;
2843 } 2863 }
2844 if (y < y0 || y > y1) { 2864 if (y < y0 || y > y1) {
2845 return 0; 2865 return 0;
2846 } 2866 }
2847 if (y == pts[1].fY) { 2867 if (checkOnCurve(x, y, pts[0], pts[1])) {
2848 if (y0 == y1 && between(x0, x, x1) && x != x1) { // check if on horizon tal line 2868 *onCurveCount += 1;
2849 *onCurveCount += 1; 2869 return 0;
2850 } 2870 }
2871 if (y == y1) {
2851 return 0; 2872 return 0;
2852 } 2873 }
2853 SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x 0); 2874 SkScalar cross = SkScalarMul(x1 - x0, y - pts[0].fY) - SkScalarMul(dy, x - x 0);
2854 2875
2855 if (!cross) { 2876 if (!cross) {
2856 // zero cross means the point is on the line, and since the case where 2877 // zero cross means the point is on the line, and since the case where
2857 // y of the query point is at the end point is handled above, we can be 2878 // y of the query point is at the end point is handled above, we can be
2858 // sure that we're on the line (excluding the end point) here 2879 // sure that we're on the line (excluding the end point) here
2859 *onCurveCount += 1; 2880 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
2881 *onCurveCount += 1;
2882 }
2860 dir = 0; 2883 dir = 0;
2861 } else if (SkScalarSignAsInt(cross) == dir) { 2884 } else if (SkScalarSignAsInt(cross) == dir) {
2862 dir = 0; 2885 dir = 0;
2863 } 2886 }
2864 return dir; 2887 return dir;
2865 } 2888 }
2866 2889
2867 static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y, 2890 static void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y,
2868 SkTDArray<SkVector>* tangents) { 2891 SkTDArray<SkVector>* tangents) {
2869 if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY) 2892 if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
3016 } 3039 }
3017 if (onCurveCount <= 1) { 3040 if (onCurveCount <= 1) {
3018 return SkToBool(onCurveCount) ^ isInverse; 3041 return SkToBool(onCurveCount) ^ isInverse;
3019 } 3042 }
3020 if ((onCurveCount & 1) || evenOddFill) { 3043 if ((onCurveCount & 1) || evenOddFill) {
3021 return SkToBool(onCurveCount & 1) ^ isInverse; 3044 return SkToBool(onCurveCount & 1) ^ isInverse;
3022 } 3045 }
3023 // If the point touches an even number of curves, and the fill is winding, c heck for 3046 // If the point touches an even number of curves, and the fill is winding, c heck for
3024 // coincidence. Count coincidence as places where the on curve points have i dentical tangents. 3047 // coincidence. Count coincidence as places where the on curve points have i dentical tangents.
3025 iter.setPath(*this, true); 3048 iter.setPath(*this, true);
3049 done = false;
3026 SkTDArray<SkVector> tangents; 3050 SkTDArray<SkVector> tangents;
3027 do { 3051 do {
3028 SkPoint pts[4]; 3052 SkPoint pts[4];
3029 int oldCount = tangents.count(); 3053 int oldCount = tangents.count();
3030 switch (iter.next(pts, false)) { 3054 switch (iter.next(pts, false)) {
3031 case SkPath::kMove_Verb: 3055 case SkPath::kMove_Verb:
3032 case SkPath::kClose_Verb: 3056 case SkPath::kClose_Verb:
3033 break; 3057 break;
3034 case SkPath::kLine_Verb: 3058 case SkPath::kLine_Verb:
3035 tangent_line(pts, x, y, &tangents); 3059 tangent_line(pts, x, y, &tangents);
(...skipping 13 matching lines...) Expand all
3049 } 3073 }
3050 if (tangents.count() > oldCount) { 3074 if (tangents.count() > oldCount) {
3051 int last = tangents.count() - 1; 3075 int last = tangents.count() - 1;
3052 const SkVector& tangent = tangents[last]; 3076 const SkVector& tangent = tangents[last];
3053 if (SkScalarNearlyZero(tangent.lengthSqd())) { 3077 if (SkScalarNearlyZero(tangent.lengthSqd())) {
3054 tangents.remove(last); 3078 tangents.remove(last);
3055 } else { 3079 } else {
3056 for (int index = 0; index < last; ++index) { 3080 for (int index = 0; index < last; ++index) {
3057 const SkVector& test = tangents[index]; 3081 const SkVector& test = tangents[index];
3058 if (SkScalarNearlyZero(test.cross(tangent)) 3082 if (SkScalarNearlyZero(test.cross(tangent))
3059 && SkScalarSignAsInt(tangent.fX - test.fX) <= 0 3083 && SkScalarSignAsInt(tangent.fX * test.fX) <= 0
3060 && SkScalarSignAsInt(tangent.fY - test.fY) <= 0) { 3084 && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) {
3061 tangents.remove(last); 3085 tangents.remove(last);
3062 tangents.removeShuffle(index); 3086 tangents.removeShuffle(index);
3063 break; 3087 break;
3064 } 3088 }
3065 } 3089 }
3066 } 3090 }
3067 } 3091 }
3068 } while (!done); 3092 } while (!done);
3069 return SkToBool(tangents.count()) ^ isInverse; 3093 return SkToBool(tangents.count()) ^ isInverse;
3070 } 3094 }
3071 3095
3072 int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPo int& p2, 3096 int SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPo int& p2,
3073 SkScalar w, SkPoint pts[], int pow2) { 3097 SkScalar w, SkPoint pts[], int pow2) {
3074 const SkConic conic(p0, p1, p2, w); 3098 const SkConic conic(p0, p1, p2, w);
3075 return conic.chopIntoQuadsPOW2(pts, pow2); 3099 return conic.chopIntoQuadsPOW2(pts, pow2);
3076 } 3100 }
OLDNEW
« no previous file with comments | « no previous file | tests/PathTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698