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