• 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/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"
17 #include "include/core/SkPath.h"
18 #include "include/core/SkPicture.h"
19 #include "include/core/SkPictureRecorder.h"
20 #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"
27 #include "include/core/SkSurface.h"
28 #include "include/core/SkTypes.h"
29 #include "include/effects/SkImageFilters.h"
30 #include "include/private/SkTArray.h"
31 
32 #include <utility>
33 
34 namespace skiagm {
35 
36 // Each method of this type must draw its geometry inside 'r' using 'p'
37 typedef void(*drawMth)(SkCanvas* canvas, const SkRect& r, const SkPaint& p);
38 
draw_rect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)39 static void draw_rect(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
40     canvas->drawRect(r, p);
41 }
42 
draw_oval(SkCanvas * canvas,const SkRect & r,const SkPaint & p)43 static void draw_oval(SkCanvas* canvas, const SkRect& r, const SkPaint& p) {
44     canvas->drawOval(r, p);
45 }
46 
draw_rrect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)47 static 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 
draw_drrect(SkCanvas * canvas,const SkRect & r,const SkPaint & p)56 static 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 
draw_path(SkCanvas * canvas,const SkRect & r,const SkPaint & p)67 static 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 
draw_points(SkCanvas * canvas,const SkRect & r,const SkPaint & p)78 static 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 
draw_bitmap(SkCanvas * canvas,const SkRect & r,const SkPaint & p)86 static 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 
96 constexpr drawMth gDrawMthds[] = {
97     draw_rect, draw_oval, draw_rrect, draw_drrect, draw_path, draw_points, draw_bitmap
98 };
99 
add_paint(SkTArray<SkPaint> * paints,sk_sp<SkImageFilter> filter)100 static void add_paint(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> filter) {
101     SkPaint& p = paints->push_back();
102     p.setImageFilter(std::move(filter));
103     SkASSERT(p.canComputeFastBounds());
104 }
105 
106 // Create a selection of imagefilter-based paints to test
create_paints(SkTArray<SkPaint> * paints,sk_sp<SkImageFilter> source)107 static void create_paints(SkTArray<SkPaint>* paints, sk_sp<SkImageFilter> source) {
108     {
109         SkMatrix scale;
110         scale.setScale(2.0f, 2.0f);
111 
112         sk_sp<SkImageFilter> scaleMIF(
113             SkImageFilters::MatrixTransform(scale, kLow_SkFilterQuality, source));
114 
115         add_paint(paints, std::move(scaleMIF));
116     }
117 
118     {
119         SkMatrix rot;
120         rot.setRotate(-33.3f);
121 
122         sk_sp<SkImageFilter> rotMIF(
123             SkImageFilters::MatrixTransform(rot, kLow_SkFilterQuality, source));
124 
125         add_paint(paints, std::move(rotMIF));
126     }
127 
128     {
129         SkRect src = SkRect::MakeXYWH(20, 20, 10, 10);
130         SkRect dst = SkRect::MakeXYWH(30, 30, 30, 30);
131         sk_sp<SkImageFilter> tileIF(SkImageFilters::Tile(src, dst, nullptr));
132 
133         add_paint(paints, std::move(tileIF));
134     }
135 
136     {
137         sk_sp<SkImageFilter> dsif =
138                 SkImageFilters::DropShadow(10.0f, 10.0f, 3.0f, 3.0f, SK_ColorRED, source);
139 
140         add_paint(paints, std::move(dsif));
141     }
142 
143     {
144         sk_sp<SkImageFilter> dsif =
145             SkImageFilters::DropShadowOnly(27.0f, 27.0f, 3.0f, 3.0f, SK_ColorRED, source);
146 
147         add_paint(paints, std::move(dsif));
148     }
149 
150     add_paint(paints, SkImageFilters::Blur(3, 3, source));
151     add_paint(paints, SkImageFilters::Offset(15, 15, source));
152 }
153 
154 // This GM visualizes the fast bounds for various combinations of geometry
155 // and image filter
156 class ImageFilterFastBoundGM : public GM {
157 public:
ImageFilterFastBoundGM()158     ImageFilterFastBoundGM() {
159         this->setBGColor(0xFFCCCCCC);
160     }
161 
162 protected:
163     static constexpr int kTileWidth = 100;
164     static constexpr int kTileHeight = 100;
165     static constexpr int kNumVertTiles = 7;
166     static constexpr int kNumXtraCols = 2;
167 
onShortName()168     SkString onShortName() override { return SkString("filterfastbounds"); }
169 
onISize()170     SkISize onISize() override {
171         return SkISize::Make((SK_ARRAY_COUNT(gDrawMthds) + kNumXtraCols) * kTileWidth,
172                              kNumVertTiles * kTileHeight);
173     }
174 
draw_geom_with_paint(drawMth draw,const SkIPoint & off,SkCanvas * canvas,const SkPaint & p)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 
draw_savelayer_with_paint(const SkIPoint & off,SkCanvas * canvas,const SkPaint & p)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 
onDraw(SkCanvas * canvas)233     void onDraw(SkCanvas* canvas) override {
234 
235         SkPaint blackFill;
236 
237         //-----------
238         // Normal paints (no source)
239         SkTArray<SkPaint> paints;
240         create_paints(&paints, nullptr);
241 
242         //-----------
243         // Paints with a PictureImageFilter as a source
244         sk_sp<SkPicture> pic;
245 
246         {
247             SkPictureRecorder rec;
248 
249             SkCanvas* c = rec.beginRecording(10, 10);
250             c->drawRect(SkRect::MakeWH(10, 10), blackFill);
251             pic = rec.finishRecordingAsPicture();
252         }
253 
254         SkTArray<SkPaint> pifPaints;
255         create_paints(&pifPaints, SkImageFilters::Picture(pic));
256 
257         //-----------
258         // Paints with a SkImageSource as a source
259 
260         auto surface(SkSurface::MakeRasterN32Premul(10, 10));
261         {
262             SkPaint p;
263             SkCanvas* temp = surface->getCanvas();
264             temp->clear(SK_ColorYELLOW);
265             p.setColor(SK_ColorBLUE);
266             temp->drawRect(SkRect::MakeLTRB(5, 5, 10, 10), p);
267             p.setColor(SK_ColorGREEN);
268             temp->drawRect(SkRect::MakeLTRB(5, 0, 10, 5), p);
269         }
270 
271         sk_sp<SkImage> image(surface->makeImageSnapshot());
272         sk_sp<SkImageFilter> imageSource(SkImageFilters::Image(std::move(image)));
273         SkTArray<SkPaint> bmsPaints;
274         create_paints(&bmsPaints, std::move(imageSource));
275 
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,
293                              SkIntToScalar(i * kTileWidth),
294                              SkIntToScalar(paints.count() * kTileWidth),
295                              blackFill);
296         }
297 
298         // A column of saveLayers with PictureImageFilters
299         for (int i = 0; i < pifPaints.count(); ++i) {
300             draw_savelayer_with_paint(SkIPoint::Make(0, i*kTileHeight),
301                                       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 
321 private:
322     typedef GM INHERITED;
323 };
324 
325 //////////////////////////////////////////////////////////////////////////////
326 
327 DEF_GM(return new ImageFilterFastBoundGM;)
328 }
329