blob: 812c6668eae7db747fd2236044c9dd935d0cea6f [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
mtkleindbfd7ab2016-09-01 11:24:54 -070081constexpr drawMth gDrawMthds[] = {
robertphillips9a264102014-12-08 09:18:58 -080082 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
83};
84
robertphillips6e7025a2016-04-04 04:31:25 -070085static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
robertphillips9a264102014-12-08 09:18:58 -080086 SkPaint& p = paints->push_back();
robertphillips6e7025a2016-04-04 04:31:25 -070087 p.setImageFilter(std::move(filter));
robertphillips9a264102014-12-08 09:18:58 -080088 SkASSERT(p.canComputeFastBounds());
89}
90
91// Create a selection of imagefilter-based paints to test
robertphillips6e7025a2016-04-04 04:31:25 -070092static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
robertphillips9a264102014-12-08 09:18:58 -080093 {
94 SkMatrix scale;
95 scale.setScale(2.0f, 2.0f);
96
robertphillips6e7025a2016-04-04 04:31:25 -070097 sk_sp<SkImageFilter> scaleMIF(
robertphillipsae8c9332016-04-05 15:09:00 -070098 SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -080099
robertphillips6e7025a2016-04-04 04:31:25 -0700100 add_paint(paints, std::move(scaleMIF));
robertphillips9a264102014-12-08 09:18:58 -0800101 }
102
103 {
104 SkMatrix rot;
105 rot.setRotate(-33.3f);
106
robertphillips6e7025a2016-04-04 04:31:25 -0700107 sk_sp<SkImageFilter> rotMIF(
robertphillipsae8c9332016-04-05 15:09:00 -0700108 SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800109
robertphillips6e7025a2016-04-04 04:31:25 -0700110 add_paint(paints, std::move(rotMIF));
robertphillips9a264102014-12-08 09:18:58 -0800111 }
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);
robertphillips534c2702016-04-15 07:57:40 -0700116 sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
senorblancod18b1b52015-12-07 10:36:30 -0800117
robertphillips6e7025a2016-04-04 04:31:25 -0700118 add_paint(paints, std::move(tileIF));
senorblancod18b1b52015-12-07 10:36:30 -0800119 }
120
121 {
mtkleindbfd7ab2016-09-01 11:24:54 -0700122 constexpr SkDropShadowImageFilter::ShadowMode kBoth =
robertphillips9a264102014-12-08 09:18:58 -0800123 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
124
robertphillipsc4169122016-04-06 08:40:59 -0700125 sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
126 3.0f, 3.0f,
127 SK_ColorRED, kBoth,
128 source));
robertphillips9a264102014-12-08 09:18:58 -0800129
robertphillips6e7025a2016-04-04 04:31:25 -0700130 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800131 }
132
133 {
robertphillips6e7025a2016-04-04 04:31:25 -0700134 sk_sp<SkImageFilter> dsif(
robertphillipsc4169122016-04-06 08:40:59 -0700135 SkDropShadowImageFilter::Make(27.0f, 27.0f,
robertphillips9a264102014-12-08 09:18:58 -0800136 3.0f, 3.0f,
137 SK_ColorRED,
138 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700139 source));
robertphillips9a264102014-12-08 09:18:58 -0800140
robertphillips6e7025a2016-04-04 04:31:25 -0700141 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800142 }
143
robertphillips6e7025a2016-04-04 04:31:25 -0700144 add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
145 add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
robertphillips9a264102014-12-08 09:18:58 -0800146}
147
148// This GM visualizes the fast bounds for various combinations of geometry
149// and image filter
150class ImageFilterFastBoundGM : public GM {
151public:
152 ImageFilterFastBoundGM() {
caryclark65cdba62015-06-15 06:51:08 -0700153 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
robertphillips9a264102014-12-08 09:18:58 -0800154 }
155
156protected:
mtkleindbfd7ab2016-09-01 11:24:54 -0700157 static constexpr int kTileWidth = 100;
158 static constexpr int kTileHeight = 100;
159 static constexpr int kNumVertTiles = 7;
160 static constexpr int kNumXtraCols = 2;
robertphillips9a264102014-12-08 09:18:58 -0800161
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;
robertphillips6e7025a2016-04-04 04:31:25 -0700234 create_paints(&paints, nullptr);
robertphillips9a264102014-12-08 09:18:58 -0800235
236 //-----------
237 // Paints with a PictureImageFilter as a source
reedca2622b2016-03-18 07:25:55 -0700238 sk_sp<SkPicture> pic;
robertphillips9a264102014-12-08 09:18:58 -0800239
240 {
241 SkPictureRecorder rec;
242
243 SkCanvas* c = rec.beginRecording(10, 10);
244 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
reedca2622b2016-03-18 07:25:55 -0700245 pic = rec.finishRecordingAsPicture();
robertphillips9a264102014-12-08 09:18:58 -0800246 }
247
robertphillips9a264102014-12-08 09:18:58 -0800248 SkTArray<SkPaint> pifPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700249 create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
robertphillips9a264102014-12-08 09:18:58 -0800250
251 //-----------
fmalita2f5891e2015-09-25 09:15:55 -0700252 // Paints with a SkImageSource as a source
robertphillips9a264102014-12-08 09:18:58 -0800253
reede8f30622016-03-23 18:59:25 -0700254 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
robertphillips9a264102014-12-08 09:18:58 -0800255 {
256 SkPaint p;
fmalita2f5891e2015-09-25 09:15:55 -0700257 SkCanvas* temp = surface->getCanvas();
258 temp->clear(SK_ColorYELLOW);
robertphillips9a264102014-12-08 09:18:58 -0800259 p.setColor(SK_ColorBLUE);
fmalita2f5891e2015-09-25 09:15:55 -0700260 temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
robertphillips9a264102014-12-08 09:18:58 -0800261 p.setColor(SK_ColorGREEN);
fmalita2f5891e2015-09-25 09:15:55 -0700262 temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
robertphillips9a264102014-12-08 09:18:58 -0800263 }
264
reed9ce9d672016-03-17 10:51:11 -0700265 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -0700266 sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
robertphillips9a264102014-12-08 09:18:58 -0800267 SkTArray<SkPaint> bmsPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700268 create_paints(&bmsPaints, std::move(imageSource));
robertphillips9a264102014-12-08 09:18:58 -0800269
270 //-----------
271 SkASSERT(paints.count() == kNumVertTiles);
272 SkASSERT(paints.count() == pifPaints.count());
273 SkASSERT(paints.count() == bmsPaints.count());
274
275 // horizontal separators
276 for (int i = 1; i < paints.count(); ++i) {
277 canvas->drawLine(0,
278 i*SkIntToScalar(kTileHeight),
279 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
280 i*SkIntToScalar(kTileHeight),
281 blackFill);
282 }
283 // vertical separators
284 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
285 canvas->drawLine(SkIntToScalar(i * kTileWidth),
286 0,
halcanary9d524f22016-03-29 09:03:52 -0700287 SkIntToScalar(i * kTileWidth),
robertphillips9a264102014-12-08 09:18:58 -0800288 SkIntToScalar(paints.count() * kTileWidth),
289 blackFill);
290 }
291
292 // A column of saveLayers with PictureImageFilters
293 for (int i = 0; i < pifPaints.count(); ++i) {
halcanary9d524f22016-03-29 09:03:52 -0700294 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
robertphillips9a264102014-12-08 09:18:58 -0800295 canvas, pifPaints[i]);
296 }
297
298 // A column of saveLayers with BitmapSources
299 for (int i = 0; i < pifPaints.count(); ++i) {
300 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
301 canvas, bmsPaints[i]);
302 }
303
304 // Multiple columns with different geometry
305 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
306 for (int j = 0; j < paints.count(); ++j) {
307 draw_geom_with_paint(*gDrawMthds[i],
308 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
309 canvas, paints[j]);
310 }
311 }
312
313 }
314
315private:
316 typedef GM INHERITED;
317};
318
319//////////////////////////////////////////////////////////////////////////////
320
halcanary385fe4d2015-08-26 13:07:48 -0700321DEF_GM(return new ImageFilterFastBoundGM;)
robertphillips9a264102014-12-08 09:18:58 -0800322}