• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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"
9 #include "sk_tool_utils.h"
10 #include "SkBlurImageFilter.h"
11 #include "SkDropShadowImageFilter.h"
12 #include "SkImageSource.h"
13 #include "SkOffsetImageFilter.h"
14 #include "SkPath.h"
15 #include "SkPictureImageFilter.h"
16 #include "SkPictureRecorder.h"
17 #include "SkRandom.h"
18 #include "SkSurface.h"
19 #include "SkTileImageFilter.h"
20 
21 namespace skiagm {
22 
23 // Each method of this type must draw its geometry inside 'r' using 'p'
24 typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
25 
draw_rect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)26 static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
27     canvas->drawRect(r, p);
28 }
29 
draw_oval(SkCanvas * canvas,const SkRect & r,const SkPaint & p)30 static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
31     canvas->drawOval(r, p);
32 }
33 
draw_rrect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)34 static 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 
draw_drrect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)43 static 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 
draw_path(SkCanvas * canvas,const SkRect & r,const SkPaint & p)54 static 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 
draw_points(SkCanvas * canvas,const SkRect & r,const SkPaint & p)65 static 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 
draw_bitmap(SkCanvas * canvas,const SkRect & r,const SkPaint & p)73 static 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 
83 constexpr drawMth gDrawMthds[] = {
84     draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
85 };
86 
add_paint(SkTArray<SkPaint> * paints,sk_sp<SkImageFilter> filter)87 static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
88     SkPaint& p = paints->push_back();
89     p.setImageFilter(std::move(filter));
90     SkASSERT(p.canComputeFastBounds());
91 }
92 
93 // Create a selection of imagefilter-based paints to test
create_paints(SkTArray<SkPaint> * paints,sk_sp<SkImageFilter> source)94 static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
95     {
96         SkMatrix scale;
97         scale.setScale(2.0f, 2.0f);
98 
99         sk_sp<SkImageFilter> scaleMIF(
100             SkImageFilter::MakeMatrixFilter(scale, kLow_SkFilterQuality, source));
101 
102         add_paint(paints, std::move(scaleMIF));
103     }
104 
105     {
106         SkMatrix rot;
107         rot.setRotate(-33.3f);
108 
109         sk_sp<SkImageFilter> rotMIF(
110             SkImageFilter::MakeMatrixFilter(rot, kLow_SkFilterQuality, source));
111 
112         add_paint(paints, std::move(rotMIF));
113     }
114 
115     {
116         SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
117         SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
118         sk_sp<SkImageFilter> tileIF(SkTileImageFilter::Make(src, dst, nullptr));
119 
120         add_paint(paints, std::move(tileIF));
121     }
122 
123     {
124         constexpr SkDropShadowImageFilter::ShadowMode kBoth =
125                     SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode;
126 
127         sk_sp<SkImageFilter> dsif(SkDropShadowImageFilter::Make(10.0f, 10.0f,
128                                                                 3.0f, 3.0f,
129                                                                 SK_ColorRED, kBoth,
130                                                                 source));
131 
132         add_paint(paints, std::move(dsif));
133     }
134 
135     {
136         sk_sp<SkImageFilter> dsif(
137             SkDropShadowImageFilter::Make(27.0f, 27.0f,
138                                             3.0f, 3.0f,
139                                             SK_ColorRED,
140                                             SkDropShadowImageFilter::kDrawShadowOnly_ShadowMode,
141                                             source));
142 
143         add_paint(paints, std::move(dsif));
144     }
145 
146     add_paint(paints, SkBlurImageFilter::Make(3, 3, source));
147     add_paint(paints, SkOffsetImageFilter::Make(15, 15, source));
148 }
149 
150 // This GM visualizes the fast bounds for various combinations of geometry
151 // and image filter
152 class ImageFilterFastBoundGM : public GM {
153 public:
ImageFilterFastBoundGM()154     ImageFilterFastBoundGM() {
155         this->setBGColor(sk_tool_utils::color_to_565(0xFFCCCCCC));
156     }
157 
158 protected:
159     static constexpr int kTileWidth = 100;
160     static constexpr int kTileHeight = 100;
161     static constexpr int kNumVertTiles = 7;
162     static constexpr int kNumXtraCols = 2;
163 
onShortName()164     SkString onShortName() override{ return SkString("filterfastbounds"); }
165 
onISize()166     SkISize onISize() override{
167         return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
168                              kNumVertTiles * kTileHeight);
169     }
170 
draw_geom_with_paint(drawMth draw,const SkIPoint & off,SkCanvas * canvas,const SkPaint & p)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 
draw_savelayer_with_paint(const SkIPoint & off,SkCanvas * canvas,const SkPaint & p)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 
onDraw(SkCanvas * canvas)229     void onDraw(SkCanvas* canvas) override{
230 
231         SkPaint blackFill;
232 
233         //-----------
234         // Normal paints (no source)
235         SkTArray<SkPaint> paints;
236         create_paints(&paints, nullptr);
237 
238         //-----------
239         // Paints with a PictureImageFilter as a source
240         sk_sp<SkPicture> pic;
241 
242         {
243             SkPictureRecorder rec;
244 
245             SkCanvas* c = rec.beginRecording(10, 10);
246             c->drawRect(SkRect::MakeWH(10, 10), blackFill);
247             pic = rec.finishRecordingAsPicture();
248         }
249 
250         SkTArray<SkPaint> pifPaints;
251         create_paints(&pifPaints, SkPictureImageFilter::Make(pic));
252 
253         //-----------
254         // Paints with a SkImageSource as a source
255 
256         auto surface(SkSurface::MakeRasterN32Premul(10, 10));
257         {
258             SkPaint p;
259             SkCanvas* temp = surface->getCanvas();
260             temp->clear(SK_ColorYELLOW);
261             p.setColor(SK_ColorBLUE);
262             temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
263             p.setColor(SK_ColorGREEN);
264             temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
265         }
266 
267         sk_sp<SkImage> image(surface->makeImageSnapshot());
268         sk_sp<SkImageFilter> imageSource(SkImageSource::Make(std::move(image)));
269         SkTArray<SkPaint> bmsPaints;
270         create_paints(&bmsPaints, std::move(imageSource));
271 
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,
289                              SkIntToScalar(i * kTileWidth),
290                              SkIntToScalar(paints.count() * kTileWidth),
291                              blackFill);
292         }
293 
294         // A column of saveLayers with PictureImageFilters
295         for (int i = 0; i < pifPaints.count(); ++i) {
296             draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
297                                       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 
317 private:
318     typedef GM INHERITED;
319 };
320 
321 //////////////////////////////////////////////////////////////////////////////
322 
323 DEF_GM(return new ImageFilterFastBoundGM;)
324 }
325