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