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