blob: 206903f3ebfab3af2e6a96bd57eeb6ad55a8834d [file] [log] [blame]
robertphillips9a264102014-12-08 09:18:58 -08001/*
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 "SkBitmapSource.h"
10#include "SkBlurImageFilter.h"
11#include "SkDropShadowImageFilter.h"
12#include "SkMatrixImageFilter.h"
13#include "SkOffsetImageFilter.h"
14#include "SkPictureImageFilter.h"
15#include "SkPictureRecorder.h"
16#include "SkRandom.h"
17
18namespace skiagm {
19
20// Each method of this type must draw its geometry inside 'r' using 'p'
21typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
22
23static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
24 canvas->drawRect(r, p);
25}
26
27static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
28 canvas->drawOval(r, p);
29}
30
31static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
32 SkScalar xRad = r.width() / 4.0f;
33 SkScalar yRad = r.height() / 4.0f;
34
35 SkRRect rr;
36 rr.setRectXY(r, xRad, yRad);
37 canvas->drawRRect(rr, p);
38}
39
40static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
41 SkScalar xRad = r.width() / 4.0f;
42 SkScalar yRad = r.height() / 4.0f;
43
44 SkRRect outer;
45 outer.setRectXY(r, xRad, yRad);
46 SkRRect inner = outer;
47 inner.inset(xRad, yRad);
48 canvas->drawDRRect(outer, inner, p);
49}
50
51static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
52 SkPath path;
53
54 path.moveTo(r.fLeft, r.fTop);
55 path.lineTo(r.fLeft, r.fBottom);
56 path.lineTo(r.fRight, r.fBottom);
57 path.close();
58
59 canvas->drawPath(path, p);
60}
61
62static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
63 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
64 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
65
66 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
67 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
68}
69
70static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
71 SkBitmap bm;
72
73 bm.allocN32Pixels(64, 64);
74 SkCanvas temp(bm);
75 temp.clear(SK_ColorMAGENTA);
76
77 canvas->drawBitmapRect(bm, r, &p);
78}
79
80static const drawMth gDrawMthds[] = {
81 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
82};
83
84static void add_paint(SkImageFilter* filter, SkTArray<SkPaint>* paints) {
85 SkPaint& p = paints->push_back();
86 p.setImageFilter(filter);
87 SkASSERT(p.canComputeFastBounds());
88}
89
90// Create a selection of imagefilter-based paints to test
91static void create_paints(SkImageFilter* source, SkTArray<SkPaint>* paints) {
92 {
93 SkMatrix scale;
94 scale.setScale(2.0f, 2.0f);
95
96 SkAutoTUnref<SkMatrixImageFilter> scaleMIF(
97 SkMatrixImageFilter::Create(scale, SkPaint::kLow_FilterLevel, source));
98
99 add_paint(scaleMIF, paints);
100 }
101
102 {
103 SkMatrix rot;
104 rot.setRotate(-33.3f);
105
106 SkAutoTUnref<SkMatrixImageFilter> rotMIF(
107 SkMatrixImageFilter::Create(rot, SkPaint::kLow_FilterLevel, source));
108
109 add_paint(rotMIF, paints);
110 }
111
112 {
113 static const SkDropShadowImageFilter::ShadowMode kBoth =
114 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
115
116 SkAutoTUnref<SkDropShadowImageFilter> dsif(
117 SkDropShadowImageFilter::Create(10.0f, 10.0f,
118 3.0f, 3.0f,
119 SK_ColorRED, kBoth,
120 source, NULL, 0));
121
122 add_paint(dsif, paints);
123 }
124
125 {
126 SkAutoTUnref<SkDropShadowImageFilter> dsif(
127 SkDropShadowImageFilter::Create(27.0f, 27.0f,
128 3.0f, 3.0f,
129 SK_ColorRED,
130 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
131 source, NULL, 0));
132
133 add_paint(dsif, paints);
134 }
135
136 {
137 SkAutoTUnref<SkBlurImageFilter> bif(SkBlurImageFilter::Create(3, 3, source));
138
139 add_paint(bif, paints);
140 }
141
142 {
143 SkAutoTUnref<SkOffsetImageFilter> oif(SkOffsetImageFilter::Create(15, 15, source));
144
145 add_paint(oif, paints);
146 }
147}
148
149// This GM visualizes the fast bounds for various combinations of geometry
150// and image filter
151class ImageFilterFastBoundGM : public GM {
152public:
153 ImageFilterFastBoundGM() {
154 this->setBGColor(0xFFCCCCCC);
155 }
156
157protected:
158 static const int kTileWidth = 100;
159 static const int kTileHeight = 100;
160 static const int kNumVertTiles = 6;
161 static const int kNumXtraCols = 2;
162
robertphillips9a264102014-12-08 09:18:58 -0800163 SkString onShortName() SK_OVERRIDE{ return SkString("filterfastbounds"); }
164
165 SkISize onISize() SK_OVERRIDE{
166 return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
167 kNumVertTiles * kTileHeight);
168 }
169
170 static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
171 SkCanvas* canvas, const SkPaint& p) {
172 SkPaint redStroked;
173 redStroked.setColor(SK_ColorRED);
174 redStroked.setStyle(SkPaint::kStroke_Style);
175
176 SkPaint blueStroked;
177 blueStroked.setColor(SK_ColorBLUE);
178 blueStroked.setStyle(SkPaint::kStroke_Style);
179
180 const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
181 SkRect storage;
182
183 canvas->save();
184 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
185 canvas->scale(1.5f, 1.5f);
186
187 const SkRect& fastBound = p.computeFastBounds(r, &storage);
188
189 canvas->save();
190 canvas->clipRect(fastBound);
191 (*draw)(canvas, r, p);
192 canvas->restore();
193
194 canvas->drawRect(r, redStroked);
195 canvas->drawRect(fastBound, blueStroked);
196 canvas->restore();
197 }
198
199 static void draw_savelayer_with_paint(const SkIPoint& off,
200 SkCanvas* canvas,
201 const SkPaint& p) {
202 SkPaint redStroked;
203 redStroked.setColor(SK_ColorRED);
204 redStroked.setStyle(SkPaint::kStroke_Style);
205
206 SkPaint blueStroked;
207 blueStroked.setColor(SK_ColorBLUE);
208 blueStroked.setStyle(SkPaint::kStroke_Style);
209
210 const SkRect bounds = SkRect::MakeWH(10, 10);
211 SkRect storage;
212
213 canvas->save();
214 canvas->translate(30, 30);
215 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
216 canvas->scale(1.5f, 1.5f);
217
218 const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
219
220 canvas->saveLayer(&fastBound, &p);
221 canvas->restore();
222
223 canvas->drawRect(bounds, redStroked);
224 canvas->drawRect(fastBound, blueStroked);
225 canvas->restore();
226 }
227
228 void onDraw(SkCanvas* canvas) SK_OVERRIDE{
229
230 SkPaint blackFill;
231
232 //-----------
233 // Normal paints (no source)
234 SkTArray<SkPaint> paints;
235 create_paints(NULL, &paints);
236
237 //-----------
238 // Paints with a PictureImageFilter as a source
239 SkAutoTUnref<SkPicture> pic;
240
241 {
242 SkPictureRecorder rec;
243
244 SkCanvas* c = rec.beginRecording(10, 10);
245 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
246 pic.reset(rec.endRecording());
247 }
248
249 SkAutoTUnref<SkPictureImageFilter> pif(SkPictureImageFilter::Create(pic));
250
251 SkTArray<SkPaint> pifPaints;
252 create_paints(pif, &pifPaints);
253
254 //-----------
255 // Paints with a BitmapSource as a source
256 SkBitmap bm;
257
258 {
259 SkPaint p;
260 bm.allocN32Pixels(10, 10);
261 SkCanvas temp(bm);
262 temp.clear(SK_ColorYELLOW);
263 p.setColor(SK_ColorBLUE);
264 temp.drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
265 p.setColor(SK_ColorGREEN);
266 temp.drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
267 }
268
269 SkAutoTUnref<SkBitmapSource> bms(SkBitmapSource::Create(bm));
270
271 SkTArray<SkPaint> bmsPaints;
272 create_paints(bms, &bmsPaints);
273
274 //-----------
275 SkASSERT(paints.count() == kNumVertTiles);
276 SkASSERT(paints.count() == pifPaints.count());
277 SkASSERT(paints.count() == bmsPaints.count());
278
279 // horizontal separators
280 for (int i = 1; i < paints.count(); ++i) {
281 canvas->drawLine(0,
282 i*SkIntToScalar(kTileHeight),
283 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
284 i*SkIntToScalar(kTileHeight),
285 blackFill);
286 }
287 // vertical separators
288 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
289 canvas->drawLine(SkIntToScalar(i * kTileWidth),
290 0,
291 SkIntToScalar(i * kTileWidth),
292 SkIntToScalar(paints.count() * kTileWidth),
293 blackFill);
294 }
295
296 // A column of saveLayers with PictureImageFilters
297 for (int i = 0; i < pifPaints.count(); ++i) {
298 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
299 canvas, pifPaints[i]);
300 }
301
302 // A column of saveLayers with BitmapSources
303 for (int i = 0; i < pifPaints.count(); ++i) {
304 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
305 canvas, bmsPaints[i]);
306 }
307
308 // Multiple columns with different geometry
309 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
310 for (int j = 0; j < paints.count(); ++j) {
311 draw_geom_with_paint(*gDrawMthds[i],
312 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
313 canvas, paints[j]);
314 }
315 }
316
317 }
318
319private:
320 typedef GM INHERITED;
321};
322
323//////////////////////////////////////////////////////////////////////////////
324
325DEF_GM(return SkNEW(ImageFilterFastBoundGM);)
326
327}