OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #include <initializer_list> |
| 9 #include <functional> |
| 10 #include "Test.h" |
| 11 #if SK_SUPPORT_GPU |
| 12 #include "GrShape.h" |
| 13 #include "SkPath.h" |
| 14 #include "SkDashPathEffect.h" |
| 15 |
| 16 namespace { |
| 17 class TestCase { |
| 18 public: |
| 19 TestCase(const SkRRect& rrect, const SkPaint& paint) : fBase(rrect, paint) { |
| 20 this->init(); |
| 21 } |
| 22 |
| 23 struct SelfExpectations { |
| 24 bool fPEHasEffect; |
| 25 bool fPEHasValidKey; |
| 26 bool fStrokeApplies; |
| 27 }; |
| 28 |
| 29 void testExpectations(skiatest::Reporter* reporter, SelfExpectations expecta
tions) const; |
| 30 |
| 31 enum ComparisonExpecation { |
| 32 kAllDifferent_ComparisonExpecation, |
| 33 kSameUpToPE_ComparisonExpecation, |
| 34 kSameUpToStroke_ComparisonExpecation, |
| 35 kAllSame_ComparisonExpecation, |
| 36 }; |
| 37 |
| 38 void compare(skiatest::Reporter*, const TestCase& that, ComparisonExpecation
) const; |
| 39 |
| 40 private: |
| 41 void init() { |
| 42 fAppliedPE = fBase.applyPathEffect(); |
| 43 fAppliedPEThenStroke = fAppliedPE.applyFullStyle(); |
| 44 fAppliedFull = fBase.applyFullStyle(); |
| 45 |
| 46 fBaseKeyIsValid = MakeKey(&fBaseKey, fBase); |
| 47 fAppliedPEKeyIsValid = MakeKey(&fAppliedPEKey, fAppliedPE); |
| 48 fAppliedPEThenStrokeKeyIsValid = MakeKey(&fAppliedPEThenStrokeKey, fAppl
iedPEThenStroke); |
| 49 fAppliedFullKeyIsValid = MakeKey(&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 } |
| 63 |
| 64 GrShape fBase; |
| 65 GrShape fAppliedPE; |
| 66 GrShape fAppliedPEThenStroke; |
| 67 GrShape fAppliedFull; |
| 68 |
| 69 Key fBaseKey; |
| 70 Key fAppliedPEKey; |
| 71 Key fAppliedPEThenStrokeKey; |
| 72 Key fAppliedFullKey; |
| 73 |
| 74 bool fBaseKeyIsValid; |
| 75 bool fAppliedPEKeyIsValid; |
| 76 bool fAppliedPEThenStrokeKeyIsValid; |
| 77 bool fAppliedFullKeyIsValid; |
| 78 }; |
| 79 |
| 80 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 |
| 82 // both in one go. |
| 83 REPORTER_ASSERT(reporter, fAppliedPEThenStrokeKey == fAppliedFullKey); |
| 84 // The base's key should always be valid (unless the path is volatile) |
| 85 REPORTER_ASSERT(reporter, fBaseKeyIsValid); |
| 86 if (expectations.fPEHasEffect) { |
| 87 REPORTER_ASSERT(reporter, fBaseKey != fAppliedPEKey); |
| 88 REPORTER_ASSERT(reporter, expectations.fPEHasEffect == fAppliedPEKeyIsVa
lid); |
| 89 REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey); |
| 90 REPORTER_ASSERT(reporter, expectations.fPEHasEffect == fAppliedFullKeyIs
Valid); |
| 91 if (expectations.fStrokeApplies && expectations.fPEHasValidKey) { |
| 92 REPORTER_ASSERT(reporter, fAppliedPEKey != fAppliedFullKey); |
| 93 REPORTER_ASSERT(reporter, expectations.fPEHasEffect == fAppliedFullK
eyIsValid); |
| 94 } |
| 95 } else { |
| 96 REPORTER_ASSERT(reporter, fBaseKey == fAppliedPEKey); |
| 97 if (expectations.fStrokeApplies) { |
| 98 REPORTER_ASSERT(reporter, fBaseKey != fAppliedFullKey); |
| 99 } else { |
| 100 REPORTER_ASSERT(reporter, fBaseKey == fAppliedFullKey); |
| 101 } |
| 102 } |
| 103 } |
| 104 |
| 105 void TestCase::compare(skiatest::Reporter* reporter, const TestCase& that, |
| 106 ComparisonExpecation expectation) const { |
| 107 switch (expectation) { |
| 108 case kAllDifferent_ComparisonExpecation: |
| 109 REPORTER_ASSERT(reporter, fBaseKey != that.fBaseKey); |
| 110 REPORTER_ASSERT(reporter, fAppliedPEKey != that.fAppliedPEKey); |
| 111 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); |
| 112 break; |
| 113 case kSameUpToPE_ComparisonExpecation: |
| 114 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); |
| 115 REPORTER_ASSERT(reporter, fAppliedPEKey != that.fAppliedPEKey); |
| 116 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); |
| 117 break; |
| 118 case kSameUpToStroke_ComparisonExpecation: |
| 119 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); |
| 120 REPORTER_ASSERT(reporter, fAppliedPEKey == that.fAppliedPEKey); |
| 121 REPORTER_ASSERT(reporter, fAppliedFullKey != that.fAppliedFullKey); |
| 122 break; |
| 123 case kAllSame_ComparisonExpecation: |
| 124 REPORTER_ASSERT(reporter, fBaseKey == that.fBaseKey); |
| 125 REPORTER_ASSERT(reporter, fAppliedPEKey == that.fAppliedPEKey); |
| 126 REPORTER_ASSERT(reporter, fAppliedFullKey == that.fAppliedFullKey); |
| 127 break; |
| 128 } |
| 129 } |
| 130 } // namespace |
| 131 |
| 132 static sk_sp<SkPathEffect> make_dash() { |
| 133 static const SkScalar kIntervals[] = { 0.25, 3.f, 0.5, 2.f }; |
| 134 static const SkScalar kPhase = 0.75; |
| 135 return SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), kPhase
); |
| 136 } |
| 137 |
| 138 static sk_sp<SkPathEffect> make_null_dash() { |
| 139 static const SkScalar kNullIntervals[] = {0, 0, 0, 0, 0, 0}; |
| 140 return SkDashPathEffect::Make(kNullIntervals, SK_ARRAY_COUNT(kNullIntervals)
, 0.f); |
| 141 } |
| 142 |
| 143 static void test_basic(skiatest::Reporter* reporter, const SkRRect& rrect) { |
| 144 sk_sp<SkPathEffect> dashPE = make_dash(); |
| 145 |
| 146 TestCase::SelfExpectations expectations; |
| 147 SkPaint fill; |
| 148 |
| 149 TestCase fillCase(rrect, fill); |
| 150 expectations.fPEHasEffect = false; |
| 151 expectations.fPEHasValidKey = false; |
| 152 expectations.fStrokeApplies = false; |
| 153 fillCase.testExpectations(reporter, expectations); |
| 154 // 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); |
| 156 |
| 157 SkPaint stroke2RoundBevel; |
| 158 stroke2RoundBevel.setStyle(SkPaint::kStroke_Style); |
| 159 stroke2RoundBevel.setStrokeCap(SkPaint::kRound_Cap); |
| 160 stroke2RoundBevel.setStrokeJoin(SkPaint::kBevel_Join); |
| 161 stroke2RoundBevel.setStrokeWidth(2.f); |
| 162 TestCase stroke2RoundBevelCase(rrect, stroke2RoundBevel); |
| 163 expectations.fPEHasValidKey = true; |
| 164 expectations.fPEHasEffect = false; |
| 165 expectations.fStrokeApplies = true; |
| 166 stroke2RoundBevelCase.testExpectations(reporter, expectations); |
| 167 TestCase(rrect, stroke2RoundBevel).compare(reporter, stroke2RoundBevelCase, |
| 168 TestCase::kAllSame_ComparisonExpe
cation); |
| 169 |
| 170 SkPaint stroke2RoundBevelDash = stroke2RoundBevel; |
| 171 stroke2RoundBevelDash.setPathEffect(make_dash()); |
| 172 TestCase stroke2RoundBevelDashCase(rrect, stroke2RoundBevelDash); |
| 173 expectations.fPEHasValidKey = true; |
| 174 expectations.fPEHasEffect = true; |
| 175 expectations.fStrokeApplies = true; |
| 176 stroke2RoundBevelDashCase.testExpectations(reporter, expectations); |
| 177 TestCase(rrect, stroke2RoundBevelDash).compare(reporter, stroke2RoundBevelDa
shCase, |
| 178 TestCase::kAllSame_Comparison
Expecation); |
| 179 |
| 180 fillCase.compare(reporter, stroke2RoundBevelCase, |
| 181 TestCase::kSameUpToStroke_ComparisonExpecation); |
| 182 fillCase.compare(reporter, stroke2RoundBevelDashCase, |
| 183 TestCase::kSameUpToPE_ComparisonExpecation); |
| 184 stroke2RoundBevelCase.compare(reporter, stroke2RoundBevelDashCase, |
| 185 TestCase::kSameUpToPE_ComparisonExpecation); |
| 186 } |
| 187 |
| 188 template <typename T> |
| 189 static void test_stroke_param(skiatest::Reporter* reporter, const SkRRect& rrect
, |
| 190 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 |
| 192 // it can override. |
| 193 SkPaint strokeA; |
| 194 strokeA.setStyle(SkPaint::kStroke_Style); |
| 195 strokeA.setStrokeWidth(2.f); |
| 196 setter(&strokeA, a); |
| 197 SkPaint strokeB; |
| 198 strokeB.setStyle(SkPaint::kStroke_Style); |
| 199 strokeB.setStrokeWidth(2.f); |
| 200 setter(&strokeB, b); |
| 201 |
| 202 TestCase strokeACase(rrect, strokeA); |
| 203 TestCase strokeBCase(rrect, strokeB); |
| 204 strokeACase.compare(reporter, strokeBCase, TestCase::kSameUpToStroke_Compari
sonExpecation); |
| 205 |
| 206 // Make sure stroking params don't affect fill style. |
| 207 SkPaint fillA = strokeA, fillB = strokeB; |
| 208 fillA.setStyle(SkPaint::kFill_Style); |
| 209 fillB.setStyle(SkPaint::kFill_Style); |
| 210 TestCase fillACase(rrect, fillA); |
| 211 TestCase fillBCase(rrect, fillB); |
| 212 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecati
on); |
| 213 |
| 214 // Make sure just applying the dash but not stroke gives the same key for bo
th stroking |
| 215 // variations. |
| 216 SkPaint dashA = strokeA, dashB = strokeB; |
| 217 dashA.setPathEffect(make_dash()); |
| 218 dashB.setPathEffect(make_dash()); |
| 219 TestCase dashACase(rrect, dashA); |
| 220 TestCase dashBCase(rrect, dashB); |
| 221 dashACase.compare(reporter, dashBCase, TestCase::kSameUpToStroke_ComparisonE
xpecation); |
| 222 } |
| 223 |
| 224 static void test_miter_limit(skiatest::Reporter* reporter, const SkRRect& rrect)
{ |
| 225 // Miter limit should only matter when stroking with miter joins. It shouldn
't affect other |
| 226 // joins or fills. |
| 227 SkPaint miterA; |
| 228 miterA.setStyle(SkPaint::kStroke_Style); |
| 229 miterA.setStrokeWidth(2.f); |
| 230 miterA.setStrokeJoin(SkPaint::kMiter_Join); |
| 231 miterA.setStrokeMiter(0.5f); |
| 232 SkPaint miterB = miterA; |
| 233 miterA.setStrokeMiter(0.6f); |
| 234 |
| 235 TestCase miterACase(rrect, miterA); |
| 236 TestCase miterBCase(rrect, miterB); |
| 237 miterACase.compare(reporter, miterBCase, TestCase::kSameUpToStroke_Compariso
nExpecation); |
| 238 |
| 239 SkPaint noMiterA = miterA, noMiterB = miterB; |
| 240 noMiterA.setStrokeJoin(SkPaint::kRound_Join); |
| 241 noMiterB.setStrokeJoin(SkPaint::kRound_Join); |
| 242 TestCase noMiterACase(rrect, noMiterA); |
| 243 TestCase noMiterBCase(rrect, noMiterB); |
| 244 noMiterACase.compare(reporter, noMiterBCase, TestCase::kAllSame_ComparisonEx
pecation); |
| 245 |
| 246 SkPaint fillA = miterA, fillB = miterB; |
| 247 fillA.setStyle(SkPaint::kFill_Style); |
| 248 fillB.setStyle(SkPaint::kFill_Style); |
| 249 TestCase fillACase(rrect, fillA); |
| 250 TestCase fillBCase(rrect, fillB); |
| 251 fillACase.compare(reporter, fillBCase, TestCase::kAllSame_ComparisonExpecati
on); |
| 252 } |
| 253 |
| 254 static void test_dash_fill(skiatest::Reporter* reporter, const SkRRect& rrect) { |
| 255 // A dash with no stroke should have no effect |
| 256 using DashFactoryFn = sk_sp<SkPathEffect>(*)(); |
| 257 for (DashFactoryFn md : {&make_dash, &make_null_dash}) { |
| 258 SkPaint dashFill; |
| 259 dashFill.setPathEffect((*md)()); |
| 260 TestCase dashFillCase(rrect, dashFill); |
| 261 |
| 262 TestCase fillCase(rrect, SkPaint()); |
| 263 dashFillCase.compare(reporter, fillCase, TestCase::kAllSame_ComparisonEx
pecation); |
| 264 } |
| 265 } |
| 266 |
| 267 void test_null_dash(skiatest::Reporter* reporter, const SkRRect& rrect) { |
| 268 SkPaint fill; |
| 269 SkPaint stroke; |
| 270 stroke.setStyle(SkPaint::kStroke_Style); |
| 271 stroke.setStrokeWidth(1.f); |
| 272 SkPaint dash; |
| 273 dash.setStyle(SkPaint::kStroke_Style); |
| 274 dash.setStrokeWidth(1.f); |
| 275 dash.setPathEffect(make_dash()); |
| 276 SkPaint nullDash; |
| 277 nullDash.setStyle(SkPaint::kStroke_Style); |
| 278 nullDash.setStrokeWidth(1.f); |
| 279 nullDash.setPathEffect(make_null_dash()); |
| 280 |
| 281 TestCase fillCase(rrect, fill); |
| 282 TestCase strokeCase(rrect, stroke); |
| 283 TestCase dashCase(rrect, dash); |
| 284 TestCase nullDashCase(rrect, nullDash); |
| 285 |
| 286 nullDashCase.compare(reporter, fillCase, TestCase::kSameUpToStroke_Compariso
nExpecation); |
| 287 nullDashCase.compare(reporter, strokeCase, TestCase::kAllSame_ComparisonExpe
cation); |
| 288 nullDashCase.compare(reporter, dashCase, TestCase::kSameUpToPE_ComparisonExp
ecation); |
| 289 } |
| 290 |
| 291 DEF_TEST(GrShape, reporter) { |
| 292 sk_sp<SkPathEffect> dashPE = make_dash(); |
| 293 |
| 294 for (auto rr : { SkRRect::MakeRect(SkRect::MakeWH(10, 10)), |
| 295 SkRRect::MakeRectXY(SkRect::MakeWH(10, 10), 3, 4)}) { |
| 296 test_basic(reporter, rr); |
| 297 test_dash_fill(reporter, rr); |
| 298 test_null_dash(reporter, rr); |
| 299 // Test modifying various stroke params. |
| 300 test_stroke_param<SkScalar>( |
| 301 reporter, rr, |
| 302 [](SkPaint* p, SkScalar w) { p->setStrokeWidth(w);}, |
| 303 SkIntToScalar(2), SkIntToScalar(4)); |
| 304 test_stroke_param<SkPaint::Cap>( |
| 305 reporter, rr, |
| 306 [](SkPaint* p, SkPaint::Cap c) { p->setStrokeCap(c);}, |
| 307 SkPaint::kButt_Cap, SkPaint::kRound_Cap); |
| 308 test_stroke_param<SkPaint::Join>( |
| 309 reporter, rr, |
| 310 [](SkPaint* p, SkPaint::Join j) { p->setStrokeJoin(j);
}, |
| 311 SkPaint::kMiter_Join, SkPaint::kRound_Join); |
| 312 test_miter_limit(reporter, rr); |
| 313 } |
| 314 } |
| 315 |
| 316 #endif |
OLD | NEW |