| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 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 "Test.h" | 8 #include "Test.h" |
| 9 #if SK_SUPPORT_GPU | |
| 10 #include "GrReducedClip.h" | |
| 11 #endif | |
| 12 #include "SkClipStack.h" | 9 #include "SkClipStack.h" |
| 13 #include "SkPath.h" | 10 #include "SkPath.h" |
| 14 #include "SkRandom.h" | 11 #include "SkRandom.h" |
| 15 #include "SkRect.h" | 12 #include "SkRect.h" |
| 16 #include "SkRegion.h" | 13 #include "SkRegion.h" |
| 17 | 14 |
| 15 #if SK_SUPPORT_GPU |
| 16 #include "GrReducedClip.h" |
| 17 typedef GrReducedClip::ElementList ElementList; |
| 18 typedef GrReducedClip::InitialState InitialState; |
| 19 #endif |
| 20 |
| 18 static void test_assign_and_comparison(skiatest::Reporter* reporter) { | 21 static void test_assign_and_comparison(skiatest::Reporter* reporter) { |
| 19 SkClipStack s; | 22 SkClipStack s; |
| 20 bool doAA = false; | 23 bool doAA = false; |
| 21 | 24 |
| 22 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); | 25 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); |
| 23 | 26 |
| 24 // Build up a clip stack with a path, an empty clip, and a rect. | 27 // Build up a clip stack with a path, an empty clip, and a rect. |
| 25 s.save(); | 28 s.save(); |
| 26 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); | 29 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); |
| 27 | 30 |
| (...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 842 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 845 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 843 | 846 |
| 844 #if SK_SUPPORT_GPU | 847 #if SK_SUPPORT_GPU |
| 845 // Functions that add a shape to the clip stack. The shape is computed from a re
ctangle. | 848 // Functions that add a shape to the clip stack. The shape is computed from a re
ctangle. |
| 846 // AA is always disabled since the clip stack reducer can cause changes in aa ra
sterization of the | 849 // AA is always disabled since the clip stack reducer can cause changes in aa ra
sterization of the |
| 847 // stack. A fractional edge repeated in different elements may be rasterized few
er times using the | 850 // stack. A fractional edge repeated in different elements may be rasterized few
er times using the |
| 848 // reduced stack. | 851 // reduced stack. |
| 849 typedef void (*AddElementFunc) (const SkRect& rect, | 852 typedef void (*AddElementFunc) (const SkRect& rect, |
| 850 bool invert, | 853 bool invert, |
| 851 SkRegion::Op op, | 854 SkRegion::Op op, |
| 852 SkClipStack* stack); | 855 SkClipStack* stack, |
| 856 bool doAA); |
| 853 | 857 |
| 854 static void add_round_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkC
lipStack* stack) { | 858 static void add_round_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkC
lipStack* stack, |
| 859 bool doAA) { |
| 855 SkScalar rx = rect.width() / 10; | 860 SkScalar rx = rect.width() / 10; |
| 856 SkScalar ry = rect.height() / 20; | 861 SkScalar ry = rect.height() / 20; |
| 857 if (invert) { | 862 if (invert) { |
| 858 SkPath path; | 863 SkPath path; |
| 859 path.addRoundRect(rect, rx, ry); | 864 path.addRoundRect(rect, rx, ry); |
| 860 path.setFillType(SkPath::kInverseWinding_FillType); | 865 path.setFillType(SkPath::kInverseWinding_FillType); |
| 861 stack->clipDevPath(path, op, false); | 866 stack->clipDevPath(path, op, doAA); |
| 862 } else { | 867 } else { |
| 863 SkRRect rrect; | 868 SkRRect rrect; |
| 864 rrect.setRectXY(rect, rx, ry); | 869 rrect.setRectXY(rect, rx, ry); |
| 865 stack->clipDevRRect(rrect, op, false); | 870 stack->clipDevRRect(rrect, op, doAA); |
| 866 } | 871 } |
| 867 }; | 872 }; |
| 868 | 873 |
| 869 static void add_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta
ck* stack) { | 874 static void add_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta
ck* stack, |
| 875 bool doAA) { |
| 870 if (invert) { | 876 if (invert) { |
| 871 SkPath path; | 877 SkPath path; |
| 872 path.addRect(rect); | 878 path.addRect(rect); |
| 873 path.setFillType(SkPath::kInverseWinding_FillType); | 879 path.setFillType(SkPath::kInverseWinding_FillType); |
| 874 stack->clipDevPath(path, op, false); | 880 stack->clipDevPath(path, op, doAA); |
| 875 } else { | 881 } else { |
| 876 stack->clipDevRect(rect, op, false); | 882 stack->clipDevRect(rect, op, doAA); |
| 877 } | 883 } |
| 878 }; | 884 }; |
| 879 | 885 |
| 880 static void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta
ck* stack) { | 886 static void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta
ck* stack, |
| 887 bool doAA) { |
| 881 SkPath path; | 888 SkPath path; |
| 882 path.addOval(rect); | 889 path.addOval(rect); |
| 883 if (invert) { | 890 if (invert) { |
| 884 path.setFillType(SkPath::kInverseWinding_FillType); | 891 path.setFillType(SkPath::kInverseWinding_FillType); |
| 885 } | 892 } |
| 886 stack->clipDevPath(path, op, false); | 893 stack->clipDevPath(path, op, doAA); |
| 887 }; | 894 }; |
| 888 | 895 |
| 889 static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack*
stack) { | 896 static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack*
stack) { |
| 890 switch (element.getType()) { | 897 switch (element.getType()) { |
| 891 case SkClipStack::Element::kRect_Type: | 898 case SkClipStack::Element::kRect_Type: |
| 892 stack->clipDevRect(element.getRect(), element.getOp(), element.isAA(
)); | 899 stack->clipDevRect(element.getRect(), element.getOp(), element.isAA(
)); |
| 893 break; | 900 break; |
| 894 case SkClipStack::Element::kRRect_Type: | 901 case SkClipStack::Element::kRRect_Type: |
| 895 stack->clipDevRRect(element.getRRect(), element.getOp(), element.isA
A()); | 902 stack->clipDevRRect(element.getRRect(), element.getOp(), element.isA
A()); |
| 896 break; | 903 break; |
| 897 case SkClipStack::Element::kPath_Type: | 904 case SkClipStack::Element::kPath_Type: |
| 898 stack->clipDevPath(element.getPath(), element.getOp(), element.isAA(
)); | 905 stack->clipDevPath(element.getPath(), element.getOp(), element.isAA(
)); |
| 899 break; | 906 break; |
| 900 case SkClipStack::Element::kEmpty_Type: | 907 case SkClipStack::Element::kEmpty_Type: |
| 901 SkDEBUGFAIL("Why did the reducer produce an explicit empty."); | 908 SkDEBUGFAIL("Why did the reducer produce an explicit empty."); |
| 902 stack->clipEmpty(); | 909 stack->clipEmpty(); |
| 903 break; | 910 break; |
| 904 } | 911 } |
| 905 } | 912 } |
| 906 | 913 |
| 907 static void test_reduced_clip_stack(skiatest::Reporter* reporter) { | 914 static void test_reduced_clip_stack(skiatest::Reporter* reporter) { |
| 908 // We construct random clip stacks, reduce them, and then rasterize both ver
sions to verify that | 915 // We construct random clip stacks, reduce them, and then rasterize both ver
sions to verify that |
| 909 // they are equal. | 916 // they are equal. |
| 910 | 917 |
| 911 // All the clip elements will be contained within these bounds. | 918 // All the clip elements will be contained within these bounds. |
| 912 static const SkRect kBounds = SkRect::MakeWH(100, 100); | 919 static const SkRect kBounds = SkRect::MakeWH(100, 100); |
| 913 | 920 |
| 914 enum { | 921 enum { |
| 915 kNumTests = 200, | 922 kNumTests = 250, |
| 916 kMinElemsPerTest = 1, | 923 kMinElemsPerTest = 1, |
| 917 kMaxElemsPerTest = 50, | 924 kMaxElemsPerTest = 50, |
| 918 }; | 925 }; |
| 919 | 926 |
| 920 // min/max size of a clip element as a fraction of kBounds. | 927 // min/max size of a clip element as a fraction of kBounds. |
| 921 static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5; | 928 static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5; |
| 922 static const SkScalar kMaxElemSizeFrac = SK_Scalar1; | 929 static const SkScalar kMaxElemSizeFrac = SK_Scalar1; |
| 923 | 930 |
| 924 static const SkRegion::Op kOps[] = { | 931 static const SkRegion::Op kOps[] = { |
| 925 SkRegion::kDifference_Op, | 932 SkRegion::kDifference_Op, |
| 926 SkRegion::kIntersect_Op, | 933 SkRegion::kIntersect_Op, |
| 927 SkRegion::kUnion_Op, | 934 SkRegion::kUnion_Op, |
| 928 SkRegion::kXOR_Op, | 935 SkRegion::kXOR_Op, |
| 929 SkRegion::kReverseDifference_Op, | 936 SkRegion::kReverseDifference_Op, |
| 930 SkRegion::kReplace_Op, | 937 SkRegion::kReplace_Op, |
| 931 }; | 938 }; |
| 932 | 939 |
| 933 // Replace operations short-circuit the optimizer. We want to make sure that
we test this code | 940 // Replace operations short-circuit the optimizer. We want to make sure that
we test this code |
| 934 // path a little bit but we don't want it to prevent us from testing many lo
nger traversals in | 941 // path a little bit but we don't want it to prevent us from testing many lo
nger traversals in |
| 935 // the optimizer. | 942 // the optimizer. |
| 936 static const int kReplaceDiv = 4 * kMaxElemsPerTest; | 943 static const int kReplaceDiv = 4 * kMaxElemsPerTest; |
| 937 | 944 |
| 938 // We want to test inverse fills. However, they are quite rare in practice s
o don't over do it. | 945 // We want to test inverse fills. However, they are quite rare in practice s
o don't over do it. |
| 939 static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest; | 946 static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest; |
| 940 | 947 |
| 948 static const SkScalar kFractionAntialiased = 0.25; |
| 949 |
| 941 static const AddElementFunc kElementFuncs[] = { | 950 static const AddElementFunc kElementFuncs[] = { |
| 942 add_rect, | 951 add_rect, |
| 943 add_round_rect, | 952 add_round_rect, |
| 944 add_oval, | 953 add_oval, |
| 945 }; | 954 }; |
| 946 | 955 |
| 947 SkRandom r; | 956 SkRandom r; |
| 948 | 957 |
| 949 for (int i = 0; i < kNumTests; ++i) { | 958 for (int i = 0; i < kNumTests; ++i) { |
| 959 SkString testCase; |
| 960 testCase.printf("Iteration %d", i); |
| 961 |
| 950 // Randomly generate a clip stack. | 962 // Randomly generate a clip stack. |
| 951 SkClipStack stack; | 963 SkClipStack stack; |
| 952 int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest); | 964 int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest); |
| 965 bool doAA = r.nextBiasedBool(kFractionAntialiased); |
| 953 for (int e = 0; e < numElems; ++e) { | 966 for (int e = 0; e < numElems; ++e) { |
| 954 SkRegion::Op op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))]; | 967 SkRegion::Op op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))]; |
| 955 if (op == SkRegion::kReplace_Op) { | 968 if (op == SkRegion::kReplace_Op) { |
| 956 if (r.nextU() % kReplaceDiv) { | 969 if (r.nextU() % kReplaceDiv) { |
| 957 --e; | 970 --e; |
| 958 continue; | 971 continue; |
| 959 } | 972 } |
| 960 } | 973 } |
| 961 | 974 |
| 962 // saves can change the clip stack behavior when an element is added
. | 975 // saves can change the clip stack behavior when an element is added
. |
| 963 bool doSave = r.nextBool(); | 976 bool doSave = r.nextBool(); |
| 964 | 977 |
| 965 SkSize size = SkSize::Make( | 978 SkSize size = SkSize::Make( |
| 966 SkScalarFloorToScalar(SkScalarMul(kBounds.width(), r.nextRangeSc
alar(kMinElemSizeFrac, kMaxElemSizeFrac))), | 979 SkScalarMul(kBounds.width(), r.nextRangeScalar(kMinElemSizeFrac,
kMaxElemSizeFrac)), |
| 967 SkScalarFloorToScalar(SkScalarMul(kBounds.height(), r.nextRangeS
calar(kMinElemSizeFrac, kMaxElemSizeFrac)))); | 980 SkScalarMul(kBounds.height(), r.nextRangeScalar(kMinElemSizeFrac
, kMaxElemSizeFrac))); |
| 968 | 981 |
| 969 SkPoint xy = {SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fLeft,
kBounds.fRight - size.fWidth)), | 982 SkPoint xy = {r.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size
.fWidth), |
| 970 SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fTop,
kBounds.fBottom - size.fHeight))}; | 983 r.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size
.fHeight)}; |
| 971 | 984 |
| 972 SkRect rect = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeig
ht); | 985 SkRect rect; |
| 986 if (doAA) { |
| 987 rect.setXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight); |
| 988 if (GrClip::IsPixelAligned(rect)) { |
| 989 // Don't create an element that may accidentally become not
antialiased. |
| 990 rect.outset(0.5f, 0.5f); |
| 991 } |
| 992 SkASSERT(!GrClip::IsPixelAligned(rect)); |
| 993 } else { |
| 994 rect.setXYWH(SkScalarFloorToScalar(xy.fX), |
| 995 SkScalarFloorToScalar(xy.fY), |
| 996 SkScalarCeilToScalar(size.fWidth), |
| 997 SkScalarCeilToScalar(size.fHeight)); |
| 998 } |
| 973 | 999 |
| 974 bool invert = r.nextBiasedBool(kFractionInverted); | 1000 bool invert = r.nextBiasedBool(kFractionInverted); |
| 975 | 1001 |
| 976 kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect,
invert, op, &stack); | 1002 kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect,
invert, op, &stack, |
| 1003 doAA); |
| 977 if (doSave) { | 1004 if (doSave) { |
| 978 stack.save(); | 1005 stack.save(); |
| 979 } | 1006 } |
| 980 } | 1007 } |
| 981 | 1008 |
| 982 SkRect inflatedBounds = kBounds; | 1009 SkRect queryBounds = kBounds; |
| 983 inflatedBounds.outset(kBounds.width() / 2, kBounds.height() / 2); | 1010 queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2); |
| 984 SkIRect inflatedIBounds; | |
| 985 inflatedBounds.roundOut(&inflatedIBounds); | |
| 986 | 1011 |
| 987 typedef GrReducedClip::ElementList ElementList; | |
| 988 // Get the reduced version of the stack. | 1012 // Get the reduced version of the stack. |
| 989 ElementList reducedClips; | 1013 ElementList reducedClips; |
| 990 int32_t reducedGenID; | 1014 int32_t reducedGenID; |
| 991 GrReducedClip::InitialState initial; | 1015 SkIRect clipIBounds; |
| 992 SkIRect tighterBounds; | |
| 993 bool requiresAA; | 1016 bool requiresAA; |
| 994 GrReducedClip::ReduceClipStack(stack, | 1017 InitialState initial = GrReducedClip::ReduceClipStack(stack, |
| 995 inflatedIBounds, | 1018 queryBounds, |
| 996 &reducedClips, | 1019 &reducedClips, |
| 997 &reducedGenID, | 1020 &reducedGenID, |
| 998 &initial, | 1021 &clipIBounds, |
| 999 &tighterBounds, | 1022 &requiresAA); |
| 1000 &requiresAA); | |
| 1001 | 1023 |
| 1002 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID); | 1024 REPORTER_ASSERT_MESSAGE(reporter, SkClipStack::kInvalidGenID != reducedG
enID, |
| 1025 testCase.c_str()); |
| 1026 |
| 1027 if (!reducedClips.isEmpty()) { |
| 1028 SkRect stackBounds; |
| 1029 SkClipStack::BoundsType stackBoundsType; |
| 1030 stack.getBounds(&stackBounds, &stackBoundsType); |
| 1031 if (SkClipStack::kNormal_BoundsType == stackBoundsType) { |
| 1032 // Unless GrReducedClip starts doing some heroic tightening of t
he clip bounds, this |
| 1033 // will be true since the stack bounds are completely contained
inside the query. |
| 1034 REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(clipIBoun
ds, stackBounds), |
| 1035 testCase.c_str()); |
| 1036 } |
| 1037 REPORTER_ASSERT_MESSAGE(reporter, requiresAA == doAA, testCase.c_str
()); |
| 1038 } |
| 1003 | 1039 |
| 1004 // Build a new clip stack based on the reduced clip elements | 1040 // Build a new clip stack based on the reduced clip elements |
| 1005 SkClipStack reducedStack; | 1041 SkClipStack reducedStack; |
| 1006 if (GrReducedClip::kAllOut_InitialState == initial) { | 1042 if (GrReducedClip::kAllOut_InitialState == initial) { |
| 1007 // whether the result is bounded or not, the whole plane should star
t outside the clip. | 1043 // whether the result is bounded or not, the whole plane should star
t outside the clip. |
| 1008 reducedStack.clipEmpty(); | 1044 reducedStack.clipEmpty(); |
| 1009 } | 1045 } |
| 1010 for (ElementList::Iter iter = reducedClips.headIter(); iter.get(); iter.
next()) { | 1046 for (ElementList::Iter iter = reducedClips.headIter(); iter.get(); iter.
next()) { |
| 1011 add_elem_to_stack(*iter.get(), &reducedStack); | 1047 add_elem_to_stack(*iter.get(), &reducedStack); |
| 1012 } | 1048 } |
| 1013 | 1049 |
| 1014 // GrReducedClipStack assumes that the final result is clipped to the re
turned bounds | 1050 // GrReducedClipStack assumes that the final result is clipped to the re
turned bounds |
| 1015 reducedStack.clipDevRect(tighterBounds, SkRegion::kIntersect_Op); | 1051 reducedStack.clipDevRect(clipIBounds, SkRegion::kIntersect_Op); |
| 1016 stack.clipDevRect(tighterBounds, SkRegion::kIntersect_Op); | 1052 stack.clipDevRect(clipIBounds, SkRegion::kIntersect_Op); |
| 1017 | 1053 |
| 1018 // convert both the original stack and reduced stack to SkRegions and se
e if they're equal | 1054 // convert both the original stack and reduced stack to SkRegions and se
e if they're equal |
| 1019 SkRegion region; | 1055 SkRegion region; |
| 1020 set_region_to_stack(stack, inflatedIBounds, ®ion); | 1056 set_region_to_stack(stack, clipIBounds, ®ion); |
| 1021 | 1057 |
| 1022 SkRegion reducedRegion; | 1058 SkRegion reducedRegion; |
| 1023 set_region_to_stack(reducedStack, inflatedIBounds, &reducedRegion); | 1059 set_region_to_stack(reducedStack, clipIBounds, &reducedRegion); |
| 1024 | 1060 |
| 1025 SkString testCase; | |
| 1026 testCase.printf("Iteration %d", i); | |
| 1027 REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_st
r()); | 1061 REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_st
r()); |
| 1028 } | 1062 } |
| 1029 } | 1063 } |
| 1030 | 1064 |
| 1031 #ifdef SK_BUILD_FOR_WIN | 1065 #ifdef SK_BUILD_FOR_WIN |
| 1032 #define SUPPRESS_VISIBILITY_WARNING | 1066 #define SUPPRESS_VISIBILITY_WARNING |
| 1033 #else | 1067 #else |
| 1034 #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden"))) | 1068 #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden"))) |
| 1035 #endif | 1069 #endif |
| 1036 | 1070 |
| 1037 static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) { | 1071 static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) { |
| 1038 { | 1072 { |
| 1039 SkClipStack stack; | 1073 SkClipStack stack; |
| 1040 stack.clipDevRect(SkRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_O
p, true); | 1074 stack.clipDevRect(SkRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_O
p, true); |
| 1041 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3))
, SkRegion::kReplace_Op, true); | 1075 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3))
, SkRegion::kReplace_Op, true); |
| 1042 SkIRect inflatedIBounds = SkIRect::MakeXYWH(0, 0, 100, 100); | 1076 SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100); |
| 1043 | 1077 |
| 1044 GrReducedClip::ElementList reducedClips; | 1078 ElementList reducedClips; |
| 1045 int32_t reducedGenID; | 1079 int32_t reducedGenID; |
| 1046 GrReducedClip::InitialState initial; | |
| 1047 SkIRect tightBounds; | 1080 SkIRect tightBounds; |
| 1048 bool requiresAA; | 1081 bool requiresAA; |
| 1049 | 1082 |
| 1050 GrReducedClip::ReduceClipStack(stack, | 1083 GrReducedClip::ReduceClipStack(stack, |
| 1051 inflatedIBounds, | 1084 bounds, |
| 1052 &reducedClips, | 1085 &reducedClips, |
| 1053 &reducedGenID, | 1086 &reducedGenID, |
| 1054 &initial, | |
| 1055 &tightBounds, | 1087 &tightBounds, |
| 1056 &requiresAA); | 1088 &requiresAA); |
| 1057 | 1089 |
| 1058 REPORTER_ASSERT(reporter, reducedClips.count() == 1); | 1090 REPORTER_ASSERT(reporter, reducedClips.count() == 1); |
| 1059 // Clips will be cached based on the generation id. Make sure the gen id
is valid. | 1091 // Clips will be cached based on the generation id. Make sure the gen id
is valid. |
| 1060 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID); | 1092 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID); |
| 1061 } | 1093 } |
| 1062 { | 1094 { |
| 1063 SkClipStack stack; | 1095 SkClipStack stack; |
| 1064 | 1096 |
| 1065 // Create a clip with following 25.3, 25.3 boxes which are 25 apart: | 1097 // Create a clip with following 25.3, 25.3 boxes which are 25 apart: |
| 1066 // A B | 1098 // A B |
| 1067 // C D | 1099 // C D |
| 1068 | 1100 |
| 1069 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(25.3), SkScalar(25.3))
, SkRegion::kReplace_Op, true); | 1101 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(25.3), SkScalar(25.3))
, SkRegion::kReplace_Op, true); |
| 1070 int32_t genIDA = stack.getTopmostGenID(); | 1102 int32_t genIDA = stack.getTopmostGenID(); |
| 1071 stack.clipDevRect(SkRect::MakeXYWH(50, 0, SkScalar(25.3), SkScalar(25.3)
), SkRegion::kUnion_Op, true); | 1103 stack.clipDevRect(SkRect::MakeXYWH(50, 0, SkScalar(25.3), SkScalar(25.3)
), SkRegion::kUnion_Op, true); |
| 1072 int32_t genIDB = stack.getTopmostGenID(); | 1104 int32_t genIDB = stack.getTopmostGenID(); |
| 1073 stack.clipDevRect(SkRect::MakeXYWH(0, 50, SkScalar(25.3), SkScalar(25.3)
), SkRegion::kUnion_Op, true); | 1105 stack.clipDevRect(SkRect::MakeXYWH(0, 50, SkScalar(25.3), SkScalar(25.3)
), SkRegion::kUnion_Op, true); |
| 1074 int32_t genIDC = stack.getTopmostGenID(); | 1106 int32_t genIDC = stack.getTopmostGenID(); |
| 1075 stack.clipDevRect(SkRect::MakeXYWH(50, 50, SkScalar(25.3), SkScalar(25.3
)), SkRegion::kUnion_Op, true); | 1107 stack.clipDevRect(SkRect::MakeXYWH(50, 50, SkScalar(25.3), SkScalar(25.3
)), SkRegion::kUnion_Op, true); |
| 1076 int32_t genIDD = stack.getTopmostGenID(); | 1108 int32_t genIDD = stack.getTopmostGenID(); |
| 1077 | 1109 |
| 1078 | 1110 |
| 1079 #define XYWH SkIRect::MakeXYWH | 1111 #define IXYWH SkIRect::MakeXYWH |
| 1112 #define XYWH SkRect::MakeXYWH |
| 1080 | 1113 |
| 1081 SkIRect stackBounds = XYWH(0, 0, 76, 76); | 1114 SkIRect stackBounds = IXYWH(0, 0, 76, 76); |
| 1082 | 1115 |
| 1083 // The base test is to test each rect in two ways: | 1116 // The base test is to test each rect in two ways: |
| 1084 // 1) The box dimensions. (Should reduce to "all in", no elements). | 1117 // 1) The box dimensions. (Should reduce to "all in", no elements). |
| 1085 // 2) A bit over the box dimensions. | 1118 // 2) A bit over the box dimensions. |
| 1086 // In the case 2, test that the generation id is what is expected. | 1119 // In the case 2, test that the generation id is what is expected. |
| 1087 // The rects are of fractional size so that case 2 never gets optimized
to an empty element | 1120 // The rects are of fractional size so that case 2 never gets optimized
to an empty element |
| 1088 // list. | 1121 // list. |
| 1089 | 1122 |
| 1090 // Not passing in tighter bounds is tested for consistency. | 1123 // Not passing in tighter bounds is tested for consistency. |
| 1091 static const struct SUPPRESS_VISIBILITY_WARNING { | 1124 static const struct SUPPRESS_VISIBILITY_WARNING { |
| 1092 SkIRect testBounds; | 1125 SkRect testBounds; |
| 1093 int reducedClipCount; | 1126 int reducedClipCount; |
| 1094 int32_t reducedGenID; | 1127 int32_t reducedGenID; |
| 1095 GrReducedClip::InitialState initialState; | 1128 InitialState initialState; |
| 1096 SkIRect tighterBounds; // If this is empty, the query will not pass
tighter bounds | 1129 SkIRect clipIRect; |
| 1097 // parameter. | 1130 // parameter. |
| 1098 } testCases[] = { | 1131 } testCases[] = { |
| 1099 // Rect A. | 1132 // Rect A. |
| 1100 { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip:
:kAllIn_InitialState, XYWH(0, 0, 25, 25) }, | 1133 { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip:
:kAllIn_InitialState, IXYWH(0, 0, 25, 25) }, |
| 1101 { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState
, XYWH(0, 0, 27, 27)}, | 1134 { XYWH(0.1f, 0.1f, 25.1f, 25.1f), 0, SkClipStack::kWideOpenGenID, Gr
ReducedClip::kAllIn_InitialState, IXYWH(0, 0, 26, 26) }, |
| 1135 { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState
, IXYWH(0, 0, 27, 27)}, |
| 1102 | 1136 |
| 1103 // Rect B. | 1137 // Rect B. |
| 1104 { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip
::kAllIn_InitialState, XYWH(50, 0, 25, 25) }, | 1138 { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip
::kAllIn_InitialState, IXYWH(50, 0, 25, 25) }, |
| 1105 { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialStat
e, XYWH(50, 0, 26, 27) }, | 1139 { XYWH(50, 0, 25.3f, 25.3f), 0, SkClipStack::kWideOpenGenID, GrReduc
edClip::kAllIn_InitialState, IXYWH(50, 0, 26, 26) }, |
| 1140 { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialStat
e, IXYWH(50, 0, 26, 27) }, |
| 1106 | 1141 |
| 1107 // Rect C. | 1142 // Rect C. |
| 1108 { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip
::kAllIn_InitialState, XYWH(0, 50, 25, 25) }, | 1143 { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip
::kAllIn_InitialState, IXYWH(0, 50, 25, 25) }, |
| 1109 { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialStat
e, XYWH(0, 50, 27, 26) }, | 1144 { XYWH(0.2f, 50.1f, 25.1f, 25.2f), 0, SkClipStack::kWideOpenGenID, G
rReducedClip::kAllIn_InitialState, IXYWH(0, 50, 26, 26) }, |
| 1145 { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialStat
e, IXYWH(0, 50, 27, 26) }, |
| 1110 | 1146 |
| 1111 // Rect D. | 1147 // Rect D. |
| 1112 { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedCli
p::kAllIn_InitialState, XYWH(50, 50, 25, 25)}, | 1148 { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedCli
p::kAllIn_InitialState, IXYWH(50, 50, 25, 25)}, |
| 1113 { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialSta
te, XYWH(50, 50, 26, 26)}, | 1149 { XYWH(50.3f, 50.3f, 25, 25), 0, SkClipStack::kWideOpenGenID, GrRedu
cedClip::kAllIn_InitialState, IXYWH(50, 50, 26, 26)}, |
| 1150 { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialSta
te, IXYWH(50, 50, 26, 26)}, |
| 1114 | 1151 |
| 1115 // Other tests: | 1152 // Other tests: |
| 1116 { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialSta
te, stackBounds }, | 1153 { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialSta
te, stackBounds }, |
| 1117 | 1154 |
| 1118 // Rect in the middle, touches none. | 1155 // Rect in the middle, touches none. |
| 1119 { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip::
kAllOut_InitialState, XYWH(26, 26, 24, 24) }, | 1156 { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip::
kAllOut_InitialState, IXYWH(26, 26, 24, 24) }, |
| 1120 | 1157 |
| 1121 // Rect in the middle, touches all the rects. GenID is the last rect
. | 1158 // Rect in the middle, touches all the rects. GenID is the last rect
. |
| 1122 { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialSta
te, XYWH(24, 24, 27, 27) }, | 1159 { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialSta
te, IXYWH(24, 24, 27, 27) }, |
| 1123 }; | 1160 }; |
| 1124 | 1161 |
| 1125 #undef XYWH | 1162 #undef XYWH |
| 1163 #undef IXYWH |
| 1126 | 1164 |
| 1127 for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) { | 1165 for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) { |
| 1128 GrReducedClip::ElementList reducedClips; | 1166 ElementList reducedClips; |
| 1129 int32_t reducedGenID; | 1167 int32_t reducedGenID; |
| 1130 GrReducedClip::InitialState initial; | 1168 SkIRect clipIRect; |
| 1131 SkIRect tightBounds; | |
| 1132 bool requiresAA; | 1169 bool requiresAA; |
| 1133 | 1170 |
| 1134 GrReducedClip::ReduceClipStack(stack, | 1171 InitialState initial = GrReducedClip::ReduceClipStack(stack, |
| 1135 testCases[i].testBounds, | 1172 testCases[i].t
estBounds, |
| 1136 &reducedClips, | 1173 &reducedClips, |
| 1137 &reducedGenID, | 1174 &reducedGenID, |
| 1138 &initial, | 1175 &clipIRect, |
| 1139 &tightBounds, | 1176 &requiresAA); |
| 1140 &requiresAA); | |
| 1141 | 1177 |
| 1142 REPORTER_ASSERT(reporter, reducedClips.count() == testCases[i].reduc
edClipCount); | 1178 REPORTER_ASSERT(reporter, reducedClips.count() == testCases[i].reduc
edClipCount); |
| 1143 SkASSERT(reducedClips.count() == testCases[i].reducedClipCount); | 1179 SkASSERT(reducedClips.count() == testCases[i].reducedClipCount); |
| 1144 REPORTER_ASSERT(reporter, reducedGenID == testCases[i].reducedGenID)
; | 1180 REPORTER_ASSERT(reporter, reducedGenID == testCases[i].reducedGenID)
; |
| 1145 SkASSERT(reducedGenID == testCases[i].reducedGenID); | 1181 SkASSERT(reducedGenID == testCases[i].reducedGenID); |
| 1146 REPORTER_ASSERT(reporter, initial == testCases[i].initialState); | 1182 REPORTER_ASSERT(reporter, initial == testCases[i].initialState); |
| 1147 SkASSERT(initial == testCases[i].initialState); | 1183 SkASSERT(initial == testCases[i].initialState); |
| 1148 REPORTER_ASSERT(reporter, tightBounds == testCases[i].tighterBounds)
; | 1184 REPORTER_ASSERT(reporter, clipIRect == testCases[i].clipIRect); |
| 1149 SkASSERT(tightBounds == testCases[i].tighterBounds); | 1185 SkASSERT(clipIRect == testCases[i].clipIRect); |
| 1150 } | 1186 } |
| 1151 } | 1187 } |
| 1152 } | 1188 } |
| 1153 | 1189 |
| 1154 static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) { | 1190 static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) { |
| 1155 SkClipStack stack; | 1191 SkClipStack stack; |
| 1156 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_Op); | 1192 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_Op); |
| 1157 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkRegion::kReplace_Op); | 1193 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkRegion::kReplace_Op); |
| 1158 SkIRect inflatedIBounds = SkIRect::MakeXYWH(0, 0, 100, 100); | 1194 SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100); |
| 1159 | 1195 |
| 1160 GrReducedClip::ElementList reducedClips; | 1196 ElementList reducedClips; |
| 1161 int32_t reducedGenID; | 1197 int32_t reducedGenID; |
| 1162 GrReducedClip::InitialState initial; | |
| 1163 SkIRect tightBounds; | 1198 SkIRect tightBounds; |
| 1164 bool requiresAA; | 1199 bool requiresAA; |
| 1165 | 1200 |
| 1166 // At the time, this would crash. | 1201 // At the time, this would crash. |
| 1167 GrReducedClip::ReduceClipStack(stack, | 1202 GrReducedClip::ReduceClipStack(stack, |
| 1168 inflatedIBounds, | 1203 bounds, |
| 1169 &reducedClips, | 1204 &reducedClips, |
| 1170 &reducedGenID, | 1205 &reducedGenID, |
| 1171 &initial, | |
| 1172 &tightBounds, | 1206 &tightBounds, |
| 1173 &requiresAA); | 1207 &requiresAA); |
| 1174 | 1208 |
| 1175 REPORTER_ASSERT(reporter, 0 == reducedClips.count()); | 1209 REPORTER_ASSERT(reporter, 0 == reducedClips.count()); |
| 1176 } | 1210 } |
| 1177 | 1211 |
| 1212 enum class ClipMethod { |
| 1213 kSkipDraw, |
| 1214 kIgnoreClip, |
| 1215 kScissor, |
| 1216 kAAElements |
| 1217 }; |
| 1218 |
| 1219 static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
, |
| 1220 const SkClipStack& stack, const SkMatrix& queryXform, |
| 1221 const SkRect& preXformQuery, ClipMethod expectedMethod
, |
| 1222 int numExpectedElems = 0) { |
| 1223 ElementList reducedElems; |
| 1224 int32_t reducedGenID; |
| 1225 SkIRect clipIBounds; |
| 1226 bool requiresAA; |
| 1227 |
| 1228 SkRect queryBounds; |
| 1229 queryXform.mapRect(&queryBounds, preXformQuery); |
| 1230 |
| 1231 InitialState initialState = GrReducedClip::ReduceClipStack(stack, |
| 1232 queryBounds, |
| 1233 &reducedElems, |
| 1234 &reducedGenID, |
| 1235 &clipIBounds, |
| 1236 &requiresAA); |
| 1237 |
| 1238 SkClipStack::BoundsType stackBoundsType; |
| 1239 SkRect stackBounds; |
| 1240 stack.getBounds(&stackBounds, &stackBoundsType); |
| 1241 |
| 1242 switch (expectedMethod) { |
| 1243 case ClipMethod::kSkipDraw: |
| 1244 SkASSERT(0 == numExpectedElems); |
| 1245 REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c
_str()); |
| 1246 REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllOut_InitialStat
e == initialState, |
| 1247 testName.c_str()); |
| 1248 return; |
| 1249 case ClipMethod::kIgnoreClip: |
| 1250 SkASSERT(0 == numExpectedElems); |
| 1251 REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c
_str()); |
| 1252 REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(clipIBounds,
queryBounds), |
| 1253 testName.c_str()); |
| 1254 REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllIn_InitialState
== initialState, |
| 1255 testName.c_str()); |
| 1256 return; |
| 1257 case ClipMethod::kScissor: { |
| 1258 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType); |
| 1259 SkASSERT(0 == numExpectedElems); |
| 1260 SkIRect expectedScissor; |
| 1261 stackBounds.round(&expectedScissor); |
| 1262 REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c
_str()); |
| 1263 REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == clipIBounds, te
stName.c_str()); |
| 1264 REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllIn_InitialState
== initialState, |
| 1265 testName.c_str()); |
| 1266 return; |
| 1267 } |
| 1268 case ClipMethod::kAAElements: { |
| 1269 SkIRect expectedClipIBounds = GrClip::GetPixelIBounds(queryBounds); |
| 1270 if (SkClipStack::kNormal_BoundsType == stackBoundsType) { |
| 1271 SkAssertResult(expectedClipIBounds.intersect(GrClip::GetPixelIBo
unds(stackBounds))); |
| 1272 } |
| 1273 REPORTER_ASSERT_MESSAGE(reporter, numExpectedElems == reducedElems.c
ount(), |
| 1274 testName.c_str()); |
| 1275 REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == clipIBounds
, testName.c_str()); |
| 1276 REPORTER_ASSERT_MESSAGE(reporter, requiresAA == !reducedElems.isEmpt
y(), |
| 1277 testName.c_str()); |
| 1278 break; |
| 1279 } |
| 1280 } |
| 1281 } |
| 1282 |
| 1283 static void test_reduced_clip_stack_aa(skiatest::Reporter* reporter) { |
| 1284 constexpr SkScalar IL = 2, IT = 1, IR = 6, IB = 7; // Pixel aligned
rect. |
| 1285 constexpr SkScalar L = 2.2f, T = 1.7f, R = 5.8f, B = 7.3f; // Generic rect. |
| 1286 constexpr SkScalar l = 3.3f, t = 2.8f, r = 4.7f, b = 6.2f; // Small rect con
tained in R. |
| 1287 |
| 1288 SkRect alignedRect = {IL, IT, IR, IB}; |
| 1289 SkRect rect = {L, T, R, B}; |
| 1290 SkRect innerRect = {l, t, r, b}; |
| 1291 |
| 1292 SkMatrix m; |
| 1293 m.setIdentity(); |
| 1294 |
| 1295 constexpr SkScalar kMinScale = 2.0001f; |
| 1296 constexpr SkScalar kMaxScale = 3; |
| 1297 constexpr int kNumIters = 8; |
| 1298 |
| 1299 SkString name; |
| 1300 SkRandom rand; |
| 1301 |
| 1302 for (int i = 0; i < kNumIters; ++i) { |
| 1303 // Pixel-aligned rect (iior=true). |
| 1304 name.printf("Pixel-aligned rect test, iter %i", i); |
| 1305 SkClipStack stack; |
| 1306 stack.clipDevRect(alignedRect, SkRegion::kIntersect_Op, true); |
| 1307 test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kI
gnoreClip); |
| 1308 test_aa_query(reporter, name, stack, m, {IL, IT-1, IR, IT}, ClipMethod::
kSkipDraw); |
| 1309 test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kS
cissor); |
| 1310 test_aa_query(reporter, name, stack, m, {IL, IT+2, IR, IB-3}, ClipMethod
::kScissor); |
| 1311 |
| 1312 // Rect (iior=true). |
| 1313 name.printf("Rect test, iter %i", i); |
| 1314 stack.reset(); |
| 1315 stack.clipDevRect(rect, SkRegion::kIntersect_Op, true); |
| 1316 test_aa_query(reporter, name, stack, m, {L, T, R, B}, ClipMethod::kIgno
reClip); |
| 1317 test_aa_query(reporter, name, stack, m, {L-.1f, T, L, B}, ClipMethod::kS
kipDraw); |
| 1318 test_aa_query(reporter, name, stack, m, {L-.1f, T, L+.1f, B}, ClipMethod
::kAAElements, 1); |
| 1319 |
| 1320 // Difference rect (iior=false, inside-out bounds). |
| 1321 name.printf("Difference rect test, iter %i", i); |
| 1322 stack.reset(); |
| 1323 stack.clipDevRect(rect, SkRegion::kDifference_Op, true); |
| 1324 test_aa_query(reporter, name, stack, m, {L, T, R, B}, ClipMethod::kSkipD
raw); |
| 1325 test_aa_query(reporter, name, stack, m, {L, T-.1f, R, T}, ClipMethod::kI
gnoreClip); |
| 1326 test_aa_query(reporter, name, stack, m, {L, T-.1f, R, T+.1f}, ClipMethod
::kAAElements, 1); |
| 1327 |
| 1328 // Complex clip (iior=false, normal bounds). |
| 1329 name.printf("Complex clip test, iter %i", i); |
| 1330 stack.reset(); |
| 1331 stack.clipDevRect(rect, SkRegion::kIntersect_Op, true); |
| 1332 stack.clipDevRect(innerRect, SkRegion::kXOR_Op, true); |
| 1333 test_aa_query(reporter, name, stack, m, {l, t, r, b}, ClipMethod::kSkipD
raw); |
| 1334 test_aa_query(reporter, name, stack, m, {r-.1f, t, R, b}, ClipMethod::kA
AElements, 1); |
| 1335 test_aa_query(reporter, name, stack, m, {r-.1f, t, R+.1f, b}, ClipMethod
::kAAElements, 2); |
| 1336 test_aa_query(reporter, name, stack, m, {r, t, R+.1f, b}, ClipMethod::kA
AElements, 1); |
| 1337 test_aa_query(reporter, name, stack, m, {r, t, R, b}, ClipMethod::kIgnor
eClip); |
| 1338 test_aa_query(reporter, name, stack, m, {R, T, R+.1f, B}, ClipMethod::kS
kipDraw); |
| 1339 |
| 1340 // Complex clip where outer rect is pixel aligned (iior=false, normal bo
unds). |
| 1341 name.printf("Aligned Complex clip test, iter %i", i); |
| 1342 stack.reset(); |
| 1343 stack.clipDevRect(alignedRect, SkRegion::kIntersect_Op, true); |
| 1344 stack.clipDevRect(innerRect, SkRegion::kXOR_Op, true); |
| 1345 test_aa_query(reporter, name, stack, m, {l, t, r, b}, ClipMethod::kSkipD
raw); |
| 1346 test_aa_query(reporter, name, stack, m, {l, b-.1f, r, IB}, ClipMethod::k
AAElements, 1); |
| 1347 test_aa_query(reporter, name, stack, m, {l, b-.1f, r, IB+.1f}, ClipMetho
d::kAAElements, 1); |
| 1348 test_aa_query(reporter, name, stack, m, {l, b, r, IB+.1f}, ClipMethod::k
AAElements, 0); |
| 1349 test_aa_query(reporter, name, stack, m, {l, b, r, IB}, ClipMethod::kIgno
reClip); |
| 1350 test_aa_query(reporter, name, stack, m, {IL, IB, IR, IB+.1f}, ClipMethod
::kSkipDraw); |
| 1351 |
| 1352 // Apply random transforms and try again. This ensures the clip stack re
duction is hardened |
| 1353 // against FP rounding error. |
| 1354 SkScalar sx = rand.nextRangeScalar(kMinScale, kMaxScale); |
| 1355 sx = SkScalarFloorToScalar(sx * alignedRect.width()) / alignedRect.width
(); |
| 1356 SkScalar sy = rand.nextRangeScalar(kMinScale, kMaxScale); |
| 1357 sy = SkScalarFloorToScalar(sy * alignedRect.height()) / alignedRect.heig
ht(); |
| 1358 SkScalar tx = SkScalarRoundToScalar(sx * alignedRect.x()) - sx * aligned
Rect.x(); |
| 1359 SkScalar ty = SkScalarRoundToScalar(sy * alignedRect.y()) - sy * aligned
Rect.y(); |
| 1360 |
| 1361 SkMatrix xform = SkMatrix::MakeScale(sx, sy); |
| 1362 xform.postTranslate(tx, ty); |
| 1363 xform.mapRect(&alignedRect); |
| 1364 xform.mapRect(&rect); |
| 1365 xform.mapRect(&innerRect); |
| 1366 m.postConcat(xform); |
| 1367 } |
| 1368 } |
| 1369 |
| 1178 #endif | 1370 #endif |
| 1179 | 1371 |
| 1180 DEF_TEST(ClipStack, reporter) { | 1372 DEF_TEST(ClipStack, reporter) { |
| 1181 SkClipStack stack; | 1373 SkClipStack stack; |
| 1182 | 1374 |
| 1183 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); | 1375 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); |
| 1184 assert_count(reporter, stack, 0); | 1376 assert_count(reporter, stack, 0); |
| 1185 | 1377 |
| 1186 static const SkIRect gRects[] = { | 1378 static const SkIRect gRects[] = { |
| 1187 { 0, 0, 100, 100 }, | 1379 { 0, 0, 100, 100 }, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1219 test_rect_merging(reporter); | 1411 test_rect_merging(reporter); |
| 1220 test_rect_replace(reporter); | 1412 test_rect_replace(reporter); |
| 1221 test_rect_inverse_fill(reporter); | 1413 test_rect_inverse_fill(reporter); |
| 1222 test_path_replace(reporter); | 1414 test_path_replace(reporter); |
| 1223 test_quickContains(reporter); | 1415 test_quickContains(reporter); |
| 1224 test_invfill_diff_bug(reporter); | 1416 test_invfill_diff_bug(reporter); |
| 1225 #if SK_SUPPORT_GPU | 1417 #if SK_SUPPORT_GPU |
| 1226 test_reduced_clip_stack(reporter); | 1418 test_reduced_clip_stack(reporter); |
| 1227 test_reduced_clip_stack_genid(reporter); | 1419 test_reduced_clip_stack_genid(reporter); |
| 1228 test_reduced_clip_stack_no_aa_crash(reporter); | 1420 test_reduced_clip_stack_no_aa_crash(reporter); |
| 1421 test_reduced_clip_stack_aa(reporter); |
| 1229 #endif | 1422 #endif |
| 1230 } | 1423 } |
| OLD | NEW |