1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2017 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkBitmap.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageFilter.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkImageFilters.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
26*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
27*c8dee2aaSAndroid Build Coastguard Worker
make_image(SkCanvas * canvas,int direction)28*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> make_image(SkCanvas* canvas, int direction) {
29*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo info = SkImageInfo::MakeN32Premul(250, 200);
30*c8dee2aaSAndroid Build Coastguard Worker auto surface = ToolUtils::makeSurface(canvas, info);
31*c8dee2aaSAndroid Build Coastguard Worker SkCanvas* c = surface->getCanvas();
32*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
33*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker const SkColor colors[] = {
36*c8dee2aaSAndroid Build Coastguard Worker SK_ColorRED, SK_ColorBLUE, SK_ColorGREEN, SK_ColorYELLOW, SK_ColorBLACK
37*c8dee2aaSAndroid Build Coastguard Worker };
38*c8dee2aaSAndroid Build Coastguard Worker
39*c8dee2aaSAndroid Build Coastguard Worker int width = 25;
40*c8dee2aaSAndroid Build Coastguard Worker bool xDirection = (direction & 0x1) == 1;
41*c8dee2aaSAndroid Build Coastguard Worker bool yDirection = (direction & 0x2) == 2;
42*c8dee2aaSAndroid Build Coastguard Worker if (xDirection) {
43*c8dee2aaSAndroid Build Coastguard Worker for (int x = 0; x < info.width(); x += width) {
44*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(colors[x/width % 5]);
45*c8dee2aaSAndroid Build Coastguard Worker if (yDirection) {
46*c8dee2aaSAndroid Build Coastguard Worker paint.setAlphaf(0.5f);
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker c->drawRect(SkRect::MakeXYWH(x, 0, width, info.height()), paint);
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker }
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker if (yDirection) {
53*c8dee2aaSAndroid Build Coastguard Worker for (int y = 0; y < info.height(); y += width) {
54*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(colors[y/width % 5]);
55*c8dee2aaSAndroid Build Coastguard Worker if (xDirection) {
56*c8dee2aaSAndroid Build Coastguard Worker paint.setAlphaf(0.5f);
57*c8dee2aaSAndroid Build Coastguard Worker }
58*c8dee2aaSAndroid Build Coastguard Worker c->drawRect(SkRect::MakeXYWH(0, y, info.width(), width), paint);
59*c8dee2aaSAndroid Build Coastguard Worker }
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker return surface->makeImageSnapshot();
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker
draw_image(SkCanvas * canvas,const sk_sp<SkImage> image,sk_sp<SkImageFilter> filter)64*c8dee2aaSAndroid Build Coastguard Worker static void draw_image(SkCanvas* canvas, const sk_sp<SkImage> image, sk_sp<SkImageFilter> filter) {
65*c8dee2aaSAndroid Build Coastguard Worker SkAutoCanvasRestore acr(canvas, true);
66*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
67*c8dee2aaSAndroid Build Coastguard Worker paint.setImageFilter(std::move(filter));
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(SkIntToScalar(30), 0);
70*c8dee2aaSAndroid Build Coastguard Worker canvas->clipIRect(image->bounds());
71*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(image, 0, 0, SkSamplingOptions(), &paint);
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker namespace skiagm {
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Worker // This GM draws a colorful grids with different blur settings.
77*c8dee2aaSAndroid Build Coastguard Worker class ImageBlurRepeatModeGM : public GM {
78*c8dee2aaSAndroid Build Coastguard Worker public:
ImageBlurRepeatModeGM()79*c8dee2aaSAndroid Build Coastguard Worker ImageBlurRepeatModeGM() {
80*c8dee2aaSAndroid Build Coastguard Worker this->setBGColor(0xFFCCCCCC);
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker protected:
getName() const84*c8dee2aaSAndroid Build Coastguard Worker SkString getName() const override { return SkString("imageblurrepeatmode"); }
85*c8dee2aaSAndroid Build Coastguard Worker
getISize()86*c8dee2aaSAndroid Build Coastguard Worker SkISize getISize() override { return SkISize::Make(850, 920); }
87*c8dee2aaSAndroid Build Coastguard Worker
runAsBench() const88*c8dee2aaSAndroid Build Coastguard Worker bool runAsBench() const override { return true; }
89*c8dee2aaSAndroid Build Coastguard Worker
onDraw(SkCanvas * canvas)90*c8dee2aaSAndroid Build Coastguard Worker void onDraw(SkCanvas* canvas) override {
91*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> image[] =
92*c8dee2aaSAndroid Build Coastguard Worker { make_image(canvas, 1), make_image(canvas, 2), make_image(canvas, 3) };
93*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImageFilter> filter;
94*c8dee2aaSAndroid Build Coastguard Worker
95*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 30);
96*c8dee2aaSAndroid Build Coastguard Worker // Test different kernel size, including the one to launch 2d Gaussian
97*c8dee2aaSAndroid Build Coastguard Worker // blur.
98*c8dee2aaSAndroid Build Coastguard Worker for (auto sigma: { 0.6f, 3.0f, 8.0f, 20.0f }) {
99*c8dee2aaSAndroid Build Coastguard Worker // FIXME crops
100*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
101*c8dee2aaSAndroid Build Coastguard Worker filter = SkImageFilters::Blur(
102*c8dee2aaSAndroid Build Coastguard Worker sigma, 0.0f, SkTileMode::kRepeat, nullptr, image[0]->bounds());
103*c8dee2aaSAndroid Build Coastguard Worker draw_image(canvas, image[0], std::move(filter));
104*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(image[0]->width() + 20, 0);
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker filter = SkImageFilters::Blur(
107*c8dee2aaSAndroid Build Coastguard Worker 0.0f, sigma, SkTileMode::kRepeat, nullptr, image[1]->bounds());
108*c8dee2aaSAndroid Build Coastguard Worker draw_image(canvas, image[1], std::move(filter));
109*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(image[1]->width() + 20, 0);
110*c8dee2aaSAndroid Build Coastguard Worker
111*c8dee2aaSAndroid Build Coastguard Worker filter = SkImageFilters::Blur(
112*c8dee2aaSAndroid Build Coastguard Worker sigma, sigma, SkTileMode::kRepeat, nullptr, image[2]->bounds());
113*c8dee2aaSAndroid Build Coastguard Worker draw_image(canvas, image[2], std::move(filter));
114*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(image[2]->width() + 20, 0);
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
117*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, image[0]->height() + 20);
118*c8dee2aaSAndroid Build Coastguard Worker }
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker
121*c8dee2aaSAndroid Build Coastguard Worker private:
122*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GM;
123*c8dee2aaSAndroid Build Coastguard Worker };
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
126*c8dee2aaSAndroid Build Coastguard Worker
127*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new ImageBlurRepeatModeGM;)
128*c8dee2aaSAndroid Build Coastguard Worker } // namespace skiagm
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker // See skbug.com/10145 for more context, but if the blur doesn't have its own crop rect and
131*c8dee2aaSAndroid Build Coastguard Worker // the canvas is not clipped, repeat can behave strangely (before fixes, this meant:
132*c8dee2aaSAndroid Build Coastguard Worker // 1. The filtered results became semi-transparent when they should have remained opaque.
133*c8dee2aaSAndroid Build Coastguard Worker // 2. The filtered results clip to 3xSigma, which makes sense for the decal tile mode, but not
134*c8dee2aaSAndroid Build Coastguard Worker // the others.
135*c8dee2aaSAndroid Build Coastguard Worker // 3. The repeat filter interacts non-intuitively when an expanded clip rect intersects the draw
136*c8dee2aaSAndroid Build Coastguard Worker // geometry (it repeats across the edges of the intersection instead of repeating across the
137*c8dee2aaSAndroid Build Coastguard Worker // draw and then clipping)).
138*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(imageblurrepeatunclipped, canvas, 256, 128) {
139*c8dee2aaSAndroid Build Coastguard Worker // To show translucency
140*c8dee2aaSAndroid Build Coastguard Worker auto checkerboard = ToolUtils::create_checkerboard_image(256, 128, SK_ColorLTGRAY,
141*c8dee2aaSAndroid Build Coastguard Worker SK_ColorGRAY, 8);
142*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(checkerboard, 0, 0);
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker // Make an image with one red and one blue band
145*c8dee2aaSAndroid Build Coastguard Worker SkBitmap bmp;
146*c8dee2aaSAndroid Build Coastguard Worker bmp.allocN32Pixels(100, 20);
147*c8dee2aaSAndroid Build Coastguard Worker bmp.eraseArea(SkIRect::MakeWH(100, 10), SK_ColorRED);
148*c8dee2aaSAndroid Build Coastguard Worker bmp.eraseArea(SkIRect::MakeXYWH(0, 10, 100, 10), SK_ColorBLUE);
149*c8dee2aaSAndroid Build Coastguard Worker
150*c8dee2aaSAndroid Build Coastguard Worker auto img = bmp.asImage();
151*c8dee2aaSAndroid Build Coastguard Worker // The blur filter uses a repeat crop applied to the image bounds to define the tiling geometry,
152*c8dee2aaSAndroid Build Coastguard Worker // but the crop IF is created directly since the tilemode factory for ::Blur also adds a kDecal
153*c8dee2aaSAndroid Build Coastguard Worker // post-crop that is undesired for this GM.
154*c8dee2aaSAndroid Build Coastguard Worker auto filter = SkImageFilters::Blur(0, 10,
155*c8dee2aaSAndroid Build Coastguard Worker SkImageFilters::Crop(SkRect::Make(img->bounds()), SkTileMode::kRepeat, nullptr));
156*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
157*c8dee2aaSAndroid Build Coastguard Worker paint.setImageFilter(std::move(filter));
158*c8dee2aaSAndroid Build Coastguard Worker
159*c8dee2aaSAndroid Build Coastguard Worker // Draw the blurred image once with a clip that shows the repeat is tiled several times.
160*c8dee2aaSAndroid Build Coastguard Worker // 3xsigma is used to match the historic, but underspecified behavior for when kRepeat was used
161*c8dee2aaSAndroid Build Coastguard Worker // with no crop rect (which must now be provided or kRepeat is ignored).
162*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, 50);
163*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
164*c8dee2aaSAndroid Build Coastguard Worker canvas->clipIRect(img->bounds().makeOutset(0, 30));
165*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(img, 0, 0, SkSamplingOptions(), &paint);
166*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Worker // Draw the blurred image with a clip positioned such that the draw would be excluded except
169*c8dee2aaSAndroid Build Coastguard Worker // that the image filter causes it to intersect with the clip. It should look like the
170*c8dee2aaSAndroid Build Coastguard Worker // left image, but clipped to the debug-black rectangle.
171*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(110, 0);
172*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
173*c8dee2aaSAndroid Build Coastguard Worker canvas->clipIRect(SkIRect::MakeXYWH(0, -30, 100, 10));
174*c8dee2aaSAndroid Build Coastguard Worker canvas->drawImage(img, 0, 0, SkSamplingOptions(), &paint);
175*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Worker // Visualize the clip
178*c8dee2aaSAndroid Build Coastguard Worker SkPaint line;
179*c8dee2aaSAndroid Build Coastguard Worker line.setStyle(SkPaint::kStroke_Style);
180*c8dee2aaSAndroid Build Coastguard Worker canvas->drawRect(SkRect::MakeXYWH(0, -30, 99, 9), line);
181*c8dee2aaSAndroid Build Coastguard Worker }
182