blob: ad042aca49a58b5e24f709cfe65c323b447f46b7 [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"
Mike Reedc090c642017-05-16 10:39:06 -040014#include "SkPath.h"
robertphillips9a264102014-12-08 09:18:58 -080015#include "SkPictureImageFilter.h"
16#include "SkPictureRecorder.h"
17#include "SkRandom.h"
fmalita2f5891e2015-09-25 09:15:55 -070018#include "SkSurface.h"
senorblancod18b1b52015-12-07 10:36:30 -080019#include "SkTileImageFilter.h"
robertphillips9a264102014-12-08 09:18:58 -080020
21namespace skiagm {
22
23// Each method of this type must draw its geometry inside 'r' using 'p'
24typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
25
26static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
27 canvas->drawRect(r, p);
28}
29
30static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
31 canvas->drawOval(r, p);
32}
33
34static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
35 SkScalar xRad = r.width() / 4.0f;
36 SkScalar yRad = r.height() / 4.0f;
37
38 SkRRect rr;
39 rr.setRectXY(r, xRad, yRad);
40 canvas->drawRRect(rr, p);
41}
42
43static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
44 SkScalar xRad = r.width() / 4.0f;
45 SkScalar yRad = r.height() / 4.0f;
46
47 SkRRect outer;
48 outer.setRectXY(r, xRad, yRad);
49 SkRRect inner = outer;
50 inner.inset(xRad, yRad);
51 canvas->drawDRRect(outer, inner, p);
52}
53
54static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
55 SkPath path;
56
57 path.moveTo(r.fLeft, r.fTop);
58 path.lineTo(r.fLeft, r.fBottom);
59 path.lineTo(r.fRight, r.fBottom);
60 path.close();
61
62 canvas->drawPath(path, p);
63}
64
65static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
66 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
67 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
68
69 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
70 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
71}
72
73static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
74 SkBitmap bm;
75
76 bm.allocN32Pixels(64, 64);
77 SkCanvas temp(bm);
78 temp.clear(SK_ColorMAGENTA);
79
80 canvas->drawBitmapRect(bm, r, &p);
81}
82
mtkleindbfd7ab2016-09-01 11:24:54 -070083constexpr drawMth gDrawMthds[] = {
robertphillips9a264102014-12-08 09:18:58 -080084 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
85};
86
robertphillips6e7025a2016-04-04 04:31:25 -070087static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
robertphillips9a264102014-12-08 09:18:58 -080088 SkPaint& p = paints->push_back();
robertphillips6e7025a2016-04-04 04:31:25 -070089 p.setImageFilter(std::move(filter));
robertphillips9a264102014-12-08 09:18:58 -080090 SkASSERT(p.canComputeFastBounds());
91}
92
93// Create a selection of imagefilter-based paints to test
robertphillips6e7025a2016-04-04 04:31:25 -070094static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
robertphillips9a264102014-12-08 09:18:58 -080095 {
96 SkMatrix scale;
97 scale.setScale(2.0f, 2.0f);
98
robertphillips6e7025a2016-04-04 04:31:25 -070099 sk_sp<SkImageFilter> scaleMIF(
robertphillipsae8c9332016-04-05 15:09:00 -0700100 SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800101
robertphillips6e7025a2016-04-04 04:31:25 -0700102 add_paint(paints, std::move(scaleMIF));
robertphillips9a264102014-12-08 09:18:58 -0800103 }
104
105 {
106 SkMatrix rot;
107 rot.setRotate(-33.3f);
108
robertphillips6e7025a2016-04-04 04:31:25 -0700109 sk_sp<SkImageFilter> rotMIF(
robertphillipsae8c9332016-04-05 15:09:00 -0700110 SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800111
robertphillips6e7025a2016-04-04 04:31:25 -0700112 add_paint(paints, std::move(rotMIF));
robertphillips9a264102014-12-08 09:18:58 -0800113 }
114
115 {
senorblancod18b1b52015-12-07 10:36:30 -0800116 SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
117 SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
robertphillips534c2702016-04-15 07:57:40 -0700118 sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
senorblancod18b1b52015-12-07 10:36:30 -0800119
robertphillips6e7025a2016-04-04 04:31:25 -0700120 add_paint(paints, std::move(tileIF));
senorblancod18b1b52015-12-07 10:36:30 -0800121 }
122
123 {
mtkleindbfd7ab2016-09-01 11:24:54 -0700124 constexpr SkDropShadowImageFilter::ShadowMode kBoth =
robertphillips9a264102014-12-08 09:18:58 -0800125 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
126
robertphillipsc4169122016-04-06 08:40:59 -0700127 sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
128 3.0f, 3.0f,
129 SK_ColorRED, kBoth,
130 source));
robertphillips9a264102014-12-08 09:18:58 -0800131
robertphillips6e7025a2016-04-04 04:31:25 -0700132 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800133 }
134
135 {
robertphillips6e7025a2016-04-04 04:31:25 -0700136 sk_sp<SkImageFilter> dsif(
robertphillipsc4169122016-04-06 08:40:59 -0700137 SkDropShadowImageFilter::Make(27.0f, 27.0f,
robertphillips9a264102014-12-08 09:18:58 -0800138 3.0f, 3.0f,
139 SK_ColorRED,
140 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700141 source));
robertphillips9a264102014-12-08 09:18:58 -0800142
robertphillips6e7025a2016-04-04 04:31:25 -0700143 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800144 }
145
robertphillips6e7025a2016-04-04 04:31:25 -0700146 add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
147 add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
robertphillips9a264102014-12-08 09:18:58 -0800148}
149
150// This GM visualizes the fast bounds for various combinations of geometry
151// and image filter
152class ImageFilterFastBoundGM : public GM {
153public:
154 ImageFilterFastBoundGM() {
caryclark65cdba62015-06-15 06:51:08 -0700155 this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
robertphillips9a264102014-12-08 09:18:58 -0800156 }
157
158protected:
mtkleindbfd7ab2016-09-01 11:24:54 -0700159 static constexpr int kTileWidth = 100;
160 static constexpr int kTileHeight = 100;
161 static constexpr int kNumVertTiles = 7;
162 static constexpr int kNumXtraCols = 2;
robertphillips9a264102014-12-08 09:18:58 -0800163
mtklein36352bf2015-03-25 18:17:31 -0700164 SkString onShortName() override{ return SkString("filterfastbounds"); }
robertphillips9a264102014-12-08 09:18:58 -0800165
mtklein36352bf2015-03-25 18:17:31 -0700166 SkISize onISize() override{
robertphillips9a264102014-12-08 09:18:58 -0800167 return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
168 kNumVertTiles * kTileHeight);
169 }
170
171 static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
172 SkCanvas* canvas, const SkPaint& p) {
173 SkPaint redStroked;
174 redStroked.setColor(SK_ColorRED);
175 redStroked.setStyle(SkPaint::kStroke_Style);
176
177 SkPaint blueStroked;
178 blueStroked.setColor(SK_ColorBLUE);
179 blueStroked.setStyle(SkPaint::kStroke_Style);
180
181 const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
182 SkRect storage;
183
184 canvas->save();
185 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
186 canvas->scale(1.5f, 1.5f);
187
188 const SkRect& fastBound = p.computeFastBounds(r, &storage);
189
190 canvas->save();
191 canvas->clipRect(fastBound);
192 (*draw)(canvas, r, p);
193 canvas->restore();
194
195 canvas->drawRect(r, redStroked);
196 canvas->drawRect(fastBound, blueStroked);
197 canvas->restore();
198 }
199
200 static void draw_savelayer_with_paint(const SkIPoint& off,
201 SkCanvas* canvas,
202 const SkPaint& p) {
203 SkPaint redStroked;
204 redStroked.setColor(SK_ColorRED);
205 redStroked.setStyle(SkPaint::kStroke_Style);
206
207 SkPaint blueStroked;
208 blueStroked.setColor(SK_ColorBLUE);
209 blueStroked.setStyle(SkPaint::kStroke_Style);
210
211 const SkRect bounds = SkRect::MakeWH(10, 10);
212 SkRect storage;
213
214 canvas->save();
215 canvas->translate(30, 30);
216 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
217 canvas->scale(1.5f, 1.5f);
218
219 const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
220
221 canvas->saveLayer(&fastBound, &p);
222 canvas->restore();
223
224 canvas->drawRect(bounds, redStroked);
225 canvas->drawRect(fastBound, blueStroked);
226 canvas->restore();
227 }
228
mtklein36352bf2015-03-25 18:17:31 -0700229 void onDraw(SkCanvas* canvas) override{
robertphillips9a264102014-12-08 09:18:58 -0800230
231 SkPaint blackFill;
232
233 //-----------
234 // Normal paints (no source)
235 SkTArray<SkPaint> paints;
robertphillips6e7025a2016-04-04 04:31:25 -0700236 create_paints(&paints, nullptr);
robertphillips9a264102014-12-08 09:18:58 -0800237
238 //-----------
239 // Paints with a PictureImageFilter as a source
reedca2622b2016-03-18 07:25:55 -0700240 sk_sp<SkPicture> pic;
robertphillips9a264102014-12-08 09:18:58 -0800241
242 {
243 SkPictureRecorder rec;
244
245 SkCanvas* c = rec.beginRecording(10, 10);
246 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
reedca2622b2016-03-18 07:25:55 -0700247 pic = rec.finishRecordingAsPicture();
robertphillips9a264102014-12-08 09:18:58 -0800248 }
249
robertphillips9a264102014-12-08 09:18:58 -0800250 SkTArray<SkPaint> pifPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700251 create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
robertphillips9a264102014-12-08 09:18:58 -0800252
253 //-----------
fmalita2f5891e2015-09-25 09:15:55 -0700254 // Paints with a SkImageSource as a source
robertphillips9a264102014-12-08 09:18:58 -0800255
reede8f30622016-03-23 18:59:25 -0700256 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
robertphillips9a264102014-12-08 09:18:58 -0800257 {
258 SkPaint p;
fmalita2f5891e2015-09-25 09:15:55 -0700259 SkCanvas* temp = surface->getCanvas();
260 temp->clear(SK_ColorYELLOW);
robertphillips9a264102014-12-08 09:18:58 -0800261 p.setColor(SK_ColorBLUE);
fmalita2f5891e2015-09-25 09:15:55 -0700262 temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
robertphillips9a264102014-12-08 09:18:58 -0800263 p.setColor(SK_ColorGREEN);
fmalita2f5891e2015-09-25 09:15:55 -0700264 temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
robertphillips9a264102014-12-08 09:18:58 -0800265 }
266
reed9ce9d672016-03-17 10:51:11 -0700267 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -0700268 sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
robertphillips9a264102014-12-08 09:18:58 -0800269 SkTArray<SkPaint> bmsPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700270 create_paints(&bmsPaints, std::move(imageSource));
robertphillips9a264102014-12-08 09:18:58 -0800271
272 //-----------
273 SkASSERT(paints.count() == kNumVertTiles);
274 SkASSERT(paints.count() == pifPaints.count());
275 SkASSERT(paints.count() == bmsPaints.count());
276
277 // horizontal separators
278 for (int i = 1; i < paints.count(); ++i) {
279 canvas->drawLine(0,
280 i*SkIntToScalar(kTileHeight),
281 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
282 i*SkIntToScalar(kTileHeight),
283 blackFill);
284 }
285 // vertical separators
286 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
287 canvas->drawLine(SkIntToScalar(i * kTileWidth),
288 0,
halcanary9d524f22016-03-29 09:03:52 -0700289 SkIntToScalar(i * kTileWidth),
robertphillips9a264102014-12-08 09:18:58 -0800290 SkIntToScalar(paints.count() * kTileWidth),
291 blackFill);
292 }
293
294 // A column of saveLayers with PictureImageFilters
295 for (int i = 0; i < pifPaints.count(); ++i) {
halcanary9d524f22016-03-29 09:03:52 -0700296 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
robertphillips9a264102014-12-08 09:18:58 -0800297 canvas, pifPaints[i]);
298 }
299
300 // A column of saveLayers with BitmapSources
301 for (int i = 0; i < pifPaints.count(); ++i) {
302 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
303 canvas, bmsPaints[i]);
304 }
305
306 // Multiple columns with different geometry
307 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
308 for (int j = 0; j < paints.count(); ++j) {
309 draw_geom_with_paint(*gDrawMthds[i],
310 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
311 canvas, paints[j]);
312 }
313 }
314
315 }
316
317private:
318 typedef GM INHERITED;
319};
320
321//////////////////////////////////////////////////////////////////////////////
322
halcanary385fe4d2015-08-26 13:07:48 -0700323DEF_GM(return new ImageFilterFastBoundGM;)
robertphillips9a264102014-12-08 09:18:58 -0800324}