xref: /aosp_15_r20/external/skia/gm/convexpolyclip.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2014 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/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkClipOp.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkFont.h"
14 #include "include/core/SkFontTypes.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkPaint.h"
17 #include "include/core/SkPathBuilder.h"
18 #include "include/core/SkPoint.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkScalar.h"
21 #include "include/core/SkShader.h"
22 #include "include/core/SkSize.h"
23 #include "include/core/SkString.h"
24 #include "include/core/SkTileMode.h"
25 #include "include/core/SkTypeface.h"
26 #include "include/core/SkTypes.h"
27 #include "include/effects/SkGradientShader.h"
28 #include "tools/ToolUtils.h"
29 #include "tools/fonts/FontToolUtils.h"
30 
make_img(int w,int h)31 static sk_sp<SkImage> make_img(int w, int h) {
32     auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType));
33     auto canvas = surf->getCanvas();
34 
35     SkScalar wScalar = SkIntToScalar(w);
36     SkScalar hScalar = SkIntToScalar(h);
37 
38     SkPoint     pt = { wScalar / 2, hScalar / 2 };
39 
40     SkScalar    radius = 3 * std::max(wScalar, hScalar);
41 
42     SkColor colors[] = {SK_ColorDKGRAY,
43                         ToolUtils::color_to_565(0xFF222255),
44                         ToolUtils::color_to_565(0xFF331133),
45                         ToolUtils::color_to_565(0xFF884422),
46                         ToolUtils::color_to_565(0xFF000022),
47                         SK_ColorWHITE,
48                         ToolUtils::color_to_565(0xFFAABBCC)};
49 
50     SkScalar    pos[] = {0,
51                          SK_Scalar1 / 6,
52                          2 * SK_Scalar1 / 6,
53                          3 * SK_Scalar1 / 6,
54                          4 * SK_Scalar1 / 6,
55                          5 * SK_Scalar1 / 6,
56                          SK_Scalar1};
57 
58     SkPaint paint;
59     SkRect rect = SkRect::MakeWH(wScalar, hScalar);
60     SkMatrix mat = SkMatrix::I();
61     for (int i = 0; i < 4; ++i) {
62         paint.setShader(SkGradientShader::MakeRadial(
63                         pt, radius,
64                         colors, pos,
65                         std::size(colors),
66                         SkTileMode::kRepeat,
67                         0, &mat));
68         canvas->drawRect(rect, paint);
69         rect.inset(wScalar / 8, hScalar / 8);
70         mat.preTranslate(6 * wScalar, 6 * hScalar);
71         mat.postScale(SK_Scalar1 / 3, SK_Scalar1 / 3);
72     }
73 
74     SkFont font(ToolUtils::DefaultPortableTypeface(), wScalar / 2.2f);
75 
76     paint.setShader(nullptr);
77     paint.setColor(SK_ColorLTGRAY);
78     constexpr char kTxt[] = "Skia";
79     SkPoint texPos = { wScalar / 17, hScalar / 2 + font.getSize() / 2.5f };
80     canvas->drawSimpleText(kTxt, std::size(kTxt)-1, SkTextEncoding::kUTF8,
81                            texPos.fX, texPos.fY, font, paint);
82     paint.setColor(SK_ColorBLACK);
83     paint.setStyle(SkPaint::kStroke_Style);
84     paint.setStrokeWidth(SK_Scalar1);
85     canvas->drawSimpleText(kTxt, std::size(kTxt)-1, SkTextEncoding::kUTF8,
86                            texPos.fX, texPos.fY, font, paint);
87     return surf->makeImageSnapshot();
88 }
89 
90 namespace skiagm {
91 /**
92  * This GM tests convex polygon clips.
93  */
94 class ConvexPolyClip : public GM {
95 public:
ConvexPolyClip()96     ConvexPolyClip() {
97         this->setBGColor(0xFFFFFFFF);
98     }
99 
100 protected:
getName() const101     SkString getName() const override { return SkString("convex_poly_clip"); }
102 
getISize()103     SkISize getISize() override {
104         // When benchmarking the saveLayer set of draws is skipped.
105         int w = 435;
106         if (kBench_Mode != this->getMode()) {
107             w *= 2;
108         }
109         return SkISize::Make(w, 540);
110     }
111 
onOnceBeforeDraw()112     void onOnceBeforeDraw() override {
113         // On < c++17, emplace_back() returns a void :(
114         auto emplace_back = [](std::vector<Clip>& clips) -> Clip& {
115             clips.emplace_back();
116             return clips.back();
117         };
118 
119         emplace_back(fClips).setPath(SkPath::Polygon({
120             {  5.f,   5.f},
121             {100.f,  20.f},
122             { 15.f, 100.f},
123         }, false));
124 
125         SkPathBuilder hexagon;
126         constexpr SkScalar kRadius = 45.f;
127         const SkPoint center = { kRadius, kRadius };
128         for (int i = 0; i < 6; ++i) {
129             SkScalar angle = 2 * SK_ScalarPI * i / 6;
130             SkPoint point = { SkScalarCos(angle), SkScalarSin(angle) };
131             point.scale(kRadius);
132             point = center + point;
133             if (0 == i) {
134                 hexagon.moveTo(point);
135             } else {
136                 hexagon.lineTo(point);
137             }
138         }
139         emplace_back(fClips).setPath(hexagon.snapshot());
140 
141         SkMatrix scaleM;
142         scaleM.setScale(1.1f, 0.4f, kRadius, kRadius);
143         emplace_back(fClips).setPath(hexagon.detach().makeTransform(scaleM));
144 
145         emplace_back(fClips).setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f));
146 
147         SkRect rect = SkRect::MakeLTRB(10.f, 12.f, 80.f, 86.f);
148         SkMatrix rotM;
149         rotM.setRotate(23.f, rect.centerX(), rect.centerY());
150         emplace_back(fClips).setPath(SkPath::Rect(rect).makeTransform(rotM));
151 
152         fImg = make_img(100, 100);
153     }
154 
onDraw(SkCanvas * canvas)155     void onDraw(SkCanvas* canvas) override {
156         SkScalar y = 0;
157         constexpr SkScalar kMargin = 10.f;
158 
159         SkPaint bgPaint;
160         bgPaint.setAlpha(0x15);
161         SkISize size = canvas->getBaseLayerSize();
162         canvas->drawImageRect(fImg, SkRect::MakeIWH(size.fWidth, size.fHeight),
163                               SkSamplingOptions(), &bgPaint);
164 
165         constexpr char kTxt[] = "Clip Me!";
166         SkFont         font(ToolUtils::DefaultPortableTypeface(), 23);
167         SkScalar textW = font.measureText(kTxt, std::size(kTxt)-1, SkTextEncoding::kUTF8);
168         SkPaint txtPaint;
169         txtPaint.setColor(SK_ColorDKGRAY);
170 
171         SkScalar startX = 0;
172         int testLayers = kBench_Mode != this->getMode();
173         for (int doLayer = 0; doLayer <= testLayers; ++doLayer) {
174             for (const Clip& clip : fClips) {
175                 SkScalar x = startX;
176                 for (int aa = 0; aa < 2; ++aa) {
177                     if (doLayer) {
178                         SkRect bounds;
179                         clip.getBounds(&bounds);
180                         bounds.outset(2, 2);
181                         bounds.offset(x, y);
182                         canvas->saveLayer(&bounds, nullptr);
183                     } else {
184                         canvas->save();
185                     }
186                     canvas->translate(x, y);
187                     clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
188                     canvas->drawImage(fImg, 0, 0);
189                     canvas->restore();
190                     x += fImg->width() + kMargin;
191                 }
192                 for (int aa = 0; aa < 2; ++aa) {
193 
194                     SkPaint clipOutlinePaint;
195                     clipOutlinePaint.setAntiAlias(true);
196                     clipOutlinePaint.setColor(0x50505050);
197                     clipOutlinePaint.setStyle(SkPaint::kStroke_Style);
198                     clipOutlinePaint.setStrokeWidth(0);
199 
200                     if (doLayer) {
201                         SkRect bounds;
202                         clip.getBounds(&bounds);
203                         bounds.outset(2, 2);
204                         bounds.offset(x, y);
205                         canvas->saveLayer(&bounds, nullptr);
206                     } else {
207                         canvas->save();
208                     }
209                     canvas->translate(x, y);
210                     SkPath closedClipPath = clip.asClosedPath();
211                     canvas->drawPath(closedClipPath, clipOutlinePaint);
212                     clip.setOnCanvas(canvas, SkClipOp::kIntersect, SkToBool(aa));
213                     canvas->scale(1.f, 1.8f);
214                     canvas->drawSimpleText(kTxt, std::size(kTxt)-1, SkTextEncoding::kUTF8,
215                                      0, 1.5f * font.getSize(), font, txtPaint);
216                     canvas->restore();
217                     x += textW + 2 * kMargin;
218                 }
219                 y += fImg->height() + kMargin;
220             }
221             y = 0;
222             startX += 2 * fImg->width() + SkScalarCeilToInt(2 * textW) + 6 * kMargin;
223         }
224     }
225 
runAsBench() const226     bool runAsBench() const override { return true; }
227 
228 private:
229     class Clip {
230     public:
231         enum ClipType {
232             kNone_ClipType,
233             kPath_ClipType,
234             kRect_ClipType
235         };
236 
Clip()237         Clip () : fClipType(kNone_ClipType) {}
238 
setOnCanvas(SkCanvas * canvas,SkClipOp op,bool aa) const239         void setOnCanvas(SkCanvas* canvas, SkClipOp op, bool aa) const {
240             switch (fClipType) {
241                 case kPath_ClipType:
242                     canvas->clipPath(fPathBuilder.snapshot(), op, aa);
243                     break;
244                 case kRect_ClipType:
245                     canvas->clipRect(fRect, op, aa);
246                     break;
247                 case kNone_ClipType:
248                     SkDEBUGFAIL("Uninitialized Clip.");
249                     break;
250             }
251         }
252 
asClosedPath() const253         SkPath asClosedPath() const {
254             switch (fClipType) {
255                 case kPath_ClipType:
256                     return SkPathBuilder(fPathBuilder).close().detach();
257                 case kRect_ClipType:
258                     return SkPath::Rect(fRect);
259                 case kNone_ClipType:
260                     SkDEBUGFAIL("Uninitialized Clip.");
261                     break;
262             }
263             return SkPath();
264         }
265 
setPath(const SkPath & path)266         void setPath(const SkPath& path) {
267             fClipType = kPath_ClipType;
268             fPathBuilder = path;
269         }
270 
setRect(const SkRect & rect)271         void setRect(const SkRect& rect) {
272             fClipType = kRect_ClipType;
273             fRect = rect;
274             fPathBuilder.reset();
275         }
276 
getType() const277         ClipType getType() const { return fClipType; }
278 
getBounds(SkRect * bounds) const279         void getBounds(SkRect* bounds) const {
280             switch (fClipType) {
281                 case kPath_ClipType:
282                     *bounds = fPathBuilder.computeBounds();
283                     break;
284                 case kRect_ClipType:
285                     *bounds = fRect;
286                     break;
287                 case kNone_ClipType:
288                     SkDEBUGFAIL("Uninitialized Clip.");
289                     break;
290             }
291         }
292 
293     private:
294         ClipType fClipType;
295         SkPathBuilder fPathBuilder;
296         SkRect fRect;
297     };
298 
299     std::vector<Clip> fClips;
300     sk_sp<SkImage>    fImg;
301 
302     using INHERITED = GM;
303 };
304 
305 DEF_GM(return new ConvexPolyClip;)
306 }  // namespace skiagm
307