blob: 453dded8cc3e0d3328121d42bf58e2a5283ea4e1 [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"
robertphillips9a264102014-12-08 09:18:58 -08009#include "SkBlurImageFilter.h"
10#include "SkDropShadowImageFilter.h"
fmalita2f5891e2015-09-25 09:15:55 -070011#include "SkImageSource.h"
robertphillips9a264102014-12-08 09:18:58 -080012#include "SkOffsetImageFilter.h"
13#include "SkPictureImageFilter.h"
14#include "SkPictureRecorder.h"
15#include "SkRandom.h"
fmalita2f5891e2015-09-25 09:15:55 -070016#include "SkSurface.h"
senorblancod18b1b52015-12-07 10:36:30 -080017#include "SkTileImageFilter.h"
robertphillips9a264102014-12-08 09:18:58 -080018
19namespace skiagm {
20
21// Each method of this type must draw its geometry inside 'r' using 'p'
22typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
23
24static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
25 canvas->drawRect(r, p);
26}
27
28static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
29 canvas->drawOval(r, p);
30}
31
32static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
33 SkScalar xRad = r.width() / 4.0f;
34 SkScalar yRad = r.height() / 4.0f;
35
36 SkRRect rr;
37 rr.setRectXY(r, xRad, yRad);
38 canvas->drawRRect(rr, p);
39}
40
41static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
42 SkScalar xRad = r.width() / 4.0f;
43 SkScalar yRad = r.height() / 4.0f;
44
45 SkRRect outer;
46 outer.setRectXY(r, xRad, yRad);
47 SkRRect inner = outer;
48 inner.inset(xRad, yRad);
49 canvas->drawDRRect(outer, inner, p);
50}
51
52static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
53 SkPath path;
54
55 path.moveTo(r.fLeft, r.fTop);
56 path.lineTo(r.fLeft, r.fBottom);
57 path.lineTo(r.fRight, r.fBottom);
58 path.close();
59
60 canvas->drawPath(path, p);
61}
62
63static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
64 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
65 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
66
67 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
68 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
69}
70
71static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
72 SkBitmap bm;
73
74 bm.allocN32Pixels(64, 64);
75 SkCanvas temp(bm);
76 temp.clear(SK_ColorMAGENTA);
77
78 canvas->drawBitmapRect(bm, r, &p);
79}
80
81static const drawMth gDrawMthds[] = {
82 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
83};
84
85static void add_paint(SkImageFilter* filter, SkTArray<SkPaint>* paints) {
86 SkPaint& p = paints->push_back();
87 p.setImageFilter(filter);
88 SkASSERT(p.canComputeFastBounds());
89}
90
91// Create a selection of imagefilter-based paints to test
92static void create_paints(SkImageFilter* source, SkTArray<SkPaint>* paints) {
93 {
94 SkMatrix scale;
95 scale.setScale(2.0f, 2.0f);
96
senorblanco8c874ee2015-03-20 06:38:17 -070097 SkAutoTUnref<SkImageFilter> scaleMIF(
98 SkImageFilter::CreateMatrixFilter(scale, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -080099
100 add_paint(scaleMIF, paints);
101 }
102
103 {
104 SkMatrix rot;
105 rot.setRotate(-33.3f);
106
senorblanco8c874ee2015-03-20 06:38:17 -0700107 SkAutoTUnref<SkImageFilter> rotMIF(
108 SkImageFilter::CreateMatrixFilter(rot, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800109
110 add_paint(rotMIF, paints);
111 }
112
113 {
senorblancod18b1b52015-12-07 10:36:30 -0800114 SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
115 SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
116 SkAutoTUnref<SkImageFilter> tileIF(
117 SkTileImageFilter::Create(src, dst, nullptr));
118
119 add_paint(tileIF, paints);
120 }
121
122 {
robertphillips9a264102014-12-08 09:18:58 -0800123 static const SkDropShadowImageFilter::ShadowMode kBoth =
124 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
125
reed5ea95df2015-10-06 14:05:32 -0700126 SkAutoTUnref<SkImageFilter> dsif(
robertphillips9a264102014-12-08 09:18:58 -0800127 SkDropShadowImageFilter::Create(10.0f, 10.0f,
128 3.0f, 3.0f,
129 SK_ColorRED, kBoth,
halcanary96fcdcc2015-08-27 07:41:13 -0700130 source, nullptr));
robertphillips9a264102014-12-08 09:18:58 -0800131
132 add_paint(dsif, paints);
133 }
134
135 {
reed5ea95df2015-10-06 14:05:32 -0700136 SkAutoTUnref<SkImageFilter> dsif(
robertphillips9a264102014-12-08 09:18:58 -0800137 SkDropShadowImageFilter::Create(27.0f, 27.0f,
138 3.0f, 3.0f,
139 SK_ColorRED,
140 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
halcanary96fcdcc2015-08-27 07:41:13 -0700141 source, nullptr));
robertphillips9a264102014-12-08 09:18:58 -0800142
143 add_paint(dsif, paints);
144 }
145
146 {
reed5ea95df2015-10-06 14:05:32 -0700147 SkAutoTUnref<SkImageFilter> bif(SkBlurImageFilter::Create(3, 3, source));
robertphillips9a264102014-12-08 09:18:58 -0800148
149 add_paint(bif, paints);
150 }
151
152 {
reed5ea95df2015-10-06 14:05:32 -0700153 SkAutoTUnref<SkImageFilter> oif(SkOffsetImageFilter::Create(15, 15, source));
robertphillips9a264102014-12-08 09:18:58 -0800154
155 add_paint(oif, paints);
156 }
157}
158
159// This GM visualizes the fast bounds for various combinations of geometry
160// and image filter
161class ImageFilterFastBoundGM : public GM {
162public:
163 ImageFilterFastBoundGM() {
caryclark65cdba62015-06-15 06:51:08 -0700164 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
robertphillips9a264102014-12-08 09:18:58 -0800165 }
166
167protected:
168 static const int kTileWidth = 100;
169 static const int kTileHeight = 100;
senorblancod18b1b52015-12-07 10:36:30 -0800170 static const int kNumVertTiles = 7;
robertphillips9a264102014-12-08 09:18:58 -0800171 static const int kNumXtraCols = 2;
172
mtklein36352bf2015-03-25 18:17:31 -0700173 SkString onShortName() override{ return SkString("filterfastbounds"); }
robertphillips9a264102014-12-08 09:18:58 -0800174
mtklein36352bf2015-03-25 18:17:31 -0700175 SkISize onISize() override{
robertphillips9a264102014-12-08 09:18:58 -0800176 return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
177 kNumVertTiles * kTileHeight);
178 }
179
180 static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
181 SkCanvas* canvas, const SkPaint& p) {
182 SkPaint redStroked;
183 redStroked.setColor(SK_ColorRED);
184 redStroked.setStyle(SkPaint::kStroke_Style);
185
186 SkPaint blueStroked;
187 blueStroked.setColor(SK_ColorBLUE);
188 blueStroked.setStyle(SkPaint::kStroke_Style);
189
190 const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
191 SkRect storage;
192
193 canvas->save();
194 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
195 canvas->scale(1.5f, 1.5f);
196
197 const SkRect& fastBound = p.computeFastBounds(r, &storage);
198
199 canvas->save();
200 canvas->clipRect(fastBound);
201 (*draw)(canvas, r, p);
202 canvas->restore();
203
204 canvas->drawRect(r, redStroked);
205 canvas->drawRect(fastBound, blueStroked);
206 canvas->restore();
207 }
208
209 static void draw_savelayer_with_paint(const SkIPoint& off,
210 SkCanvas* canvas,
211 const SkPaint& p) {
212 SkPaint redStroked;
213 redStroked.setColor(SK_ColorRED);
214 redStroked.setStyle(SkPaint::kStroke_Style);
215
216 SkPaint blueStroked;
217 blueStroked.setColor(SK_ColorBLUE);
218 blueStroked.setStyle(SkPaint::kStroke_Style);
219
220 const SkRect bounds = SkRect::MakeWH(10, 10);
221 SkRect storage;
222
223 canvas->save();
224 canvas->translate(30, 30);
225 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
226 canvas->scale(1.5f, 1.5f);
227
228 const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
229
230 canvas->saveLayer(&fastBound, &p);
231 canvas->restore();
232
233 canvas->drawRect(bounds, redStroked);
234 canvas->drawRect(fastBound, blueStroked);
235 canvas->restore();
236 }
237
mtklein36352bf2015-03-25 18:17:31 -0700238 void onDraw(SkCanvas* canvas) override{
robertphillips9a264102014-12-08 09:18:58 -0800239
240 SkPaint blackFill;
241
242 //-----------
243 // Normal paints (no source)
244 SkTArray<SkPaint> paints;
halcanary96fcdcc2015-08-27 07:41:13 -0700245 create_paints(nullptr, &paints);
robertphillips9a264102014-12-08 09:18:58 -0800246
247 //-----------
248 // Paints with a PictureImageFilter as a source
249 SkAutoTUnref<SkPicture> pic;
250
251 {
252 SkPictureRecorder rec;
253
254 SkCanvas* c = rec.beginRecording(10, 10);
255 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
256 pic.reset(rec.endRecording());
257 }
258
reed5ea95df2015-10-06 14:05:32 -0700259 SkAutoTUnref<SkImageFilter> pif(SkPictureImageFilter::Create(pic));
robertphillips9a264102014-12-08 09:18:58 -0800260
261 SkTArray<SkPaint> pifPaints;
262 create_paints(pif, &pifPaints);
263
264 //-----------
fmalita2f5891e2015-09-25 09:15:55 -0700265 // Paints with a SkImageSource as a source
robertphillips9a264102014-12-08 09:18:58 -0800266
fmalita2f5891e2015-09-25 09:15:55 -0700267 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(10, 10));
robertphillips9a264102014-12-08 09:18:58 -0800268 {
269 SkPaint p;
fmalita2f5891e2015-09-25 09:15:55 -0700270 SkCanvas* temp = surface->getCanvas();
271 temp->clear(SK_ColorYELLOW);
robertphillips9a264102014-12-08 09:18:58 -0800272 p.setColor(SK_ColorBLUE);
fmalita2f5891e2015-09-25 09:15:55 -0700273 temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
robertphillips9a264102014-12-08 09:18:58 -0800274 p.setColor(SK_ColorGREEN);
fmalita2f5891e2015-09-25 09:15:55 -0700275 temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
robertphillips9a264102014-12-08 09:18:58 -0800276 }
277
fmalita2f5891e2015-09-25 09:15:55 -0700278 SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
279 SkAutoTUnref<SkImageFilter> imageSource(SkImageSource::Create(image));
robertphillips9a264102014-12-08 09:18:58 -0800280
281 SkTArray<SkPaint> bmsPaints;
fmalita2f5891e2015-09-25 09:15:55 -0700282 create_paints(imageSource, &bmsPaints);
robertphillips9a264102014-12-08 09:18:58 -0800283
284 //-----------
285 SkASSERT(paints.count() == kNumVertTiles);
286 SkASSERT(paints.count() == pifPaints.count());
287 SkASSERT(paints.count() == bmsPaints.count());
288
289 // horizontal separators
290 for (int i = 1; i < paints.count(); ++i) {
291 canvas->drawLine(0,
292 i*SkIntToScalar(kTileHeight),
293 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
294 i*SkIntToScalar(kTileHeight),
295 blackFill);
296 }
297 // vertical separators
298 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
299 canvas->drawLine(SkIntToScalar(i * kTileWidth),
300 0,
301 SkIntToScalar(i * kTileWidth),
302 SkIntToScalar(paints.count() * kTileWidth),
303 blackFill);
304 }
305
306 // A column of saveLayers with PictureImageFilters
307 for (int i = 0; i < pifPaints.count(); ++i) {
308 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
309 canvas, pifPaints[i]);
310 }
311
312 // A column of saveLayers with BitmapSources
313 for (int i = 0; i < pifPaints.count(); ++i) {
314 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
315 canvas, bmsPaints[i]);
316 }
317
318 // Multiple columns with different geometry
319 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
320 for (int j = 0; j < paints.count(); ++j) {
321 draw_geom_with_paint(*gDrawMthds[i],
322 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
323 canvas, paints[j]);
324 }
325 }
326
327 }
328
329private:
330 typedef GM INHERITED;
331};
332
333//////////////////////////////////////////////////////////////////////////////
334
halcanary385fe4d2015-08-26 13:07:48 -0700335DEF_GM(return new ImageFilterFastBoundGM;)
robertphillips9a264102014-12-08 09:18:58 -0800336}