OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 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 <initializer_list> | 8 #include <initializer_list> |
9 #include <functional> | 9 #include <functional> |
10 #include "Test.h" | 10 #include "Test.h" |
11 #if SK_SUPPORT_GPU | 11 #if SK_SUPPORT_GPU |
12 #include "GrShape.h" | 12 #include "GrShape.h" |
13 #include "SkPath.h" | 13 #include "SkPath.h" |
14 #include "SkDashPathEffect.h" | 14 #include "SkDashPathEffect.h" |
15 | 15 |
16 using Key = SkTArray<uint32_t>; | |
17 | |
18 static bool make_key(Key* key, const GrShape& shape) { | |
19 int size = shape.unstyledKeySize(); | |
20 if (size <= 0) { | |
21 key->reset(0); | |
22 return false; | |
23 } | |
24 SkASSERT(size); | |
25 key->reset(size); | |
26 shape.writeUnstyledKey(key->begin()); | |
27 return true; | |
28 } | |
29 | |
16 namespace { | 30 namespace { |
31 | |
17 class TestCase { | 32 class TestCase { |
18 public: | 33 public: |
19 TestCase(const SkRRect& rrect, const SkPaint& paint) : fBase(rrect, paint) { | 34 template <typename GEO> |
35 TestCase(const GEO& geo, const SkPaint& paint) : fBase(geo, paint) { | |
20 this->init(); | 36 this->init(); |
21 } | 37 } |
22 | 38 |
23 struct SelfExpectations { | 39 struct SelfExpectations { |
24 bool fPEHasEffect; | 40 bool fPEHasEffect; |
25 bool fPEHasValidKey; | 41 bool fPEHasValidKey; |
26 bool fStrokeApplies; | 42 bool fStrokeApplies; |
27 }; | 43 }; |
28 | 44 |
29 void testExpectations(skiatest::Reporter* reporter, SelfExpectations expecta tions) const; | 45 void testExpectations(skiatest::Reporter* reporter, SelfExpectations expecta tions) const; |
30 | 46 |
31 enum ComparisonExpecation { | 47 enum ComparisonExpecation { |
32 kAllDifferent_ComparisonExpecation, | 48 kAllDifferent_ComparisonExpecation, |
33 kSameUpToPE_ComparisonExpecation, | 49 kSameUpToPE_ComparisonExpecation, |
34 kSameUpToStroke_ComparisonExpecation, | 50 kSameUpToStroke_ComparisonExpecation, |
35 kAllSame_ComparisonExpecation, | 51 kAllSame_ComparisonExpecation, |
36 }; | 52 }; |
37 | 53 |
38 void compare(skiatest::Reporter*, const TestCase& that, ComparisonExpecation ) const; | 54 void compare(skiatest::Reporter*, const TestCase& that, ComparisonExpecation ) const; |
39 | 55 |
56 const GrShape& baseShape() const { return fBase; } | |
57 const GrShape& appliedPathEffectShape() const { return fAppliedPE; } | |
58 const GrShape& appliedFullStyleShape() const { return fAppliedFull; } | |
59 | |
60 // The returned array's count will be 0 if the key shape has no key. | |
61 const Key& baseKey() const { return fBaseKey; } | |
62 const Key& appliedPathEffectKey() const { return fAppliedPEKey; } | |
63 const Key& appliedFullStyleKey() const { return fAppliedFullKey; } | |
64 | |
40 private: | 65 private: |
41 void init() { | 66 void init() { |
42 fAppliedPE = fBase.applyPathEffect(); | 67 fAppliedPE = fBase.applyPathEffect(); |
43 fAppliedPEThenStroke = fAppliedPE.applyFullStyle(); | 68 fAppliedPEThenStroke = fAppliedPE.applyFullStyle(); |
44 fAppliedFull = fBase.applyFullStyle(); | 69 fAppliedFull = fBase.applyFullStyle(); |
45 | 70 |
46 fBaseKeyIsValid = MakeKey(&fBaseKey, fBase); | 71 make_key(&fBaseKey, fBase); |
47 fAppliedPEKeyIsValid = MakeKey(&fAppliedPEKey, fAppliedPE); | 72 make_key(&fAppliedPEKey, fAppliedPE); |
48 fAppliedPEThenStrokeKeyIsValid = MakeKey(&fAppliedPEThenStrokeKey, fAppl iedPEThenStroke); | 73 make_key(&fAppliedPEThenStrokeKey, fAppliedPEThenStroke); |
49 fAppliedFullKeyIsValid = MakeKey(&fAppliedFullKey, fAppliedFull) ; | 74 make_key(&fAppliedFullKey, fAppliedFull); |
50 } | |
51 | |
52 using Key = SkTArray<uint32_t>; | |
53 | |
54 static bool MakeKey(Key* key, const GrShape& shape) { | |
55 int size = shape.unstyledKeySize(); | |
56 if (size <= 0) { | |
57 return false; | |
58 } | |
59 key->reset(size); | |
60 shape.writeUnstyledKey(key->begin()); | |
61 return true; | |
62 } | 75 } |
63 | 76 |
64 GrShape fBase; | 77 GrShape fBase; |
65 GrShape fAppliedPE; | 78 GrShape fAppliedPE; |
66 GrShape fAppliedPEThenStroke; | 79 GrShape fAppliedPEThenStroke; |
67 GrShape fAppliedFull; | 80 GrShape fAppliedFull; |
68 | 81 |
69 Key fBaseKey; | 82 Key fBaseKey; |
70 Key fAppliedPEKey; | 83 Key fAppliedPEKey; |
71 Key fAppliedPEThenStrokeKey; | 84 Key fAppliedPEThenStrokeKey; |
72 Key fAppliedFullKey; | 85 Key fAppliedFullKey; |
73 | 86 |
74 bool fBaseKeyIsValid; | |
75 bool fAppliedPEKeyIsValid; | |
76 bool fAppliedPEThenStrokeKeyIsValid; | |
77 bool fAppliedFullKeyIsValid; | |
78 }; | 87 }; |
79 | 88 |
80 void TestCase::testExpectations(skiatest::Reporter* reporter, SelfExpectations e xpectations) const { | 89 void TestCase::testExpectations(skiatest::Reporter* reporter, SelfExpectations e xpectations) const { |
81 // Applying the path effect and then the stroke should always be the same as applying | 90 // Applying the path effect and then the stroke should always be the same as applying |
82 // both in one go. | 91 // both in one go. |
83 REPORTER_ASSERT(reporter, fAppliedPEThenStrokeKey == fAppliedFullKey); | 92 REPORTER_ASSERT(reporter, fAppliedPEThenStrokeKey == fAppliedFullKey); |
93 SkPath a, b; | |
94 fAppliedPEThenStroke.asPath(&a); | |
95 fAppliedFull.asPath(&b); | |
96 REPORTER_ASSERT(reporter, a == b); | |
84 // The base's key should always be valid (unless the path is volatile) | 97 // The base's key should always be valid (unless the path is volatile) |
85 REPORTER_ASSERT(reporter, fBaseKeyIsValid); | 98 REPORTER_ASSERT(reporter, fBaseKey.count()); |
86 if (expectations.fPEHasEffect) { | 99 if (expectations.fPEHasEffect) { |
87 REPORTER_ASSERT(reporter, fBaseKey != fAppliedPEKey); | 100 REPORTER_ASSERT(reporter, fBaseKey != fAppliedPEKey); |
88 REPORTER_ASSERT(reporter, expectations.fPEHasEffect == fAppliedPEKeyIsVa lid); | 101 REPORTER_ASSERT(reporter, expectations.fPEHasValidKey == SkToBool(fAppli edPEKey.count())); |
89 REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey); | 102 REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey); |
90 REPORTER_ASSERT(reporter, expectations.fPEHasEffect == fAppliedFullKeyIs Valid); | 103 REPORTER_ASSERT(reporter, expectations.fPEHasValidKey == SkToBool(fAppli edFullKey.count())); |
91 if (expectations.fStrokeApplies && expectations.fPEHasValidKey) { | 104 if (expectations.fStrokeApplies && expectations.fPEHasValidKey) { |
92 REPORTER_ASSERT(reporter, fAppliedPEKey != fAppliedFullKey); | 105 REPORTER_ASSERT(reporter, fAppliedPEKey != fAppliedFullKey); |
93 REPORTER_ASSERT(reporter, expectations.fPEHasEffect == fAppliedFullK eyIsValid); | 106 REPORTER_ASSERT(reporter, SkToBool(fAppliedFullKey.count())); |
94 } | 107 } |
95 } else { | 108 } else { |
96 REPORTER_ASSERT(reporter, fBaseKey == fAppliedPEKey); | 109 REPORTER_ASSERT(reporter, fBaseKey == fAppliedPEKey); |
110 fBase.asPath(&a); | |
111 fAppliedPE.asPath(&b); | |
112 REPORTER_ASSERT(reporter, a == b); | |
97 if (expectations.fStrokeApplies) { | 113 if (expectations.fStrokeApplies) { |
98 REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey); | 114 REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey); |
99 } else { | 115 } else { |
100 REPORTER_ASSERT(reporter, fBaseKey == fAppliedFullKey); | 116 REPORTER_ASSERT(reporter, fBaseKey == fAppliedFullKey); |
101 } | 117 } |
102 } | 118 } |
103 } | 119 } |
104 | 120 |
105 void TestCase::compare(skiatest::Reporter* reporter, const TestCase& that, | 121 void TestCase::compare(skiatest::Reporter* reporter, const TestCase& that, |
106 ComparisonExpecation expectation) const { | 122 ComparisonExpecation expectation) const { |
123 SkPath a, b; | |
107 switch (expectation) { | 124 switch (expectation) { |
108 case kAllDifferent_ComparisonExpecation: | 125 case kAllDifferent_ComparisonExpecation: |
109 REPORTER_ASSERT(reporter, fBaseKey != that.fBaseKey); | 126 REPORTER_ASSERT(reporter, fBaseKey != that.fBaseKey); |
110 REPORTER_ASSERT(reporter, fAppliedPEKey != that.fAppliedPEKey); | 127 REPORTER_ASSERT(reporter, fAppliedPEKey != that.fAppliedPEKey); |
111 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); | 128 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); |
112 break; | 129 break; |
113 case kSameUpToPE_ComparisonExpecation: | 130 case kSameUpToPE_ComparisonExpecation: |
114 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); | 131 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); |
132 fBase.asPath(&a); | |
133 that.fBase.asPath(&b); | |
134 REPORTER_ASSERT(reporter, a == b); | |
115 REPORTER_ASSERT(reporter, fAppliedPEKey != that.fAppliedPEKey); | 135 REPORTER_ASSERT(reporter, fAppliedPEKey != that.fAppliedPEKey); |
116 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); | 136 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); |
117 break; | 137 break; |
118 case kSameUpToStroke_ComparisonExpecation: | 138 case kSameUpToStroke_ComparisonExpecation: |
119 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); | 139 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); |
140 fBase.asPath(&a); | |
141 that.fBase.asPath(&b); | |
142 REPORTER_ASSERT(reporter, a == b); | |
120 REPORTER_ASSERT(reporter, fAppliedPEKey == that.fAppliedPEKey); | 143 REPORTER_ASSERT(reporter, fAppliedPEKey == that.fAppliedPEKey); |
144 fAppliedPE.asPath(&a); | |
145 that.fAppliedPE.asPath(&b); | |
146 REPORTER_ASSERT(reporter, a == b); | |
121 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); | 147 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); |
122 break; | 148 break; |
123 case kAllSame_ComparisonExpecation: | 149 case kAllSame_ComparisonExpecation: |
124 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); | 150 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); |
151 fBase.asPath(&a); | |
152 that.fBase.asPath(&b); | |
153 REPORTER_ASSERT(reporter, a == b); | |
125 REPORTER_ASSERT(reporter, fAppliedPEKey == that.fAppliedPEKey); | 154 REPORTER_ASSERT(reporter, fAppliedPEKey == that.fAppliedPEKey); |
155 fAppliedPE.asPath(&a); | |
156 that.fAppliedPE.asPath(&b); | |
157 REPORTER_ASSERT(reporter, a == b); | |
126 REPORTER_ASSERT(reporter, fAppliedFullKey == that.fAppliedFullKey); | 158 REPORTER_ASSERT(reporter, fAppliedFullKey == that.fAppliedFullKey); |
159 fAppliedFull.asPath(&a); | |
160 that.fAppliedFull.asPath(&b); | |
161 REPORTER_ASSERT(reporter, a == b); | |
127 break; | 162 break; |
128 } | 163 } |
129 } | 164 } |
130 } // namespace | 165 } // namespace |
131 | 166 |
132 static sk_sp<SkPathEffect> make_dash() { | 167 static sk_sp<SkPathEffect> make_dash() { |
133 static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f }; | 168 static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f }; |
134 static const SkScalar kPhase = 0.75; | 169 static const SkScalar kPhase = 0.75; |
135 return SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), kPhase ); | 170 return SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), kPhase ); |
136 } | 171 } |
137 | 172 |
138 static sk_sp<SkPathEffect> make_null_dash() { | 173 static sk_sp<SkPathEffect> make_null_dash() { |
139 static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0}; | 174 static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0}; |
140 return SkDashPathEffect::Make(kNullIntervals, SK_ARRAY_COUNT(kNullIntervals) , 0.f); | 175 return SkDashPathEffect::Make(kNullIntervals, SK_ARRAY_COUNT(kNullIntervals) , 0.f); |
141 } | 176 } |
142 | 177 |
143 static void test_basic(skiatest::Reporter* reporter, const SkRRect& rrect) { | 178 template<typename GEO> |
179 static void test_basic(skiatest::Reporter* reporter, const GEO& geo) { | |
144 sk_sp<SkPathEffect> dashPE = make_dash(); | 180 sk_sp<SkPathEffect> dashPE = make_dash(); |
145 | 181 |
146 TestCase::SelfExpectations expectations; | 182 TestCase::SelfExpectations expectations; |
147 SkPaint fill; | 183 SkPaint fill; |
148 | 184 |
149 TestCase fillCase(rrect, fill); | 185 TestCase fillCase(geo, fill); |
150 expectations.fPEHasEffect = false; | 186 expectations.fPEHasEffect = false; |
151 expectations.fPEHasValidKey = false; | 187 expectations.fPEHasValidKey = false; |
152 expectations.fStrokeApplies = false; | 188 expectations.fStrokeApplies = false; |
153 fillCase.testExpectations(reporter, expectations); | 189 fillCase.testExpectations(reporter, expectations); |
154 // Test that another GrShape instance built from the same primitive is the s ame. | 190 // Test that another GrShape instance built from the same primitive is the s ame. |
155 TestCase(rrect, fill).compare(reporter, fillCase, TestCase::kAllSame_Compari sonExpecation); | 191 TestCase(geo, fill).compare(reporter, fillCase, TestCase::kAllSame_Compariso nExpecation); |
156 | 192 |
157 SkPaint stroke2RoundBevel; | 193 SkPaint stroke2RoundBevel; |
158 stroke2RoundBevel.setStyle(SkPaint::kStroke_Style); | 194 stroke2RoundBevel.setStyle(SkPaint::kStroke_Style); |
159 stroke2RoundBevel.setStrokeCap(SkPaint::kRound_Cap); | 195 stroke2RoundBevel.setStrokeCap(SkPaint::kRound_Cap); |
160 stroke2RoundBevel.setStrokeJoin(SkPaint::kBevel_Join); | 196 stroke2RoundBevel.setStrokeJoin(SkPaint::kBevel_Join); |
161 stroke2RoundBevel.setStrokeWidth(2.f); | 197 stroke2RoundBevel.setStrokeWidth(2.f); |
162 TestCase stroke2RoundBevelCase(rrect, stroke2RoundBevel); | 198 TestCase stroke2RoundBevelCase(geo, stroke2RoundBevel); |
163 expectations.fPEHasValidKey = true; | 199 expectations.fPEHasValidKey = true; |
164 expectations.fPEHasEffect = false; | 200 expectations.fPEHasEffect = false; |
165 expectations.fStrokeApplies = true; | 201 expectations.fStrokeApplies = true; |
166 stroke2RoundBevelCase.testExpectations(reporter, expectations); | 202 stroke2RoundBevelCase.testExpectations(reporter, expectations); |
167 TestCase(rrect, stroke2RoundBevel).compare(reporter, stroke2RoundBevelCase, | 203 TestCase(geo, stroke2RoundBevel).compare(reporter, stroke2RoundBevelCase, |
168 TestCase::kAllSame_ComparisonExpe cation); | 204 TestCase::kAllSame_ComparisonExpeca tion); |
169 | 205 |
170 SkPaint stroke2RoundBevelDash = stroke2RoundBevel; | 206 SkPaint stroke2RoundBevelDash = stroke2RoundBevel; |
171 stroke2RoundBevelDash.setPathEffect(make_dash()); | 207 stroke2RoundBevelDash.setPathEffect(make_dash()); |
172 TestCase stroke2RoundBevelDashCase(rrect, stroke2RoundBevelDash); | 208 TestCase stroke2RoundBevelDashCase(geo, stroke2RoundBevelDash); |
173 expectations.fPEHasValidKey = true; | 209 expectations.fPEHasValidKey = true; |
174 expectations.fPEHasEffect = true; | 210 expectations.fPEHasEffect = true; |
175 expectations.fStrokeApplies = true; | 211 expectations.fStrokeApplies = true; |
176 stroke2RoundBevelDashCase.testExpectations(reporter, expectations); | 212 stroke2RoundBevelDashCase.testExpectations(reporter, expectations); |
177 TestCase(rrect, stroke2RoundBevelDash).compare(reporter, stroke2RoundBevelDa shCase, | 213 TestCase(geo, stroke2RoundBevelDash).compare(reporter, stroke2RoundBevelDash Case, |
178 TestCase::kAllSame_Comparison Expecation); | 214 TestCase::kAllSame_ComparisonEx pecation); |
179 | 215 |
180 fillCase.compare(reporter, stroke2RoundBevelCase, | 216 fillCase.compare(reporter, stroke2RoundBevelCase, |
181 TestCase::kSameUpToStroke_ComparisonExpecation); | 217 TestCase::kSameUpToStroke_ComparisonExpecation); |
182 fillCase.compare(reporter, stroke2RoundBevelDashCase, | 218 fillCase.compare(reporter, stroke2RoundBevelDashCase, |
183 TestCase::kSameUpToPE_ComparisonExpecation); | 219 TestCase::kSameUpToPE_ComparisonExpecation); |
184 stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase, | 220 stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase, |
185 TestCase::kSameUpToPE_ComparisonExpecation); | 221 TestCase::kSameUpToPE_ComparisonExpecation); |
222 | |
223 SkPaint hairline; | |
224 hairline.setStyle(SkPaint::kStroke_Style); | |
225 hairline.setStrokeWidth(0.f); | |
226 TestCase hairlineCase(geo, hairline); | |
227 // Since hairline style doesn't change the SkPath data, it is keyed identica lly to fill. | |
228 hairlineCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonExpeca tion); | |
186 } | 229 } |
187 | 230 |
188 template <typename T> | 231 template <typename GEO, typename T> |
189 static void test_stroke_param(skiatest::Reporter* reporter, const SkRRect& rrect , | 232 static void test_stroke_param(skiatest::Reporter* reporter, const GEO& geo, |
190 std::function<void(SkPaint*, T)> setter, T a, T b) { | 233 std::function<void(SkPaint*, T)> setter, T a, T b) { |
191 // Set the stroke width so that we don't get hairline. However, call the fun ction second so that | 234 // Set the stroke width so that we don't get hairline. However, call the fun ction second so that |
192 // it can override. | 235 // it can override. |
193 SkPaint strokeA; | 236 SkPaint strokeA; |
194 strokeA.setStyle(SkPaint::kStroke_Style); | 237 strokeA.setStyle(SkPaint::kStroke_Style); |
195 strokeA.setStrokeWidth(2.f); | 238 strokeA.setStrokeWidth(2.f); |
196 setter(&strokeA, a); | 239 setter(&strokeA, a); |
197 SkPaint strokeB; | 240 SkPaint strokeB; |
198 strokeB.setStyle(SkPaint::kStroke_Style); | 241 strokeB.setStyle(SkPaint::kStroke_Style); |
199 strokeB.setStrokeWidth(2.f); | 242 strokeB.setStrokeWidth(2.f); |
200 setter(&strokeB, b); | 243 setter(&strokeB, b); |
201 | 244 |
202 TestCase strokeACase(rrect, strokeA); | 245 TestCase strokeACase(geo, strokeA); |
203 TestCase strokeBCase(rrect, strokeB); | 246 TestCase strokeBCase(geo, strokeB); |
204 strokeACase.compare(reporter, strokeBCase, TestCase::kSameUpToStroke_Compari sonExpecation); | 247 strokeACase.compare(reporter, strokeBCase, TestCase::kSameUpToStroke_Compari sonExpecation); |
205 | 248 |
206 // Make sure stroking params don't affect fill style. | 249 // Make sure stroking params don't affect fill style. |
207 SkPaint fillA = strokeA, fillB = strokeB; | 250 SkPaint fillA = strokeA, fillB = strokeB; |
208 fillA.setStyle(SkPaint::kFill_Style); | 251 fillA.setStyle(SkPaint::kFill_Style); |
209 fillB.setStyle(SkPaint::kFill_Style); | 252 fillB.setStyle(SkPaint::kFill_Style); |
210 TestCase fillACase(rrect, fillA); | 253 TestCase fillACase(geo, fillA); |
211 TestCase fillBCase(rrect, fillB); | 254 TestCase fillBCase(geo, fillB); |
212 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecati on); | 255 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecati on); |
213 | 256 |
214 // Make sure just applying the dash but not stroke gives the same key for bo th stroking | 257 // Make sure just applying the dash but not stroke gives the same key for bo th stroking |
215 // variations. | 258 // variations. |
216 SkPaint dashA = strokeA, dashB = strokeB; | 259 SkPaint dashA = strokeA, dashB = strokeB; |
217 dashA.setPathEffect(make_dash()); | 260 dashA.setPathEffect(make_dash()); |
218 dashB.setPathEffect(make_dash()); | 261 dashB.setPathEffect(make_dash()); |
219 TestCase dashACase(rrect, dashA); | 262 TestCase dashACase(geo, dashA); |
220 TestCase dashBCase(rrect, dashB); | 263 TestCase dashBCase(geo, dashB); |
221 dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonE xpecation); | 264 dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonE xpecation); |
222 } | 265 } |
223 | 266 |
224 static void test_miter_limit(skiatest::Reporter* reporter, const SkRRect& rrect) { | 267 template <typename GEO> |
268 static void test_miter_limit(skiatest::Reporter* reporter, const GEO& geo) { | |
225 // Miter limit should only matter when stroking with miter joins. It shouldn 't affect other | 269 // Miter limit should only matter when stroking with miter joins. It shouldn 't affect other |
226 // joins or fills. | 270 // joins or fills. |
227 SkPaint miterA; | 271 SkPaint miterA; |
228 miterA.setStyle(SkPaint::kStroke_Style); | 272 miterA.setStyle(SkPaint::kStroke_Style); |
229 miterA.setStrokeWidth(2.f); | 273 miterA.setStrokeWidth(2.f); |
230 miterA.setStrokeJoin(SkPaint::kMiter_Join); | 274 miterA.setStrokeJoin(SkPaint::kMiter_Join); |
231 miterA.setStrokeMiter(0.5f); | 275 miterA.setStrokeMiter(0.5f); |
232 SkPaint miterB = miterA; | 276 SkPaint miterB = miterA; |
233 miterA.setStrokeMiter(0.6f); | 277 miterA.setStrokeMiter(0.6f); |
234 | 278 |
235 TestCase miterACase(rrect, miterA); | 279 TestCase miterACase(geo, miterA); |
236 TestCase miterBCase(rrect, miterB); | 280 TestCase miterBCase(geo, miterB); |
237 miterACase.compare(reporter, miterBCase, TestCase::kSameUpToStroke_Compariso nExpecation); | 281 miterACase.compare(reporter, miterBCase, TestCase::kSameUpToStroke_Compariso nExpecation); |
238 | 282 |
239 SkPaint noMiterA = miterA, noMiterB = miterB; | 283 SkPaint noMiterA = miterA, noMiterB = miterB; |
240 noMiterA.setStrokeJoin(SkPaint::kRound_Join); | 284 noMiterA.setStrokeJoin(SkPaint::kRound_Join); |
241 noMiterB.setStrokeJoin(SkPaint::kRound_Join); | 285 noMiterB.setStrokeJoin(SkPaint::kRound_Join); |
242 TestCase noMiterACase(rrect, noMiterA); | 286 TestCase noMiterACase(geo, noMiterA); |
243 TestCase noMiterBCase(rrect, noMiterB); | 287 TestCase noMiterBCase(geo, noMiterB); |
244 noMiterACase.compare(reporter, noMiterBCase, TestCase::kAllSame_ComparisonEx pecation); | 288 noMiterACase.compare(reporter, noMiterBCase, TestCase::kAllSame_ComparisonEx pecation); |
245 | 289 |
246 SkPaint fillA = miterA, fillB = miterB; | 290 SkPaint fillA = miterA, fillB = miterB; |
247 fillA.setStyle(SkPaint::kFill_Style); | 291 fillA.setStyle(SkPaint::kFill_Style); |
248 fillB.setStyle(SkPaint::kFill_Style); | 292 fillB.setStyle(SkPaint::kFill_Style); |
249 TestCase fillACase(rrect, fillA); | 293 TestCase fillACase(geo, fillA); |
250 TestCase fillBCase(rrect, fillB); | 294 TestCase fillBCase(geo, fillB); |
251 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecati on); | 295 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecati on); |
252 } | 296 } |
253 | 297 |
254 static void test_dash_fill(skiatest::Reporter* reporter, const SkRRect& rrect) { | 298 template<typename GEO> |
299 static void test_dash_fill(skiatest::Reporter* reporter, const GEO& geo) { | |
255 // A dash with no stroke should have no effect | 300 // A dash with no stroke should have no effect |
256 using DashFactoryFn = sk_sp<SkPathEffect>(*)(); | 301 using DashFactoryFn = sk_sp<SkPathEffect>(*)(); |
257 for (DashFactoryFn md : {&make_dash, &make_null_dash}) { | 302 for (DashFactoryFn md : {&make_dash, &make_null_dash}) { |
258 SkPaint dashFill; | 303 SkPaint dashFill; |
259 dashFill.setPathEffect((*md)()); | 304 dashFill.setPathEffect((*md)()); |
260 TestCase dashFillCase(rrect, dashFill); | 305 TestCase dashFillCase(geo, dashFill); |
261 | 306 |
262 TestCase fillCase(rrect, SkPaint()); | 307 TestCase fillCase(geo, SkPaint()); |
263 dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonEx pecation); | 308 dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonEx pecation); |
264 } | 309 } |
265 } | 310 } |
266 | 311 |
267 void test_null_dash(skiatest::Reporter* reporter, const SkRRect& rrect) { | 312 template<typename GEO> |
313 void test_null_dash(skiatest::Reporter* reporter, const GEO& geo) { | |
268 SkPaint fill; | 314 SkPaint fill; |
269 SkPaint stroke; | 315 SkPaint stroke; |
270 stroke.setStyle(SkPaint::kStroke_Style); | 316 stroke.setStyle(SkPaint::kStroke_Style); |
271 stroke.setStrokeWidth(1.f); | 317 stroke.setStrokeWidth(1.f); |
272 SkPaint dash; | 318 SkPaint dash; |
273 dash.setStyle(SkPaint::kStroke_Style); | 319 dash.setStyle(SkPaint::kStroke_Style); |
274 dash.setStrokeWidth(1.f); | 320 dash.setStrokeWidth(1.f); |
275 dash.setPathEffect(make_dash()); | 321 dash.setPathEffect(make_dash()); |
276 SkPaint nullDash; | 322 SkPaint nullDash; |
277 nullDash.setStyle(SkPaint::kStroke_Style); | 323 nullDash.setStyle(SkPaint::kStroke_Style); |
278 nullDash.setStrokeWidth(1.f); | 324 nullDash.setStrokeWidth(1.f); |
279 nullDash.setPathEffect(make_null_dash()); | 325 nullDash.setPathEffect(make_null_dash()); |
280 | 326 |
281 TestCase fillCase(rrect, fill); | 327 TestCase fillCase(geo, fill); |
282 TestCase strokeCase(rrect, stroke); | 328 TestCase strokeCase(geo, stroke); |
283 TestCase dashCase(rrect, dash); | 329 TestCase dashCase(geo, dash); |
284 TestCase nullDashCase(rrect, nullDash); | 330 TestCase nullDashCase(geo, nullDash); |
285 | 331 |
286 nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_Compariso nExpecation); | 332 nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_Compariso nExpecation); |
287 nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpe cation); | 333 nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpe cation); |
288 nullDashCase.compare(reporter, dashCase, TestCase::kSameUpToPE_ComparisonExp ecation); | 334 nullDashCase.compare(reporter, dashCase, TestCase::kSameUpToPE_ComparisonExp ecation); |
289 } | 335 } |
290 | 336 |
337 template <typename GEO> | |
338 void test_path_effect_makes_rrect(skiatest::Reporter* reporter, const GEO& geo) { | |
339 /** | |
340 * This path effect takes any input path and turns it into a rrect. It passe s through stroke | |
341 * info. | |
342 */ | |
343 class RRectPathEffect : SkPathEffect { | |
344 public: | |
345 static const SkRRect& RRect() { | |
346 static const SkRRect kRRect = SkRRect::MakeRectXY(SkRect::MakeWH(12, 12), 3, 5); | |
347 return kRRect; | |
348 } | |
349 | |
350 bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, | |
351 const SkRect* cullR) const override { | |
352 dst->reset(); | |
353 dst->addRRect(RRect()); | |
354 return true; | |
355 } | |
356 void computeFastBounds(SkRect* dst, const SkRect& src) const override { | |
357 *dst = RRect().getBounds(); | |
358 } | |
359 static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new RRect PathEffect); } | |
360 Factory getFactory() const override { return nullptr; } | |
361 void toString(SkString*) const override {} | |
362 private: | |
363 RRectPathEffect() {} | |
364 }; | |
365 | |
366 SkPaint fill; | |
367 TestCase fillGeoCase(geo, fill); | |
368 | |
369 SkPaint pe; | |
370 pe.setPathEffect(RRectPathEffect::Make()); | |
371 TestCase geoPECase(geo, pe); | |
372 | |
373 SkPaint peStroke; | |
374 peStroke.setPathEffect(RRectPathEffect::Make()); | |
375 peStroke.setStrokeWidth(2.f); | |
376 peStroke.setStyle(SkPaint::kStroke_Style); | |
377 TestCase geoPEStrokeCase(geo, peStroke); | |
378 | |
379 fillGeoCase.compare(reporter, geoPECase, TestCase::kSameUpToPE_ComparisonExp ecation); | |
380 fillGeoCase.compare(reporter, geoPEStrokeCase, TestCase::kSameUpToPE_Compari sonExpecation); | |
381 geoPECase.compare(reporter, geoPEStrokeCase, | |
382 TestCase::kSameUpToStroke_ComparisonExpecation); | |
383 | |
384 TestCase rrectFillCase(RRectPathEffect::RRect(), fill); | |
385 SkPaint stroke = peStroke; | |
386 stroke.setPathEffect(nullptr); | |
387 TestCase rrectStrokeCase(RRectPathEffect::RRect(), stroke); | |
388 | |
389 SkRRect rrect; | |
390 // Applying the path effect should make a SkRRect shape. There is no further stroking in the | |
391 // geoPECase, so the full style should be the same as just the PE. | |
392 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectShape().asRRect(&rrect) ); | |
393 REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect()); | |
394 REPORTER_ASSERT(reporter, geoPECase.appliedPathEffectKey() == rrectFillCase. baseKey()); | |
395 | |
396 REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleShape().asRRect(&rrect)) ; | |
397 REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect()); | |
398 REPORTER_ASSERT(reporter, geoPECase.appliedFullStyleKey() == rrectFillCase.b aseKey()); | |
399 | |
400 // In the PE+stroke case applying the full style should be the same as just stroking the rrect. | |
401 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectShape().asRRect(& rrect)); | |
402 REPORTER_ASSERT(reporter, rrect == RRectPathEffect::RRect()); | |
403 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedPathEffectKey() == rrectFil lCase.baseKey()); | |
404 | |
405 REPORTER_ASSERT(reporter, !geoPEStrokeCase.appliedFullStyleShape().asRRect(& rrect)); | |
406 REPORTER_ASSERT(reporter, geoPEStrokeCase.appliedFullStyleKey() == | |
407 rrectStrokeCase.appliedFullStyleKey()); | |
408 } | |
409 | |
410 template <typename GEO> | |
411 void test_unknown_path_effect(skiatest::Reporter* reporter, const GEO& geo) { | |
412 /** | |
413 * This path effect just adds two lineTos to the input path. | |
414 */ | |
415 class AddLineTosPathEffect : SkPathEffect { | |
416 public: | |
417 bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, | |
418 const SkRect* cullR) const override { | |
419 *dst = src; | |
420 dst->lineTo(0, 0); | |
421 dst->lineTo(10, 10); | |
422 return true; | |
423 } | |
424 void computeFastBounds(SkRect* dst, const SkRect& src) const override { | |
425 *dst = src; | |
426 dst->growToInclude(0, 0); | |
427 dst->growToInclude(10, 10); | |
428 } | |
429 static sk_sp<SkPathEffect> Make() { return sk_sp<SkPathEffect>(new AddLi neTosPathEffect); } | |
430 Factory getFactory() const override { return nullptr; } | |
431 void toString(SkString*) const override {} | |
432 private: | |
433 AddLineTosPathEffect() {} | |
434 }; | |
435 | |
436 /** This path effect should make the keys invalid when it is applied. */ | |
robertphillips
2016/04/26 22:18:32
Could you expand on this a bit?
bsalomon
2016/04/29 23:12:06
Done.
// This path effect should make the ke
| |
437 SkPaint peStroke; | |
438 peStroke.setPathEffect(AddLineTosPathEffect::Make()); | |
439 peStroke.setStrokeWidth(2.f); | |
440 peStroke.setStyle(SkPaint::kStroke_Style); | |
441 TestCase geoPEStrokeCase(geo, peStroke); | |
442 TestCase::SelfExpectations expectations; | |
443 expectations.fPEHasEffect = true; | |
444 expectations.fPEHasValidKey = false; | |
445 expectations.fStrokeApplies = true; | |
446 geoPEStrokeCase.testExpectations(reporter, expectations); | |
447 } | |
448 | |
291 DEF_TEST(GrShape, reporter) { | 449 DEF_TEST(GrShape, reporter) { |
292 sk_sp<SkPathEffect> dashPE = make_dash(); | 450 sk_sp<SkPathEffect> dashPE = make_dash(); |
293 | 451 |
294 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)), | 452 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)), |
295 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4)}) { | 453 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4)}) { |
296 test_basic(reporter, rr); | 454 test_basic(reporter, rr); |
297 test_dash_fill(reporter, rr); | 455 test_dash_fill(reporter, rr); |
298 test_null_dash(reporter, rr); | 456 test_null_dash(reporter, rr); |
299 // Test modifying various stroke params. | 457 // Test modifying various stroke params. |
300 test_stroke_param<SkScalar>( | 458 test_stroke_param<SkRRect, SkScalar>( |
301 reporter, rr, | 459 reporter, rr, |
302 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, | 460 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, |
303 SkIntToScalar(2), SkIntToScalar(4)); | 461 SkIntToScalar(2), SkIntToScalar(4)); |
304 test_stroke_param<SkPaint::Cap>( | 462 test_stroke_param<SkRRect, SkPaint::Cap>( |
305 reporter, rr, | 463 reporter, rr, |
306 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, | 464 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, |
307 SkPaint::kButt_Cap, SkPaint::kRound_Cap); | 465 SkPaint::kButt_Cap, SkPaint::kRound_Cap); |
308 test_stroke_param<SkPaint::Join>( | 466 test_stroke_param<SkRRect, SkPaint::Join>( |
309 reporter, rr, | 467 reporter, rr, |
310 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j); }, | 468 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j); }, |
311 SkPaint::kMiter_Join, SkPaint::kRound_Join); | 469 SkPaint::kMiter_Join, SkPaint::kRound_Join); |
312 test_miter_limit(reporter, rr); | 470 test_miter_limit(reporter, rr); |
471 test_path_effect_makes_rrect(reporter, rr); | |
472 test_unknown_path_effect(reporter, rr); | |
473 } | |
474 | |
475 struct TestPath { | |
476 TestPath(const SkPath& path, bool isRRectFill, bool isRRectStroke ,const SkRRect& rrect) | |
477 : fPath(path) | |
478 , fIsRRectForFill(isRRectFill) | |
479 , fIsRRectForStroke(isRRectStroke) | |
480 , fRRect(rrect) {} | |
481 SkPath fPath; | |
482 bool fIsRRectForFill; | |
483 bool fIsRRectForStroke; | |
484 SkRRect fRRect; | |
485 }; | |
486 SkTArray<TestPath> paths; | |
487 | |
488 SkPath circlePath; | |
489 circlePath.addCircle(10, 10, 10); | |
490 paths.emplace_back(circlePath, true, true, SkRRect::MakeOval(SkRect::MakeWH( 20,20))); | |
491 | |
492 SkPath rectPath; | |
493 rectPath.addRect(SkRect::MakeWH(10, 10)); | |
494 paths.emplace_back(rectPath, true, true, SkRRect::MakeRect(SkRect::MakeWH(10 , 10))); | |
495 | |
496 SkPath openRectPath; | |
497 openRectPath.moveTo(0, 0); | |
498 openRectPath.lineTo(10, 0); | |
499 openRectPath.lineTo(10, 10); | |
500 openRectPath.lineTo(0, 10); | |
501 paths.emplace_back(openRectPath, true, false, SkRRect::MakeRect(SkRect::Make WH(10, 10))); | |
502 | |
503 SkPath quadPath; | |
504 quadPath.quadTo(10, 10, 5, 8); | |
505 paths.emplace_back(quadPath, false, false, SkRRect()); | |
506 | |
507 for (auto testPath : paths) { | |
508 const SkPath& path = testPath.fPath; | |
robertphillips
2016/04/26 22:18:32
Theses tests all that the ?
bsalomon
2016/04/29 23:12:06
Done.
"These tests all assume that"
| |
509 // Theses tests all that the original GrShape for fill and stroke will b e the same. However, | |
510 // that is not the case in special cases (e.g. a unclosed rect becomes a RRect GrShape with | |
511 // a fill style but becomes a Path GrShape when stroked). | |
512 if (testPath.fIsRRectForFill == testPath.fIsRRectForStroke) { | |
513 test_basic(reporter, path); | |
514 test_null_dash(reporter, path); | |
515 test_path_effect_makes_rrect(reporter, path); | |
516 } | |
517 test_dash_fill(reporter, path); | |
518 // Test modifying various stroke params. | |
519 test_stroke_param<SkPath, SkScalar>( | |
520 reporter, path, | |
521 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, | |
522 SkIntToScalar(2), SkIntToScalar(4)); | |
523 test_stroke_param<SkPath, SkPaint::Cap>( | |
524 reporter, path, | |
525 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, | |
526 SkPaint::kButt_Cap, SkPaint::kRound_Cap); | |
527 test_stroke_param<SkPath, SkPaint::Join>( | |
528 reporter, path, | |
529 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);}, | |
530 SkPaint::kMiter_Join, SkPaint::kRound_Join); | |
531 test_miter_limit(reporter, path); | |
532 test_unknown_path_effect(reporter, path); | |
533 | |
534 SkPaint fillPaint; | |
535 TestCase fillPathCase(path, fillPaint); | |
536 SkRRect rrect; | |
537 REPORTER_ASSERT(reporter, testPath.fIsRRectForFill == | |
538 fillPathCase.baseShape().asRRect(&rrect)); | |
539 if (testPath.fIsRRectForFill) { | |
540 REPORTER_ASSERT(reporter, rrect == testPath.fRRect); | |
541 TestCase fillRRectCase(rrect, fillPaint); | |
542 fillPathCase.compare(reporter, fillRRectCase, TestCase::kAllSame_Com parisonExpecation); | |
543 } | |
544 | |
545 SkPaint strokePaint; | |
546 strokePaint.setStrokeWidth(3.f); | |
547 strokePaint.setStyle(SkPaint::kStroke_Style); | |
548 TestCase strokePathCase(path, strokePaint); | |
549 REPORTER_ASSERT(reporter, testPath.fIsRRectForStroke == | |
550 strokePathCase.baseShape().asRRect(&rrect)); | |
551 if (testPath.fIsRRectForStroke) { | |
552 REPORTER_ASSERT(reporter, rrect == testPath.fRRect); | |
553 TestCase strokeRRectCase(rrect, strokePaint); | |
554 strokePathCase.compare(reporter, strokeRRectCase, | |
555 TestCase::kAllSame_ComparisonExpecation); | |
556 } | |
313 } | 557 } |
314 } | 558 } |
315 | 559 |
316 #endif | 560 #endif |
OLD | NEW |