OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |