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