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