blob: 6819e9e255faf4d4293b964c4627fb4ae1c6f62d [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkBitmap.h"
10#include "include/core/SkCanvas.h"
11#include "include/core/SkColor.h"
12#include "include/core/SkFilterQuality.h"
13#include "include/core/SkImage.h"
14#include "include/core/SkImageFilter.h"
15#include "include/core/SkMatrix.h"
16#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040018#include "include/core/SkPicture.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/core/SkPictureRecorder.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040020#include "include/core/SkPoint.h"
21#include "include/core/SkRRect.h"
22#include "include/core/SkRect.h"
23#include "include/core/SkRefCnt.h"
24#include "include/core/SkScalar.h"
25#include "include/core/SkSize.h"
26#include "include/core/SkString.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050027#include "include/core/SkSurface.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040028#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "include/effects/SkBlurImageFilter.h"
30#include "include/effects/SkDropShadowImageFilter.h"
31#include "include/effects/SkImageSource.h"
32#include "include/effects/SkOffsetImageFilter.h"
33#include "include/effects/SkPictureImageFilter.h"
34#include "include/effects/SkTileImageFilter.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040035#include "include/private/SkTArray.h"
36
37#include <utility>
robertphillips9a264102014-12-08 09:18:58 -080038
39namespace skiagm {
40
41// Each method of this type must draw its geometry inside 'r' using 'p'
42typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
43
44static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
45 canvas->drawRect(r, p);
46}
47
48static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
49 canvas->drawOval(r, p);
50}
51
52static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
53 SkScalar xRad = r.width() / 4.0f;
54 SkScalar yRad = r.height() / 4.0f;
55
56 SkRRect rr;
57 rr.setRectXY(r, xRad, yRad);
58 canvas->drawRRect(rr, p);
59}
60
61static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
62 SkScalar xRad = r.width() / 4.0f;
63 SkScalar yRad = r.height() / 4.0f;
64
65 SkRRect outer;
66 outer.setRectXY(r, xRad, yRad);
67 SkRRect inner = outer;
68 inner.inset(xRad, yRad);
69 canvas->drawDRRect(outer, inner, p);
70}
71
72static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
73 SkPath path;
74
75 path.moveTo(r.fLeft, r.fTop);
76 path.lineTo(r.fLeft, r.fBottom);
77 path.lineTo(r.fRight, r.fBottom);
78 path.close();
79
80 canvas->drawPath(path, p);
81}
82
83static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
84 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
85 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
86
87 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
88 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
89}
90
91static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
92 SkBitmap bm;
93
94 bm.allocN32Pixels(64, 64);
95 SkCanvas temp(bm);
96 temp.clear(SK_ColorMAGENTA);
97
98 canvas->drawBitmapRect(bm, r, &p);
99}
100
mtkleindbfd7ab2016-09-01 11:24:54 -0700101constexpr drawMth gDrawMthds[] = {
robertphillips9a264102014-12-08 09:18:58 -0800102 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
103};
104
robertphillips6e7025a2016-04-04 04:31:25 -0700105static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
robertphillips9a264102014-12-08 09:18:58 -0800106 SkPaint& p = paints->push_back();
robertphillips6e7025a2016-04-04 04:31:25 -0700107 p.setImageFilter(std::move(filter));
robertphillips9a264102014-12-08 09:18:58 -0800108 SkASSERT(p.canComputeFastBounds());
109}
110
111// Create a selection of imagefilter-based paints to test
robertphillips6e7025a2016-04-04 04:31:25 -0700112static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
robertphillips9a264102014-12-08 09:18:58 -0800113 {
114 SkMatrix scale;
115 scale.setScale(2.0f, 2.0f);
116
robertphillips6e7025a2016-04-04 04:31:25 -0700117 sk_sp<SkImageFilter> scaleMIF(
robertphillipsae8c9332016-04-05 15:09:00 -0700118 SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800119
robertphillips6e7025a2016-04-04 04:31:25 -0700120 add_paint(paints, std::move(scaleMIF));
robertphillips9a264102014-12-08 09:18:58 -0800121 }
122
123 {
124 SkMatrix rot;
125 rot.setRotate(-33.3f);
126
robertphillips6e7025a2016-04-04 04:31:25 -0700127 sk_sp<SkImageFilter> rotMIF(
robertphillipsae8c9332016-04-05 15:09:00 -0700128 SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800129
robertphillips6e7025a2016-04-04 04:31:25 -0700130 add_paint(paints, std::move(rotMIF));
robertphillips9a264102014-12-08 09:18:58 -0800131 }
132
133 {
senorblancod18b1b52015-12-07 10:36:30 -0800134 SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
135 SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
robertphillips534c2702016-04-15 07:57:40 -0700136 sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
senorblancod18b1b52015-12-07 10:36:30 -0800137
robertphillips6e7025a2016-04-04 04:31:25 -0700138 add_paint(paints, std::move(tileIF));
senorblancod18b1b52015-12-07 10:36:30 -0800139 }
140
141 {
mtkleindbfd7ab2016-09-01 11:24:54 -0700142 constexpr SkDropShadowImageFilter::ShadowMode kBoth =
robertphillips9a264102014-12-08 09:18:58 -0800143 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
144
robertphillipsc4169122016-04-06 08:40:59 -0700145 sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
146 3.0f, 3.0f,
147 SK_ColorRED, kBoth,
148 source));
robertphillips9a264102014-12-08 09:18:58 -0800149
robertphillips6e7025a2016-04-04 04:31:25 -0700150 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800151 }
152
153 {
robertphillips6e7025a2016-04-04 04:31:25 -0700154 sk_sp<SkImageFilter> dsif(
robertphillipsc4169122016-04-06 08:40:59 -0700155 SkDropShadowImageFilter::Make(27.0f, 27.0f,
robertphillips9a264102014-12-08 09:18:58 -0800156 3.0f, 3.0f,
157 SK_ColorRED,
158 SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700159 source));
robertphillips9a264102014-12-08 09:18:58 -0800160
robertphillips6e7025a2016-04-04 04:31:25 -0700161 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800162 }
163
robertphillips6e7025a2016-04-04 04:31:25 -0700164 add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
165 add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
robertphillips9a264102014-12-08 09:18:58 -0800166}
167
168// This GM visualizes the fast bounds for various combinations of geometry
169// and image filter
170class ImageFilterFastBoundGM : public GM {
171public:
172 ImageFilterFastBoundGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400173 this->setBGColor(0xFFCCCCCC);
robertphillips9a264102014-12-08 09:18:58 -0800174 }
175
176protected:
mtkleindbfd7ab2016-09-01 11:24:54 -0700177 static constexpr int kTileWidth = 100;
178 static constexpr int kTileHeight = 100;
179 static constexpr int kNumVertTiles = 7;
180 static constexpr int kNumXtraCols = 2;
robertphillips9a264102014-12-08 09:18:58 -0800181
mtklein36352bf2015-03-25 18:17:31 -0700182 SkString onShortName() override{ return SkString("filterfastbounds"); }
robertphillips9a264102014-12-08 09:18:58 -0800183
mtklein36352bf2015-03-25 18:17:31 -0700184 SkISize onISize() override{
robertphillips9a264102014-12-08 09:18:58 -0800185 return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
186 kNumVertTiles * kTileHeight);
187 }
188
189 static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
190 SkCanvas* canvas, const SkPaint& p) {
191 SkPaint redStroked;
192 redStroked.setColor(SK_ColorRED);
193 redStroked.setStyle(SkPaint::kStroke_Style);
194
195 SkPaint blueStroked;
196 blueStroked.setColor(SK_ColorBLUE);
197 blueStroked.setStyle(SkPaint::kStroke_Style);
198
199 const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
200 SkRect storage;
201
202 canvas->save();
203 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
204 canvas->scale(1.5f, 1.5f);
205
206 const SkRect& fastBound = p.computeFastBounds(r, &storage);
207
208 canvas->save();
209 canvas->clipRect(fastBound);
210 (*draw)(canvas, r, p);
211 canvas->restore();
212
213 canvas->drawRect(r, redStroked);
214 canvas->drawRect(fastBound, blueStroked);
215 canvas->restore();
216 }
217
218 static void draw_savelayer_with_paint(const SkIPoint& off,
219 SkCanvas* canvas,
220 const SkPaint& p) {
221 SkPaint redStroked;
222 redStroked.setColor(SK_ColorRED);
223 redStroked.setStyle(SkPaint::kStroke_Style);
224
225 SkPaint blueStroked;
226 blueStroked.setColor(SK_ColorBLUE);
227 blueStroked.setStyle(SkPaint::kStroke_Style);
228
229 const SkRect bounds = SkRect::MakeWH(10, 10);
230 SkRect storage;
231
232 canvas->save();
233 canvas->translate(30, 30);
234 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
235 canvas->scale(1.5f, 1.5f);
236
237 const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
238
239 canvas->saveLayer(&fastBound, &p);
240 canvas->restore();
241
242 canvas->drawRect(bounds, redStroked);
243 canvas->drawRect(fastBound, blueStroked);
244 canvas->restore();
245 }
246
mtklein36352bf2015-03-25 18:17:31 -0700247 void onDraw(SkCanvas* canvas) override{
robertphillips9a264102014-12-08 09:18:58 -0800248
249 SkPaint blackFill;
250
251 //-----------
252 // Normal paints (no source)
253 SkTArray<SkPaint> paints;
robertphillips6e7025a2016-04-04 04:31:25 -0700254 create_paints(&paints, nullptr);
robertphillips9a264102014-12-08 09:18:58 -0800255
256 //-----------
257 // Paints with a PictureImageFilter as a source
reedca2622b2016-03-18 07:25:55 -0700258 sk_sp<SkPicture> pic;
robertphillips9a264102014-12-08 09:18:58 -0800259
260 {
261 SkPictureRecorder rec;
262
263 SkCanvas* c = rec.beginRecording(10, 10);
264 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
reedca2622b2016-03-18 07:25:55 -0700265 pic = rec.finishRecordingAsPicture();
robertphillips9a264102014-12-08 09:18:58 -0800266 }
267
robertphillips9a264102014-12-08 09:18:58 -0800268 SkTArray<SkPaint> pifPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700269 create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
robertphillips9a264102014-12-08 09:18:58 -0800270
271 //-----------
fmalita2f5891e2015-09-25 09:15:55 -0700272 // Paints with a SkImageSource as a source
robertphillips9a264102014-12-08 09:18:58 -0800273
reede8f30622016-03-23 18:59:25 -0700274 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
robertphillips9a264102014-12-08 09:18:58 -0800275 {
276 SkPaint p;
fmalita2f5891e2015-09-25 09:15:55 -0700277 SkCanvas* temp = surface->getCanvas();
278 temp->clear(SK_ColorYELLOW);
robertphillips9a264102014-12-08 09:18:58 -0800279 p.setColor(SK_ColorBLUE);
fmalita2f5891e2015-09-25 09:15:55 -0700280 temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
robertphillips9a264102014-12-08 09:18:58 -0800281 p.setColor(SK_ColorGREEN);
fmalita2f5891e2015-09-25 09:15:55 -0700282 temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
robertphillips9a264102014-12-08 09:18:58 -0800283 }
284
reed9ce9d672016-03-17 10:51:11 -0700285 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -0700286 sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
robertphillips9a264102014-12-08 09:18:58 -0800287 SkTArray<SkPaint> bmsPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700288 create_paints(&bmsPaints, std::move(imageSource));
robertphillips9a264102014-12-08 09:18:58 -0800289
290 //-----------
291 SkASSERT(paints.count() == kNumVertTiles);
292 SkASSERT(paints.count() == pifPaints.count());
293 SkASSERT(paints.count() == bmsPaints.count());
294
295 // horizontal separators
296 for (int i = 1; i < paints.count(); ++i) {
297 canvas->drawLine(0,
298 i*SkIntToScalar(kTileHeight),
299 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
300 i*SkIntToScalar(kTileHeight),
301 blackFill);
302 }
303 // vertical separators
304 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
305 canvas->drawLine(SkIntToScalar(i * kTileWidth),
306 0,
halcanary9d524f22016-03-29 09:03:52 -0700307 SkIntToScalar(i * kTileWidth),
robertphillips9a264102014-12-08 09:18:58 -0800308 SkIntToScalar(paints.count() * kTileWidth),
309 blackFill);
310 }
311
312 // A column of saveLayers with PictureImageFilters
313 for (int i = 0; i < pifPaints.count(); ++i) {
halcanary9d524f22016-03-29 09:03:52 -0700314 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
robertphillips9a264102014-12-08 09:18:58 -0800315 canvas, pifPaints[i]);
316 }
317
318 // A column of saveLayers with BitmapSources
319 for (int i = 0; i < pifPaints.count(); ++i) {
320 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
321 canvas, bmsPaints[i]);
322 }
323
324 // Multiple columns with different geometry
325 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
326 for (int j = 0; j < paints.count(); ++j) {
327 draw_geom_with_paint(*gDrawMthds[i],
328 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
329 canvas, paints[j]);
330 }
331 }
332
333 }
334
335private:
336 typedef GM INHERITED;
337};
338
339//////////////////////////////////////////////////////////////////////////////
340
halcanary385fe4d2015-08-26 13:07:48 -0700341DEF_GM(return new ImageFilterFastBoundGM;)
robertphillips9a264102014-12-08 09:18:58 -0800342}