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 #include "tools/fonts/FontToolUtils.h"
34
35 #include <utility>
36
37 class SkReadBuffer;
38
draw_paint(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)39 static void draw_paint(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
40 SkPaint paint;
41 paint.setImageFilter(std::move(imf));
42 paint.setColor(SK_ColorGREEN);
43 canvas->save();
44 canvas->clipRect(r);
45 canvas->drawPaint(paint);
46 canvas->restore();
47 }
48
draw_line(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)49 static void draw_line(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
50 SkPaint paint;
51 paint.setColor(SK_ColorBLUE);
52 paint.setImageFilter(imf);
53 paint.setStrokeWidth(r.width()/10);
54 canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
55 }
56
draw_rect(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)57 static void draw_rect(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
58 SkPaint paint;
59 paint.setColor(SK_ColorYELLOW);
60 paint.setImageFilter(imf);
61 SkRect rr(r);
62 rr.inset(r.width()/10, r.height()/10);
63 canvas->drawRect(rr, paint);
64 }
65
draw_path(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)66 static void draw_path(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
67 SkPaint paint;
68 paint.setColor(SK_ColorMAGENTA);
69 paint.setImageFilter(imf);
70 paint.setAntiAlias(true);
71 canvas->drawCircle(r.centerX(), r.centerY(), r.width()*2/5, paint);
72 }
73
draw_text(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)74 static void draw_text(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
75 SkPaint paint;
76 paint.setImageFilter(imf);
77 paint.setColor(SK_ColorCYAN);
78 SkFont font(ToolUtils::DefaultPortableTypeface(), r.height() / 2);
79 SkTextUtils::DrawString(canvas, "Text", r.centerX(), r.centerY(), font, paint,
80 SkTextUtils::kCenter_Align);
81 }
82
draw_bitmap(SkCanvas * canvas,SkImage * i,const SkRect & r,sk_sp<SkImageFilter> imf)83 static void draw_bitmap(SkCanvas* canvas, SkImage* i, const SkRect& r, sk_sp<SkImageFilter> imf) {
84 SkPaint paint;
85 paint.setImageFilter(std::move(imf));
86
87 SkIRect bounds;
88 r.roundOut(&bounds);
89
90 SkBitmap bm;
91 bm.allocN32Pixels(bounds.width(), bounds.height());
92 bm.eraseColor(SK_ColorTRANSPARENT);
93 SkCanvas c(bm);
94 draw_path(&c, i, r, nullptr);
95
96 canvas->drawImage(bm.asImage(), 0, 0, SkSamplingOptions(), &paint);
97 }
98
draw_patch(SkCanvas * canvas,SkImage *,const SkRect & r,sk_sp<SkImageFilter> imf)99 static void draw_patch(SkCanvas* canvas, SkImage*, const SkRect& r, sk_sp<SkImageFilter> imf) {
100 SkPaint paint;
101 paint.setImageFilter(std::move(imf));
102
103 // The order of the colors and points is clockwise starting at upper-left corner.
104 static constexpr SkPoint gCubics[SkPatchUtils::kNumCtrlPts] = {
105 //top points
106 {100,100},{150,50},{250,150},{300,100},
107 //right points
108 {250,150},{350,250},
109 //bottom points
110 {300,300},{250,250},{150,350},{100,300},
111 //left points
112 {50,250},{150,150}
113 };
114
115 static constexpr SkColor colors[SkPatchUtils::kNumCorners] = {
116 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorCYAN
117 };
118
119 SkAutoCanvasRestore acr(canvas, /*doSave=*/true);
120 canvas->translate(-r.fLeft, -r.fTop);
121 canvas->scale(r.width() / 400.0, r.height() / 400.0);
122 canvas->drawPatch(gCubics, colors, /*texCoords=*/nullptr, SkBlendMode::kDst, paint);
123 }
124
draw_atlas(SkCanvas * canvas,SkImage * atlas,const SkRect & r,sk_sp<SkImageFilter> imf)125 static void draw_atlas(SkCanvas* canvas, SkImage* atlas, const SkRect& r,
126 sk_sp<SkImageFilter> imf) {
127 const SkScalar rad = SkDegreesToRadians(15.0f);
128 SkRSXform xform = SkRSXform::Make(SkScalarCos(rad), SkScalarSin(rad), r.width() * 0.15f, 0);
129
130 SkPaint paint;
131 paint.setImageFilter(std::move(imf));
132 paint.setAntiAlias(true);
133 SkSamplingOptions sampling(SkCubicResampler::Mitchell());
134 canvas->drawAtlas(atlas, &xform, &r, /*colors=*/nullptr, /*count=*/1, SkBlendMode::kSrc,
135 sampling, /*cullRect=*/nullptr, &paint);
136 }
137
138 ///////////////////////////////////////////////////////////////////////////////
139
140 class ImageFiltersBaseGM : public skiagm::GM {
141 public:
ImageFiltersBaseGM()142 ImageFiltersBaseGM () {}
143
144 protected:
getName() const145 SkString getName() const override { return SkString("imagefiltersbase"); }
146
getISize()147 SkISize getISize() override { return SkISize::Make(700, 500); }
148
draw_frame(SkCanvas * canvas,const SkRect & r)149 void draw_frame(SkCanvas* canvas, const SkRect& r) {
150 SkPaint paint;
151 paint.setStyle(SkPaint::kStroke_Style);
152 paint.setColor(SK_ColorRED);
153 canvas->drawRect(r, paint);
154 }
155
onDraw(SkCanvas * canvas)156 void onDraw(SkCanvas* canvas) override {
157 if (fAtlas == nullptr) {
158 fAtlas = create_atlas_image(canvas);
159 }
160
161 void (*drawProc[])(SkCanvas*, SkImage*, const SkRect&, sk_sp<SkImageFilter>) = {
162 draw_paint,
163 draw_line, draw_rect, draw_path, draw_text,
164 draw_bitmap, draw_patch, draw_atlas
165 };
166
167 auto cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcIn);
168 sk_sp<SkImageFilter> filters[] = {
169 nullptr,
170 SkImageFilters::Offset(0.f, 0.f, nullptr), // "identity"
171 SkImageFilters::Empty(),
172 SkImageFilters::ColorFilter(std::move(cf), nullptr),
173 // The strange 0.29 value tickles an edge case where crop rect calculates
174 // a small border, but the blur really needs no border. This tickles
175 // an msan uninitialized value bug.
176 SkImageFilters::Blur(12.0f, 0.29f, nullptr),
177 SkImageFilters::DropShadow(10.0f, 5.0f, 3.0f, 3.0f, SK_ColorBLUE, nullptr),
178 };
179
180 SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64));
181 SkScalar MARGIN = SkIntToScalar(16);
182 SkScalar DX = r.width() + MARGIN;
183 SkScalar DY = r.height() + MARGIN;
184
185 canvas->translate(MARGIN, MARGIN);
186 for (size_t i = 0; i < std::size(drawProc); ++i) {
187 canvas->save();
188 for (size_t j = 0; j < std::size(filters); ++j) {
189 drawProc[i](canvas, fAtlas.get(), r, filters[j]);
190
191 draw_frame(canvas, r);
192 canvas->translate(0, DY);
193 }
194 canvas->restore();
195 canvas->translate(DX, 0);
196 }
197 }
198
199 private:
create_atlas_image(SkCanvas * canvas)200 static sk_sp<SkImage> create_atlas_image(SkCanvas* canvas) {
201 static constexpr SkSize kSize = {64, 64};
202 SkImageInfo atlasInfo = SkImageInfo::MakeN32Premul(kSize.fWidth, kSize.fHeight);
203 sk_sp<SkSurface> atlasSurface(ToolUtils::makeSurface(canvas, atlasInfo));
204 SkCanvas* atlasCanvas = atlasSurface->getCanvas();
205
206 SkPaint atlasPaint;
207 atlasPaint.setColor(SK_ColorGRAY);
208 SkFont font(ToolUtils::DefaultPortableTypeface(), kSize.fHeight * 0.4f);
209 SkTextUtils::DrawString(atlasCanvas, "Atlas", kSize.fWidth * 0.5f, kSize.fHeight * 0.5f,
210 font, atlasPaint, SkTextUtils::kCenter_Align);
211 return atlasSurface->makeImageSnapshot();
212 }
213
214 sk_sp<SkImage> fAtlas;
215
216 using INHERITED = GM;
217 };
218 DEF_GM( return new ImageFiltersBaseGM; )
219
220 ///////////////////////////////////////////////////////////////////////////////
221
222 /*
223 * Want to test combos of filter and LCD text, to be sure we disable LCD in the presence of
224 * a filter.
225 */
226 class ImageFiltersTextBaseGM : public skiagm::GM {
227 SkString fSuffix;
228 public:
ImageFiltersTextBaseGM(const char suffix[])229 ImageFiltersTextBaseGM(const char suffix[]) : fSuffix(suffix) {}
230
231 protected:
getName() const232 SkString getName() const override {
233 SkString name;
234 name.printf("%s_%s", "textfilter", fSuffix.c_str());
235 return name;
236 }
237
getISize()238 SkISize getISize() override { return SkISize::Make(512, 342); }
239
drawWaterfall(SkCanvas * canvas,const SkPaint & paint)240 void drawWaterfall(SkCanvas* canvas, const SkPaint& paint) {
241 static const SkFont::Edging kEdgings[3] = {
242 SkFont::Edging::kAlias,
243 SkFont::Edging::kAntiAlias,
244 SkFont::Edging::kSubpixelAntiAlias,
245 };
246 SkFont font(ToolUtils::DefaultPortableTypeface(), 30);
247
248 SkAutoCanvasRestore acr(canvas, true);
249 for (SkFont::Edging edging : kEdgings) {
250 font.setEdging(edging);
251 canvas->drawString("Hamburgefon", 0, 0, font, paint);
252 canvas->translate(0, 40);
253 }
254 }
255
256 virtual void installFilter(SkPaint* paint) = 0;
257
onDraw(SkCanvas * canvas)258 void onDraw(SkCanvas* canvas) override {
259 canvas->translate(20, 40);
260
261 for (int doSaveLayer = 0; doSaveLayer <= 1; ++doSaveLayer) {
262 SkAutoCanvasRestore acr(canvas, true);
263 for (int useFilter = 0; useFilter <= 1; ++useFilter) {
264 SkAutoCanvasRestore acr2(canvas, true);
265
266 SkPaint paint;
267 if (useFilter) {
268 this->installFilter(&paint);
269 }
270 if (doSaveLayer) {
271 canvas->saveLayer(nullptr, &paint);
272 paint.setImageFilter(nullptr);
273 }
274 this->drawWaterfall(canvas, paint);
275
276 acr2.restore();
277 canvas->translate(250, 0);
278 }
279 acr.restore();
280 canvas->translate(0, 200);
281 }
282 }
283
284 private:
285 using INHERITED = GM;
286 };
287
288 class ImageFiltersText_IF : public ImageFiltersTextBaseGM {
289 public:
ImageFiltersText_IF()290 ImageFiltersText_IF() : ImageFiltersTextBaseGM("image") {}
291
installFilter(SkPaint * paint)292 void installFilter(SkPaint* paint) override {
293 paint->setImageFilter(SkImageFilters::Blur(1.5f, 1.5f, nullptr));
294 }
295 };
296 DEF_GM( return new ImageFiltersText_IF; )
297
298 class ImageFiltersText_CF : public ImageFiltersTextBaseGM {
299 public:
ImageFiltersText_CF()300 ImageFiltersText_CF() : ImageFiltersTextBaseGM("color") {}
301
installFilter(SkPaint * paint)302 void installFilter(SkPaint* paint) override {
303 paint->setColorFilter(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn));
304 }
305 };
306 DEF_GM( return new ImageFiltersText_CF; )
307