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 
16 static 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 
25 class PictureShaderGM : public skiagm::GM {
26 public:
PictureShaderGM(SkScalar tileSize,SkScalar sceneSize)27     PictureShaderGM(SkScalar tileSize, SkScalar sceneSize)
28         : fTileSize(tileSize)
29         , fSceneSize(sceneSize) {
30     }
31 
32  protected:
onOnceBeforeDraw()33     void onOnceBeforeDraw() override {
34        // Build the picture.
35         SkPictureRecorder recorder;
36         SkCanvas* pictureCanvas = recorder.beginRecording(fTileSize, fTileSize, NULL, 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 
onShortName()48     SkString onShortName() override {
49         return SkString("pictureshader");
50     }
51 
onISize()52     SkISize onISize() override {
53         return SkISize::Make(1400, 1450);
54     }
55 
onDraw(SkCanvas * canvas)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 
87 private:
drawSceneColumn(SkCanvas * canvas,const SkPoint & pos,SkScalar scale,SkScalar localScale,unsigned tileMode)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 
drawTile(SkCanvas * canvas)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 
drawScene(SkCanvas * canvas,const SkMatrix & matrix,const SkMatrix & localMatrix,unsigned tileMode)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_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(SkShader::CreatePictureShader(
154                     fPicture,
155                     kTileConfigs[tileMode].tmx,
156                     kTileConfigs[tileMode].tmy,
157                     &localMatrix,
158                     NULL));
159         paint.setShader(pictureShader.get());
160         canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
161 
162         canvas->translate(fSceneSize * 1.1f, 0);
163 
164         SkAutoTUnref<SkShader> bitmapShader(SkShader::CreateBitmapShader(
165                     fBitmap,
166                     kTileConfigs[tileMode].tmx,
167                     kTileConfigs[tileMode].tmy,
168                     &localMatrix));
169         paint.setShader(bitmapShader.get());
170         canvas->drawRect(SkRect::MakeWH(fSceneSize, fSceneSize), paint);
171 
172         canvas->restore();
173     }
174 
175     SkScalar    fTileSize;
176     SkScalar    fSceneSize;
177 
178     SkAutoTUnref<SkPicture> fPicture;
179     SkBitmap fBitmap;
180 
181     typedef GM INHERITED;
182 };
183 
184 DEF_GM( return SkNEW_ARGS(PictureShaderGM, (50, 100)); )
185 
186 DEF_SIMPLE_GM(tiled_picture_shader, canvas, 400, 400) {
187     // https://code.google.com/p/skia/issues/detail?id=3398
188     SkRect tile = SkRect::MakeWH(100, 100);
189 
190     SkPictureRecorder recorder;
191     SkCanvas* c = recorder.beginRecording(tile);
192 
193     SkRect r = tile;
194     r.inset(4, 4);
195     SkPaint p;
196     p.setColor(0xFF303F9F);  // dark blue
197     c->drawRect(r, p);
198     p.setColor(0xFFC5CAE9);  // light blue
199     p.setStrokeWidth(10);
200     c->drawLine(20, 20, 80, 80, p);
201 
202     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
203     SkAutoTUnref<SkShader> shader(SkShader::CreatePictureShader(
204 	      picture.get(),
205 	      SkShader::kRepeat_TileMode,
206 	      SkShader::kRepeat_TileMode,
207 	      NULL,
208 	      NULL));
209 
210     p.setColor(0xFF8BC34A);  // green
211     canvas->drawPaint(p);
212 
213     canvas->clipRect(SkRect::MakeXYWH(0, 0, 400, 350));
214     p.setColor(0xFFB6B6B6);  // gray
215     canvas->drawPaint(p);
216     p.setShader(shader.get());
217 
218     canvas->drawPaint(p);
219 }
220