1 /*
2  * Copyright 2013 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/SkColorSpace.h"
13 #include "include/core/SkImage.h"
14 #include "include/core/SkImageFilter.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkMatrix.h"
17 #include "include/core/SkPaint.h"
18 #include "include/core/SkRect.h"
19 #include "include/core/SkRefCnt.h"
20 #include "include/core/SkRegion.h"
21 #include "include/core/SkSize.h"
22 #include "include/core/SkString.h"
23 #include "include/core/SkSurface.h"
24 #include "include/effects/SkImageFilters.h"
25 #include "include/utils/SkRandom.h"
26 #include "tools/ToolUtils.h"
27 
28 #include <utility>
29 
30 #define WIDTH 500
31 #define HEIGHT 500
32 
draw_rects(SkCanvas * canvas)33 static void draw_rects(SkCanvas* canvas) {
34     SkPaint rectPaint;
35     rectPaint.setColor(SK_ColorBLUE);
36     canvas->drawRect(SkRect::MakeXYWH(0, 0, WIDTH / 2, HEIGHT / 2), rectPaint);
37     rectPaint.setColor(0xBFFF0000);
38     canvas->drawRect(SkRect::MakeXYWH(WIDTH / 2, 0, WIDTH / 2, HEIGHT / 2), rectPaint);
39     rectPaint.setColor(0x3F00FF00);
40     canvas->drawRect(SkRect::MakeXYWH(0, HEIGHT / 2, WIDTH / 2, HEIGHT / 2), rectPaint);
41     rectPaint.setColor(SK_ColorTRANSPARENT);
42     canvas->drawRect(SkRect::MakeXYWH(WIDTH / 2, HEIGHT / 2, WIDTH / 2, HEIGHT / 2), rectPaint);
43 }
44 
create_filter_paint(SkIRect * cropRect=nullptr)45 static SkPaint create_filter_paint(SkIRect* cropRect = nullptr) {
46     SkIRect rects[2];
47     rects[0] = SkIRect::MakeXYWH(0, 150, WIDTH, HEIGHT - 300);
48     rects[1] = SkIRect::MakeXYWH(150, 0, WIDTH - 300, HEIGHT);
49     SkRegion region;
50     region.setRects(rects, 2);
51 
52     SkPaint paint;
53     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(25, 25, nullptr));
54     paint.setImageFilter(
55             SkImageFilters::AlphaThreshold(region, 0.2f, 0.7f, std::move(offset), cropRect));
56     return paint;
57 }
58 
59 class ImageAlphaThresholdGM : public skiagm::GM {
60 public:
ImageAlphaThresholdGM(bool useCropRect)61     ImageAlphaThresholdGM(bool useCropRect) : fUseCropRect(useCropRect) {
62         this->setBGColor(SK_ColorWHITE);
63     }
64 
65 protected:
66 
onShortName()67     SkString onShortName() override {
68         if (fUseCropRect) {
69             return SkString("imagealphathreshold_crop");
70         }
71 
72         return SkString("imagealphathreshold");
73     }
74 
onISize()75     SkISize onISize() override {
76         return SkISize::Make(WIDTH, HEIGHT);
77     }
78 
onDraw(SkCanvas * canvas)79     void onDraw(SkCanvas* canvas) override {
80         SkMatrix matrix;
81         matrix.reset();
82         matrix.setTranslate(WIDTH * .1f, HEIGHT * .1f);
83         matrix.postScale(.8f, .8f);
84 
85         canvas->concat(matrix);
86 
87         SkIRect cropRect = SkIRect::MakeLTRB(100, 100, WIDTH - 100, HEIGHT - 100);
88 
89         SkPaint paint = create_filter_paint(fUseCropRect ? &cropRect : nullptr);
90         canvas->saveLayer(nullptr, &paint);
91         draw_rects(canvas);
92 
93         canvas->restore();
94     }
95 
96 private:
97     bool fUseCropRect;
98 
99     using INHERITED = GM;
100 };
101 
102 // Create a 'width' x 'height' SkSurface that matches the colorType of 'canvas' as
103 // best we can
make_color_matching_surface(SkCanvas * canvas,int width,int height,SkAlphaType at)104 static sk_sp<SkSurface> make_color_matching_surface(SkCanvas* canvas, int width, int height,
105                                                     SkAlphaType at) {
106 
107     SkColorType ct = canvas->imageInfo().colorType();
108     sk_sp<SkColorSpace> cs(canvas->imageInfo().refColorSpace());
109 
110     if (kUnknown_SkColorType == ct) {
111         // For backends that aren't yet color-space aware we just fallback to N32.
112         ct = kN32_SkColorType;
113         cs = nullptr;
114     } else if (SkColorTypeIsAlwaysOpaque(ct)) {
115         at = kOpaque_SkAlphaType;
116     }
117 
118     SkImageInfo info = SkImageInfo::Make(width, height, ct, at, std::move(cs));
119 
120     return ToolUtils::makeSurface(canvas, info);
121 }
122 
123 class ImageAlphaThresholdSurfaceGM : public skiagm::GM {
124 public:
ImageAlphaThresholdSurfaceGM()125     ImageAlphaThresholdSurfaceGM() {
126         this->setBGColor(0xFFFFFFFF);
127     }
128 
129 protected:
onShortName()130     SkString onShortName() override {
131         return SkString("imagealphathreshold_surface");
132     }
133 
onISize()134     SkISize onISize() override {
135         return SkISize::Make(WIDTH, HEIGHT);
136     }
137 
onDraw(SkCanvas * canvas,SkString * errorMsg)138     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
139         SkMatrix matrix;
140         matrix.reset();
141         matrix.setTranslate(WIDTH * .1f, HEIGHT * .1f);
142         matrix.postScale(.8f, .8f);
143 
144         canvas->concat(matrix);
145 
146         sk_sp<SkSurface> surface(make_color_matching_surface(canvas, WIDTH, HEIGHT,
147                                                              kPremul_SkAlphaType));
148         if (!surface) {
149             *errorMsg = "make_color_matching_surface failed";
150             return DrawResult::kFail;
151         }
152 
153         surface->getCanvas()->clear(SK_ColorTRANSPARENT);
154         draw_rects(surface->getCanvas());
155 
156         SkPaint paint = create_filter_paint();
157         canvas->clipRect(SkRect::MakeLTRB(100, 100, WIDTH - 100, HEIGHT - 100));
158         canvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, &paint);
159         return DrawResult::kOk;
160     }
161 
162 private:
163     using INHERITED = skiagm::GM;
164 };
165 
166 //////////////////////////////////////////////////////////////////////////////
167 
168 DEF_GM(return new ImageAlphaThresholdGM(true);)
DEF_GM(return new ImageAlphaThresholdGM (false);)169 DEF_GM(return new ImageAlphaThresholdGM(false);)
170 DEF_GM(return new ImageAlphaThresholdSurfaceGM();)
171 
172 //////////////////////////////////////////////////////////////////////////////
173 
174 static sk_sp<SkImage> make_img() {
175     SkBitmap bitmap;
176     bitmap.allocPixels(SkImageInfo::MakeS32(WIDTH, HEIGHT, kPremul_SkAlphaType));
177     SkCanvas canvas(bitmap);
178 
179     SkPaint paint;
180     SkRect rect = SkRect::MakeWH(WIDTH, HEIGHT);
181     SkRandom rnd;
182 
183     while (!rect.isEmpty()) {
184         paint.setColor(rnd.nextU() | (0xFF << 24));
185         canvas.drawRect(rect, paint);
186         rect.inset(25, 25);
187     }
188 
189     return SkImage::MakeFromBitmap(bitmap);
190 }
191 
192 DEF_SIMPLE_GM_BG(imagealphathreshold_image, canvas, WIDTH * 2, HEIGHT, SK_ColorBLACK) {
193     sk_sp<SkImage> image(make_img());
194 
195     SkIRect rects[2];
196     rects[0] = SkIRect::MakeXYWH(0, 150, WIDTH, HEIGHT - 300);
197     rects[1] = SkIRect::MakeXYWH(150, 0, WIDTH - 300, HEIGHT);
198     SkRegion region;
199     region.setRects(rects, 2);
200 
201     SkPaint filterPaint;
202     sk_sp<SkImageFilter> imageSource(SkImageFilters::Image(image));
203     filterPaint.setImageFilter(SkImageFilters::AlphaThreshold(region, 0.2f, 0.7f,
204                                                               std::move(imageSource)));
205 
206     canvas->saveLayer(nullptr, &filterPaint);
207     canvas->restore();
208     canvas->translate(WIDTH, 0);
209     canvas->drawImage(image, 0, 0);
210 }
211