• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2011 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/SkBlendMode.h"
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkColorFilter.h"
14 #include "include/core/SkFlattenable.h"
15 #include "include/core/SkFont.h"
16 #include "include/core/SkImageFilter.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkPoint.h"
19 #include "include/core/SkRSXform.h"
20 #include "include/core/SkRect.h"
21 #include "include/core/SkRefCnt.h"
22 #include "include/core/SkScalar.h"
23 #include "include/core/SkSize.h"
24 #include "include/core/SkString.h"
25 #include "include/core/SkTypeface.h"
26 #include "include/core/SkTypes.h"
27 #include "include/effects/SkImageFilters.h"
28 #include "include/utils/SkTextUtils.h"
29 #include "src/core/SkImageFilter_Base.h"
30 #include "src/core/SkSpecialImage.h"
31 #include "src/utils/SkPatchUtils.h"
32 #include "tools/ToolUtils.h"
33 
34 #include <utility>
35 
36 class SkReadBuffer;
37 
38 class FailImageFilter : public SkImageFilter_Base {
39 public:
Make()40     static sk_sp<SkImageFilter> Make() {
41         return sk_sp<SkImageFilter>(new FailImageFilter);
42     }
43 
44     SK_FLATTENABLE_HOOKS(FailImageFilter)
45 protected:
FailImageFilter()46     FailImageFilter() : INHERITED(nullptr, 0, nullptr) {}
47 
onFilterImage(const Context &,SkIPoint * offset) const48     sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override {
49         return nullptr;
50     }
51 
52 private:
53 
54     using INHERITED = SkImageFilter_Base;
55 };
56 
CreateProc(SkReadBuffer & buffer)57 sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
58     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
59     return FailImageFilter::Make();
60 }
61 
62 class IdentityImageFilter : public SkImageFilter_Base {
63 public:
Make(sk_sp<SkImageFilter> input)64     static sk_sp<SkImageFilter> Make(sk_sp<SkImageFilter> input) {
65         return sk_sp<SkImageFilter>(new IdentityImageFilter(std::move(input)));
66     }
67 
68 
69     SK_FLATTENABLE_HOOKS(IdentityImageFilter)
70 protected:
onFilterImage(const Context & ctx,SkIPoint * offset) const71     sk_sp<SkSpecialImage> onFilterImage(const Context& ctx, SkIPoint* offset) const override {
72         offset->set(0, 0);
73         return sk_ref_sp<SkSpecialImage>(ctx.sourceImage());
74     }
75 
76 private:
IdentityImageFilter(sk_sp<SkImageFilter> input)77     IdentityImageFilter(sk_sp<SkImageFilter> input) : INHERITED(&input, 1, nullptr) {}
78 
79     using INHERITED = SkImageFilter_Base;
80 };
81 
82 // Register these image filters as deserializable before main().
83 namespace {
84     static struct Initializer {
Initializer__anon0f8e10c50111::Initializer85         Initializer() {
86             SK_REGISTER_FLATTENABLE(IdentityImageFilter);
87             SK_REGISTER_FLATTENABLE(FailImageFilter);
88         }
89     } initializer;
90 }  // namespace
91 
CreateProc(SkReadBuffer & buffer)92 sk_sp<SkFlattenable> IdentityImageFilter::CreateProc(SkReadBuffer& buffer) {
93     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
94     return IdentityImageFilter::Make(common.getInput(0));
95 }
96 
97 ///////////////////////////////////////////////////////////////////////////////
98 
draw_paint(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)99 static void draw_paint(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
100     SkPaint paint;
101     paint.setImageFilter(std::move(imf));
102     paint.setColor(SK_ColorGREEN);
103     canvas->save();
104     canvas->clipRect(r);
105     canvas->drawPaint(paint);
106     canvas->restore();
107 }
108 
draw_line(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)109 static void draw_line(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
110     SkPaint paint;
111     paint.setColor(SK_ColorBLUE);
112     paint.setImageFilter(imf);
113     paint.setStrokeWidth(r.width()/10);
114     canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
115 }
116 
draw_rect(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)117 static void draw_rect(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
118     SkPaint paint;
119     paint.setColor(SK_ColorYELLOW);
120     paint.setImageFilter(imf);
121     SkRect rr(r);
122     rr.inset(r.width()/10, r.height()/10);
123     canvas->drawRect(rr, paint);
124 }
125 
draw_path(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)126 static void draw_path(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
127     SkPaint paint;
128     paint.setColor(SK_ColorMAGENTA);
129     paint.setImageFilter(imf);
130     paint.setAntiAlias(true);
131     canvas->drawCircle(r.centerX(), r.centerY(), r.width()*2/5, paint);
132 }
133 
draw_text(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)134 static void draw_text(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
135     SkPaint paint;
136     paint.setImageFilter(imf);
137     paint.setColor(SK_ColorCYAN);
138     SkFont font(ToolUtils::create_portable_typeface(), r.height() / 2);
139     SkTextUtils::DrawString(canvas, "Text", r.centerX(), r.centerY(), font, paint,
140                             SkTextUtils::kCenter_Align);
141 }
142 
draw_bitmap(SkCanvas * canvas,SkImage * i,const SkRect & r,sk_sp<SkImageFilter> imf)143 static void draw_bitmap(SkCanvas* canvas, SkImage* i, const SkRect& r, sk_sp<SkImageFilter> imf) {
144     SkPaint paint;
145     paint.setImageFilter(std::move(imf));
146 
147     SkIRect bounds;
148     r.roundOut(&bounds);
149 
150     SkBitmap bm;
151     bm.allocN32Pixels(bounds.width(), bounds.height());
152     bm.eraseColor(SK_ColorTRANSPARENT);
153     SkCanvas c(bm);
154     draw_path(&c, i, r, nullptr);
155 
156     canvas->drawImage(bm.asImage(), 0, 0, SkSamplingOptions(), &paint);
157 }
158 
draw_patch(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)159 static void draw_patch(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
160     SkPaint paint;
161     paint.setImageFilter(std::move(imf));
162 
163     // The order of the colors and points is clockwise starting at upper-left corner.
164     static constexpr SkPoint gCubics[SkPatchUtils::kNumCtrlPts] = {
165         //top points
166         {100,100},{150,50},{250,150},{300,100},
167         //right points
168         {250,150},{350,250},
169         //bottom points
170         {300,300},{250,250},{150,350},{100,300},
171         //left points
172         {50,250},{150,150}
173     };
174 
175     static constexpr SkColor colors[SkPatchUtils::kNumCorners] = {
176         SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
177     };
178 
179     SkAutoCanvasRestore acr(canvas, /*doSave=*/true);
180     canvas->translate(-r.fLeft, -r.fTop);
181     canvas->scale(r.width() / 400.0, r.height() / 400.0);
182     canvas->drawPatch(gCubics, colors, /*texCoords=*/nullptr, SkBlendMode::kSrc, paint);
183 }
184 
draw_atlas(SkCanvas * canvas,SkImage * atlas,const SkRect & r,sk_sp<SkImageFilter> imf)185 static void draw_atlas(SkCanvas* canvas, SkImage* atlas, const SkRect& r,
186                        sk_sp<SkImageFilter> imf) {
187     const SkScalar rad = SkDegreesToRadians(15.0f);
188     SkRSXform xform = SkRSXform::Make(SkScalarCos(rad), SkScalarSin(rad), r.width() * 0.15f, 0);
189 
190     SkPaint paint;
191     paint.setImageFilter(std::move(imf));
192     paint.setAntiAlias(true);
193     SkSamplingOptions sampling(SkCubicResampler::Mitchell());
194     canvas->drawAtlas(atlas, &xform, &r, /*colors=*/nullptr, /*count=*/1, SkBlendMode::kSrc,
195                       sampling, /*cullRect=*/nullptr, &paint);
196 }
197 
198 ///////////////////////////////////////////////////////////////////////////////
199 
200 class ImageFiltersBaseGM : public skiagm::GM {
201 public:
ImageFiltersBaseGM()202     ImageFiltersBaseGM () {}
203 
204 protected:
onShortName()205     SkString onShortName() override {
206         return SkString("imagefiltersbase");
207     }
208 
onISize()209     SkISize onISize() override { return SkISize::Make(700, 500); }
210 
draw_frame(SkCanvas * canvas,const SkRect & r)211     void draw_frame(SkCanvas* canvas, const SkRect& r) {
212         SkPaint paint;
213         paint.setStyle(SkPaint::kStroke_Style);
214         paint.setColor(SK_ColorRED);
215         canvas->drawRect(r, paint);
216     }
217 
onDraw(SkCanvas * canvas)218     void onDraw(SkCanvas* canvas) override {
219         if (fAtlas == nullptr) {
220             fAtlas = create_atlas_image(canvas);
221         }
222 
223         void (*drawProc[])(SkCanvas*, SkImage*, const SkRect&, sk_sp<SkImageFilter>) = {
224             draw_paint,
225             draw_line, draw_rect, draw_path, draw_text,
226             draw_bitmap, draw_patch, draw_atlas
227         };
228 
229         auto cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcIn);
230         sk_sp<SkImageFilter> filters[] = {
231             nullptr,
232             IdentityImageFilter::Make(nullptr),
233             FailImageFilter::Make(),
234             SkImageFilters::ColorFilter(std::move(cf), nullptr),
235             // The strange 0.29 value tickles an edge case where crop rect calculates
236             // a small border, but the blur really needs no border. This tickles
237             // an msan uninitialized value bug.
238             SkImageFilters::Blur(12.0f, 0.29f, nullptr),
239             SkImageFilters::DropShadow(10.0f, 5.0f, 3.0f, 3.0f, SK_ColorBLUE, nullptr),
240         };
241 
242         SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
243         SkScalar MARGIN = SkIntToScalar(16);
244         SkScalar DX = r.width() + MARGIN;
245         SkScalar DY = r.height() + MARGIN;
246 
247         canvas->translate(MARGIN, MARGIN);
248         for (size_t i = 0; i < SK_ARRAY_COUNT(drawProc); ++i) {
249             canvas->save();
250             for (size_t j = 0; j < SK_ARRAY_COUNT(filters); ++j) {
251                 drawProc[i](canvas, fAtlas.get(), r, filters[j]);
252 
253                 draw_frame(canvas, r);
254                 canvas->translate(0, DY);
255             }
256             canvas->restore();
257             canvas->translate(DX, 0);
258         }
259     }
260 
261 private:
create_atlas_image(SkCanvas * canvas)262     static sk_sp<SkImage> create_atlas_image(SkCanvas* canvas) {
263         static constexpr SkSize kSize = {64, 64};
264         SkImageInfo atlasInfo = SkImageInfo::MakeN32Premul(kSize.fWidth, kSize.fHeight);
265         sk_sp<SkSurface> atlasSurface(ToolUtils::makeSurface(canvas, atlasInfo));
266         SkCanvas* atlasCanvas = atlasSurface->getCanvas();
267 
268         SkPaint atlasPaint;
269         atlasPaint.setColor(SK_ColorGRAY);
270         SkFont font(ToolUtils::create_portable_typeface(), kSize.fHeight * 0.4f);
271         SkTextUtils::DrawString(atlasCanvas, "Atlas", kSize.fWidth * 0.5f, kSize.fHeight * 0.5f,
272                                 font, atlasPaint, SkTextUtils::kCenter_Align);
273         return atlasSurface->makeImageSnapshot();
274     }
275 
276     sk_sp<SkImage> fAtlas;
277 
278     using INHERITED = GM;
279 };
280 DEF_GM( return new ImageFiltersBaseGM; )
281 
282 ///////////////////////////////////////////////////////////////////////////////
283 
284 /*
285  *  Want to test combos of filter and LCD text, to be sure we disable LCD in the presence of
286  *  a filter.
287  */
288 class ImageFiltersTextBaseGM : public skiagm::GM {
289     SkString fSuffix;
290 public:
ImageFiltersTextBaseGM(const char suffix[])291     ImageFiltersTextBaseGM(const char suffix[]) : fSuffix(suffix) {}
292 
293 protected:
onShortName()294     SkString onShortName() override {
295         SkString name;
296         name.printf("%s_%s", "textfilter", fSuffix.c_str());
297         return name;
298     }
299 
onISize()300     SkISize onISize() override { return SkISize::Make(512, 342); }
301 
drawWaterfall(SkCanvas * canvas,const SkPaint & paint)302     void drawWaterfall(SkCanvas* canvas, const SkPaint& paint) {
303         static const SkFont::Edging kEdgings[3] = {
304             SkFont::Edging::kAlias,
305             SkFont::Edging::kAntiAlias,
306             SkFont::Edging::kSubpixelAntiAlias,
307         };
308         SkFont font(ToolUtils::create_portable_typeface(), 30);
309 
310         SkAutoCanvasRestore acr(canvas, true);
311         for (SkFont::Edging edging : kEdgings) {
312             font.setEdging(edging);
313             canvas->drawString("Hamburgefon", 0, 0, font, paint);
314             canvas->translate(0, 40);
315         }
316     }
317 
318     virtual void installFilter(SkPaint* paint) = 0;
319 
onDraw(SkCanvas * canvas)320     void onDraw(SkCanvas* canvas) override {
321         canvas->translate(20, 40);
322 
323         for (int doSaveLayer = 0; doSaveLayer <= 1; ++doSaveLayer) {
324             SkAutoCanvasRestore acr(canvas, true);
325             for (int useFilter = 0; useFilter <= 1; ++useFilter) {
326                 SkAutoCanvasRestore acr2(canvas, true);
327 
328                 SkPaint paint;
329                 if (useFilter) {
330                     this->installFilter(&paint);
331                 }
332                 if (doSaveLayer) {
333                     canvas->saveLayer(nullptr, &paint);
334                     paint.setImageFilter(nullptr);
335                 }
336                 this->drawWaterfall(canvas, paint);
337 
338                 acr2.restore();
339                 canvas->translate(250, 0);
340             }
341             acr.restore();
342             canvas->translate(0, 200);
343         }
344     }
345 
346 private:
347     using INHERITED = GM;
348 };
349 
350 class ImageFiltersText_IF : public ImageFiltersTextBaseGM {
351 public:
ImageFiltersText_IF()352     ImageFiltersText_IF() : ImageFiltersTextBaseGM("image") {}
353 
installFilter(SkPaint * paint)354     void installFilter(SkPaint* paint) override {
355         paint->setImageFilter(SkImageFilters::Blur(1.5f, 1.5f, nullptr));
356     }
357 };
358 DEF_GM( return new ImageFiltersText_IF; )
359 
360 class ImageFiltersText_CF : public ImageFiltersTextBaseGM {
361 public:
ImageFiltersText_CF()362     ImageFiltersText_CF() : ImageFiltersTextBaseGM("color") {}
363 
installFilter(SkPaint * paint)364     void installFilter(SkPaint* paint) override {
365         paint->setColorFilter(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn));
366     }
367 };
368 DEF_GM( return new ImageFiltersText_CF; )
369