blob: 7da526cb6c911ea25b2c9b5dbc7c448eda0efd1d [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"
Michael Ludwig898bbfa2019-08-02 15:21:23 -040029#include "include/effects/SkImageFilters.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040030#include "include/private/SkTArray.h"
31
32#include <utility>
robertphillips9a264102014-12-08 09:18:58 -080033
34namespace skiagm {
35
36// Each method of this type must draw its geometry inside 'r' using 'p'
37typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
38
39static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
40 canvas->drawRect(r, p);
41}
42
43static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
44 canvas->drawOval(r, p);
45}
46
47static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
48 SkScalar xRad = r.width() / 4.0f;
49 SkScalar yRad = r.height() / 4.0f;
50
51 SkRRect rr;
52 rr.setRectXY(r, xRad, yRad);
53 canvas->drawRRect(rr, p);
54}
55
56static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
57 SkScalar xRad = r.width() / 4.0f;
58 SkScalar yRad = r.height() / 4.0f;
59
60 SkRRect outer;
61 outer.setRectXY(r, xRad, yRad);
62 SkRRect inner = outer;
63 inner.inset(xRad, yRad);
64 canvas->drawDRRect(outer, inner, p);
65}
66
67static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
68 SkPath path;
69
70 path.moveTo(r.fLeft, r.fTop);
71 path.lineTo(r.fLeft, r.fBottom);
72 path.lineTo(r.fRight, r.fBottom);
73 path.close();
74
75 canvas->drawPath(path, p);
76}
77
78static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
79 SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
80 SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
81
82 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
83 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
84}
85
86static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
87 SkBitmap bm;
88
89 bm.allocN32Pixels(64, 64);
90 SkCanvas temp(bm);
91 temp.clear(SK_ColorMAGENTA);
92
93 canvas->drawBitmapRect(bm, r, &p);
94}
95
mtkleindbfd7ab2016-09-01 11:24:54 -070096constexpr drawMth gDrawMthds[] = {
robertphillips9a264102014-12-08 09:18:58 -080097 draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
98};
99
robertphillips6e7025a2016-04-04 04:31:25 -0700100static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
robertphillips9a264102014-12-08 09:18:58 -0800101 SkPaint& p = paints->push_back();
robertphillips6e7025a2016-04-04 04:31:25 -0700102 p.setImageFilter(std::move(filter));
robertphillips9a264102014-12-08 09:18:58 -0800103 SkASSERT(p.canComputeFastBounds());
104}
105
106// Create a selection of imagefilter-based paints to test
robertphillips6e7025a2016-04-04 04:31:25 -0700107static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
robertphillips9a264102014-12-08 09:18:58 -0800108 {
109 SkMatrix scale;
110 scale.setScale(2.0f, 2.0f);
111
robertphillips6e7025a2016-04-04 04:31:25 -0700112 sk_sp<SkImageFilter> scaleMIF(
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400113 SkImageFilters::MatrixTransform(scale, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800114
robertphillips6e7025a2016-04-04 04:31:25 -0700115 add_paint(paints, std::move(scaleMIF));
robertphillips9a264102014-12-08 09:18:58 -0800116 }
117
118 {
119 SkMatrix rot;
120 rot.setRotate(-33.3f);
121
robertphillips6e7025a2016-04-04 04:31:25 -0700122 sk_sp<SkImageFilter> rotMIF(
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400123 SkImageFilters::MatrixTransform(rot, kLow_SkFilterQuality, source));
robertphillips9a264102014-12-08 09:18:58 -0800124
robertphillips6e7025a2016-04-04 04:31:25 -0700125 add_paint(paints, std::move(rotMIF));
robertphillips9a264102014-12-08 09:18:58 -0800126 }
127
128 {
senorblancod18b1b52015-12-07 10:36:30 -0800129 SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
130 SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400131 sk_sp<SkImageFilter> tileIF(SkImageFilters::Tile(src, dst, nullptr));
senorblancod18b1b52015-12-07 10:36:30 -0800132
robertphillips6e7025a2016-04-04 04:31:25 -0700133 add_paint(paints, std::move(tileIF));
senorblancod18b1b52015-12-07 10:36:30 -0800134 }
135
136 {
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400137 sk_sp<SkImageFilter> dsif =
138 SkImageFilters::DropShadow(10.0f, 10.0f, 3.0f, 3.0f, SK_ColorRED, source);
robertphillips9a264102014-12-08 09:18:58 -0800139
robertphillips6e7025a2016-04-04 04:31:25 -0700140 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800141 }
142
143 {
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400144 sk_sp<SkImageFilter> dsif =
145 SkImageFilters::DropShadowOnly(27.0f, 27.0f, 3.0f, 3.0f, SK_ColorRED, source);
robertphillips9a264102014-12-08 09:18:58 -0800146
robertphillips6e7025a2016-04-04 04:31:25 -0700147 add_paint(paints, std::move(dsif));
robertphillips9a264102014-12-08 09:18:58 -0800148 }
149
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400150 add_paint(paints, SkImageFilters::Blur(3, 3, source));
151 add_paint(paints, SkImageFilters::Offset(15, 15, source));
robertphillips9a264102014-12-08 09:18:58 -0800152}
153
154// This GM visualizes the fast bounds for various combinations of geometry
155// and image filter
156class ImageFilterFastBoundGM : public GM {
157public:
158 ImageFilterFastBoundGM() {
Mike Kleind46dce32018-08-16 10:17:03 -0400159 this->setBGColor(0xFFCCCCCC);
robertphillips9a264102014-12-08 09:18:58 -0800160 }
161
162protected:
mtkleindbfd7ab2016-09-01 11:24:54 -0700163 static constexpr int kTileWidth = 100;
164 static constexpr int kTileHeight = 100;
165 static constexpr int kNumVertTiles = 7;
166 static constexpr int kNumXtraCols = 2;
robertphillips9a264102014-12-08 09:18:58 -0800167
Hal Canaryfa3305a2019-07-18 12:36:54 -0400168 SkString onShortName() override { return SkString("filterfastbounds"); }
robertphillips9a264102014-12-08 09:18:58 -0800169
Hal Canaryfa3305a2019-07-18 12:36:54 -0400170 SkISize onISize() override {
robertphillips9a264102014-12-08 09:18:58 -0800171 return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
172 kNumVertTiles * kTileHeight);
173 }
174
175 static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
176 SkCanvas* canvas, const SkPaint& p) {
177 SkPaint redStroked;
178 redStroked.setColor(SK_ColorRED);
179 redStroked.setStyle(SkPaint::kStroke_Style);
180
181 SkPaint blueStroked;
182 blueStroked.setColor(SK_ColorBLUE);
183 blueStroked.setStyle(SkPaint::kStroke_Style);
184
185 const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
186 SkRect storage;
187
188 canvas->save();
189 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
190 canvas->scale(1.5f, 1.5f);
191
192 const SkRect& fastBound = p.computeFastBounds(r, &storage);
193
194 canvas->save();
195 canvas->clipRect(fastBound);
196 (*draw)(canvas, r, p);
197 canvas->restore();
198
199 canvas->drawRect(r, redStroked);
200 canvas->drawRect(fastBound, blueStroked);
201 canvas->restore();
202 }
203
204 static void draw_savelayer_with_paint(const SkIPoint& off,
205 SkCanvas* canvas,
206 const SkPaint& p) {
207 SkPaint redStroked;
208 redStroked.setColor(SK_ColorRED);
209 redStroked.setStyle(SkPaint::kStroke_Style);
210
211 SkPaint blueStroked;
212 blueStroked.setColor(SK_ColorBLUE);
213 blueStroked.setStyle(SkPaint::kStroke_Style);
214
215 const SkRect bounds = SkRect::MakeWH(10, 10);
216 SkRect storage;
217
218 canvas->save();
219 canvas->translate(30, 30);
220 canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
221 canvas->scale(1.5f, 1.5f);
222
223 const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
224
225 canvas->saveLayer(&fastBound, &p);
226 canvas->restore();
227
228 canvas->drawRect(bounds, redStroked);
229 canvas->drawRect(fastBound, blueStroked);
230 canvas->restore();
231 }
232
Hal Canaryfa3305a2019-07-18 12:36:54 -0400233 void onDraw(SkCanvas* canvas) override {
robertphillips9a264102014-12-08 09:18:58 -0800234
235 SkPaint blackFill;
236
237 //-----------
238 // Normal paints (no source)
239 SkTArray<SkPaint> paints;
robertphillips6e7025a2016-04-04 04:31:25 -0700240 create_paints(&paints, nullptr);
robertphillips9a264102014-12-08 09:18:58 -0800241
242 //-----------
243 // Paints with a PictureImageFilter as a source
reedca2622b2016-03-18 07:25:55 -0700244 sk_sp<SkPicture> pic;
robertphillips9a264102014-12-08 09:18:58 -0800245
246 {
247 SkPictureRecorder rec;
248
249 SkCanvas* c = rec.beginRecording(10, 10);
250 c->drawRect(SkRect::MakeWH(10, 10), blackFill);
reedca2622b2016-03-18 07:25:55 -0700251 pic = rec.finishRecordingAsPicture();
robertphillips9a264102014-12-08 09:18:58 -0800252 }
253
robertphillips9a264102014-12-08 09:18:58 -0800254 SkTArray<SkPaint> pifPaints;
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400255 create_paints(&pifPaints, SkImageFilters::Picture(pic));
robertphillips9a264102014-12-08 09:18:58 -0800256
257 //-----------
fmalita2f5891e2015-09-25 09:15:55 -0700258 // Paints with a SkImageSource as a source
robertphillips9a264102014-12-08 09:18:58 -0800259
reede8f30622016-03-23 18:59:25 -0700260 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
robertphillips9a264102014-12-08 09:18:58 -0800261 {
262 SkPaint p;
fmalita2f5891e2015-09-25 09:15:55 -0700263 SkCanvas* temp = surface->getCanvas();
264 temp->clear(SK_ColorYELLOW);
robertphillips9a264102014-12-08 09:18:58 -0800265 p.setColor(SK_ColorBLUE);
fmalita2f5891e2015-09-25 09:15:55 -0700266 temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
robertphillips9a264102014-12-08 09:18:58 -0800267 p.setColor(SK_ColorGREEN);
fmalita2f5891e2015-09-25 09:15:55 -0700268 temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
robertphillips9a264102014-12-08 09:18:58 -0800269 }
270
reed9ce9d672016-03-17 10:51:11 -0700271 sk_sp<SkImage> image(surface->makeImageSnapshot());
Michael Ludwig898bbfa2019-08-02 15:21:23 -0400272 sk_sp<SkImageFilter> imageSource(SkImageFilters::Image(std::move(image)));
robertphillips9a264102014-12-08 09:18:58 -0800273 SkTArray<SkPaint> bmsPaints;
robertphillips6e7025a2016-04-04 04:31:25 -0700274 create_paints(&bmsPaints, std::move(imageSource));
robertphillips9a264102014-12-08 09:18:58 -0800275
276 //-----------
277 SkASSERT(paints.count() == kNumVertTiles);
278 SkASSERT(paints.count() == pifPaints.count());
279 SkASSERT(paints.count() == bmsPaints.count());
280
281 // horizontal separators
282 for (int i = 1; i < paints.count(); ++i) {
283 canvas->drawLine(0,
284 i*SkIntToScalar(kTileHeight),
285 SkIntToScalar((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols)*kTileWidth),
286 i*SkIntToScalar(kTileHeight),
287 blackFill);
288 }
289 // vertical separators
290 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols; ++i) {
291 canvas->drawLine(SkIntToScalar(i * kTileWidth),
292 0,
halcanary9d524f22016-03-29 09:03:52 -0700293 SkIntToScalar(i * kTileWidth),
robertphillips9a264102014-12-08 09:18:58 -0800294 SkIntToScalar(paints.count() * kTileWidth),
295 blackFill);
296 }
297
298 // A column of saveLayers with PictureImageFilters
299 for (int i = 0; i < pifPaints.count(); ++i) {
halcanary9d524f22016-03-29 09:03:52 -0700300 draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
robertphillips9a264102014-12-08 09:18:58 -0800301 canvas, pifPaints[i]);
302 }
303
304 // A column of saveLayers with BitmapSources
305 for (int i = 0; i < pifPaints.count(); ++i) {
306 draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
307 canvas, bmsPaints[i]);
308 }
309
310 // Multiple columns with different geometry
311 for (int i = 0; i < (int)SK_ARRAY_COUNT(gDrawMthds); ++i) {
312 for (int j = 0; j < paints.count(); ++j) {
313 draw_geom_with_paint(*gDrawMthds[i],
314 SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
315 canvas, paints[j]);
316 }
317 }
318
319 }
320
321private:
322 typedef GM INHERITED;
323};
324
325//////////////////////////////////////////////////////////////////////////////
326
halcanary385fe4d2015-08-26 13:07:48 -0700327DEF_GM(return new ImageFilterFastBoundGM;)
robertphillips9a264102014-12-08 09:18:58 -0800328}