1 /*
2  * Copyright 2015 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 "src/gpu/GrTestUtils.h"
9 
10 #include "include/core/SkMatrix.h"
11 #include "include/core/SkPath.h"
12 #include "include/core/SkRRect.h"
13 #include "include/gpu/GrContext.h"
14 #include "src/core/SkMakeUnique.h"
15 #include "src/core/SkRectPriv.h"
16 #include "src/gpu/GrColorInfo.h"
17 #include "src/gpu/GrProcessorUnitTest.h"
18 #include "src/gpu/GrStyle.h"
19 #include "src/utils/SkDashPathPriv.h"
20 
21 #if GR_TEST_UTILS
22 
test_matrix(SkRandom * random,bool includeNonPerspective,bool includePerspective)23 static const SkMatrix& test_matrix(SkRandom* random,
24                                    bool includeNonPerspective,
25                                    bool includePerspective) {
26     static SkMatrix gMatrices[5];
27     static const int kPerspectiveCount = 1;
28     static bool gOnce;
29     if (!gOnce) {
30         gOnce = true;
31         gMatrices[0].reset();
32         gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
33         gMatrices[2].setRotate(SkIntToScalar(17));
34         gMatrices[3].setRotate(SkIntToScalar(185));
35         gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
36         gMatrices[3].postScale(SkIntToScalar(2), SK_ScalarHalf);
37 
38         // Perspective matrices
39         gMatrices[4].setRotate(SkIntToScalar(215));
40         gMatrices[4].set(SkMatrix::kMPersp0, 0.00013f);
41         gMatrices[4].set(SkMatrix::kMPersp1, -0.000039f);
42     }
43 
44     uint32_t count = static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices));
45     if (includeNonPerspective && includePerspective) {
46         return gMatrices[random->nextULessThan(count)];
47     } else if (!includeNonPerspective) {
48         return gMatrices[count - 1 - random->nextULessThan(kPerspectiveCount)];
49     } else {
50         SkASSERT(includeNonPerspective && !includePerspective);
51         return gMatrices[random->nextULessThan(count - kPerspectiveCount)];
52     }
53 }
54 
55 namespace GrTest {
TestMatrix(SkRandom * random)56 const SkMatrix& TestMatrix(SkRandom* random) { return test_matrix(random, true, true); }
57 
TestMatrixPreservesRightAngles(SkRandom * random)58 const SkMatrix& TestMatrixPreservesRightAngles(SkRandom* random) {
59     static SkMatrix gMatrices[5];
60     static bool gOnce;
61     if (!gOnce) {
62         gOnce = true;
63         // identity
64         gMatrices[0].reset();
65         // translation
66         gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
67         // scale
68         gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
69         // scale + translation
70         gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
71         gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
72         // orthogonal basis vectors
73         gMatrices[4].reset();
74         gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
75         gMatrices[4].setRotate(47);
76 
77         for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) {
78             SkASSERT(gMatrices[i].preservesRightAngles());
79         }
80     }
81     return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
82 }
83 
TestMatrixRectStaysRect(SkRandom * random)84 const SkMatrix& TestMatrixRectStaysRect(SkRandom* random) {
85     static SkMatrix gMatrices[6];
86     static bool gOnce;
87     if (!gOnce) {
88         gOnce = true;
89         // identity
90         gMatrices[0].reset();
91         // translation
92         gMatrices[1].setTranslate(SkIntToScalar(-100), SkIntToScalar(100));
93         // scale
94         gMatrices[2].setScale(SkIntToScalar(17), SkIntToScalar(17));
95         // scale + translation
96         gMatrices[3].setScale(SkIntToScalar(-17), SkIntToScalar(-17));
97         gMatrices[3].postTranslate(SkIntToScalar(66), SkIntToScalar(-33));
98         // reflection
99         gMatrices[4].setScale(SkIntToScalar(-1), SkIntToScalar(-1));
100         // 90 degress rotation
101         gMatrices[5].setRotate(90);
102 
103         for (size_t i = 0; i < SK_ARRAY_COUNT(gMatrices); i++) {
104             SkASSERT(gMatrices[i].rectStaysRect());
105         }
106     }
107     return gMatrices[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gMatrices)))];
108 }
109 
TestMatrixInvertible(SkRandom * random)110 const SkMatrix& TestMatrixInvertible(SkRandom* random) { return test_matrix(random, true, false); }
TestMatrixPerspective(SkRandom * random)111 const SkMatrix& TestMatrixPerspective(SkRandom* random) { return test_matrix(random, false, true); }
112 
TestWrapModes(SkRandom * random,GrSamplerState::WrapMode wrapModes[2])113 void TestWrapModes(SkRandom* random, GrSamplerState::WrapMode wrapModes[2]) {
114     static const GrSamplerState::WrapMode kWrapModes[] = {
115             GrSamplerState::WrapMode::kClamp,
116             GrSamplerState::WrapMode::kRepeat,
117             GrSamplerState::WrapMode::kMirrorRepeat,
118     };
119     wrapModes[0] = kWrapModes[random->nextULessThan(SK_ARRAY_COUNT(kWrapModes))];
120     wrapModes[1] = kWrapModes[random->nextULessThan(SK_ARRAY_COUNT(kWrapModes))];
121 }
TestRect(SkRandom * random)122 const SkRect& TestRect(SkRandom* random) {
123     static SkRect gRects[7];
124     static bool gOnce;
125     if (!gOnce) {
126         gOnce = true;
127         gRects[0] = SkRect::MakeWH(1.f, 1.f);
128         gRects[1] = SkRect::MakeWH(1.0f, 256.0f);
129         gRects[2] = SkRect::MakeWH(256.0f, 1.0f);
130         gRects[3] = SkRectPriv::MakeLargest();
131         gRects[4] = SkRect::MakeLTRB(-65535.0f, -65535.0f, 65535.0f, 65535.0f);
132         gRects[5] = SkRect::MakeLTRB(-10.0f, -10.0f, 10.0f, 10.0f);
133     }
134     return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))];
135 }
136 
137 // Just some simple rects for code which expects its input very sanitized
TestSquare(SkRandom * random)138 const SkRect& TestSquare(SkRandom* random) {
139     static SkRect gRects[2];
140     static bool gOnce;
141     if (!gOnce) {
142         gOnce = true;
143         gRects[0] = SkRect::MakeWH(128.f, 128.f);
144         gRects[1] = SkRect::MakeWH(256.0f, 256.0f);
145     }
146     return gRects[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRects)))];
147 }
148 
TestRRectSimple(SkRandom * random)149 const SkRRect& TestRRectSimple(SkRandom* random) {
150     static SkRRect gRRect[2];
151     static bool gOnce;
152     if (!gOnce) {
153         gOnce = true;
154         SkRect rectangle = SkRect::MakeWH(10.f, 20.f);
155         // true round rect with circular corners
156         gRRect[0].setRectXY(rectangle, 1.f, 1.f);
157         // true round rect with elliptical corners
158         gRRect[1].setRectXY(rectangle, 2.0f, 1.0f);
159 
160         for (size_t i = 0; i < SK_ARRAY_COUNT(gRRect); i++) {
161             SkASSERT(gRRect[i].isSimple());
162         }
163     }
164     return gRRect[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gRRect)))];
165 }
166 
TestPath(SkRandom * random)167 const SkPath& TestPath(SkRandom* random) {
168     static SkPath gPath[7];
169     static bool gOnce;
170     if (!gOnce) {
171         gOnce = true;
172         // line
173         gPath[0].moveTo(0.f, 0.f);
174         gPath[0].lineTo(10.f, 10.f);
175         // quad
176         gPath[1].moveTo(0.f, 0.f);
177         gPath[1].quadTo(10.f, 10.f, 20.f, 20.f);
178         // conic
179         gPath[2].moveTo(0.f, 0.f);
180         gPath[2].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
181         // cubic
182         gPath[3].moveTo(0.f, 0.f);
183         gPath[3].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
184         // all three
185         gPath[4].moveTo(0.f, 0.f);
186         gPath[4].lineTo(10.f, 10.f);
187         gPath[4].quadTo(10.f, 10.f, 20.f, 20.f);
188         gPath[4].conicTo(10.f, 10.f, 20.f, 20.f, 1.f);
189         gPath[4].cubicTo(10.f, 10.f, 20.f, 20.f, 30.f, 30.f);
190         // convex
191         gPath[5].moveTo(0.0f, 0.0f);
192         gPath[5].lineTo(10.0f, 0.0f);
193         gPath[5].lineTo(10.0f, 10.0f);
194         gPath[5].lineTo(0.0f, 10.0f);
195         gPath[5].close();
196         // concave
197         gPath[6].moveTo(0.0f, 0.0f);
198         gPath[6].lineTo(5.0f, 5.0f);
199         gPath[6].lineTo(10.0f, 0.0f);
200         gPath[6].lineTo(10.0f, 10.0f);
201         gPath[6].lineTo(0.0f, 10.0f);
202         gPath[6].close();
203     }
204 
205     return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
206 }
207 
TestPathConvex(SkRandom * random)208 const SkPath& TestPathConvex(SkRandom* random) {
209     static SkPath gPath[3];
210     static bool gOnce;
211     if (!gOnce) {
212         gOnce = true;
213         // narrow rect
214         gPath[0].moveTo(-1.5f, -50.0f);
215         gPath[0].lineTo(-1.5f, -50.0f);
216         gPath[0].lineTo( 1.5f, -50.0f);
217         gPath[0].lineTo( 1.5f,  50.0f);
218         gPath[0].lineTo(-1.5f,  50.0f);
219         // degenerate
220         gPath[1].moveTo(-0.025f, -0.025f);
221         gPath[1].lineTo(-0.025f, -0.025f);
222         gPath[1].lineTo( 0.025f, -0.025f);
223         gPath[1].lineTo( 0.025f,  0.025f);
224         gPath[1].lineTo(-0.025f,  0.025f);
225         // clipped triangle
226         gPath[2].moveTo(-10.0f, -50.0f);
227         gPath[2].lineTo(-10.0f, -50.0f);
228         gPath[2].lineTo( 10.0f, -50.0f);
229         gPath[2].lineTo( 50.0f,  31.0f);
230         gPath[2].lineTo( 40.0f,  50.0f);
231         gPath[2].lineTo(-40.0f,  50.0f);
232         gPath[2].lineTo(-50.0f,  31.0f);
233 
234         for (size_t i = 0; i < SK_ARRAY_COUNT(gPath); i++) {
235             SkASSERT(SkPath::kConvex_Convexity == gPath[i].getConvexity());
236         }
237     }
238 
239     return gPath[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gPath)))];
240 }
241 
randomize_stroke_rec(SkStrokeRec * rec,SkRandom * random)242 static void randomize_stroke_rec(SkStrokeRec* rec, SkRandom* random) {
243     bool strokeAndFill = random->nextBool();
244     SkScalar strokeWidth = random->nextBool() ? 0.f : 1.f;
245     rec->setStrokeStyle(strokeWidth, strokeAndFill);
246 
247     SkPaint::Cap cap = SkPaint::Cap(random->nextULessThan(SkPaint::kCapCount));
248     SkPaint::Join join = SkPaint::Join(random->nextULessThan(SkPaint::kJoinCount));
249     SkScalar miterLimit = random->nextRangeScalar(1.f, 5.f);
250     rec->setStrokeParams(cap, join, miterLimit);
251 }
252 
TestStrokeRec(SkRandom * random)253 SkStrokeRec TestStrokeRec(SkRandom* random) {
254     SkStrokeRec::InitStyle style =
255             SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
256     SkStrokeRec rec(style);
257     randomize_stroke_rec(&rec, random);
258     return rec;
259 }
260 
TestStyle(SkRandom * random,GrStyle * style)261 void TestStyle(SkRandom* random, GrStyle* style) {
262     SkStrokeRec::InitStyle initStyle =
263             SkStrokeRec::InitStyle(random->nextULessThan(SkStrokeRec::kFill_InitStyle + 1));
264     SkStrokeRec stroke(initStyle);
265     randomize_stroke_rec(&stroke, random);
266     sk_sp<SkPathEffect> pe;
267     if (random->nextBool()) {
268         int cnt = random->nextRangeU(1, 50) * 2;
269         std::unique_ptr<SkScalar[]> intervals(new SkScalar[cnt]);
270         SkScalar sum = 0;
271         for (int i = 0; i < cnt; i++) {
272             intervals[i] = random->nextRangeScalar(SkDoubleToScalar(0.01),
273                                                    SkDoubleToScalar(10.0));
274             sum += intervals[i];
275         }
276         SkScalar phase = random->nextRangeScalar(0, sum);
277         pe = TestDashPathEffect::Make(intervals.get(), cnt, phase);
278     }
279     *style = GrStyle(stroke, std::move(pe));
280 }
281 
TestDashPathEffect(const SkScalar * intervals,int count,SkScalar phase)282 TestDashPathEffect::TestDashPathEffect(const SkScalar* intervals, int count, SkScalar phase) {
283     fCount = count;
284     fIntervals.reset(count);
285     memcpy(fIntervals.get(), intervals, count * sizeof(SkScalar));
286     SkDashPath::CalcDashParameters(phase, intervals, count, &fInitialDashLength,
287                                    &fInitialDashIndex, &fIntervalLength, &fPhase);
288 }
289 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect) const290     bool TestDashPathEffect::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
291                                           const SkRect* cullRect) const {
292     return SkDashPath::InternalFilter(dst, src, rec, cullRect, fIntervals.get(), fCount,
293                                       fInitialDashLength, fInitialDashIndex, fIntervalLength);
294 }
295 
onAsADash(DashInfo * info) const296 SkPathEffect::DashType TestDashPathEffect::onAsADash(DashInfo* info) const {
297     if (info) {
298         if (info->fCount >= fCount && info->fIntervals) {
299             memcpy(info->fIntervals, fIntervals.get(), fCount * sizeof(SkScalar));
300         }
301         info->fCount = fCount;
302         info->fPhase = fPhase;
303     }
304     return kDash_DashType;
305 }
306 
TestColorSpace(SkRandom * random)307 sk_sp<SkColorSpace> TestColorSpace(SkRandom* random) {
308     static sk_sp<SkColorSpace> gColorSpaces[3];
309     static bool gOnce;
310     if (!gOnce) {
311         gOnce = true;
312         // No color space (legacy mode)
313         gColorSpaces[0] = nullptr;
314         // sRGB or color-spin sRGB
315         gColorSpaces[1] = SkColorSpace::MakeSRGB();
316         gColorSpaces[2] = SkColorSpace::MakeSRGB()->makeColorSpin();
317     }
318     return gColorSpaces[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gColorSpaces)))];
319 }
320 
TestColorXform(SkRandom * random)321 sk_sp<GrColorSpaceXform> TestColorXform(SkRandom* random) {
322     // TODO: Add many more kinds of xforms here
323     static sk_sp<GrColorSpaceXform> gXforms[3];
324     static bool gOnce;
325     if (!gOnce) {
326         gOnce = true;
327         sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB();
328         sk_sp<SkColorSpace> spin = SkColorSpace::MakeSRGB()->makeColorSpin();
329         // No gamut change
330         gXforms[0] = nullptr;
331         gXforms[1] = GrColorSpaceXform::Make(srgb.get(), kPremul_SkAlphaType,
332                                              spin.get(), kPremul_SkAlphaType);
333         gXforms[2] = GrColorSpaceXform::Make(spin.get(), kPremul_SkAlphaType,
334                                              srgb.get(), kPremul_SkAlphaType);
335     }
336     return gXforms[random->nextULessThan(static_cast<uint32_t>(SK_ARRAY_COUNT(gXforms)))];
337 }
338 
TestAsFPArgs(GrProcessorTestData * d)339 TestAsFPArgs::TestAsFPArgs(GrProcessorTestData* d)
340         : fViewMatrixStorage(TestMatrix(d->fRandom))
341         , fColorInfoStorage(skstd::make_unique<GrColorInfo>(
342                   GrColorType::kRGBA_8888, kPremul_SkAlphaType, TestColorSpace(d->fRandom)))
343         , fArgs(d->context(), &fViewMatrixStorage, kNone_SkFilterQuality, fColorInfoStorage.get()) {
344 }
345 
~TestAsFPArgs()346 TestAsFPArgs::~TestAsFPArgs() {}
347 
348 }  // namespace GrTest
349 
350 #endif
351