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