xref: /aosp_15_r20/external/skia/gm/polygons.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 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 "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPathBuilder.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkScalar.h"
15 #include "include/core/SkSize.h"
16 #include "include/core/SkString.h"
17 #include "include/core/SkTypes.h"
18 #include "include/private/base/SkTArray.h"
19 #include "src/base/SkRandom.h"
20 
21 using namespace skia_private;
22 
23 namespace skiagm {
24 
25 // This GM tests a grab-bag of convex and concave polygons. They are triangles,
26 // trapezoid, diamond, polygons with lots of edges, several concave polygons...
27 // But rectangles are excluded.
28 class PolygonsGM: public GM {
29 public:
PolygonsGM()30     PolygonsGM() {}
31 
32 protected:
getName() const33     SkString getName() const override { return SkString("polygons"); }
34 
getISize()35     SkISize getISize() override {
36         int width = kNumPolygons * kCellSize + 40;
37         int height = (kNumJoins * kNumStrokeWidths + kNumExtraStyles) * kCellSize + 40;
38         return SkISize::Make(width, height);
39     }
40 
41     // Construct all polygons
onOnceBeforeDraw()42     void onOnceBeforeDraw() override {
43         SkPoint p0[] = {{0, 0}, {60, 0}, {90, 40}};  // triangle
44         SkPoint p1[] = {{0, 0}, {0, 40}, {60, 40}, {40, 0}};  // trapezoid
45         SkPoint p2[] = {{0, 0}, {40, 40}, {80, 40}, {40, 0}};  // diamond
46         SkPoint p3[] = {{10, 0}, {50, 0}, {60, 10}, {60, 30}, {50, 40},
47                         {10, 40}, {0, 30}, {0, 10}};  // octagon
48         SkPoint p4[32];  // circle-like polygons with 32-edges.
49         SkPoint p5[] = {{0, 0}, {20, 20}, {0, 40}, {60, 20}};  // concave polygon with 4 edges
50         SkPoint p6[] = {{0, 40}, {0, 30}, {15, 30}, {15, 20}, {30, 20},
51                         {30, 10}, {45, 10}, {45, 0}, {60, 0}, {60, 40}};  // stairs-like polygon
52         SkPoint p7[] = {{0, 20}, {20, 20}, {30, 0}, {40, 20}, {60, 20},
53                         {45, 30}, {55, 50}, {30, 40}, {5, 50}, {15, 30}};  // five-point stars
54 
55         for (size_t i = 0; i < std::size(p4); ++i) {
56             SkScalar angle = 2 * SK_ScalarPI * i / std::size(p4);
57             p4[i].set(20 * SkScalarCos(angle) + 20, 20 * SkScalarSin(angle) + 20);
58         }
59 
60         struct Polygons {
61             SkPoint* fPoints;
62             size_t fPointNum;
63         } pgs[] = {
64             { p0, std::size(p0) },
65             { p1, std::size(p1) },
66             { p2, std::size(p2) },
67             { p3, std::size(p3) },
68             { p4, std::size(p4) },
69             { p5, std::size(p5) },
70             { p6, std::size(p6) },
71             { p7, std::size(p7) }
72         };
73 
74         SkASSERT(std::size(pgs) == kNumPolygons);
75         for (size_t pgIndex = 0; pgIndex < std::size(pgs); ++pgIndex) {
76             SkPathBuilder b;
77             b.moveTo(pgs[pgIndex].fPoints[0].fX,
78                      pgs[pgIndex].fPoints[0].fY);
79             for (size_t ptIndex = 1; ptIndex < pgs[pgIndex].fPointNum; ++ptIndex) {
80                 b.lineTo(pgs[pgIndex].fPoints[ptIndex].fX,
81                          pgs[pgIndex].fPoints[ptIndex].fY);
82             }
83             b.close();
84             fPolygons.push_back(b.detach());
85         }
86     }
87 
88     // Set the location for the current test on the canvas
SetLocation(SkCanvas * canvas,int counter,int lineNum)89     static void SetLocation(SkCanvas* canvas, int counter, int lineNum) {
90         SkScalar x = SK_Scalar1 * kCellSize * (counter % lineNum) + 30 + SK_Scalar1 / 4;
91         SkScalar y = SK_Scalar1 * kCellSize * (counter / lineNum) + 30 + 3 * SK_Scalar1 / 4;
92         canvas->translate(x, y);
93     }
94 
SetColorAndAlpha(SkPaint * paint,SkRandom * rand)95     static void SetColorAndAlpha(SkPaint* paint, SkRandom* rand) {
96         SkColor color = rand->nextU();
97         color |= 0xff000000;
98         paint->setColor(color);
99         if (40 == paint->getStrokeWidth()) {
100             paint->setAlpha(0xA0);
101         }
102     }
103 
onDraw(SkCanvas * canvas)104     void onDraw(SkCanvas* canvas) override {
105         // Stroke widths are:
106         // 0(may use hairline rendering), 10(common case for stroke-style)
107         // 40(>= geometry width/height, make the contour filled in fact)
108         constexpr int kStrokeWidths[] = {0, 10, 40};
109         SkASSERT(kNumStrokeWidths == std::size(kStrokeWidths));
110 
111         constexpr SkPaint::Join kJoins[] = {
112             SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join
113         };
114         SkASSERT(kNumJoins == std::size(kJoins));
115 
116         int counter = 0;
117         SkPaint paint;
118         paint.setAntiAlias(true);
119 
120         SkRandom rand;
121         // For stroke style painter
122         paint.setStyle(SkPaint::kStroke_Style);
123         for (int join = 0; join < kNumJoins; ++join) {
124             for (int width = 0; width < kNumStrokeWidths; ++width) {
125                 for (int i = 0; i < fPolygons.size(); ++i) {
126                     canvas->save();
127                     SetLocation(canvas, counter, fPolygons.size());
128 
129                     SetColorAndAlpha(&paint, &rand);
130                     paint.setStrokeJoin(kJoins[join]);
131                     paint.setStrokeWidth(SkIntToScalar(kStrokeWidths[width]));
132 
133                     canvas->drawPath(fPolygons[i], paint);
134                     canvas->restore();
135                     ++counter;
136                 }
137             }
138         }
139 
140         // For stroke-and-fill style painter and fill style painter
141         constexpr SkPaint::Style kStyles[] = {
142             SkPaint::kStrokeAndFill_Style, SkPaint::kFill_Style
143         };
144         SkASSERT(kNumExtraStyles == std::size(kStyles));
145 
146         paint.setStrokeJoin(SkPaint::kMiter_Join);
147         paint.setStrokeWidth(SkIntToScalar(20));
148         for (int style = 0; style < kNumExtraStyles; ++style) {
149             paint.setStyle(kStyles[style]);
150             for (int i = 0; i < fPolygons.size(); ++i) {
151                 canvas->save();
152                 SetLocation(canvas, counter, fPolygons.size());
153                 SetColorAndAlpha(&paint, &rand);
154                 canvas->drawPath(fPolygons[i], paint);
155                 canvas->restore();
156                 ++counter;
157             }
158         }
159     }
160 
161 private:
162     inline static constexpr int kNumPolygons = 8;
163     inline static constexpr int kCellSize = 100;
164     inline static constexpr int kNumExtraStyles = 2;
165     inline static constexpr int kNumStrokeWidths = 3;
166     inline static constexpr int kNumJoins = 3;
167 
168     TArray<SkPath> fPolygons;
169     using INHERITED = GM;
170 };
171 
172 //////////////////////////////////////////////////////////////////////////////
173 
174 DEF_GM(return new PolygonsGM;)
175 
176 // see crbug.com/1197461
177 DEF_SIMPLE_GM(conjoined_polygons, canvas, 400, 400) {
178     SkPathBuilder b;
179     b.moveTo(0.f, 120.f);
180     b.lineTo(0.f, 0.f);
181     b.lineTo(50.f, 330.f);
182     b.lineTo(90.f, 0.f);
183     b.lineTo(340.f, 0.f);
184     b.lineTo(90.f, 330.f);
185     b.lineTo(50.f, 330.f);
186     b.close();
187 
188     SkPaint paint;
189     paint.setAntiAlias(true);
190     canvas->drawPath(b.detach(), paint);
191 }
192 
193 }  // namespace skiagm
194