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    paint.setTextSize(wScalar / 2.2f);
58    paint.setShader(0);
59    paint.setColor(SK_ColorLTGRAY);
60    static const char kTxt[] = "Skia";
61    SkPoint texPos = { wScalar / 17, hScalar / 2 + paint.getTextSize() / 2.5f };
62    canvas.drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1, texPos.fX, texPos.fY, paint);
63    paint.setColor(SK_ColorBLACK);
64    paint.setStyle(SkPaint::kStroke_Style);
65    paint.setStrokeWidth(SK_Scalar1);
66    canvas.drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1, texPos.fX, texPos.fY, paint);
67    return bmp;
68}
69
70namespace skiagm {
71/**
72 * This GM tests convex polygon clips.
73 */
74class ConvexPolyClip : public GM {
75public:
76    ConvexPolyClip() {
77        this->setBGColor(0xFFFFFFFF);
78    }
79
80protected:
81    virtual SkString onShortName() SK_OVERRIDE {
82        return SkString("convex_poly_clip");
83    }
84
85    virtual SkISize onISize() SK_OVERRIDE {
86        // When benchmarking the saveLayer set of draws is skipped.
87        int w = 435;
88        if (kBench_Mode != this->getMode()) {
89            w *= 2;
90        }
91        return SkISize::Make(w, 540);
92    }
93
94    virtual void onOnceBeforeDraw() SK_OVERRIDE {
95        SkPath tri;
96        tri.moveTo(5.f, 5.f);
97        tri.lineTo(100.f, 20.f);
98        tri.lineTo(15.f, 100.f);
99
100        fClips.addToTail()->setPath(tri);
101
102        SkPath hexagon;
103        static const SkScalar kRadius = 45.f;
104        const SkPoint center = { kRadius, kRadius };
105        for (int i = 0; i < 6; ++i) {
106            SkScalar angle = 2 * SK_ScalarPI * i / 6;
107            SkPoint point;
108            point.fY = SkScalarSinCos(angle, &point.fX);
109            point.scale(kRadius);
110            point = center + point;
111            if (0 == i) {
112                hexagon.moveTo(point);
113            } else {
114                hexagon.lineTo(point);
115            }
116        }
117        fClips.addToTail()->setPath(hexagon);
118
119        SkMatrix scaleM;
120        scaleM.setScale(1.1f, 0.4f, kRadius, kRadius);
121        hexagon.transform(scaleM);
122        fClips.addToTail()->setPath(hexagon);
123
124        fClips.addToTail()->setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f));
125
126        SkPath rotRect;
127        SkRect rect = SkRect::MakeLTRB(10.f, 12.f, 80.f, 86.f);
128        rotRect.addRect(rect);
129        SkMatrix rotM;
130        rotM.setRotate(23.f, rect.centerX(), rect.centerY());
131        rotRect.transform(rotM);
132        fClips.addToTail()->setPath(rotRect);
133
134        fBmp = make_bmp(100, 100);
135    }
136
137    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
138        SkScalar y = 0;
139        static const SkScalar kMargin = 10.f;
140
141        SkPaint bgPaint;
142        bgPaint.setAlpha(0x15);
143        SkISize size = canvas->getDeviceSize();
144        SkRect dstRect = SkRect::MakeWH(SkIntToScalar(size.fWidth),
145                                        SkIntToScalar(size.fHeight));
146        canvas->drawBitmapRectToRect(fBmp, NULL, dstRect, &bgPaint);
147
148        static const char kTxt[] = "Clip Me!";
149        SkPaint txtPaint;
150        txtPaint.setTextSize(23.f);
151        txtPaint.setAntiAlias(true);
152        txtPaint.setColor(SK_ColorDKGRAY);
153        SkScalar textW = txtPaint.measureText(kTxt, SK_ARRAY_COUNT(kTxt)-1);
154
155        SkScalar startX = 0;
156        int testLayers = kBench_Mode != this->getMode();
157        for (int doLayer = 0; doLayer <= testLayers; ++doLayer) {
158            for (SkTLList<Clip>::Iter iter(fClips, SkTLList<Clip>::Iter::kHead_IterStart);
159                 NULL != iter.get();
160                 iter.next()) {
161                const Clip* clip = iter.get();
162                SkScalar x = startX;
163                for (int aa = 0; aa < 2; ++aa) {
164                    if (doLayer) {
165                        SkRect bounds;
166                        clip->getBounds(&bounds);
167                        bounds.outset(2, 2);
168                        bounds.offset(x, y);
169                        canvas->saveLayer(&bounds, NULL);
170                    } else {
171                        canvas->save();
172                    }
173                    canvas->translate(x, y);
174                    clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa));
175                    canvas->drawBitmap(fBmp, 0, 0);
176                    canvas->restore();
177                    x += fBmp.width() + kMargin;
178                }
179                for (int aa = 0; aa < 2; ++aa) {
180
181                    SkPaint clipOutlinePaint;
182                    clipOutlinePaint.setAntiAlias(true);
183                    clipOutlinePaint.setColor(0x50505050);
184                    clipOutlinePaint.setStyle(SkPaint::kStroke_Style);
185                    clipOutlinePaint.setStrokeWidth(0);
186
187                    if (doLayer) {
188                        SkRect bounds;
189                        clip->getBounds(&bounds);
190                        bounds.outset(2, 2);
191                        bounds.offset(x, y);
192                        canvas->saveLayer(&bounds, NULL);
193                    } else {
194                        canvas->save();
195                    }
196                    canvas->translate(x, y);
197                    SkPath closedClipPath;
198                    clip->asClosedPath(&closedClipPath);
199                    canvas->drawPath(closedClipPath, clipOutlinePaint);
200                    clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa));
201                    canvas->scale(1.f, 1.8f);
202                    canvas->drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1,
203                                     0, 1.5f * txtPaint.getTextSize(),
204                                     txtPaint);
205                    canvas->restore();
206                    x += textW + 2 * kMargin;
207                }
208                y += fBmp.height() + kMargin;
209            }
210            y = 0;
211            startX += 2 * fBmp.width() + SkScalarCeilToInt(2 * textW) + 6 * kMargin;
212        }
213    }
214
215    virtual uint32_t onGetFlags() const {
216        return kAsBench_Flag | kSkipTiled_Flag;
217    }
218
219private:
220    class Clip {
221    public:
222        enum ClipType {
223            kNone_ClipType,
224            kPath_ClipType,
225            kRect_ClipType
226        };
227
228        Clip () : fClipType(kNone_ClipType) {}
229
230        void setOnCanvas(SkCanvas* canvas, SkRegion::Op 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
244        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
260        void setPath(const SkPath& path) {
261            fClipType = kPath_ClipType;
262            fPath = path;
263        }
264
265        void setRect(const SkRect& rect) {
266            fClipType = kRect_ClipType;
267            fRect = rect;
268            fPath.reset();
269        }
270
271        ClipType getType() const { return fClipType; }
272
273        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    SkTLList<Clip>   fClips;
294    SkBitmap         fBmp;
295
296    typedef GM INHERITED;
297};
298
299DEF_GM( return SkNEW(ConvexPolyClip); )
300
301}
302