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