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
33static 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
45static 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
59class ImageAlphaThresholdGM : public skiagm::GM {
60public:
61    ImageAlphaThresholdGM(bool useCropRect) : fUseCropRect(useCropRect) {
62        this->setBGColor(SK_ColorWHITE);
63    }
64
65protected:
66
67    SkString onShortName() override {
68        if (fUseCropRect) {
69            return SkString("imagealphathreshold_crop");
70        }
71
72        return SkString("imagealphathreshold");
73    }
74
75    SkISize onISize() override {
76        return SkISize::Make(WIDTH, HEIGHT);
77    }
78
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
96private:
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
104static 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
123class ImageAlphaThresholdSurfaceGM : public skiagm::GM {
124public:
125    ImageAlphaThresholdSurfaceGM() {
126        this->setBGColor(0xFFFFFFFF);
127    }
128
129protected:
130    SkString onShortName() override {
131        return SkString("imagealphathreshold_surface");
132    }
133
134    SkISize onISize() override {
135        return SkISize::Make(WIDTH, HEIGHT);
136    }
137
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, SkSamplingOptions(), &paint);
159        return DrawResult::kOk;
160    }
161
162private:
163    using INHERITED = skiagm::GM;
164};
165
166//////////////////////////////////////////////////////////////////////////////
167
168DEF_GM(return new ImageAlphaThresholdGM(true);)
169DEF_GM(return new ImageAlphaThresholdGM(false);)
170DEF_GM(return new ImageAlphaThresholdSurfaceGM();)
171
172//////////////////////////////////////////////////////////////////////////////
173
174static 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 bitmap.asImage();
190}
191
192DEF_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