xref: /aosp_15_r20/external/skia/gm/shapes.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2016 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRRect.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
23*c8dee2aaSAndroid Build Coastguard Worker 
24*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
25*c8dee2aaSAndroid Build Coastguard Worker 
26*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker /*
29*c8dee2aaSAndroid Build Coastguard Worker  * This is the base class for two GMs that cover various corner cases with primitive Skia shapes
30*c8dee2aaSAndroid Build Coastguard Worker  * (zero radius, near-zero radius, inner shape overlap, etc.) It uses an xfermode of darken to help
31*c8dee2aaSAndroid Build Coastguard Worker  * double-blended and/or dropped pixels stand out.
32*c8dee2aaSAndroid Build Coastguard Worker  */
33*c8dee2aaSAndroid Build Coastguard Worker class ShapesGM : public GM {
34*c8dee2aaSAndroid Build Coastguard Worker protected:
ShapesGM(const char * name,bool antialias)35*c8dee2aaSAndroid Build Coastguard Worker     ShapesGM(const char* name, bool antialias) : fName(name), fAntialias(antialias) {
36*c8dee2aaSAndroid Build Coastguard Worker         if (!antialias) {
37*c8dee2aaSAndroid Build Coastguard Worker             fName.append("_bw");
38*c8dee2aaSAndroid Build Coastguard Worker         }
39*c8dee2aaSAndroid Build Coastguard Worker     }
40*c8dee2aaSAndroid Build Coastguard Worker 
getName() const41*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return fName; }
getISize()42*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return SkISize::Make(500, 500); }
43*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()44*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
45*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setOval(SkRect::MakeXYWH(-5, 25, 200, 100));
46*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(21);
47*c8dee2aaSAndroid Build Coastguard Worker 
48*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setRect(SkRect::MakeXYWH(95, 75, 125, 100));
49*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(94);
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setRectXY(SkRect::MakeXYWH(0, 75, 150, 100), 1e-5f, 1e-5f);
52*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(132);
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setRectXY(SkRect::MakeXYWH(15, -20, 100, 100), 20, 15);
55*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(282);
56*c8dee2aaSAndroid Build Coastguard Worker 
57*c8dee2aaSAndroid Build Coastguard Worker         fSimpleShapeCount = fShapes.size();
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setNinePatch(SkRect::MakeXYWH(140, -50, 90, 110), 10, 5, 25, 35);
60*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(0);
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setNinePatch(SkRect::MakeXYWH(160, -60, 60, 90), 10, 60, 50, 30);
63*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(-35);
64*c8dee2aaSAndroid Build Coastguard Worker 
65*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setNinePatch(SkRect::MakeXYWH(220, -120, 60, 90), 1, 89, 59, 1);
66*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(65);
67*c8dee2aaSAndroid Build Coastguard Worker 
68*c8dee2aaSAndroid Build Coastguard Worker         SkVector radii[4] = {{4, 6}, {12, 8}, {24, 16}, {32, 48}};
69*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setRectRadii(SkRect::MakeXYWH(150, -129, 80, 160), radii);
70*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(265);
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker         SkVector radii2[4] = {{0, 0}, {80, 60}, {0, 0}, {80, 60}};
73*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back().setRectRadii(SkRect::MakeXYWH(180, -30, 80, 60), radii2);
74*c8dee2aaSAndroid Build Coastguard Worker         fRotations.push_back(295);
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker         fPaint.setAntiAlias(fAntialias);
77*c8dee2aaSAndroid Build Coastguard Worker     }
78*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas)79*c8dee2aaSAndroid Build Coastguard Worker     void onDraw(SkCanvas* canvas) override {
80*c8dee2aaSAndroid Build Coastguard Worker         canvas->clear(SK_ColorWHITE);
81*c8dee2aaSAndroid Build Coastguard Worker 
82*c8dee2aaSAndroid Build Coastguard Worker         canvas->save();
83*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(canvas->imageInfo().width() / 2.f, canvas->imageInfo().height() / 2.f);
84*c8dee2aaSAndroid Build Coastguard Worker         this->drawShapes(canvas);
85*c8dee2aaSAndroid Build Coastguard Worker         canvas->restore();
86*c8dee2aaSAndroid Build Coastguard Worker     }
87*c8dee2aaSAndroid Build Coastguard Worker 
88*c8dee2aaSAndroid Build Coastguard Worker     virtual void drawShapes(SkCanvas* canvas) const = 0;
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker protected:
91*c8dee2aaSAndroid Build Coastguard Worker     SkString             fName;
92*c8dee2aaSAndroid Build Coastguard Worker     bool                 fAntialias;
93*c8dee2aaSAndroid Build Coastguard Worker     SkPaint              fPaint;
94*c8dee2aaSAndroid Build Coastguard Worker     TArray<SkRRect>    fShapes;
95*c8dee2aaSAndroid Build Coastguard Worker     TArray<SkScalar>   fRotations;
96*c8dee2aaSAndroid Build Coastguard Worker     int                  fSimpleShapeCount;
97*c8dee2aaSAndroid Build Coastguard Worker 
98*c8dee2aaSAndroid Build Coastguard Worker private:
99*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GM;
100*c8dee2aaSAndroid Build Coastguard Worker };
101*c8dee2aaSAndroid Build Coastguard Worker 
102*c8dee2aaSAndroid Build Coastguard Worker class SimpleShapesGM : public ShapesGM {
103*c8dee2aaSAndroid Build Coastguard Worker public:
SimpleShapesGM(bool antialias)104*c8dee2aaSAndroid Build Coastguard Worker     SimpleShapesGM(bool antialias) : INHERITED("simpleshapes", antialias) {}
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker private:
drawShapes(SkCanvas * canvas) const107*c8dee2aaSAndroid Build Coastguard Worker     void drawShapes(SkCanvas* canvas) const override {
108*c8dee2aaSAndroid Build Coastguard Worker         SkRandom rand(2);
109*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fShapes.size(); i++) {
110*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint(fPaint);
111*c8dee2aaSAndroid Build Coastguard Worker             paint.setColor(rand.nextU() & ~0x808080);
112*c8dee2aaSAndroid Build Coastguard Worker             paint.setAlphaf(0.5f);  // Use alpha to detect double blends.
113*c8dee2aaSAndroid Build Coastguard Worker             const SkRRect& shape = fShapes[i];
114*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
115*c8dee2aaSAndroid Build Coastguard Worker             canvas->rotate(fRotations[i]);
116*c8dee2aaSAndroid Build Coastguard Worker             switch (shape.getType()) {
117*c8dee2aaSAndroid Build Coastguard Worker                 case SkRRect::kRect_Type:
118*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawRect(shape.rect(), paint);
119*c8dee2aaSAndroid Build Coastguard Worker                     break;
120*c8dee2aaSAndroid Build Coastguard Worker                 case SkRRect::kOval_Type:
121*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawOval(shape.rect(), paint);
122*c8dee2aaSAndroid Build Coastguard Worker                     break;
123*c8dee2aaSAndroid Build Coastguard Worker                 default:
124*c8dee2aaSAndroid Build Coastguard Worker                     canvas->drawRRect(shape, paint);
125*c8dee2aaSAndroid Build Coastguard Worker                     break;
126*c8dee2aaSAndroid Build Coastguard Worker             }
127*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
128*c8dee2aaSAndroid Build Coastguard Worker         }
129*c8dee2aaSAndroid Build Coastguard Worker     }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = ShapesGM;
132*c8dee2aaSAndroid Build Coastguard Worker };
133*c8dee2aaSAndroid Build Coastguard Worker 
134*c8dee2aaSAndroid Build Coastguard Worker class InnerShapesGM : public ShapesGM {
135*c8dee2aaSAndroid Build Coastguard Worker public:
InnerShapesGM(bool antialias)136*c8dee2aaSAndroid Build Coastguard Worker     InnerShapesGM(bool antialias) : INHERITED("innershapes", antialias) {}
137*c8dee2aaSAndroid Build Coastguard Worker 
138*c8dee2aaSAndroid Build Coastguard Worker private:
drawShapes(SkCanvas * canvas) const139*c8dee2aaSAndroid Build Coastguard Worker     void drawShapes(SkCanvas* canvas) const override {
140*c8dee2aaSAndroid Build Coastguard Worker         SkRandom rand;
141*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fShapes.size(); i++) {
142*c8dee2aaSAndroid Build Coastguard Worker             const SkRRect& outer = fShapes[i];
143*c8dee2aaSAndroid Build Coastguard Worker             const SkRRect& inner = fShapes[(i * 7 + 11) % fSimpleShapeCount];
144*c8dee2aaSAndroid Build Coastguard Worker             float s = 0.95f * std::min(outer.rect().width() / inner.rect().width(),
145*c8dee2aaSAndroid Build Coastguard Worker                                        outer.rect().height() / inner.rect().height());
146*c8dee2aaSAndroid Build Coastguard Worker             SkMatrix innerXform;
147*c8dee2aaSAndroid Build Coastguard Worker             float dx = (rand.nextF() - 0.5f) * (outer.rect().width() - s * inner.rect().width());
148*c8dee2aaSAndroid Build Coastguard Worker             float dy = (rand.nextF() - 0.5f) * (outer.rect().height() - s * inner.rect().height());
149*c8dee2aaSAndroid Build Coastguard Worker             // Fixup inner rects so they don't reach outside the outer rect.
150*c8dee2aaSAndroid Build Coastguard Worker             switch (i) {
151*c8dee2aaSAndroid Build Coastguard Worker                 case 0:
152*c8dee2aaSAndroid Build Coastguard Worker                     s *= .85f;
153*c8dee2aaSAndroid Build Coastguard Worker                     break;
154*c8dee2aaSAndroid Build Coastguard Worker                 case 8:
155*c8dee2aaSAndroid Build Coastguard Worker                     s *= .4f;
156*c8dee2aaSAndroid Build Coastguard Worker                     dx = dy = 0;
157*c8dee2aaSAndroid Build Coastguard Worker                     break;
158*c8dee2aaSAndroid Build Coastguard Worker                 case 5:
159*c8dee2aaSAndroid Build Coastguard Worker                     s *= .75f;
160*c8dee2aaSAndroid Build Coastguard Worker                     dx = dy = 0;
161*c8dee2aaSAndroid Build Coastguard Worker                     break;
162*c8dee2aaSAndroid Build Coastguard Worker                 case 6:
163*c8dee2aaSAndroid Build Coastguard Worker                     s *= .65f;
164*c8dee2aaSAndroid Build Coastguard Worker                     dx = -5;
165*c8dee2aaSAndroid Build Coastguard Worker                     dy = 10;
166*c8dee2aaSAndroid Build Coastguard Worker                     break;
167*c8dee2aaSAndroid Build Coastguard Worker             }
168*c8dee2aaSAndroid Build Coastguard Worker             innerXform.setTranslate(outer.rect().centerX() + dx, outer.rect().centerY() + dy);
169*c8dee2aaSAndroid Build Coastguard Worker             if (s < 1) {
170*c8dee2aaSAndroid Build Coastguard Worker                 innerXform.preScale(s, s);
171*c8dee2aaSAndroid Build Coastguard Worker             }
172*c8dee2aaSAndroid Build Coastguard Worker             innerXform.preTranslate(-inner.rect().centerX(), -inner.rect().centerY());
173*c8dee2aaSAndroid Build Coastguard Worker             SkRRect xformedInner;
174*c8dee2aaSAndroid Build Coastguard Worker             inner.transform(innerXform, &xformedInner);
175*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint(fPaint);
176*c8dee2aaSAndroid Build Coastguard Worker             paint.setColor(rand.nextU() & ~0x808080);
177*c8dee2aaSAndroid Build Coastguard Worker             paint.setAlphaf(0.5f);  // Use alpha to detect double blends.
178*c8dee2aaSAndroid Build Coastguard Worker             canvas->save();
179*c8dee2aaSAndroid Build Coastguard Worker             canvas->rotate(fRotations[i]);
180*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawDRRect(outer, xformedInner, paint);
181*c8dee2aaSAndroid Build Coastguard Worker             canvas->restore();
182*c8dee2aaSAndroid Build Coastguard Worker         }
183*c8dee2aaSAndroid Build Coastguard Worker     }
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = ShapesGM;
186*c8dee2aaSAndroid Build Coastguard Worker };
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new SimpleShapesGM(true); )
191*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new SimpleShapesGM(false); )
192*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new InnerShapesGM(true); )
193*c8dee2aaSAndroid Build Coastguard Worker DEF_GM( return new InnerShapesGM(false); )
194*c8dee2aaSAndroid Build Coastguard Worker 
195*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skiagm
196