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 |
30 namespace { | 32 namespace { |
33 static bool test_bounds_by_rasterizing(const SkPath& path, const SkRect& bounds) { | |
34 static constexpr int kRes = 2000; | |
35 static constexpr int kTol = 1; | |
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); | |
robertphillips
2016/05/12 17:18:47
Is this outset really kosher? If we're going to us
bsalomon
2016/05/12 18:37:58
For the current set of test cases it works at 0 (a
| |
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 static constexpr uint8_t kZeros[kRes] = {0}; | |
52 for (int y = 0; y < kRes; ++y) { | |
53 const uint8_t* row = pixmap.addr8(0, y); | |
54 if (0 != memcmp(kZeros, row, kRes)) { | |
55 return false; | |
56 } | |
57 } | |
58 return true; | |
59 } | |
31 | 60 |
32 class TestCase { | 61 class TestCase { |
33 public: | 62 public: |
34 template <typename GEO> | 63 template <typename GEO> |
35 TestCase(const GEO& geo, const SkPaint& paint, skiatest::Reporter* r, | 64 TestCase(const GEO& geo, const SkPaint& paint, skiatest::Reporter* r, |
36 SkScalar scale = SK_Scalar1) : fBase(geo, paint) { | 65 SkScalar scale = SK_Scalar1) : fBase(geo, paint) { |
37 this->init(r, scale); | 66 this->init(r, scale); |
38 } | 67 } |
39 | 68 |
40 struct SelfExpectations { | 69 struct SelfExpectations { |
(...skipping 17 matching lines...) Expand all Loading... | |
58 const GrShape& appliedPathEffectShape() const { return fAppliedPE; } | 87 const GrShape& appliedPathEffectShape() const { return fAppliedPE; } |
59 const GrShape& appliedFullStyleShape() const { return fAppliedFull; } | 88 const GrShape& appliedFullStyleShape() const { return fAppliedFull; } |
60 | 89 |
61 // The returned array's count will be 0 if the key shape has no key. | 90 // The returned array's count will be 0 if the key shape has no key. |
62 const Key& baseKey() const { return fBaseKey; } | 91 const Key& baseKey() const { return fBaseKey; } |
63 const Key& appliedPathEffectKey() const { return fAppliedPEKey; } | 92 const Key& appliedPathEffectKey() const { return fAppliedPEKey; } |
64 const Key& appliedFullStyleKey() const { return fAppliedFullKey; } | 93 const Key& appliedFullStyleKey() const { return fAppliedFullKey; } |
65 const Key& appliedPathEffectThenStrokeKey() const { return fAppliedPEThenStr okeKey; } | 94 const Key& appliedPathEffectThenStrokeKey() const { return fAppliedPEThenStr okeKey; } |
66 | 95 |
67 private: | 96 private: |
97 static void CheckBounds(skiatest::Reporter* r, const GrShape& shape, const S kRect& bounds) { | |
98 SkPath path; | |
99 shape.asPath(&path); | |
100 // If the bounds are empty, the path ought to be as well. | |
101 if (bounds.isEmpty()) { | |
102 REPORTER_ASSERT(r, path.isEmpty()); | |
103 return; | |
104 } | |
105 if (path.isEmpty()) { | |
106 return; | |
107 } | |
108 REPORTER_ASSERT(r, test_bounds_by_rasterizing(path, bounds)); | |
109 } | |
110 | |
68 void init(skiatest::Reporter* r, SkScalar scale) { | 111 void init(skiatest::Reporter* r, SkScalar scale) { |
69 fAppliedPE = fBase.applyStyle(GrStyle::Apply::kPathEffectOnly, scale); | 112 fAppliedPE = fBase.applyStyle(GrStyle::Apply::kPathEffectOnly, scale); |
70 fAppliedPEThenStroke = fAppliedPE.applyStyle(GrStyle::Apply::kPathEffect AndStrokeRec, | 113 fAppliedPEThenStroke = fAppliedPE.applyStyle(GrStyle::Apply::kPathEffect AndStrokeRec, |
71 scale); | 114 scale); |
72 fAppliedFull = fBase.applyStyle(GrStyle::Apply::kPathEffectAndSt rokeRec, scale); | 115 fAppliedFull = fBase.applyStyle(GrStyle::Apply::kPathEffectAndSt rokeRec, scale); |
73 | 116 |
74 make_key(&fBaseKey, fBase); | 117 make_key(&fBaseKey, fBase); |
75 make_key(&fAppliedPEKey, fAppliedPE); | 118 make_key(&fAppliedPEKey, fAppliedPE); |
76 make_key(&fAppliedPEThenStrokeKey, fAppliedPEThenStroke); | 119 make_key(&fAppliedPEThenStrokeKey, fAppliedPEThenStroke); |
77 make_key(&fAppliedFullKey, fAppliedFull); | 120 make_key(&fAppliedFullKey, fAppliedFull); |
78 | 121 |
79 // Applying the path effect and then the stroke should always be the sam e as applying | 122 // Applying the path effect and then the stroke should always be the sam e as applying |
80 // both in one go. | 123 // both in one go. |
81 REPORTER_ASSERT(r, fAppliedPEThenStrokeKey == fAppliedFullKey); | 124 REPORTER_ASSERT(r, fAppliedPEThenStrokeKey == fAppliedFullKey); |
82 SkPath a, b; | 125 SkPath a, b; |
83 fAppliedPEThenStroke.asPath(&a); | 126 fAppliedPEThenStroke.asPath(&a); |
84 fAppliedFull.asPath(&b); | 127 fAppliedFull.asPath(&b); |
85 REPORTER_ASSERT(r, a == b); | 128 REPORTER_ASSERT(r, a == b); |
86 REPORTER_ASSERT(r, fAppliedFull.isEmpty() == fAppliedPEThenStroke.isEmpt y()); | 129 REPORTER_ASSERT(r, fAppliedFull.isEmpty() == fAppliedPEThenStroke.isEmpt y()); |
87 | 130 |
88 SkPath path; | 131 SkPath path; |
89 fBase.asPath(&path); | 132 fBase.asPath(&path); |
90 REPORTER_ASSERT(r, path.isEmpty() == fBase.isEmpty()); | 133 REPORTER_ASSERT(r, path.isEmpty() == fBase.isEmpty()); |
91 fAppliedPE.asPath(&path); | 134 fAppliedPE.asPath(&path); |
92 REPORTER_ASSERT(r, path.isEmpty() == fAppliedPE.isEmpty()); | 135 REPORTER_ASSERT(r, path.isEmpty() == fAppliedPE.isEmpty()); |
93 fAppliedFull.asPath(&path); | 136 fAppliedFull.asPath(&path); |
94 REPORTER_ASSERT(r, path.isEmpty() == fAppliedFull.isEmpty()); | 137 REPORTER_ASSERT(r, path.isEmpty() == fAppliedFull.isEmpty()); |
95 | 138 |
139 CheckBounds(r, fBase, fBase.bounds()); | |
140 CheckBounds(r, fAppliedPE, fAppliedPE.bounds()); | |
141 CheckBounds(r, fAppliedPEThenStroke, fAppliedPEThenStroke.bounds()); | |
142 CheckBounds(r, fAppliedFull, fAppliedFull.bounds()); | |
143 SkRect styledBounds; | |
144 fBase.styledBounds(&styledBounds); | |
145 CheckBounds(r, fAppliedFull, styledBounds); | |
146 fAppliedPE.styledBounds(&styledBounds); | |
147 CheckBounds(r, fAppliedFull, styledBounds); | |
148 | |
96 // Check that the same path is produced when style is applied by GrShape and GrStyle. | 149 // Check that the same path is produced when style is applied by GrShape and GrStyle. |
97 SkPath preStyle; | 150 SkPath preStyle; |
98 SkPath postPathEffect; | 151 SkPath postPathEffect; |
99 SkPath postAllStyle; | 152 SkPath postAllStyle; |
100 | 153 |
101 fBase.asPath(&preStyle); | 154 fBase.asPath(&preStyle); |
102 SkStrokeRec postPEStrokeRec(SkStrokeRec::kFill_InitStyle); | 155 SkStrokeRec postPEStrokeRec(SkStrokeRec::kFill_InitStyle); |
103 if (fBase.style().applyPathEffectToPath(&postPathEffect, &postPEStrokeRe c, preStyle, | 156 if (fBase.style().applyPathEffectToPath(&postPathEffect, &postPEStrokeRe c, preStyle, |
104 scale)) { | 157 scale)) { |
105 // run postPathEffect through GrShape to get any geometry reductions that would have | 158 // 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 } | 996 } |
944 } | 997 } |
945 | 998 |
946 // Test a volatile empty path. | 999 // Test a volatile empty path. |
947 test_volatile_path(reporter, SkPath(), true); | 1000 test_volatile_path(reporter, SkPath(), true); |
948 | 1001 |
949 test_empty_shape(reporter); | 1002 test_empty_shape(reporter); |
950 } | 1003 } |
951 | 1004 |
952 #endif | 1005 #endif |
OLD | NEW |