blob: 5102b863c2ee7920d7a8d7709ecb999ce1efa35a [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"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
robertphillips9a264102014-12-08 09:18:58 -080010#include "SkBlurImageFilter.h"
11#include "SkDropShadowImageFilter.h"
fmalita2f5891e2015-09-25 09:15:55 -070012#include "SkImageSource.h"
robertphillips9a264102014-12-08 09:18:58 -080013#include "SkOffsetImageFilter.h"
14#include "SkPictureImageFilter.h"
15#include "SkPictureRecorder.h"
16#include "SkRandom.h"
fmalita2f5891e2015-09-25 09:15:55 -070017#include "SkSurface.h"
senorblancod18b1b52015-12-07 10:36:30 -080018#include "SkTileImageFilter.h"
robertphillips9a264102014-12-08 09:18:58 -080019
20namespace skiagm {
21
22// Each method of this type must draw its geometry inside 'r' using 'p'
23typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
24
25static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
26 canvas->drawRect(r, p);
27}
28
29static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
30 canvas->drawOval(r, p);
31}
32
33static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
34 SkScalar xRad = r.width() / 4.0f;
35 SkScalar yRad = r.height() / 4.0f;
36
37 SkRRect rr;
38 rr.setRectXY(r, xRad, yRad);
39 canvas->drawRRect(rr, p);
40}
41
42static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
43 SkScalar xRad = r.width() / 4.0f;
44 SkScalar yRad = r.height() / 4.0f;
45
46 SkRRect outer;
47 outer.setRectXY(r, xRad, yRad);
48 SkRRect inner = outer;
49 inner.inset(xRad, yRad);
50 canvas->drawDRRect(outer, inner, p);
51}
52
53static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
54 SkPath path;
55
56 path.moveTo(r.fLeft, r.fTop);
57 path.lineTo(r.fLeft, r.fBottom);
58 path.lineTo(r.fRight, r.fBottom);
59 path.close();
60
61 canvas->drawPath(path, p);
62}
63
64static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
65 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
66 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
67
68 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
69 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
70}
71
72static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
73 SkBitmap bm;
74
75 bm.allocN32Pixels(64, 64);
76 SkCanvas temp(bm);
77 temp.clear(SK_ColorMAGENTA);
78
79 canvas->drawBitmapRect(bm, r, &p);
80}
81
mtkleindbfd7ab2016-09-01 11:24:54 -070082constexpr drawMth gDrawMthds[] = {
robertphillips9a264102014-12-08 09:18:58 -080083 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
84};
85
robertphillips6e7025a2016-04-04 04:31:25 -070086static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
robertphillips9a264102014-12-08 09:18:58 -080087 SkPaint& p = paints->push_back();
robertphillips6e7025a2016-04-04 04:31:25 -070088 p.setImageFilter(std::move(filter));
robertphillips9a264102014-12-08 09:18:58 -080089 SkASSERT(p.canComputeFastBounds());
90}
91
92// Create a selection of imagefilter-based paints to test
robertphillips6e7025a2016-04-04 04:31:25 -070093static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
robertphillips9a264102014-12-08 09:18:58 -080094 {
95 SkMatrix scale;
96 scale.setScale(2.0f, 2.0f);
97
robertphillips6e7025a2016-04-04 04:31:25 -070098 sk_sp<SkImageFilter> scaleMIF(
robertphillipsae8c9332016-04-05 15:09:00 -070099 SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800100
robertphillips6e7025a2016-04-04 04:31:25 -0700101 add_paint(paints, std::move(scaleMIF));
robertphillips9a264102014-12-08 09:18:58 -0800102 }
103
104 {
105 SkMatrix rot;
106 rot.setRotate(-33.3f);
107
robertphillips6e7025a2016-04-04 04:31:25 -0700108 sk_sp<SkImageFilter> rotMIF(
robertphillipsae8c9332016-04-05 15:09:00 -0700109 SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800110
robertphillips6e7025a2016-04-04 04:31:25 -0700111 add_paint(paints, std::move(rotMIF));
robertphillips9a264102014-12-08 09:18:58 -0800112 }
113
114 {
senorblancod18b1b52015-12-07 10:36:30 -0800115 SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
116 SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
robertphillips534c2702016-04-15 07:57:40 -0700117 sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
senorblancod18b1b52015-12-07 10:36:30 -0800118
robertphillips6e7025a2016-04-04 04:31:25 -0700119 add_paint(paints, std::move(tileIF));
senorblancod18b1b52015-12-07 10:36:30 -0800120 }
121
122 {
mtkleindbfd7ab2016-09-01 11:24:54 -0700123 constexpr SkDropShadowImageFilter::ShadowMode kBoth =
robertphillips9a264102014-12-08 09:18:58 -0800124 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
125
robertphillipsc4169122016-04-06 08:40:59 -0700126 sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
127 3.0f, 3.0f,
128 SK_ColorRED, kBoth,
129 source));
robertphillips9a264102014-12-08 09:18:58 -0800130
robertphillips6e7025a2016-04-04 04:31:25 -0700131 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800132 }
133
134 {
robertphillips6e7025a2016-04-04 04:31:25 -0700135 sk_sp<SkImageFilter> dsif(
robertphillipsc4169122016-04-06 08:40:59 -0700136 SkDropShadowImageFilter::Make(27.0f, 27.0f,
robertphillips9a264102014-12-08 09:18:58 -0800137 3.0f, 3.0f,
138 SK_ColorRED,
139 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700140 source));
robertphillips9a264102014-12-08 09:18:58 -0800141
robertphillips6e7025a2016-04-04 04:31:25 -0700142 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800143 }
144
robertphillips6e7025a2016-04-04 04:31:25 -0700145 add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
146 add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
robertphillips9a264102014-12-08 09:18:58 -0800147}
148
149// This GM visualizes the fast bounds for various combinations of geometry
150// and image filter
151class ImageFilterFastBoundGM : public GM {
152public:
153 ImageFilterFastBoundGM() {
caryclark65cdba62015-06-15 06:51:08 -0700154 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
robertphillips9a264102014-12-08 09:18:58 -0800155 }
156
157protected:
mtkleindbfd7ab2016-09-01 11:24:54 -0700158 static constexpr int kTileWidth = 100;
159 static constexpr int kTileHeight = 100;
160 static constexpr int kNumVertTiles = 7;
161 static constexpr int kNumXtraCols = 2;
robertphillips9a264102014-12-08 09:18:58 -0800162
mtklein36352bf2015-03-25 18:17:31 -0700163 SkString onShortName() override{ return SkString("filterfastbounds"); }
robertphillips9a264102014-12-08 09:18:58 -0800164
mtklein36352bf2015-03-25 18:17:31 -0700165 SkISize onISize() override{
robertphillips9a264102014-12-08 09:18:58 -0800166 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
mtklein36352bf2015-03-25 18:17:31 -0700228 void onDraw(SkCanvas* canvas) override{
robertphillips9a264102014-12-08 09:18:58 -0800229
230 SkPaint blackFill;
231
232 //-----------
233 // Normal paints (no source)
234 SkTArray<SkPaint> paints;
robertphillips6e7025a2016-04-04 04:31:25 -0700235 create_paints(&paints, nullptr);
robertphillips9a264102014-12-08 09:18:58 -0800236
237 //-----------
238 // Paints with a PictureImageFilter as a source
reedca2622b2016-03-18 07:25:55 -0700239 sk_sp<SkPicture> pic;
robertphillips9a264102014-12-08 09:18:58 -0800240
241 {
242 SkPictureRecorder rec;
243
244 SkCanvas* c = rec.beginRecording(10, 10);
245 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
reedca2622b2016-03-18 07:25:55 -0700246 pic = rec.finishRecordingAsPicture();
robertphillips9a264102014-12-08 09:18:58 -0800247 }
248
robertphillips9a264102014-12-08 09:18:58 -0800249 SkTArray<SkPaint> pifPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700250 create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
robertphillips9a264102014-12-08 09:18:58 -0800251
252 //-----------
fmalita2f5891e2015-09-25 09:15:55 -0700253 // Paints with a SkImageSource as a source
robertphillips9a264102014-12-08 09:18:58 -0800254
reede8f30622016-03-23 18:59:25 -0700255 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
robertphillips9a264102014-12-08 09:18:58 -0800256 {
257 SkPaint p;
fmalita2f5891e2015-09-25 09:15:55 -0700258 SkCanvas* temp = surface->getCanvas();
259 temp->clear(SK_ColorYELLOW);
robertphillips9a264102014-12-08 09:18:58 -0800260 p.setColor(SK_ColorBLUE);
fmalita2f5891e2015-09-25 09:15:55 -0700261 temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
robertphillips9a264102014-12-08 09:18:58 -0800262 p.setColor(SK_ColorGREEN);
fmalita2f5891e2015-09-25 09:15:55 -0700263 temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
robertphillips9a264102014-12-08 09:18:58 -0800264 }
265
reed9ce9d672016-03-17 10:51:11 -0700266 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -0700267 sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
robertphillips9a264102014-12-08 09:18:58 -0800268 SkTArray<SkPaint> bmsPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700269 create_paints(&bmsPaints, std::move(imageSource));
robertphillips9a264102014-12-08 09:18:58 -0800270
271 //-----------
272 SkASSERT(paints.count() == kNumVertTiles);
273 SkASSERT(paints.count() == pifPaints.count());
274 SkASSERT(paints.count() == bmsPaints.count());
275
276 // horizontal separators
277 for (int i = 1; i < paints.count(); ++i) {
278 canvas->drawLine(0,
279 i*SkIntToScalar(kTileHeight),
280 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
281 i*SkIntToScalar(kTileHeight),
282 blackFill);
283 }
284 // vertical separators
285 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
286 canvas->drawLine(SkIntToScalar(i * kTileWidth),
287 0,
halcanary9d524f22016-03-29 09:03:52 -0700288 SkIntToScalar(i * kTileWidth),
robertphillips9a264102014-12-08 09:18:58 -0800289 SkIntToScalar(paints.count() * kTileWidth),
290 blackFill);
291 }
292
293 // A column of saveLayers with PictureImageFilters
294 for (int i = 0; i < pifPaints.count(); ++i) {
halcanary9d524f22016-03-29 09:03:52 -0700295 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
robertphillips9a264102014-12-08 09:18:58 -0800296 canvas, pifPaints[i]);
297 }
298
299 // A column of saveLayers with BitmapSources
300 for (int i = 0; i < pifPaints.count(); ++i) {
301 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
302 canvas, bmsPaints[i]);
303 }
304
305 // Multiple columns with different geometry
306 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
307 for (int j = 0; j < paints.count(); ++j) {
308 draw_geom_with_paint(*gDrawMthds[i],
309 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
310 canvas, paints[j]);
311 }
312 }
313
314 }
315
316private:
317 typedef GM INHERITED;
318};
319
320//////////////////////////////////////////////////////////////////////////////
321
halcanary385fe4d2015-08-26 13:07:48 -0700322DEF_GM(return new ImageFilterFastBoundGM;)
robertphillips9a264102014-12-08 09:18:58 -0800323}