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