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 "SkCanvas.h" |
| 14 #include "SkDashPathEffect.h" |
13 #include "SkPath.h" | 15 #include "SkPath.h" |
14 #include "SkDashPathEffect.h" | 16 #include "SkSurface.h" |
15 | 17 |
16 using Key = SkTArray<uint32_t>; | 18 using Key = SkTArray<uint32_t>; |
17 | 19 |
18 static bool make_key(Key* key, const GrShape& shape) { | 20 static bool make_key(Key* key, const GrShape& shape) { |
19 int size = shape.unstyledKeySize(); | 21 int size = shape.unstyledKeySize(); |
20 if (size <= 0) { | 22 if (size <= 0) { |
21 key->reset(0); | 23 key->reset(0); |
22 return false; | 24 return false; |
23 } | 25 } |
24 SkASSERT(size); | 26 SkASSERT(size); |
25 key->reset(size); | 27 key->reset(size); |
26 shape.writeUnstyledKey(key->begin()); | 28 shape.writeUnstyledKey(key->begin()); |
27 return true; | 29 return true; |
28 } | 30 } |
29 | 31 |
| 32 static bool test_bounds_by_rasterizing(const SkPath& path, const SkRect& bounds)
{ |
| 33 static constexpr int kRes = 2000; |
| 34 // This tolerance is in units of 1/kRes fractions of the bounds width/height
. |
| 35 static constexpr int kTol = 0; |
| 36 GR_STATIC_ASSERT(kRes % 4 == 0); |
| 37 SkImageInfo info = SkImageInfo::MakeA8(kRes, kRes); |
| 38 sk_sp<SkSurface> surface = SkSurface::MakeRaster(info); |
| 39 surface->getCanvas()->clear(0x0); |
| 40 SkRect clip = SkRect::MakeXYWH(kRes/4, kRes/4, kRes/2, kRes/2); |
| 41 SkMatrix matrix; |
| 42 matrix.setRectToRect(bounds, clip, SkMatrix::kFill_ScaleToFit); |
| 43 clip.outset(SkIntToScalar(kTol), SkIntToScalar(kTol)); |
| 44 surface->getCanvas()->clipRect(clip, SkRegion::kDifference_Op); |
| 45 surface->getCanvas()->concat(matrix); |
| 46 SkPaint whitePaint; |
| 47 whitePaint.setColor(SK_ColorWHITE); |
| 48 surface->getCanvas()->drawPath(path, whitePaint); |
| 49 SkPixmap pixmap; |
| 50 surface->getCanvas()->peekPixels(&pixmap); |
| 51 #if defined(SK_BUILD_FOR_WIN) |
| 52 // The static constexpr version in #else causes cl.exe to crash. |
| 53 const uint8_t* kZeros = reinterpret_cast<uint8_t*>(calloc(kRes, 1)); |
| 54 #else |
| 55 static constexpr uint8_t kZeros[kRes] = {0}; |
| 56 #endif |
| 57 for (int y = 0; y < kRes/4; ++y) { |
| 58 const uint8_t* row = pixmap.addr8(0, y); |
| 59 if (0 != memcmp(kZeros, row, kRes)) { |
| 60 return false; |
| 61 } |
| 62 } |
| 63 #ifdef SK_BUILD_FOR_WIN |
| 64 free(const_cast<uint8_t*>(kZeros)); |
| 65 #endif |
| 66 return true; |
| 67 } |
| 68 |
30 namespace { | 69 namespace { |
31 | |
32 class TestCase { | 70 class TestCase { |
33 public: | 71 public: |
34 template <typename GEO> | 72 template <typename GEO> |
35 TestCase(const GEO& geo, const SkPaint& paint, skiatest::Reporter* r, | 73 TestCase(const GEO& geo, const SkPaint& paint, skiatest::Reporter* r, |
36 SkScalar scale = SK_Scalar1) : fBase(geo, paint) { | 74 SkScalar scale = SK_Scalar1) : fBase(geo, paint) { |
37 this->init(r, scale); | 75 this->init(r, scale); |
38 } | 76 } |
39 | 77 |
40 struct SelfExpectations { | 78 struct SelfExpectations { |
41 bool fPEHasEffect; | 79 bool fPEHasEffect; |
(...skipping 16 matching lines...) Expand all Loading... |
58 const GrShape& appliedPathEffectShape() const { return fAppliedPE; } | 96 const GrShape& appliedPathEffectShape() const { return fAppliedPE; } |
59 const GrShape& appliedFullStyleShape() const { return fAppliedFull; } | 97 const GrShape& appliedFullStyleShape() const { return fAppliedFull; } |
60 | 98 |
61 // The returned array's count will be 0 if the key shape has no key. | 99 // The returned array's count will be 0 if the key shape has no key. |
62 const Key& baseKey() const { return fBaseKey; } | 100 const Key& baseKey() const { return fBaseKey; } |
63 const Key& appliedPathEffectKey() const { return fAppliedPEKey; } | 101 const Key& appliedPathEffectKey() const { return fAppliedPEKey; } |
64 const Key& appliedFullStyleKey() const { return fAppliedFullKey; } | 102 const Key& appliedFullStyleKey() const { return fAppliedFullKey; } |
65 const Key& appliedPathEffectThenStrokeKey() const { return fAppliedPEThenStr
okeKey; } | 103 const Key& appliedPathEffectThenStrokeKey() const { return fAppliedPEThenStr
okeKey; } |
66 | 104 |
67 private: | 105 private: |
| 106 static void CheckBounds(skiatest::Reporter* r, const GrShape& shape, const S
kRect& bounds) { |
| 107 SkPath path; |
| 108 shape.asPath(&path); |
| 109 // If the bounds are empty, the path ought to be as well. |
| 110 if (bounds.isEmpty()) { |
| 111 REPORTER_ASSERT(r, path.isEmpty()); |
| 112 return; |
| 113 } |
| 114 if (path.isEmpty()) { |
| 115 return; |
| 116 } |
| 117 REPORTER_ASSERT(r, test_bounds_by_rasterizing(path, bounds)); |
| 118 } |
| 119 |
68 void init(skiatest::Reporter* r, SkScalar scale) { | 120 void init(skiatest::Reporter* r, SkScalar scale) { |
69 fAppliedPE = fBase.applyStyle(GrStyle::Apply::kPathEffectOnly,
scale); | 121 fAppliedPE = fBase.applyStyle(GrStyle::Apply::kPathEffectOnly,
scale); |
70 fAppliedPEThenStroke = fAppliedPE.applyStyle(GrStyle::Apply::kPathEffect
AndStrokeRec, | 122 fAppliedPEThenStroke = fAppliedPE.applyStyle(GrStyle::Apply::kPathEffect
AndStrokeRec, |
71 scale); | 123 scale); |
72 fAppliedFull = fBase.applyStyle(GrStyle::Apply::kPathEffectAndSt
rokeRec, scale); | 124 fAppliedFull = fBase.applyStyle(GrStyle::Apply::kPathEffectAndSt
rokeRec, scale); |
73 | 125 |
74 make_key(&fBaseKey, fBase); | 126 make_key(&fBaseKey, fBase); |
75 make_key(&fAppliedPEKey, fAppliedPE); | 127 make_key(&fAppliedPEKey, fAppliedPE); |
76 make_key(&fAppliedPEThenStrokeKey, fAppliedPEThenStroke); | 128 make_key(&fAppliedPEThenStrokeKey, fAppliedPEThenStroke); |
77 make_key(&fAppliedFullKey, fAppliedFull); | 129 make_key(&fAppliedFullKey, fAppliedFull); |
78 | 130 |
79 // Applying the path effect and then the stroke should always be the sam
e as applying | 131 // Applying the path effect and then the stroke should always be the sam
e as applying |
80 // both in one go. | 132 // both in one go. |
81 REPORTER_ASSERT(r, fAppliedPEThenStrokeKey == fAppliedFullKey); | 133 REPORTER_ASSERT(r, fAppliedPEThenStrokeKey == fAppliedFullKey); |
82 SkPath a, b; | 134 SkPath a, b; |
83 fAppliedPEThenStroke.asPath(&a); | 135 fAppliedPEThenStroke.asPath(&a); |
84 fAppliedFull.asPath(&b); | 136 fAppliedFull.asPath(&b); |
85 REPORTER_ASSERT(r, a == b); | 137 REPORTER_ASSERT(r, a == b); |
86 REPORTER_ASSERT(r, fAppliedFull.isEmpty() == fAppliedPEThenStroke.isEmpt
y()); | 138 REPORTER_ASSERT(r, fAppliedFull.isEmpty() == fAppliedPEThenStroke.isEmpt
y()); |
87 | 139 |
88 SkPath path; | 140 SkPath path; |
89 fBase.asPath(&path); | 141 fBase.asPath(&path); |
90 REPORTER_ASSERT(r, path.isEmpty() == fBase.isEmpty()); | 142 REPORTER_ASSERT(r, path.isEmpty() == fBase.isEmpty()); |
91 fAppliedPE.asPath(&path); | 143 fAppliedPE.asPath(&path); |
92 REPORTER_ASSERT(r, path.isEmpty() == fAppliedPE.isEmpty()); | 144 REPORTER_ASSERT(r, path.isEmpty() == fAppliedPE.isEmpty()); |
93 fAppliedFull.asPath(&path); | 145 fAppliedFull.asPath(&path); |
94 REPORTER_ASSERT(r, path.isEmpty() == fAppliedFull.isEmpty()); | 146 REPORTER_ASSERT(r, path.isEmpty() == fAppliedFull.isEmpty()); |
95 | 147 |
| 148 CheckBounds(r, fBase, fBase.bounds()); |
| 149 CheckBounds(r, fAppliedPE, fAppliedPE.bounds()); |
| 150 CheckBounds(r, fAppliedPEThenStroke, fAppliedPEThenStroke.bounds()); |
| 151 CheckBounds(r, fAppliedFull, fAppliedFull.bounds()); |
| 152 SkRect styledBounds; |
| 153 fBase.styledBounds(&styledBounds); |
| 154 CheckBounds(r, fAppliedFull, styledBounds); |
| 155 fAppliedPE.styledBounds(&styledBounds); |
| 156 CheckBounds(r, fAppliedFull, styledBounds); |
| 157 |
96 // Check that the same path is produced when style is applied by GrShape
and GrStyle. | 158 // Check that the same path is produced when style is applied by GrShape
and GrStyle. |
97 SkPath preStyle; | 159 SkPath preStyle; |
98 SkPath postPathEffect; | 160 SkPath postPathEffect; |
99 SkPath postAllStyle; | 161 SkPath postAllStyle; |
100 | 162 |
101 fBase.asPath(&preStyle); | 163 fBase.asPath(&preStyle); |
102 SkStrokeRec postPEStrokeRec(SkStrokeRec::kFill_InitStyle); | 164 SkStrokeRec postPEStrokeRec(SkStrokeRec::kFill_InitStyle); |
103 if (fBase.style().applyPathEffectToPath(&postPathEffect, &postPEStrokeRe
c, preStyle, | 165 if (fBase.style().applyPathEffectToPath(&postPathEffect, &postPEStrokeRe
c, preStyle, |
104 scale)) { | 166 scale)) { |
105 // run postPathEffect through GrShape to get any geometry reductions
that would have | 167 // run postPathEffect through GrShape to get any geometry reductions
that would have |
(...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
943 } | 1005 } |
944 } | 1006 } |
945 | 1007 |
946 // Test a volatile empty path. | 1008 // Test a volatile empty path. |
947 test_volatile_path(reporter, SkPath(), true); | 1009 test_volatile_path(reporter, SkPath(), true); |
948 | 1010 |
949 test_empty_shape(reporter); | 1011 test_empty_shape(reporter); |
950 } | 1012 } |
951 | 1013 |
952 #endif | 1014 #endif |
OLD | NEW |