• 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/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkImage.h"
13 #include "include/core/SkImageFilter.h"
14 #include "include/core/SkMatrix.h"
15 #include "include/core/SkPaint.h"
16 #include "include/core/SkPath.h"
17 #include "include/core/SkPicture.h"
18 #include "include/core/SkPictureRecorder.h"
19 #include "include/core/SkPoint.h"
20 #include "include/core/SkRRect.h"
21 #include "include/core/SkRect.h"
22 #include "include/core/SkRefCnt.h"
23 #include "include/core/SkScalar.h"
24 #include "include/core/SkSize.h"
25 #include "include/core/SkString.h"
26 #include "include/core/SkSurface.h"
27 #include "include/core/SkTypes.h"
28 #include "include/effects/SkImageFilters.h"
29 #include "include/private/base/SkTArray.h"
30 
31 #include <utility>
32 
33 namespace skiagm {
34 
35 // Each method of this type must draw its geometry inside 'r' using 'p'
36 typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
37 
draw_rect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)38 static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
39     canvas->drawRect(r, p);
40 }
41 
draw_oval(SkCanvas * canvas,const SkRect & r,const SkPaint & p)42 static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
43     canvas->drawOval(r, p);
44 }
45 
draw_rrect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)46 static void draw_rrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
47     SkScalar xRad = r.width() / 4.0f;
48     SkScalar yRad = r.height() / 4.0f;
49 
50     SkRRect rr;
51     rr.setRectXY(r, xRad, yRad);
52     canvas->drawRRect(rr, p);
53 }
54 
draw_drrect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)55 static void draw_drrect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
56     SkScalar xRad = r.width() / 4.0f;
57     SkScalar yRad = r.height() / 4.0f;
58 
59     SkRRect outer;
60     outer.setRectXY(r, xRad, yRad);
61     SkRRect inner = outer;
62     inner.inset(xRad, yRad);
63     canvas->drawDRRect(outer, inner, p);
64 }
65 
draw_path(SkCanvas * canvas,const SkRect & r,const SkPaint & p)66 static void draw_path(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
67     canvas->drawPath(SkPath::Polygon({
68         {r.fLeft, r.fTop},
69         {r.fLeft, r.fBottom},
70         {r.fRight, r.fBottom},
71     }, true), p);
72 }
73 
draw_points(SkCanvas * canvas,const SkRect & r,const SkPaint & p)74 static void draw_points(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
75     SkPoint pts0[2] = { { r.fLeft, r.fTop }, { r.fRight, r.fBottom } };
76     SkPoint pts1[2] = { { r.fLeft, r.fBottom }, { r.fRight, r.fTop } };
77 
78     canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts0, p);
79     canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts1, p);
80 }
81 
draw_bitmap(SkCanvas * canvas,const SkRect & r,const SkPaint & p)82 static void draw_bitmap(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
83     SkBitmap bm;
84 
85     bm.allocN32Pixels(64, 64);
86     SkCanvas temp(bm);
87     temp.clear(SK_ColorMAGENTA);
88 
89     canvas->drawImageRect(bm.asImage(), r, SkSamplingOptions(), &p);
90 }
91 
92 constexpr drawMth gDrawMthds[] = {
93     draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
94 };
95 
add_paint(SkTArray<SkPaint> * paints,sk_sp<SkImageFilter> filter)96 static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
97     SkPaint& p = paints->push_back();
98     p.setImageFilter(std::move(filter));
99     SkASSERT(p.canComputeFastBounds());
100 }
101 
102 // Create a selection of imagefilter-based paints to test
create_paints(SkTArray<SkPaint> * paints,sk_sp<SkImageFilter> source)103 static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
104     {
105         SkMatrix scale;
106         scale.setScale(2.0f, 2.0f);
107 
108         sk_sp<SkImageFilter> scaleMIF(
109             SkImageFilters::MatrixTransform(scale, SkSamplingOptions(SkFilterMode::kLinear),
110                                             source));
111 
112         add_paint(paints, std::move(scaleMIF));
113     }
114 
115     {
116         SkMatrix rot;
117         rot.setRotate(-33.3f);
118 
119         sk_sp<SkImageFilter> rotMIF(
120             SkImageFilters::MatrixTransform(rot, SkSamplingOptions(SkFilterMode::kLinear), source));
121 
122         add_paint(paints, std::move(rotMIF));
123     }
124 
125     {
126         SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
127         SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
128         sk_sp<SkImageFilter> tileIF(SkImageFilters::Tile(src, dst, nullptr));
129 
130         add_paint(paints, std::move(tileIF));
131     }
132 
133     {
134         sk_sp<SkImageFilter> dsif =
135                 SkImageFilters::DropShadow(10.0f, 10.0f, 3.0f, 3.0f, SK_ColorRED, source);
136 
137         add_paint(paints, std::move(dsif));
138     }
139 
140     {
141         sk_sp<SkImageFilter> dsif =
142             SkImageFilters::DropShadowOnly(27.0f, 27.0f, 3.0f, 3.0f, SK_ColorRED, source);
143 
144         add_paint(paints, std::move(dsif));
145     }
146 
147     add_paint(paints, SkImageFilters::Blur(3, 3, source));
148     add_paint(paints, SkImageFilters::Offset(15, 15, source));
149 }
150 
151 // This GM visualizes the fast bounds for various combinations of geometry
152 // and image filter
153 class ImageFilterFastBoundGM : public GM {
154 public:
ImageFilterFastBoundGM()155     ImageFilterFastBoundGM() {
156         this->setBGColor(0xFFCCCCCC);
157     }
158 
159 protected:
160     inline static constexpr int kTileWidth = 100;
161     inline static constexpr int kTileHeight = 100;
162     inline static constexpr int kNumVertTiles = 7;
163     inline static constexpr int kNumXtraCols = 2;
164 
onShortName()165     SkString onShortName() override { return SkString("filterfastbounds"); }
166 
onISize()167     SkISize onISize() override {
168         return SkISize::Make((std::size(gDrawMthds) + kNumXtraCols) * kTileWidth,
169                              kNumVertTiles * kTileHeight);
170     }
171 
draw_geom_with_paint(drawMth draw,const SkIPoint & off,SkCanvas * canvas,const SkPaint & p)172     static void draw_geom_with_paint(drawMth draw, const SkIPoint& off,
173                                      SkCanvas* canvas, const SkPaint& p) {
174         SkPaint redStroked;
175         redStroked.setColor(SK_ColorRED);
176         redStroked.setStyle(SkPaint::kStroke_Style);
177 
178         SkPaint blueStroked;
179         blueStroked.setColor(SK_ColorBLUE);
180         blueStroked.setStyle(SkPaint::kStroke_Style);
181 
182         const SkRect r = SkRect::MakeLTRB(20, 20, 30, 30);
183         SkRect storage;
184 
185         canvas->save();
186             canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
187             canvas->scale(1.5f, 1.5f);
188 
189             const SkRect& fastBound = p.computeFastBounds(r, &storage);
190 
191             canvas->save();
192                 canvas->clipRect(fastBound);
193                 (*draw)(canvas, r, p);
194             canvas->restore();
195 
196             canvas->drawRect(r, redStroked);
197             canvas->drawRect(fastBound, blueStroked);
198         canvas->restore();
199     }
200 
draw_savelayer_with_paint(const SkIPoint & off,SkCanvas * canvas,const SkPaint & p)201     static void draw_savelayer_with_paint(const SkIPoint& off,
202                                           SkCanvas* canvas,
203                                           const SkPaint& p) {
204         SkPaint redStroked;
205         redStroked.setColor(SK_ColorRED);
206         redStroked.setStyle(SkPaint::kStroke_Style);
207 
208         SkPaint blueStroked;
209         blueStroked.setColor(SK_ColorBLUE);
210         blueStroked.setStyle(SkPaint::kStroke_Style);
211 
212         const SkRect bounds = SkRect::MakeWH(10, 10);
213         SkRect storage;
214 
215         canvas->save();
216             canvas->translate(30, 30);
217             canvas->translate(SkIntToScalar(off.fX), SkIntToScalar(off.fY));
218             canvas->scale(1.5f, 1.5f);
219 
220             const SkRect& fastBound = p.computeFastBounds(bounds, &storage);
221 
222             canvas->saveLayer(&fastBound, &p);
223             canvas->restore();
224 
225             canvas->drawRect(bounds, redStroked);
226             canvas->drawRect(fastBound, blueStroked);
227         canvas->restore();
228     }
229 
onDraw(SkCanvas * canvas)230     void onDraw(SkCanvas* canvas) override {
231 
232         SkPaint blackFill;
233 
234         //-----------
235         // Normal paints (no source)
236         SkTArray<SkPaint> paints;
237         create_paints(&paints, nullptr);
238 
239         //-----------
240         // Paints with a PictureImageFilter as a source
241         sk_sp<SkPicture> pic;
242 
243         {
244             SkPictureRecorder rec;
245 
246             SkCanvas* c = rec.beginRecording(10, 10);
247             c->drawRect(SkRect::MakeWH(10, 10), blackFill);
248             pic = rec.finishRecordingAsPicture();
249         }
250 
251         SkTArray<SkPaint> pifPaints;
252         create_paints(&pifPaints, SkImageFilters::Picture(pic));
253 
254         //-----------
255         // Paints with a SkImageSource as a source
256 
257         auto surface(SkSurface::MakeRasterN32Premul(10, 10));
258         {
259             SkPaint p;
260             SkCanvas* temp = surface->getCanvas();
261             temp->clear(SK_ColorYELLOW);
262             p.setColor(SK_ColorBLUE);
263             temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
264             p.setColor(SK_ColorGREEN);
265             temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
266         }
267 
268         sk_sp<SkImage> image(surface->makeImageSnapshot());
269         sk_sp<SkImageFilter> imageSource(SkImageFilters::Image(std::move(image)));
270         SkTArray<SkPaint> bmsPaints;
271         create_paints(&bmsPaints, std::move(imageSource));
272 
273         //-----------
274         SkASSERT(paints.size() == kNumVertTiles);
275         SkASSERT(paints.size() == pifPaints.size());
276         SkASSERT(paints.size() == bmsPaints.size());
277 
278         // horizontal separators
279         for (int i = 1; i < paints.size(); ++i) {
280             canvas->drawLine(0,
281                              i*SkIntToScalar(kTileHeight),
282                              SkIntToScalar((std::size(gDrawMthds) + kNumXtraCols)*kTileWidth),
283                              i*SkIntToScalar(kTileHeight),
284                              blackFill);
285         }
286         // vertical separators
287         for (int i = 0; i < (int)std::size(gDrawMthds) + kNumXtraCols; ++i) {
288             canvas->drawLine(SkIntToScalar(i * kTileWidth),
289                              0,
290                              SkIntToScalar(i * kTileWidth),
291                              SkIntToScalar(paints.size() * kTileWidth),
292                              blackFill);
293         }
294 
295         // A column of saveLayers with PictureImageFilters
296         for (int i = 0; i < pifPaints.size(); ++i) {
297             draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
298                                       canvas, pifPaints[i]);
299         }
300 
301         // A column of saveLayers with BitmapSources
302         for (int i = 0; i < pifPaints.size(); ++i) {
303             draw_savelayer_with_paint(SkIPoint::Make(kTileWidth, i*kTileHeight),
304                                       canvas, bmsPaints[i]);
305         }
306 
307         // Multiple columns with different geometry
308         for (int i = 0; i < (int)std::size(gDrawMthds); ++i) {
309             for (int j = 0; j < paints.size(); ++j) {
310                 draw_geom_with_paint(*gDrawMthds[i],
311                                      SkIPoint::Make((i+kNumXtraCols) * kTileWidth, j*kTileHeight),
312                                      canvas, paints[j]);
313             }
314         }
315 
316     }
317 
318 private:
319     using INHERITED = GM;
320 };
321 
322 //////////////////////////////////////////////////////////////////////////////
323 
324 DEF_GM(return new ImageFilterFastBoundGM;)
325 }  // namespace skiagm
326