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
10#include "SkBitmap.h"
11#include "SkPaint.h"
12#include "SkPicture.h"
13#include "SkPictureRecorder.h"
14#include "SkShader.h"
15
16static struct {
17    SkShader::TileMode tmx;
18    SkShader::TileMode tmy;
19} kTileConfigs[] = {
20    { SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode },
21    { SkShader::kRepeat_TileMode, SkShader::kClamp_TileMode  },
22    { SkShader::kMirror_TileMode, SkShader::kRepeat_TileMode },
23};
24
25class PictureShaderGM : public skiagm::GM {
26public:
27    PictureShaderGM(SkScalar tileSize, SkScalar sceneSize)
28        : fTileSize(tileSize)
29        , fSceneSize(sceneSize) {
30    }
31
32 protected:
33    void onOnceBeforeDraw() override {
34       // Build the picture.
35        SkPictureRecorder recorder;
36        SkCanvas* pictureCanvas = recorder.beginRecording(fTileSize, fTileSize, nullptr, 0);
37        this->drawTile(pictureCanvas);
38        fPicture.reset(recorder.endRecording());
39
40        // Build a reference bitmap.
41        fBitmap.allocN32Pixels(SkScalarCeilToInt(fTileSize), SkScalarCeilToInt(fTileSize));
42        fBitmap.eraseColor(SK_ColorTRANSPARENT);
43        SkCanvas bitmapCanvas(fBitmap);
44        this->drawTile(&bitmapCanvas);
45    }
46
47
48    SkString onShortName() override {
49        return SkString("pictureshader");
50    }
51
52    SkISize onISize() override {
53        return SkISize::Make(1400, 1450);
54    }
55
56    void onDraw(SkCanvas* canvas) override {
57        this->drawSceneColumn(canvas, SkPoint::Make(0, 0), 1, 1, 0);
58        this->drawSceneColumn(canvas, SkPoint::Make(0, fSceneSize * 6.4f), 1, 2, 0);
59        this->drawSceneColumn(canvas, SkPoint::Make(fSceneSize * 2.4f, 0), 1, 1, 1);
60        this->drawSceneColumn(canvas, SkPoint::Make(fSceneSize * 2.4f, fSceneSize * 6.4f), 1, 1, 2);
61        this->drawSceneColumn(canvas, SkPoint::Make(fSceneSize * 4.8f, 0), 2, 1, 0);
62        this->drawSceneColumn(canvas, SkPoint::Make(fSceneSize * 9.6f, 0), 2, 2, 0);
63
64        // One last custom row to exercise negative scaling
65        SkMatrix ctm, localMatrix;
66        ctm.setTranslate(fSceneSize * 2.1f, fSceneSize * 13.8f);
67        ctm.preScale(-1, -1);
68        localMatrix.setScale(2, 2);
69        this->drawScene(canvas, ctm, localMatrix, 0);
70
71        ctm.setTranslate(fSceneSize * 2.4f, fSceneSize * 12.8f);
72        localMatrix.setScale(-1, -1);
73        this->drawScene(canvas, ctm, localMatrix, 0);
74
75        ctm.setTranslate(fSceneSize * 4.8f, fSceneSize * 12.3f);
76        ctm.preScale(2, 2);
77        this->drawScene(canvas, ctm, localMatrix, 0);
78
79        ctm.setTranslate(fSceneSize * 13.8f, fSceneSize * 14.3f);
80        ctm.preScale(-2, -2);
81        localMatrix.setTranslate(fTileSize / 4, fTileSize / 4);
82        localMatrix.preRotate(45);
83        localMatrix.preScale(-2, -2);
84        this->drawScene(canvas, ctm, localMatrix, 0);
85    }
86
87private:
88    void drawSceneColumn(SkCanvas* canvas, const SkPoint& pos, SkScalar scale, SkScalar localScale,
89                         unsigned tileMode) {
90        SkMatrix ctm, localMatrix;
91
92        ctm.setTranslate(pos.x(), pos.y());
93        ctm.preScale(scale, scale);
94        localMatrix.setScale(localScale, localScale);
95        this->drawScene(canvas, ctm, localMatrix, tileMode);
96
97        ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 1.2f * scale);
98        ctm.preScale(scale, scale);
99        localMatrix.setTranslate(fTileSize / 4, fTileSize / 4);
100        localMatrix.preScale(localScale, localScale);
101        this->drawScene(canvas, ctm, localMatrix, tileMode);
102
103        ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 2.4f * scale);
104        ctm.preScale(scale, scale);
105        localMatrix.setRotate(45);
106        localMatrix.preScale(localScale, localScale);
107        this->drawScene(canvas, ctm, localMatrix, tileMode);
108
109        ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 3.6f * scale);
110        ctm.preScale(scale, scale);
111        localMatrix.setSkew(1, 0);
112        localMatrix.preScale(localScale, localScale);
113        this->drawScene(canvas, ctm, localMatrix, tileMode);
114
115        ctm.setTranslate(pos.x(), pos.y() + fSceneSize * 4.8f * scale);
116        ctm.preScale(scale, scale);
117        localMatrix.setTranslate(fTileSize / 4, fTileSize / 4);
118        localMatrix.preRotate(45);
119        localMatrix.preScale(localScale, localScale);
120        this->drawScene(canvas, ctm, localMatrix, tileMode);
121    }
122
123    void drawTile(SkCanvas* canvas) {
124        SkPaint paint;
125        paint.setColor(SK_ColorGREEN);
126        paint.setStyle(SkPaint::kFill_Style);
127        paint.setAntiAlias(true);
128
129        canvas->drawCircle(fTileSize / 4, fTileSize / 4, fTileSize / 4, paint);
130        canvas->drawRect(SkRect::MakeXYWH(fTileSize / 2, fTileSize / 2,
131                                          fTileSize / 2, fTileSize / 2), paint);
132
133        paint.setColor(SK_ColorRED);
134        canvas->drawLine(fTileSize / 2, fTileSize * 1 / 3,
135                         fTileSize / 2, fTileSize * 2 / 3, paint);
136        canvas->drawLine(fTileSize * 1 / 3, fTileSize / 2,
137                         fTileSize * 2 / 3, fTileSize / 2, paint);
138    }
139
140    void drawScene(SkCanvas* canvas, const SkMatrix& matrix, const SkMatrix& localMatrix,
141                   unsigned tileMode) {
142        SkASSERT(tileMode < SK_ARRAY_COUNT(kTileConfigs));
143
144        SkPaint paint;
145        paint.setStyle(SkPaint::kFill_Style);
146        paint.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY));
147
148        canvas->save();
149        canvas->concat(matrix);
150        canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
151        canvas->drawRect(SkRect::MakeXYWH(fSceneSize * 1.1f, 0, fSceneSize, fSceneSize), paint);
152
153        SkAutoTUnref<SkShader> pictureShader(
154                SkShader::CreatePictureShader(fPicture, kTileConfigs[tileMode].tmx,
155                                              kTileConfigs[tileMode].tmy, &localMatrix, nullptr));
156        paint.setShader(pictureShader.get());
157        canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
158
159        canvas->translate(fSceneSize * 1.1f, 0);
160
161        SkAutoTUnref<SkShader> bitmapShader(SkShader::CreateBitmapShader(
162                    fBitmap,
163                    kTileConfigs[tileMode].tmx,
164                    kTileConfigs[tileMode].tmy,
165                    &localMatrix));
166        paint.setShader(bitmapShader.get());
167        canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
168
169        canvas->restore();
170    }
171
172    SkScalar    fTileSize;
173    SkScalar    fSceneSize;
174
175    SkAutoTUnref<SkPicture> fPicture;
176    SkBitmap fBitmap;
177
178    typedef GM INHERITED;
179};
180
181DEF_GM(return new PictureShaderGM(50, 100);)
182
183DEF_SIMPLE_GM(tiled_picture_shader, canvas, 400, 400) {
184    // https://code.google.com/p/skia/issues/detail?id=3398
185    SkRect tile = SkRect::MakeWH(100, 100);
186
187    SkPictureRecorder recorder;
188    SkCanvas* c = recorder.beginRecording(tile);
189
190    SkRect r = tile;
191    r.inset(4, 4);
192    SkPaint p;
193    p.setColor(sk_tool_utils::color_to_565(0xFF303F9F));  // dark blue
194    c->drawRect(r, p);
195    p.setColor(sk_tool_utils::color_to_565(0xFFC5CAE9));  // light blue
196    p.setStrokeWidth(10);
197    c->drawLine(20, 20, 80, 80, p);
198
199    SkAutoTUnref<SkPicture> picture(recorder.endRecording());
200    SkAutoTUnref<SkShader> shader(
201            SkShader::CreatePictureShader(picture.get(), SkShader::kRepeat_TileMode,
202                                          SkShader::kRepeat_TileMode, nullptr, nullptr));
203
204    p.setColor(sk_tool_utils::color_to_565(0xFF8BC34A));  // green
205    canvas->drawPaint(p);
206
207    canvas->clipRect(SkRect::MakeXYWH(0, 0, 400, 350));
208    p.setColor(sk_tool_utils::color_to_565(0xFFB6B6B6));  // gray
209    canvas->drawPaint(p);
210    p.setShader(shader.get());
211
212    canvas->drawPaint(p);
213}
214