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. We onl
y produce a pathe |
| 437 // effect key for dash path effects. So the only way another arbitrary path
effect can produce |
| 438 // a styled result with a key is to produce a non-path shape that has a pur
ely geometric key. |
| 439 SkPaint peStroke; |
| 440 peStroke.setPathEffect(AddLineTosPathEffect::Make()); |
| 441 peStroke.setStrokeWidth(2.f); |
| 442 peStroke.setStyle(SkPaint::kStroke_Style); |
| 443 TestCase geoPEStrokeCase(geo, peStroke); |
| 444 TestCase::SelfExpectations expectations; |
| 445 expectations.fPEHasEffect = true; |
| 446 expectations.fPEHasValidKey = false; |
| 447 expectations.fStrokeApplies = true; |
| 448 geoPEStrokeCase.testExpectations(reporter, expectations); |
| 449 } |
| 450 |
291 DEF_TEST(GrShape, reporter) { | 451 DEF_TEST(GrShape, reporter) { |
292 sk_sp<SkPathEffect> dashPE = make_dash(); | 452 sk_sp<SkPathEffect> dashPE = make_dash(); |
293 | 453 |
294 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)), | 454 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)), |
295 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4)}) { | 455 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4)}) { |
296 test_basic(reporter, rr); | 456 test_basic(reporter, rr); |
297 test_dash_fill(reporter, rr); | 457 test_dash_fill(reporter, rr); |
298 test_null_dash(reporter, rr); | 458 test_null_dash(reporter, rr); |
299 // Test modifying various stroke params. | 459 // Test modifying various stroke params. |
300 test_stroke_param<SkScalar>( | 460 test_stroke_param<SkRRect, SkScalar>( |
301 reporter, rr, | 461 reporter, rr, |
302 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, | 462 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, |
303 SkIntToScalar(2), SkIntToScalar(4)); | 463 SkIntToScalar(2), SkIntToScalar(4)); |
304 test_stroke_param<SkPaint::Cap>( | 464 test_stroke_param<SkRRect, SkPaint::Cap>( |
305 reporter, rr, | 465 reporter, rr, |
306 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, | 466 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, |
307 SkPaint::kButt_Cap, SkPaint::kRound_Cap); | 467 SkPaint::kButt_Cap, SkPaint::kRound_Cap); |
308 test_stroke_param<SkPaint::Join>( | 468 test_stroke_param<SkRRect, SkPaint::Join>( |
309 reporter, rr, | 469 reporter, rr, |
310 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);
}, | 470 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);
}, |
311 SkPaint::kMiter_Join, SkPaint::kRound_Join); | 471 SkPaint::kMiter_Join, SkPaint::kRound_Join); |
312 test_miter_limit(reporter, rr); | 472 test_miter_limit(reporter, rr); |
| 473 test_path_effect_makes_rrect(reporter, rr); |
| 474 test_unknown_path_effect(reporter, rr); |
| 475 } |
| 476 |
| 477 struct TestPath { |
| 478 TestPath(const SkPath& path, bool isRRectFill, bool isRRectStroke ,const
SkRRect& rrect) |
| 479 : fPath(path) |
| 480 , fIsRRectForFill(isRRectFill) |
| 481 , fIsRRectForStroke(isRRectStroke) |
| 482 , fRRect(rrect) {} |
| 483 SkPath fPath; |
| 484 bool fIsRRectForFill; |
| 485 bool fIsRRectForStroke; |
| 486 SkRRect fRRect; |
| 487 }; |
| 488 SkTArray<TestPath> paths; |
| 489 |
| 490 SkPath circlePath; |
| 491 circlePath.addCircle(10, 10, 10); |
| 492 paths.emplace_back(circlePath, true, true, SkRRect::MakeOval(SkRect::MakeWH(
20,20))); |
| 493 |
| 494 SkPath rectPath; |
| 495 rectPath.addRect(SkRect::MakeWH(10, 10)); |
| 496 paths.emplace_back(rectPath, true, true, SkRRect::MakeRect(SkRect::MakeWH(10
, 10))); |
| 497 |
| 498 SkPath openRectPath; |
| 499 openRectPath.moveTo(0, 0); |
| 500 openRectPath.lineTo(10, 0); |
| 501 openRectPath.lineTo(10, 10); |
| 502 openRectPath.lineTo(0, 10); |
| 503 paths.emplace_back(openRectPath, true, false, SkRRect::MakeRect(SkRect::Make
WH(10, 10))); |
| 504 |
| 505 SkPath quadPath; |
| 506 quadPath.quadTo(10, 10, 5, 8); |
| 507 paths.emplace_back(quadPath, false, false, SkRRect()); |
| 508 |
| 509 for (auto testPath : paths) { |
| 510 const SkPath& path = testPath.fPath; |
| 511 // These tests all assume that the original GrShape for fill and stroke
will be the same. |
| 512 // However, that is not the case in special cases (e.g. a unclosed rect
becomes a RRect |
| 513 // GrShape with a fill style but becomes a Path GrShape when stroked). |
| 514 if (testPath.fIsRRectForFill == testPath.fIsRRectForStroke) { |
| 515 test_basic(reporter, path); |
| 516 test_null_dash(reporter, path); |
| 517 test_path_effect_makes_rrect(reporter, path); |
| 518 } |
| 519 test_dash_fill(reporter, path); |
| 520 // Test modifying various stroke params. |
| 521 test_stroke_param<SkPath, SkScalar>( |
| 522 reporter, path, |
| 523 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, |
| 524 SkIntToScalar(2), SkIntToScalar(4)); |
| 525 test_stroke_param<SkPath, SkPaint::Cap>( |
| 526 reporter, path, |
| 527 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, |
| 528 SkPaint::kButt_Cap, SkPaint::kRound_Cap); |
| 529 test_stroke_param<SkPath, SkPaint::Join>( |
| 530 reporter, path, |
| 531 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);}, |
| 532 SkPaint::kMiter_Join, SkPaint::kRound_Join); |
| 533 test_miter_limit(reporter, path); |
| 534 test_unknown_path_effect(reporter, path); |
| 535 |
| 536 SkPaint fillPaint; |
| 537 TestCase fillPathCase(path, fillPaint); |
| 538 SkRRect rrect; |
| 539 REPORTER_ASSERT(reporter, testPath.fIsRRectForFill == |
| 540 fillPathCase.baseShape().asRRect(&rrect)); |
| 541 if (testPath.fIsRRectForFill) { |
| 542 REPORTER_ASSERT(reporter, rrect == testPath.fRRect); |
| 543 TestCase fillRRectCase(rrect, fillPaint); |
| 544 fillPathCase.compare(reporter, fillRRectCase, TestCase::kAllSame_Com
parisonExpecation); |
| 545 } |
| 546 |
| 547 SkPaint strokePaint; |
| 548 strokePaint.setStrokeWidth(3.f); |
| 549 strokePaint.setStyle(SkPaint::kStroke_Style); |
| 550 TestCase strokePathCase(path, strokePaint); |
| 551 REPORTER_ASSERT(reporter, testPath.fIsRRectForStroke == |
| 552 strokePathCase.baseShape().asRRect(&rrect)); |
| 553 if (testPath.fIsRRectForStroke) { |
| 554 REPORTER_ASSERT(reporter, rrect == testPath.fRRect); |
| 555 TestCase strokeRRectCase(rrect, strokePaint); |
| 556 strokePathCase.compare(reporter, strokeRRectCase, |
| 557 TestCase::kAllSame_ComparisonExpecation); |
| 558 } |
313 } | 559 } |
314 } | 560 } |
315 | 561 |
316 #endif | 562 #endif |
OLD | NEW |