Chromium Code Reviews| 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 |