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