blob: e6469bb1c910d9f5d6d55fdffcacfac35071fd62 [file] [log] [blame]
senorblanco@chromium.org194d7752013-07-24 22:19:24 +00001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkBitmap.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkImage.h"
11#include "include/core/SkPicture.h"
12#include "include/core/SkPictureRecorder.h"
13#include "include/core/SkPoint3.h"
14#include "include/core/SkRect.h"
15#include "include/core/SkSurface.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/effects/SkColorMatrixFilter.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/effects/SkGradientShader.h"
Michael Ludwig55edb502019-08-05 10:41:10 -040018#include "include/effects/SkImageFilters.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "include/effects/SkPerlinNoiseShader.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/effects/SkTableColorFilter.h"
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040021#include "src/core/SkImageFilter_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050022#include "src/core/SkReadBuffer.h"
23#include "src/core/SkSpecialImage.h"
24#include "src/core/SkSpecialSurface.h"
25#include "tests/Test.h"
26#include "tools/Resources.h"
27#include "tools/ToolUtils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000028
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "include/gpu/GrContext.h"
30#include "src/gpu/GrCaps.h"
31#include "src/gpu/GrContextPriv.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000032
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000033static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000034
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000035namespace {
36
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040037class MatrixTestImageFilter : public SkImageFilter_Base {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000038public:
robertphillips43c2ad42016-04-04 05:05:11 -070039 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
40 const SkMatrix& expectedMatrix) {
41 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000042 }
43
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000044protected:
Michael Ludwige30a4852019-08-14 14:35:42 -040045 sk_sp<SkSpecialImage> onFilterImage(const Context& ctx, SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070046 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070047 offset->fX = offset->fY = 0;
Michael Ludwige30a4852019-08-14 14:35:42 -040048 return sk_ref_sp<SkSpecialImage>(ctx.sourceImage());
robertphillips43c2ad42016-04-04 05:05:11 -070049 }
50
mtklein36352bf2015-03-25 18:17:31 -070051 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070052 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000053 }
54
55private:
Mike Klein4fee3232018-10-18 17:27:16 -040056 SK_FLATTENABLE_HOOKS(MatrixTestImageFilter)
57
robertphillips43c2ad42016-04-04 05:05:11 -070058 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
59 : INHERITED(nullptr, 0, nullptr)
60 , fReporter(reporter)
61 , fExpectedMatrix(expectedMatrix) {
62 }
63
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000064 skiatest::Reporter* fReporter;
65 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080066
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040067 typedef SkImageFilter_Base INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000068};
69
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040070class FailImageFilter : public SkImageFilter_Base {
senorblanco6a93fa12016-04-05 04:43:45 -070071public:
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040072 FailImageFilter() : INHERITED(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070073
Michael Ludwige30a4852019-08-14 14:35:42 -040074 sk_sp<SkSpecialImage> onFilterImage(const Context& ctx, SkIPoint* offset) const override {
senorblanco6a93fa12016-04-05 04:43:45 -070075 return nullptr;
76 }
77
Mike Klein4fee3232018-10-18 17:27:16 -040078 SK_FLATTENABLE_HOOKS(FailImageFilter)
senorblanco6a93fa12016-04-05 04:43:45 -070079
80private:
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040081 typedef SkImageFilter_Base INHERITED;
senorblanco6a93fa12016-04-05 04:43:45 -070082};
83
84sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
85 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
86 return sk_sp<SkFlattenable>(new FailImageFilter());
87}
88
senorblanco297f7ce2016-03-23 13:44:26 -070089void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
90 SkScalar x = SkIntToScalar(width / 2);
91 SkScalar y = SkIntToScalar(height / 2);
92 SkScalar radius = SkMinScalar(x, y) * 0.8f;
93 canvas->clear(0x00000000);
94 SkColor colors[2];
95 colors[0] = SK_ColorWHITE;
96 colors[1] = SK_ColorBLACK;
97 sk_sp<SkShader> shader(
98 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
Mike Reedfae8fce2019-04-03 10:27:45 -040099 SkTileMode::kClamp)
senorblanco297f7ce2016-03-23 13:44:26 -0700100 );
101 SkPaint paint;
102 paint.setShader(shader);
103 canvas->drawCircle(x, y, radius, paint);
104}
105
106SkBitmap make_gradient_circle(int width, int height) {
107 SkBitmap bitmap;
108 bitmap.allocN32Pixels(width, height);
109 SkCanvas canvas(bitmap);
110 draw_gradient_circle(&canvas, width, height);
111 return bitmap;
112}
113
114class FilterList {
115public:
Michael Ludwig55edb502019-08-05 10:41:10 -0400116 FilterList(sk_sp<SkImageFilter> input, const SkIRect* cropRect = nullptr) {
117 static const SkScalar kBlurSigma = SkIntToScalar(5);
118
senorblanco297f7ce2016-03-23 13:44:26 -0700119 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
robertphillips6e7025a2016-04-04 04:31:25 -0700120 {
Michael Ludwig55edb502019-08-05 10:41:10 -0400121 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700122
robertphillips6e7025a2016-04-04 04:31:25 -0700123 this->addFilter("color filter",
Michael Ludwig55edb502019-08-05 10:41:10 -0400124 SkImageFilters::ColorFilter(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700125 }
robertphillips6e7025a2016-04-04 04:31:25 -0700126 {
127 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
Michael Ludwig55edb502019-08-05 10:41:10 -0400128 sk_sp<SkImageFilter> gradientSource(SkImageFilters::Image(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700129
liyuqianbfebe222016-11-14 11:17:16 -0800130 this->addFilter("displacement map",
Michael Ludwig55edb502019-08-05 10:41:10 -0400131 SkImageFilters::DisplacementMap(SkColorChannel::kR, SkColorChannel::kB, 20.0f,
132 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700133 }
Michael Ludwig55edb502019-08-05 10:41:10 -0400134 this->addFilter("blur", SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, input, cropRect));
135 this->addFilter("drop shadow", SkImageFilters::DropShadow(
136 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700137 this->addFilter("diffuse lighting",
Michael Ludwig55edb502019-08-05 10:41:10 -0400138 SkImageFilters::PointLitDiffuse(location, SK_ColorGREEN, 0, 0, input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700139 this->addFilter("specular lighting",
Michael Ludwig55edb502019-08-05 10:41:10 -0400140 SkImageFilters::PointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input,
141 cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700142 {
143 SkScalar kernel[9] = {
144 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
145 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
146 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
147 };
148 const SkISize kernelSize = SkISize::Make(3, 3);
149 const SkScalar gain = SK_Scalar1, bias = 0;
150
Robert Phillips12078432018-05-17 11:17:39 -0400151 // This filter needs a saveLayer bc it is in repeat mode
robertphillips12fa47d2016-04-08 16:28:09 -0700152 this->addFilter("matrix convolution",
Michael Ludwig55edb502019-08-05 10:41:10 -0400153 SkImageFilters::MatrixConvolution(
154 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
155 SkTileMode::kRepeat, false, input, cropRect),
Robert Phillips12078432018-05-17 11:17:39 -0400156 true);
robertphillips12fa47d2016-04-08 16:28:09 -0700157 }
Michael Ludwig55edb502019-08-05 10:41:10 -0400158 this->addFilter("merge", SkImageFilters::Merge(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700159
robertphillips6e7025a2016-04-04 04:31:25 -0700160 {
161 SkPaint greenColorShaderPaint;
Mike Reedc8bea7d2019-04-09 13:55:36 -0400162 greenColorShaderPaint.setShader(SkShaders::Color(SK_ColorGREEN));
robertphillips6e7025a2016-04-04 04:31:25 -0700163
Michael Ludwig55edb502019-08-05 10:41:10 -0400164 SkIRect leftSideCropRect = SkIRect::MakeXYWH(0, 0, 32, 64);
165 sk_sp<SkImageFilter> paintFilterLeft(SkImageFilters::Paint(greenColorShaderPaint,
166 &leftSideCropRect));
167 SkIRect rightSideCropRect = SkIRect::MakeXYWH(32, 0, 32, 64);
168 sk_sp<SkImageFilter> paintFilterRight(SkImageFilters::Paint(greenColorShaderPaint,
169 &rightSideCropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700170
171
Michael Ludwig55edb502019-08-05 10:41:10 -0400172 this->addFilter("merge with disjoint inputs", SkImageFilters::Merge(
173 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700174 }
175
Michael Ludwig55edb502019-08-05 10:41:10 -0400176 this->addFilter("offset", SkImageFilters::Offset(SK_Scalar1, SK_Scalar1, input, cropRect));
177 this->addFilter("dilate", SkImageFilters::Dilate(3, 2, input, cropRect));
178 this->addFilter("erode", SkImageFilters::Erode(2, 3, input, cropRect));
179 this->addFilter("tile", SkImageFilters::Tile(SkRect::MakeXYWH(0, 0, 50, 50),
180 cropRect ? SkRect::Make(*cropRect)
181 : SkRect::MakeXYWH(0, 0, 100, 100),
182 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700183
robertphillips12fa47d2016-04-08 16:28:09 -0700184 if (!cropRect) {
185 SkMatrix matrix;
186
187 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
188 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
189
190 this->addFilter("matrix",
Michael Ludwig55edb502019-08-05 10:41:10 -0400191 SkImageFilters::MatrixTransform(matrix, kLow_SkFilterQuality, input));
robertphillips12fa47d2016-04-08 16:28:09 -0700192 }
robertphillips6e7025a2016-04-04 04:31:25 -0700193 {
Michael Ludwig55edb502019-08-05 10:41:10 -0400194 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(kBlurSigma, kBlurSigma, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700195
Michael Ludwig55edb502019-08-05 10:41:10 -0400196 this->addFilter("blur and offset", SkImageFilters::Offset(
197 kBlurSigma, kBlurSigma, std::move(blur), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700198 }
199 {
robertphillips6e7025a2016-04-04 04:31:25 -0700200 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400201 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700202
203 SkPaint greenPaint;
204 greenPaint.setColor(SK_ColorGREEN);
205 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
206 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
Michael Ludwig55edb502019-08-05 10:41:10 -0400207 sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(std::move(picture)));
robertphillips6e7025a2016-04-04 04:31:25 -0700208
Michael Ludwig55edb502019-08-05 10:41:10 -0400209 this->addFilter("picture and blur", SkImageFilters::Blur(
210 kBlurSigma, kBlurSigma, std::move(pictureFilter), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700211 }
212 {
213 SkPaint paint;
214 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
Michael Ludwig55edb502019-08-05 10:41:10 -0400215 sk_sp<SkImageFilter> paintFilter(SkImageFilters::Paint(paint));
robertphillips6e7025a2016-04-04 04:31:25 -0700216
Michael Ludwig55edb502019-08-05 10:41:10 -0400217 this->addFilter("paint and blur", SkImageFilters::Blur(
218 kBlurSigma, kBlurSigma, std::move(paintFilter), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700219 }
Michael Ludwig55edb502019-08-05 10:41:10 -0400220 this->addFilter("xfermode", SkImageFilters::Xfermode(
221 SkBlendMode::kSrc, input, input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700222 }
223 int count() const { return fFilters.count(); }
224 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
225 const char* getName(int index) const { return fFilters[index].fName; }
Robert Phillips12078432018-05-17 11:17:39 -0400226 bool needsSaveLayer(int index) const { return fFilters[index].fNeedsSaveLayer; }
senorblanco297f7ce2016-03-23 13:44:26 -0700227private:
228 struct Filter {
Robert Phillips12078432018-05-17 11:17:39 -0400229 Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
230 Filter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer)
robertphillips12fa47d2016-04-08 16:28:09 -0700231 : fName(name)
Robert Phillips12078432018-05-17 11:17:39 -0400232 , fFilter(std::move(filter))
233 , fNeedsSaveLayer(needsSaveLayer) {
robertphillips12fa47d2016-04-08 16:28:09 -0700234 }
senorblanco297f7ce2016-03-23 13:44:26 -0700235 const char* fName;
236 sk_sp<SkImageFilter> fFilter;
Robert Phillips12078432018-05-17 11:17:39 -0400237 bool fNeedsSaveLayer;
senorblanco297f7ce2016-03-23 13:44:26 -0700238 };
Robert Phillips12078432018-05-17 11:17:39 -0400239 void addFilter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer = false) {
240 fFilters.push_back(Filter(name, std::move(filter), needsSaveLayer));
senorblanco297f7ce2016-03-23 13:44:26 -0700241 }
242
243 SkTArray<Filter> fFilters;
244};
245
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400246class FixedBoundsImageFilter : public SkImageFilter_Base {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700247public:
248 FixedBoundsImageFilter(const SkIRect& bounds)
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400249 : INHERITED(nullptr, 0, nullptr), fBounds(bounds) {}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700250
251private:
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700252 Factory getFactory() const override { return nullptr; }
Mike Klein4fee3232018-10-18 17:27:16 -0400253 const char* getTypeName() const override { return nullptr; }
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700254
Michael Ludwige30a4852019-08-14 14:35:42 -0400255 sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700256 return nullptr;
257 }
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700258
Robert Phillips12078432018-05-17 11:17:39 -0400259 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&,
260 MapDirection, const SkIRect*) const override {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700261 return fBounds;
262 }
263
264 SkIRect fBounds;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400265
266 typedef SkImageFilter_Base INHERITED;
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700267};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000268}
269
reed60c9b582016-04-03 09:11:13 -0700270sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700271 SkDEBUGFAIL("Should never get here");
272 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700273}
274
reed9ce9d672016-03-17 10:51:11 -0700275static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700276 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700277 SkCanvas* canvas = surface->getCanvas();
278 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000279 SkPaint darkPaint;
280 darkPaint.setColor(0xFF804020);
281 SkPaint lightPaint;
282 lightPaint.setColor(0xFF244484);
Michael Ludwig55edb502019-08-05 10:41:10 -0400283 const int kRectSize = kBitmapSize / 4;
284 static_assert(kBitmapSize % 4 == 0, "bitmap size not multiple of 4");
285
286 for (int y = 0; y < kBitmapSize; y += kRectSize) {
287 for (int x = 0; x < kBitmapSize; x += kRectSize) {
fmalita5598b632015-09-15 11:26:13 -0700288 canvas->save();
289 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
Michael Ludwig55edb502019-08-05 10:41:10 -0400290 canvas->drawRect(
291 SkRect::MakeXYWH(0, 0, kRectSize, kRectSize), darkPaint);
292 canvas->drawRect(
293 SkRect::MakeXYWH(kRectSize, 0, kRectSize, kRectSize), lightPaint);
294 canvas->drawRect(
295 SkRect::MakeXYWH(0, kRectSize, kRectSize, kRectSize), lightPaint);
296 canvas->drawRect(
297 SkRect::MakeXYWH(kRectSize, kRectSize, kRectSize, kRectSize), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700298 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000299 }
300 }
fmalita5598b632015-09-15 11:26:13 -0700301
reed9ce9d672016-03-17 10:51:11 -0700302 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000303}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000304
robertphillips5605b562016-04-05 11:50:42 -0700305static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
Mike Reede869a1e2019-04-30 12:18:54 -0400306 float s = amount;
307 float matrix[20] = { s, 0, 0, 0, 0,
308 0, s, 0, 0, 0,
309 0, 0, s, 0, 0,
310 0, 0, 0, s, 0 };
311 sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
Michael Ludwig55edb502019-08-05 10:41:10 -0400312 return SkImageFilters::ColorFilter(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000313}
314
robertphillips5605b562016-04-05 11:50:42 -0700315static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
Michael Ludwig55edb502019-08-05 10:41:10 -0400316 const SkIRect* cropRect) {
Mike Reede869a1e2019-04-30 12:18:54 -0400317 float matrix[20];
318 memset(matrix, 0, 20 * sizeof(float));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000319 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
320 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
321 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
322 matrix[18] = 1.0f;
Mike Reede869a1e2019-04-30 12:18:54 -0400323 sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
Michael Ludwig55edb502019-08-05 10:41:10 -0400324 return SkImageFilters::ColorFilter(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000325}
326
Michael Ludwig55edb502019-08-05 10:41:10 -0400327static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input, const SkIRect* cropRect) {
Mike Reedb286bc22019-04-08 16:23:20 -0400328 sk_sp<SkColorFilter> filter(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn));
Michael Ludwig55edb502019-08-05 10:41:10 -0400329 return SkImageFilters::ColorFilter(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700330}
331
robertphillips3e302272016-04-20 11:48:36 -0700332static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillips4418dba2016-03-07 12:45:14 -0800333 if (context) {
Brian Salomon27ae52c2019-07-03 11:27:44 -0400334 return SkSpecialSurface::MakeRenderTarget(context, widthHeight, widthHeight,
335 GrColorType::kRGBA_8888, nullptr);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400336 } else {
robertphillips4418dba2016-03-07 12:45:14 -0800337 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
338 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700339 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800340 }
senorblancobf680c32016-03-16 16:15:53 -0700341}
342
senorblanco5878dbd2016-05-19 14:50:29 -0700343static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
344 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
senorblanco5878dbd2016-05-19 14:50:29 -0700345 if (context) {
346 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400347 } else {
senorblanco5878dbd2016-05-19 14:50:29 -0700348 return SkSurface::MakeRaster(info);
349 }
350}
351
robertphillips3e302272016-04-20 11:48:36 -0700352static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
353 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800354
355 SkASSERT(surf);
356
357 SkCanvas* canvas = surf->getCanvas();
358 SkASSERT(canvas);
359
360 canvas->clear(0x0);
361
robertphillips37bd7c32016-03-17 14:31:39 -0700362 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800363}
364
365
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000366DEF_TEST(ImageFilter, reporter) {
367 {
Mike Kleindadac552019-03-12 10:01:28 -0500368 // Check that a color matrix filter followed by a color matrix filter
369 // concatenates into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700370 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
371 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700372 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700373 SkColorFilter* cf;
374 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
reedcedc36f2015-03-08 04:42:52 -0700375 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000376 }
377
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000378 {
379 // Check that a color filter image filter without a crop rect can be
380 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700381 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700382 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000383 }
mtklein2afbe232016-02-07 12:23:10 -0800384
reedcedc36f2015-03-08 04:42:52 -0700385 {
386 // Check that a colorfilterimage filter without a crop rect but with an input
387 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700388 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
389 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700390 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700391 }
392
393 {
394 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
395 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700396 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700397 const int kWayTooManyForComposeColorFilter = 100;
398 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700399 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700400 // the first few of these will succeed, but after we hit the internal limit,
401 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700402 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700403 }
404 }
reed5c518a82015-03-05 14:47:29 -0800405
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000406 {
407 // Check that a color filter image filter with a crop rect cannot
408 // be expressed as a color filter.
Michael Ludwig55edb502019-08-05 10:41:10 -0400409 SkIRect cropRect = SkIRect::MakeWH(100, 100);
robertphillips5605b562016-04-05 11:50:42 -0700410 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700411 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000412 }
413
414 {
senorblanco3df05012014-07-03 11:13:09 -0700415 // Check that two non-commutative matrices are concatenated in
416 // the correct order.
Mike Reede869a1e2019-04-30 12:18:54 -0400417 float blueToRedMatrix[20] = { 0 };
418 blueToRedMatrix[2] = blueToRedMatrix[18] = 1;
419 float redToGreenMatrix[20] = { 0 };
420 redToGreenMatrix[5] = redToGreenMatrix[18] = 1;
421 sk_sp<SkColorFilter> blueToRed(SkColorFilters::Matrix(blueToRedMatrix));
Michael Ludwig55edb502019-08-05 10:41:10 -0400422 sk_sp<SkImageFilter> filter1(SkImageFilters::ColorFilter(std::move(blueToRed), nullptr));
Mike Reede869a1e2019-04-30 12:18:54 -0400423 sk_sp<SkColorFilter> redToGreen(SkColorFilters::Matrix(redToGreenMatrix));
Michael Ludwig55edb502019-08-05 10:41:10 -0400424 sk_sp<SkImageFilter> filter2(SkImageFilters::ColorFilter(std::move(redToGreen),
425 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700426
427 SkBitmap result;
428 result.allocN32Pixels(kBitmapSize, kBitmapSize);
429
430 SkPaint paint;
431 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700432 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700433 SkCanvas canvas(result);
434 canvas.clear(0x0);
435 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
436 canvas.drawRect(rect, paint);
437 uint32_t pixel = *result.getAddr32(0, 0);
438 // The result here should be green, since we have effectively shifted blue to green.
439 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
440 }
441
442 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000443 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700444 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700445 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000446 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000447
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000448 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000449 // This tests for :
450 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700451 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000452 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700453 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000454 // 3 ) large negative specular exponent value
455 SkScalar specularExponent = -1000;
456
Michael Ludwig55edb502019-08-05 10:41:10 -0400457 sk_sp<SkImageFilter> bmSrc(SkImageFilters::Image(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000458 SkPaint paint;
Michael Ludwig55edb502019-08-05 10:41:10 -0400459 paint.setImageFilter(SkImageFilters::SpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000460 location, target, specularExponent, 180,
461 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700462 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000463 SkCanvas canvas(result);
Michael Ludwig55edb502019-08-05 10:41:10 -0400464 SkRect r = SkRect::MakeIWH(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000465 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000466 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000467 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000468}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000469
Michael Ludwig55edb502019-08-05 10:41:10 -0400470static void test_cropRects(skiatest::Reporter* reporter, GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000471 // Check that all filters offset to their absolute crop rect,
472 // unaffected by the input crop rect.
473 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700474 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800475 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000476
Michael Ludwig55edb502019-08-05 10:41:10 -0400477 SkIRect inputCropRect = SkIRect::MakeXYWH(8, 13, 80, 80);
478 SkIRect cropRect = SkIRect::MakeXYWH(20, 30, 60, 60);
robertphillipsfc11b0a2016-04-05 09:09:36 -0700479 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000480
robertphillipsfc11b0a2016-04-05 09:09:36 -0700481 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000482
senorblanco297f7ce2016-03-23 13:44:26 -0700483 for (int i = 0; i < filters.count(); ++i) {
484 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000485 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400486 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400487 kN32_SkColorType, nullptr, srcImg.get());
Michael Ludwigea071232019-08-26 10:52:15 -0400488 sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
Brian Salomon1c80e992018-01-29 09:50:47 -0500489 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
490 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000491 }
492}
493
Michael Ludwig55edb502019-08-05 10:41:10 -0400494static void test_negative_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700495 // Check that SkBlurImageFilter will accept a negative sigma, either in
496 // the given arguments or after CTM application.
Michael Ludwig55edb502019-08-05 10:41:10 -0400497 static const int kWidth = 32, kHeight = 32;
498 static const SkScalar kBlurSigma = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700499
Michael Ludwig55edb502019-08-05 10:41:10 -0400500 sk_sp<SkImageFilter> positiveFilter(SkImageFilters::Blur(kBlurSigma, kBlurSigma, nullptr));
501 sk_sp<SkImageFilter> negativeFilter(SkImageFilters::Blur(-kBlurSigma, kBlurSigma, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700502
Michael Ludwig55edb502019-08-05 10:41:10 -0400503 SkBitmap gradient = make_gradient_circle(kWidth, kHeight);
504 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(kWidth, kHeight),
robertphillips37bd7c32016-03-17 14:31:39 -0700505 gradient));
Brian Osman5f955192019-10-29 15:08:37 -0400506 if (context) {
507 imgSrc = imgSrc->makeTextureImage(context);
508 }
robertphillips4418dba2016-03-07 12:45:14 -0800509
senorblanco32673b92014-09-09 09:15:04 -0700510 SkIPoint offset;
Michael Ludwig03f9ca32019-08-14 14:35:15 -0400511 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400512 kN32_SkColorType, nullptr, imgSrc.get());
robertphillips4418dba2016-03-07 12:45:14 -0800513
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400514 sk_sp<SkSpecialImage> positiveResult1(
Michael Ludwigea071232019-08-26 10:52:15 -0400515 as_IFB(positiveFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800516 REPORTER_ASSERT(reporter, positiveResult1);
517
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400518 sk_sp<SkSpecialImage> negativeResult1(
Michael Ludwigea071232019-08-26 10:52:15 -0400519 as_IFB(negativeFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800520 REPORTER_ASSERT(reporter, negativeResult1);
521
senorblanco32673b92014-09-09 09:15:04 -0700522 SkMatrix negativeScale;
523 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400524 SkImageFilter_Base::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400525 kN32_SkColorType, nullptr, imgSrc.get());
robertphillips4418dba2016-03-07 12:45:14 -0800526
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400527 sk_sp<SkSpecialImage> negativeResult2(
Michael Ludwigea071232019-08-26 10:52:15 -0400528 as_IFB(positiveFilter)->filterImage(negativeCTX).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800529 REPORTER_ASSERT(reporter, negativeResult2);
530
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400531 sk_sp<SkSpecialImage> positiveResult2(
Michael Ludwigea071232019-08-26 10:52:15 -0400532 as_IFB(negativeFilter)->filterImage(negativeCTX).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800533 REPORTER_ASSERT(reporter, positiveResult2);
534
535
536 SkBitmap positiveResultBM1, positiveResultBM2;
537 SkBitmap negativeResultBM1, negativeResultBM2;
538
robertphillips64612512016-04-08 12:10:42 -0700539 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
540 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
541 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
542 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800543
Michael Ludwig55edb502019-08-05 10:41:10 -0400544 for (int y = 0; y < kHeight; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800545 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
546 negativeResultBM1.getAddr32(0, y),
547 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700548 REPORTER_ASSERT(reporter, !diffs);
549 if (diffs) {
550 break;
551 }
robertphillips4418dba2016-03-07 12:45:14 -0800552 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
553 negativeResultBM2.getAddr32(0, y),
554 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700555 REPORTER_ASSERT(reporter, !diffs);
556 if (diffs) {
557 break;
558 }
robertphillips4418dba2016-03-07 12:45:14 -0800559 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
560 positiveResultBM2.getAddr32(0, y),
561 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700562 REPORTER_ASSERT(reporter, !diffs);
563 if (diffs) {
564 break;
565 }
566 }
567}
568
senorblanco21a465d2016-04-11 11:58:39 -0700569DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700570 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800571}
572
bsalomon68d91342016-04-12 09:59:58 -0700573DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700574 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800575}
robertphillips4418dba2016-03-07 12:45:14 -0800576
Fredrik Söderquistd1ed56e2019-10-08 14:21:14 +0200577static void test_morphology_radius_with_mirror_ctm(skiatest::Reporter* reporter, GrContext* context) {
578 // Check that SkMorphologyImageFilter maps the radius correctly when the
579 // CTM contains a mirroring transform.
580 static const int kWidth = 32, kHeight = 32;
581 static const int kRadius = 8;
582
583 sk_sp<SkImageFilter> filter(SkImageFilters::Dilate(kRadius, kRadius, nullptr));
584
585 SkBitmap bitmap;
586 bitmap.allocN32Pixels(kWidth, kHeight);
587 SkCanvas canvas(bitmap);
588 canvas.clear(SK_ColorTRANSPARENT);
589 SkPaint paint;
590 paint.setColor(SK_ColorWHITE);
591 canvas.drawRect(SkRect::MakeXYWH(kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2),
592 paint);
593
594 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(kWidth, kHeight),
595 bitmap));
Brian Osman5f955192019-10-29 15:08:37 -0400596 if (context) {
597 imgSrc = imgSrc->makeTextureImage(context);
598 }
Fredrik Söderquistd1ed56e2019-10-08 14:21:14 +0200599
600 SkIPoint offset;
601 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
602 kN32_SkColorType, nullptr, imgSrc.get());
603
604 sk_sp<SkSpecialImage> normalResult(
605 as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
606 REPORTER_ASSERT(reporter, normalResult);
607
608 SkMatrix mirrorX;
609 mirrorX.setTranslate(0, SkIntToScalar(32));
610 mirrorX.preScale(SK_Scalar1, -SK_Scalar1);
611 SkImageFilter_Base::Context mirrorXCTX(mirrorX, SkIRect::MakeWH(32, 32), nullptr,
612 kN32_SkColorType, nullptr, imgSrc.get());
613
614 sk_sp<SkSpecialImage> mirrorXResult(
615 as_IFB(filter)->filterImage(mirrorXCTX).imageAndOffset(&offset));
616 REPORTER_ASSERT(reporter, mirrorXResult);
617
618 SkMatrix mirrorY;
619 mirrorY.setTranslate(SkIntToScalar(32), 0);
620 mirrorY.preScale(-SK_Scalar1, SK_Scalar1);
621 SkImageFilter_Base::Context mirrorYCTX(mirrorY, SkIRect::MakeWH(32, 32), nullptr,
622 kN32_SkColorType, nullptr, imgSrc.get());
623
624 sk_sp<SkSpecialImage> mirrorYResult(
625 as_IFB(filter)->filterImage(mirrorYCTX).imageAndOffset(&offset));
626 REPORTER_ASSERT(reporter, mirrorYResult);
627
628 SkBitmap normalResultBM, mirrorXResultBM, mirrorYResultBM;
629
630 REPORTER_ASSERT(reporter, normalResult->getROPixels(&normalResultBM));
631 REPORTER_ASSERT(reporter, mirrorXResult->getROPixels(&mirrorXResultBM));
632 REPORTER_ASSERT(reporter, mirrorYResult->getROPixels(&mirrorYResultBM));
633
634 for (int y = 0; y < kHeight; y++) {
635 int diffs = memcmp(normalResultBM.getAddr32(0, y),
636 mirrorXResultBM.getAddr32(0, y),
637 normalResultBM.rowBytes());
638 REPORTER_ASSERT(reporter, !diffs);
639 if (diffs) {
640 break;
641 }
642 diffs = memcmp(normalResultBM.getAddr32(0, y),
643 mirrorYResultBM.getAddr32(0, y),
644 normalResultBM.rowBytes());
645 REPORTER_ASSERT(reporter, !diffs);
646 if (diffs) {
647 break;
648 }
649 }
650}
651
652DEF_TEST(MorphologyFilterRadiusWithMirrorCTM, reporter) {
653 test_morphology_radius_with_mirror_ctm(reporter, nullptr);
654}
655
656DEF_GPUTEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu, reporter, ctxInfo) {
657 test_morphology_radius_with_mirror_ctm(reporter, ctxInfo.grContext());
658}
659
robertphillips3e302272016-04-20 11:48:36 -0700660static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700661 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
Michael Ludwig55edb502019-08-05 10:41:10 -0400662 SkIRect cropRect = SkIRect::MakeXYWH(5, 0, 5, 10);
663 sk_sp<SkImageFilter> input(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
664 sk_sp<SkImageFilter> filter(SkImageFilters::Blur(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700665
robertphillips3e302272016-04-20 11:48:36 -0700666 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700667 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700668 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700669
670 SkIPoint offset;
Michael Ludwig03f9ca32019-08-14 14:35:15 -0400671 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400672 kN32_SkColorType, nullptr, image.get());
senorblancobf680c32016-03-16 16:15:53 -0700673
Michael Ludwigea071232019-08-26 10:52:15 -0400674 sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
senorblancobf680c32016-03-16 16:15:53 -0700675 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
676 REPORTER_ASSERT(reporter, result);
677 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
678
679 SkBitmap resultBM;
680
robertphillips64612512016-04-08 12:10:42 -0700681 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700682
senorblancobf680c32016-03-16 16:15:53 -0700683 for (int y = 0; y < resultBM.height(); y++) {
684 for (int x = 0; x < resultBM.width(); x++) {
685 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
686 REPORTER_ASSERT(reporter, !diff);
687 if (diff) {
688 break;
689 }
690 }
691 }
692}
693
senorblanco21a465d2016-04-11 11:58:39 -0700694DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700695 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700696}
697
bsalomon68d91342016-04-12 09:59:58 -0700698DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700699 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700700}
senorblancobf680c32016-03-16 16:15:53 -0700701
senorblanco6a93fa12016-04-05 04:43:45 -0700702
703// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
704// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700705static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700706 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700707 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400708 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400709 kN32_SkColorType, nullptr, source.get());
Mike Reedb286bc22019-04-08 16:23:20 -0400710 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700711 SkASSERT(green->affectsTransparentBlack());
Michael Ludwig55edb502019-08-05 10:41:10 -0400712 sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(std::move(green),
713 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700714 SkIPoint offset;
Michael Ludwigea071232019-08-26 10:52:15 -0400715 sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(ctx).imageAndOffset(&offset));
senorblanco6a93fa12016-04-05 04:43:45 -0700716 REPORTER_ASSERT(reporter, nullptr != result.get());
717 if (result.get()) {
718 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700719 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700720 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
721 }
722}
723
724DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700725 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700726}
727
bsalomon68d91342016-04-12 09:59:58 -0700728DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700729 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700730}
senorblanco6a93fa12016-04-05 04:43:45 -0700731
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000732DEF_TEST(ImageFilterDrawTiled, reporter) {
733 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
734 // match the same filters drawn with a single full-canvas bitmap draw.
735 // Tests pass by not asserting.
736
robertphillipsfc11b0a2016-04-05 09:09:36 -0700737 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000738
739 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700740 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000741 untiledResult.allocN32Pixels(width, height);
742 tiledResult.allocN32Pixels(width, height);
743 SkCanvas tiledCanvas(tiledResult);
744 SkCanvas untiledCanvas(untiledResult);
Robert Phillips12078432018-05-17 11:17:39 -0400745 const int tileSize = 8;
746
747 SkPaint textPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400748 textPaint.setColor(SK_ColorWHITE);
Mike Kleinea3f0142019-03-20 11:12:10 -0500749 SkFont font(ToolUtils::create_portable_typeface(), height);
Robert Phillips12078432018-05-17 11:17:39 -0400750
751 const char* text = "ABC";
752 const SkScalar yPos = SkIntToScalar(height);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000753
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000754 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700755 for (int i = 0; i < filters.count(); ++i) {
Robert Phillips12078432018-05-17 11:17:39 -0400756 SkPaint combinedPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400757 combinedPaint.setColor(SK_ColorWHITE);
758 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
759
760 untiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000761 untiledCanvas.save();
762 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500763 untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000764 untiledCanvas.restore();
Robert Phillips12078432018-05-17 11:17:39 -0400765
766 tiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000767 for (int y = 0; y < height; y += tileSize) {
768 for (int x = 0; x < width; x += tileSize) {
769 tiledCanvas.save();
Robert Phillips12078432018-05-17 11:17:39 -0400770 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
771 tiledCanvas.clipRect(clipRect);
772 if (filters.needsSaveLayer(i)) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400773 const SkRect layerBounds = SkRect::MakeIWH(width, height);
Robert Phillips12078432018-05-17 11:17:39 -0400774 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
775 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500776 tiledCanvas.drawString(text, 0, yPos, font, textPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400777 tiledCanvas.restore();
778 } else {
779 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500780 tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400781 }
782
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000783 tiledCanvas.restore();
784 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000785 }
Robert Phillips12078432018-05-17 11:17:39 -0400786
Mike Kleinea3f0142019-03-20 11:12:10 -0500787 if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500788 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400789 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000790 }
791 }
792 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000793}
794
mtklein3f3b3d02014-12-01 11:47:08 -0800795static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700796 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700797
798 SkMatrix matrix;
799 matrix.setTranslate(SkIntToScalar(50), 0);
800
Mike Reedb286bc22019-04-08 16:23:20 -0400801 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
Michael Ludwig55edb502019-08-05 10:41:10 -0400802 sk_sp<SkImageFilter> cfif(SkImageFilters::ColorFilter(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700803 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
804 kNone_SkFilterQuality,
805 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700806
807 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700808 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700809 SkPictureRecorder recorder;
810 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800811 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
812 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700813 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700814 recordingCanvas->translate(-55, 0);
815 recordingCanvas->saveLayer(&bounds, &paint);
816 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700817 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700818
819 result->allocN32Pixels(width, height);
820 SkCanvas canvas(*result);
821 canvas.clear(0);
822 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
823 canvas.drawPicture(picture1.get());
824}
825
826DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
827 // Check that matrix filter when drawn tiled with BBH exactly
828 // matches the same thing drawn without BBH.
829 // Tests pass by not asserting.
830
831 const int width = 200, height = 200;
832 const int tileSize = 100;
833 SkBitmap result1, result2;
834 SkRTreeFactory factory;
835
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700836 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700837 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700838
839 for (int y = 0; y < height; y++) {
840 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
841 REPORTER_ASSERT(reporter, !diffs);
842 if (diffs) {
843 break;
844 }
845 }
846}
847
robertphillips6e7025a2016-04-04 04:31:25 -0700848static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400849 return SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700850}
851
robertphillips6e7025a2016-04-04 04:31:25 -0700852static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400853 return SkImageFilters::DropShadow(100, 100, 10, 10, SK_ColorBLUE, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700854}
855
856DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700857 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
858 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700859
860 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000861 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400862 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
863 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700864
865 REPORTER_ASSERT(reporter, bounds == expectedBounds);
866}
867
868DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700869 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
870 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700871
872 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000873 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400874 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
875 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700876
877 REPORTER_ASSERT(reporter, bounds == expectedBounds);
878}
879
880DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400881 sk_sp<SkImageFilter> filter1(SkImageFilters::Dilate(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700882 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700883
884 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
885 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
Robert Phillips12078432018-05-17 11:17:39 -0400886 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
887 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700888
889 REPORTER_ASSERT(reporter, bounds == expectedBounds);
890}
891
jbroman203a9932016-07-11 14:07:59 -0700892DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
893 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
894 // (before the CTM). Bounds should be computed correctly in the presence of
895 // a (possibly negative) scale.
896 sk_sp<SkImageFilter> blur(make_blur(nullptr));
897 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
898 {
899 // Uniform scale by 2.
900 SkMatrix scaleMatrix;
901 scaleMatrix.setScale(2, 2);
902 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
903
Herb Derby59f8f152017-10-17 22:27:23 +0000904 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700905 SkIRect blurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400906 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700907 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
908 SkIRect reverseBlurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400909 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700910 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
911
912 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
913 SkIRect shadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400914 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700915 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
916 SkIRect expectedReverseShadowBounds =
Michael Ludwig55edb502019-08-05 10:41:10 -0400917 SkIRect::MakeLTRB(-260, -260, 200, 200);
jbroman203a9932016-07-11 14:07:59 -0700918 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400919 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
920 REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
jbroman203a9932016-07-11 14:07:59 -0700921 }
922 {
923 // Vertical flip.
924 SkMatrix scaleMatrix;
925 scaleMatrix.setScale(1, -1);
926 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
927
Herb Derby59f8f152017-10-17 22:27:23 +0000928 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700929 SkIRect blurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400930 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700931 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
932 SkIRect reverseBlurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400933 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700934 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
935
936 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
937 SkIRect shadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400938 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700939 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
940 SkIRect expectedReverseShadowBounds =
Michael Ludwig55edb502019-08-05 10:41:10 -0400941 SkIRect::MakeLTRB(-130, -100, 100, 130);
jbroman203a9932016-07-11 14:07:59 -0700942 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400943 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
944 REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
jbroman203a9932016-07-11 14:07:59 -0700945 }
946}
947
ajuma5788faa2015-02-13 09:05:47 -0800948DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700949 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
950 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
Michael Ludwig55edb502019-08-05 10:41:10 -0400951 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(filter1),
952 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800953
Michael Ludwig55edb502019-08-05 10:41:10 -0400954 SkRect boundsSrc = SkRect::MakeIWH(100, 100);
955 SkRect expectedBounds = SkRect::MakeXYWH(-6, -6, 112, 112);
senorblancoe5e79842016-03-21 14:51:59 -0700956 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800957
958 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
959}
960
jbroman0e3129d2016-03-17 12:24:23 -0700961DEF_TEST(ImageFilterUnionBounds, reporter) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400962 sk_sp<SkImageFilter> offset(SkImageFilters::Offset(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700963 // Regardless of which order they appear in, the image filter bounds should
964 // be combined correctly.
965 {
Michael Ludwig55edb502019-08-05 10:41:10 -0400966 sk_sp<SkImageFilter> composite(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, offset));
967 SkRect bounds = SkRect::MakeIWH(100, 100);
jbroman0e3129d2016-03-17 12:24:23 -0700968 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700969 bounds = composite->computeFastBounds(bounds);
Michael Ludwig55edb502019-08-05 10:41:10 -0400970 REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
jbroman0e3129d2016-03-17 12:24:23 -0700971 }
972 {
Michael Ludwig55edb502019-08-05 10:41:10 -0400973 sk_sp<SkImageFilter> composite(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, nullptr,
974 offset, nullptr));
975 SkRect bounds = SkRect::MakeIWH(100, 100);
jbroman0e3129d2016-03-17 12:24:23 -0700976 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700977 bounds = composite->computeFastBounds(bounds);
Michael Ludwig55edb502019-08-05 10:41:10 -0400978 REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
jbroman0e3129d2016-03-17 12:24:23 -0700979 }
980}
981
robertphillips3e302272016-04-20 11:48:36 -0700982static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800983 SkBitmap greenBM;
984 greenBM.allocN32Pixels(20, 20);
985 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700986 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
Michael Ludwig55edb502019-08-05 10:41:10 -0400987 sk_sp<SkImageFilter> source(SkImageFilters::Image(std::move(greenImage)));
988 sk_sp<SkImageFilter> merge(SkImageFilters::Merge(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800989
robertphillips3e302272016-04-20 11:48:36 -0700990 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800991
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400992 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400993 kN32_SkColorType, nullptr, srcImg.get());
senorblanco4a243982015-11-25 07:06:55 -0800994 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800995
Michael Ludwigea071232019-08-26 10:52:15 -0400996 sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800997 REPORTER_ASSERT(reporter, resultImg);
998
999 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -08001000}
1001
robertphillips4418dba2016-03-07 12:45:14 -08001002DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001003 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001004}
1005
egdanielab527a52016-06-28 08:07:26 -07001006DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001007 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001008}
robertphillips4418dba2016-03-07 12:45:14 -08001009
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001010static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001011 SkPaint filterPaint;
1012 filterPaint.setColor(SK_ColorWHITE);
Michael Ludwig55edb502019-08-05 10:41:10 -04001013 filterPaint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001014 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001015 SkPaint whitePaint;
1016 whitePaint.setColor(SK_ColorWHITE);
1017 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1018 canvas->restore();
1019}
1020
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001021static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001022 canvas->save();
1023 canvas->clipRect(clipRect);
1024 canvas->drawPicture(picture);
1025 canvas->restore();
1026}
1027
1028DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1029 // Check that the blur filter when recorded with RTree acceleration,
1030 // and drawn tiled (with subsequent clip rects) exactly
1031 // matches the same filter drawn with without RTree acceleration.
1032 // This tests that the "bleed" from the blur into the otherwise-blank
1033 // tiles is correctly rendered.
1034 // Tests pass by not asserting.
1035
1036 int width = 16, height = 8;
1037 SkBitmap result1, result2;
1038 result1.allocN32Pixels(width, height);
1039 result2.allocN32Pixels(width, height);
1040 SkCanvas canvas1(result1);
1041 SkCanvas canvas2(result2);
1042 int tileSize = 8;
1043
1044 canvas1.clear(0);
1045 canvas2.clear(0);
1046
1047 SkRTreeFactory factory;
1048
1049 SkPictureRecorder recorder1, recorder2;
1050 // The only difference between these two pictures is that one has RTree aceleration.
Michael Ludwig55edb502019-08-05 10:41:10 -04001051 SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height, nullptr, 0);
1052 SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory, 0);
1053
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001054 draw_blurred_rect(recordingCanvas1);
1055 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001056 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1057 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001058 for (int y = 0; y < height; y += tileSize) {
1059 for (int x = 0; x < width; x += tileSize) {
1060 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001061 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1062 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001063 }
1064 }
1065 for (int y = 0; y < height; y++) {
1066 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1067 REPORTER_ASSERT(reporter, !diffs);
1068 if (diffs) {
1069 break;
1070 }
1071 }
1072}
1073
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001074DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1075 // Check that a 1x3 filter does not cause a spurious assert.
1076 SkScalar kernel[3] = {
1077 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1078 };
1079 SkISize kernelSize = SkISize::Make(1, 3);
1080 SkScalar gain = SK_Scalar1, bias = 0;
1081 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1082
Michael Ludwig55edb502019-08-05 10:41:10 -04001083 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1084 kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kRepeat, false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001085
1086 SkBitmap result;
1087 int width = 16, height = 16;
1088 result.allocN32Pixels(width, height);
1089 SkCanvas canvas(result);
1090 canvas.clear(0);
1091
1092 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001093 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001094 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1095 canvas.drawRect(rect, paint);
1096}
1097
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001098DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1099 // Check that a filter with borders outside the target bounds
1100 // does not crash.
1101 SkScalar kernel[3] = {
1102 0, 0, 0,
1103 };
1104 SkISize kernelSize = SkISize::Make(3, 1);
1105 SkScalar gain = SK_Scalar1, bias = 0;
1106 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1107
Michael Ludwig55edb502019-08-05 10:41:10 -04001108 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1109 kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kClamp, true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001110
1111 SkBitmap result;
1112
1113 int width = 10, height = 10;
1114 result.allocN32Pixels(width, height);
1115 SkCanvas canvas(result);
1116 canvas.clear(0);
1117
1118 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001119 filterPaint.setImageFilter(std::move(filter));
Michael Ludwig55edb502019-08-05 10:41:10 -04001120 SkRect bounds = SkRect::MakeIWH(1, 10);
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001121 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1122 SkPaint rectPaint;
1123 canvas.saveLayer(&bounds, &filterPaint);
1124 canvas.drawRect(rect, rectPaint);
1125 canvas.restore();
1126}
1127
robertphillips3e302272016-04-20 11:48:36 -07001128static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001129 // Check that a kernel that is too big for the GPU still works
1130 SkScalar identityKernel[49] = {
1131 0, 0, 0, 0, 0, 0, 0,
1132 0, 0, 0, 0, 0, 0, 0,
1133 0, 0, 0, 0, 0, 0, 0,
1134 0, 0, 0, 1, 0, 0, 0,
1135 0, 0, 0, 0, 0, 0, 0,
1136 0, 0, 0, 0, 0, 0, 0,
1137 0, 0, 0, 0, 0, 0, 0
1138 };
1139 SkISize kernelSize = SkISize::Make(7, 7);
1140 SkScalar gain = SK_Scalar1, bias = 0;
1141 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1142
Michael Ludwig55edb502019-08-05 10:41:10 -04001143 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1144 kernelSize, identityKernel, gain, bias, kernelOffset,
1145 SkTileMode::kClamp, true, nullptr));
robertphillipsdada4dd2016-04-13 04:54:36 -07001146
robertphillips3e302272016-04-20 11:48:36 -07001147 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001148 SkASSERT(srcImg);
1149
1150 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001151 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001152 kN32_SkColorType, nullptr, srcImg.get());
Michael Ludwigea071232019-08-26 10:52:15 -04001153 sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
robertphillipsdada4dd2016-04-13 04:54:36 -07001154 REPORTER_ASSERT(reporter, resultImg);
1155 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1156 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1157 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1158}
1159
1160DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001161 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001162}
1163
egdanielab527a52016-06-28 08:07:26 -07001164DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1165 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001166 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001167}
robertphillipsdada4dd2016-04-13 04:54:36 -07001168
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001169DEF_TEST(ImageFilterCropRect, reporter) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001170 test_cropRects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001171}
1172
bsalomon68d91342016-04-12 09:59:58 -07001173DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001174 test_cropRects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001175}
robertphillips4418dba2016-03-07 12:45:14 -08001176
tfarina9ea53f92014-06-24 06:50:39 -07001177DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001178 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001179 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001180 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001181 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1182
1183 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1184
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001185 SkRTreeFactory factory;
1186 SkPictureRecorder recorder;
1187 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001188
1189 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001190 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001191 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001192 SkPaint solidPaint;
1193 solidPaint.setColor(0xFFFFFFFF);
1194 recordingCanvas->save();
1195 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1196 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1197 recordingCanvas->restore(); // scale
1198 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001199
reedca2622b2016-03-18 07:25:55 -07001200 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001201}
1202
robertphillips3e302272016-04-20 11:48:36 -07001203static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001204 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001205
robertphillips4418dba2016-03-07 12:45:14 -08001206 {
1207 SkRTreeFactory factory;
1208 SkPictureRecorder recorder;
1209 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1210
1211 // Create an SkPicture which simply draws a green 1x1 rectangle.
1212 SkPaint greenPaint;
1213 greenPaint.setColor(SK_ColorGREEN);
1214 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001215 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001216 }
1217
robertphillips3e302272016-04-20 11:48:36 -07001218 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001219
Michael Ludwig55edb502019-08-05 10:41:10 -04001220 sk_sp<SkImageFilter> imageFilter(SkImageFilters::Picture(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001221
senorblanco3d822c22014-07-30 14:49:31 -07001222 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001223 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001224 kN32_SkColorType, nullptr, srcImg.get());
robertphillips4418dba2016-03-07 12:45:14 -08001225
Michael Ludwigea071232019-08-26 10:52:15 -04001226 sk_sp<SkSpecialImage> resultImage(
1227 as_IFB(imageFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -08001228 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001229}
1230
robertphillips4418dba2016-03-07 12:45:14 -08001231DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001232 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001233}
1234
bsalomon68d91342016-04-12 09:59:58 -07001235DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001236 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001237}
robertphillips4418dba2016-03-07 12:45:14 -08001238
tfarina9ea53f92014-06-24 06:50:39 -07001239DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001240 // Even when there's an empty saveLayer()/restore(), ensure that an image
1241 // filter or color filter which affects transparent black still draws.
1242
1243 SkBitmap bitmap;
1244 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001245 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001246
1247 SkRTreeFactory factory;
1248 SkPictureRecorder recorder;
1249
Michael Ludwigea071232019-08-26 10:52:15 -04001250 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
Michael Ludwig55edb502019-08-05 10:41:10 -04001251 sk_sp<SkImageFilter> imageFilter(SkImageFilters::ColorFilter(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001252 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001253 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001254 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001255 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001256
Michael Ludwig55edb502019-08-05 10:41:10 -04001257 SkRect bounds = SkRect::MakeIWH(10, 10);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001258
1259 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1260 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1261 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001262 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001263
1264 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001265 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001266 uint32_t pixel = *bitmap.getAddr32(0, 0);
1267 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1268
1269 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001270 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001271 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001272 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001273
1274 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001275 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001276 pixel = *bitmap.getAddr32(0, 0);
1277 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1278
1279 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1280 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1281 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001282 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001283
1284 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001285 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001286 pixel = *bitmap.getAddr32(0, 0);
1287 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1288}
1289
robertphillips9a53fd72015-06-22 09:46:59 -07001290static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001291 SkBitmap bitmap;
1292 bitmap.allocN32Pixels(100, 100);
1293 bitmap.eraseARGB(0, 0, 0, 0);
1294
1295 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001296 SkPaint paint;
Michael Ludwig55edb502019-08-05 10:41:10 -04001297 paint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(1<<30), SkIntToScalar(1<<30), nullptr));
reedda420b92015-12-16 08:38:15 -08001298 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001299}
1300
1301DEF_TEST(HugeBlurImageFilter, reporter) {
1302 SkBitmap temp;
1303 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001304 SkCanvas canvas(temp);
1305 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001306}
1307
senorblanco21a465d2016-04-11 11:58:39 -07001308DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001309 SkScalar kernel[1] = { 0 };
1310 SkScalar gain = SK_Scalar1, bias = 0;
1311 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1312
halcanary96fcdcc2015-08-27 07:41:13 -07001313 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001314 sk_sp<SkImageFilter> conv(SkImageFilters::MatrixConvolution(
1315 SkISize::Make(1<<30, 1<<30), kernel, gain, bias, kernelOffset,
1316 SkTileMode::kRepeat, false, nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001317
halcanary96fcdcc2015-08-27 07:41:13 -07001318 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001319
halcanary96fcdcc2015-08-27 07:41:13 -07001320 // Check that a nullptr kernel gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001321 conv = SkImageFilters::MatrixConvolution(
1322 SkISize::Make(1, 1), nullptr, gain, bias, kernelOffset,
1323 SkTileMode::kRepeat, false, nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001324
halcanary96fcdcc2015-08-27 07:41:13 -07001325 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001326
halcanary96fcdcc2015-08-27 07:41:13 -07001327 // Check that a kernel width < 1 gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001328 conv = SkImageFilters::MatrixConvolution(
1329 SkISize::Make(0, 1), kernel, gain, bias, kernelOffset,
1330 SkTileMode::kRepeat, false, nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001331
halcanary96fcdcc2015-08-27 07:41:13 -07001332 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001333
halcanary96fcdcc2015-08-27 07:41:13 -07001334 // Check that kernel height < 1 gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001335 conv = SkImageFilters::MatrixConvolution(
1336 SkISize::Make(1, -1), kernel, gain, bias, kernelOffset,
1337 SkTileMode::kRepeat, false, nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001338
halcanary96fcdcc2015-08-27 07:41:13 -07001339 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001340}
1341
Mike Reedf1942192017-07-21 14:24:29 -04001342static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1343 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001344 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001345
1346 SkBitmap bitmap;
1347 bitmap.allocN32Pixels(1, 1);
1348 bitmap.eraseARGB(255, 255, 255, 255);
1349
Mike Reedb286bc22019-04-08 16:23:20 -04001350 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
Michael Ludwig55edb502019-08-05 10:41:10 -04001351 sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(green, nullptr));
1352 SkIRect cropRect = SkIRect::MakeEmpty();
1353 sk_sp<SkImageFilter> croppedOut(SkImageFilters::ColorFilter(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001354
1355 // Check that an xfermode image filter whose input has been cropped out still draws the other
1356 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001357 SkBlendMode mode = SkBlendMode::kSrcOver;
Michael Ludwig55edb502019-08-05 10:41:10 -04001358 sk_sp<SkImageFilter> xfermodeNoFg(SkImageFilters::Xfermode(
1359 mode, greenFilter, croppedOut, nullptr));
1360 sk_sp<SkImageFilter> xfermodeNoBg(SkImageFilters::Xfermode(
1361 mode, croppedOut, greenFilter, nullptr));
1362 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkImageFilters::Xfermode(
1363 mode, croppedOut, croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001364
1365 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001366 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001367 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001368
1369 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001370 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001371 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001372 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1373
robertphillips8c0326d2016-04-05 12:48:34 -07001374 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001375 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001376 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001377 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1378
robertphillips8c0326d2016-04-05 12:48:34 -07001379 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001380 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001381 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001382 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1383}
1384
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001385DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1386 SkBitmap temp;
1387 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001388 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001389 canvas.clear(0x0);
1390
1391 SkBitmap bitmap;
1392 bitmap.allocN32Pixels(10, 10);
1393 bitmap.eraseColor(SK_ColorGREEN);
1394
1395 SkMatrix matrix;
1396 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1397 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001398 sk_sp<SkImageFilter> matrixFilter(
Michael Ludwig55edb502019-08-05 10:41:10 -04001399 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001400
1401 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1402 // correct offset to the filter matrix.
1403 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001404 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001405 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001406 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001407 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1408 canvas.saveLayer(&bounds2, &filterPaint);
1409 SkPaint greenPaint;
1410 greenPaint.setColor(SK_ColorGREEN);
1411 canvas.drawRect(bounds2, greenPaint);
1412 canvas.restore();
1413 canvas.restore();
1414 SkPaint strokePaint;
1415 strokePaint.setStyle(SkPaint::kStroke_Style);
1416 strokePaint.setColor(SK_ColorRED);
1417
kkinnunena9d9a392015-03-06 07:16:00 -08001418 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001419 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001420 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001421 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1422
1423 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1424 // correct offset to the filter matrix.
1425 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001426 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001427 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001428 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001429 canvas.restore();
1430
Mike Reedf1942192017-07-21 14:24:29 -04001431 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001432 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1433}
1434
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001435DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001436 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001437}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001438
robertphillips3e302272016-04-20 11:48:36 -07001439static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1440 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001441
Michael Ludwig55edb502019-08-05 10:41:10 -04001442 SkIRect cropRect = SkIRect::MakeXYWH(1, 0, 20, 20);
1443 sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
1444 sk_sp<SkImageFilter> blurFilter(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
robertphillips6e7025a2016-04-04 04:31:25 -07001445 nullptr, &cropRect));
Michael Ludwig55edb502019-08-05 10:41:10 -04001446 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(blurFilter),
1447 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001448 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001449 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001450 kN32_SkColorType, nullptr, srcImg.get());
robertphillips4418dba2016-03-07 12:45:14 -08001451
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001452 sk_sp<SkSpecialImage> resultImg(
Michael Ludwigea071232019-08-26 10:52:15 -04001453 as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -08001454 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001455 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1456}
1457
robertphillips4418dba2016-03-07 12:45:14 -08001458DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001459 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001460}
1461
bsalomon68d91342016-04-12 09:59:58 -07001462DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001463 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001464}
robertphillips4418dba2016-03-07 12:45:14 -08001465
robertphillips3e302272016-04-20 11:48:36 -07001466static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001467 // The bounds passed to the inner filter must be filtered by the outer
1468 // filter, so that the inner filter produces the pixels that the outer
1469 // filter requires as input. This matters if the outer filter moves pixels.
1470 // Here, accounting for the outer offset is necessary so that the green
1471 // pixels of the picture are not clipped.
1472
1473 SkPictureRecorder recorder;
Michael Ludwig55edb502019-08-05 10:41:10 -04001474 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeIWH(200, 100));
jbroman17a65202016-03-21 08:38:58 -07001475 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1476 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001477 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
Michael Ludwig55edb502019-08-05 10:41:10 -04001478 sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(picture));
1479 SkIRect cropRect = SkIRect::MakeWH(100, 100);
1480 sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(-100, 0, nullptr, &cropRect));
1481 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(offsetFilter),
1482 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001483
robertphillips3e302272016-04-20 11:48:36 -07001484 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001485 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001486 kN32_SkColorType, nullptr, sourceImage.get());
jbroman17a65202016-03-21 08:38:58 -07001487 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001488 sk_sp<SkSpecialImage> result(
Michael Ludwigea071232019-08-26 10:52:15 -04001489 as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(&offset));
jbroman17a65202016-03-21 08:38:58 -07001490 REPORTER_ASSERT(reporter, offset.isZero());
1491 REPORTER_ASSERT(reporter, result);
1492 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1493
1494 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001495 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001496 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1497}
1498
1499DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001500 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001501}
1502
egdanielab527a52016-06-28 08:07:26 -07001503DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001504 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001505}
jbroman17a65202016-03-21 08:38:58 -07001506
senorblanco0abdf762015-08-20 11:10:41 -07001507DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1508
robertphillips12fa47d2016-04-08 16:28:09 -07001509 {
1510 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
Michael Ludwig55edb502019-08-05 10:41:10 -04001511 sk_sp<SkImageFilter> lighting(SkImageFilters::PointLitDiffuse(
1512 location, SK_ColorGREEN, 0, 0, nullptr));
robertphillips12fa47d2016-04-08 16:28:09 -07001513 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1514 }
senorblanco0abdf762015-08-20 11:10:41 -07001515
senorblanco0abdf762015-08-20 11:10:41 -07001516 {
robertphillips6e7025a2016-04-04 04:31:25 -07001517 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1518 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1519 {
1520 SkColorFilter* grayCF;
1521 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1522 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1523 grayCF->unref();
1524 }
1525 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1526
Michael Ludwig55edb502019-08-05 10:41:10 -04001527 sk_sp<SkImageFilter> grayBlur(SkImageFilters::Blur(
1528 SK_Scalar1, SK_Scalar1, std::move(gray)));
robertphillips6e7025a2016-04-04 04:31:25 -07001529 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001530 }
senorblanco0abdf762015-08-20 11:10:41 -07001531
robertphillips6e7025a2016-04-04 04:31:25 -07001532 {
Mike Reede869a1e2019-04-30 12:18:54 -04001533 float greenMatrix[20] = { 0, 0, 0, 0, 0,
1534 0, 0, 0, 0, 1.0f/255,
1535 0, 0, 0, 0, 0,
1536 0, 0, 0, 0, 1.0f/255
1537 };
1538 sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
Michael Ludwig55edb502019-08-05 10:41:10 -04001539 sk_sp<SkImageFilter> green(SkImageFilters::ColorFilter(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001540
robertphillips6e7025a2016-04-04 04:31:25 -07001541 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1542 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001543
Michael Ludwig55edb502019-08-05 10:41:10 -04001544 sk_sp<SkImageFilter> greenBlur(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
robertphillips6e7025a2016-04-04 04:31:25 -07001545 std::move(green)));
1546 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1547 }
senorblanco0abdf762015-08-20 11:10:41 -07001548
1549 uint8_t allOne[256], identity[256];
1550 for (int i = 0; i < 256; ++i) {
1551 identity[i] = i;
1552 allOne[i] = 255;
1553 }
1554
robertphillips5605b562016-04-05 11:50:42 -07001555 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1556 identity, allOne));
Michael Ludwig55edb502019-08-05 10:41:10 -04001557 sk_sp<SkImageFilter> identityFilter(SkImageFilters::ColorFilter(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001558 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1559 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1560
robertphillips5605b562016-04-05 11:50:42 -07001561 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1562 identity, identity));
Michael Ludwig55edb502019-08-05 10:41:10 -04001563 sk_sp<SkImageFilter> forceOpaque(SkImageFilters::ColorFilter(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001564 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1565 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1566}
1567
fmalitacd56f812015-09-14 13:31:18 -07001568// Verify that SkImageSource survives serialization
1569DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001570 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001571 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001572 sk_sp<SkImage> image(surface->makeImageSnapshot());
Michael Ludwig55edb502019-08-05 10:41:10 -04001573 sk_sp<SkImageFilter> filter(SkImageFilters::Image(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001574
Mike Reed0331d372018-01-23 11:57:30 -05001575 sk_sp<SkData> data(filter->serialize());
1576 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001577 REPORTER_ASSERT(reporter, unflattenedFilter);
1578
1579 SkBitmap bm;
1580 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001581 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001582 SkPaint paint;
1583 paint.setColor(SK_ColorRED);
1584 paint.setImageFilter(unflattenedFilter);
1585
1586 SkCanvas canvas(bm);
Michael Ludwig55edb502019-08-05 10:41:10 -04001587 canvas.drawRect(SkRect::MakeIWH(10, 10), paint);
fmalitacd56f812015-09-14 13:31:18 -07001588 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1589}
1590
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001591DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1592 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1593 if (!data) {
1594 return;
1595 }
Mike Reed0331d372018-01-23 11:57:30 -05001596 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001597 // This will fail. More importantly, msan will verify that we did not
1598 // compare against uninitialized memory.
1599 REPORTER_ASSERT(r, !unflattenedFilter);
1600}
1601
bsalomon45eefcf2016-01-05 08:39:28 -08001602static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1603 SkBitmap largeBmp;
1604 int largeW = 5000;
1605 int largeH = 5000;
bsalomon45eefcf2016-01-05 08:39:28 -08001606 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1607 if (GrContext* ctx = canvas->getGrContext()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05001608 largeW = ctx->priv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001609 }
bsalomon45eefcf2016-01-05 08:39:28 -08001610
1611 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001612 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001613 if (!largeBmp.getPixels()) {
1614 ERRORF(reporter, "Failed to allocate large bmp.");
1615 return;
1616 }
1617
reed9ce9d672016-03-17 10:51:11 -07001618 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001619 if (!largeImage) {
1620 ERRORF(reporter, "Failed to create large image.");
1621 return;
1622 }
1623
Michael Ludwig55edb502019-08-05 10:41:10 -04001624 sk_sp<SkImageFilter> largeSource(SkImageFilters::Image(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001625 if (!largeSource) {
1626 ERRORF(reporter, "Failed to create large SkImageSource.");
1627 return;
1628 }
1629
Michael Ludwig55edb502019-08-05 10:41:10 -04001630 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001631 if (!blur) {
1632 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1633 return;
1634 }
1635
1636 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001637 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001638
1639 // This should not crash (http://crbug.com/570479).
1640 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1641}
1642
senorblanco21a465d2016-04-11 11:58:39 -07001643DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001644 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001645 test_large_blur_input(reporter, surface->getCanvas());
1646}
1647
senorblanco5878dbd2016-05-19 14:50:29 -07001648static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001649 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001650 surface->getCanvas()->clear(SK_ColorRED);
1651 SkPaint bluePaint;
1652 bluePaint.setColor(SK_ColorBLUE);
1653 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1654 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1655 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1656
1657 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1658 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1659 SkIRect outSubset;
1660 SkIPoint offset;
1661 sk_sp<SkImage> result;
1662
1663 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1664 REPORTER_ASSERT(reporter, !result);
1665
1666 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1667 REPORTER_ASSERT(reporter, !result);
1668
1669 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1670 REPORTER_ASSERT(reporter, !result);
1671
1672 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1673 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1674 REPORTER_ASSERT(reporter, !result);
1675
1676 SkIRect empty = SkIRect::MakeEmpty();
1677 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1678 REPORTER_ASSERT(reporter, !result);
1679
1680 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1681 REPORTER_ASSERT(reporter, !result);
1682
1683 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1684 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1685 REPORTER_ASSERT(reporter, !result);
1686
1687 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1688
1689 REPORTER_ASSERT(reporter, result);
1690 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1691 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1692 outSubset.width(), outSubset.height());
1693 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001694
1695 // In GPU-mode, this case creates a special image with a backing size that differs from
1696 // the content size
1697 {
1698 clipBounds.setXYWH(0, 0, 170, 100);
1699 subset.setXYWH(0, 0, 160, 90);
1700
Michael Ludwig55edb502019-08-05 10:41:10 -04001701 filter = SkImageFilters::Xfermode(SkBlendMode::kSrc, nullptr);
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001702 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1703 REPORTER_ASSERT(reporter, result);
1704 }
senorblanco5878dbd2016-05-19 14:50:29 -07001705}
1706
1707DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1708 test_make_with_filter(reporter, nullptr);
1709}
1710
senorblanco5878dbd2016-05-19 14:50:29 -07001711DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1712 test_make_with_filter(reporter, ctxInfo.grContext());
1713}
reed4a8126e2014-09-22 07:29:03 -07001714
bsalomon68d91342016-04-12 09:59:58 -07001715DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001716
bsalomon8b7451a2016-05-11 06:33:06 -07001717 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001718 SkBudgeted::kNo,
1719 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001720
robertphillips3e302272016-04-20 11:48:36 -07001721
1722 SkCanvas* canvas = surf->getCanvas();
1723
1724 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001725}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001726
egdanielab527a52016-06-28 08:07:26 -07001727DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001728 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1729 ctxInfo.grContext(),
1730 SkBudgeted::kNo,
1731 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001732
Mike Reedf1942192017-07-21 14:24:29 -04001733 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001734}
senorblanco32673b92014-09-09 09:15:04 -07001735
egdanielab527a52016-06-28 08:07:26 -07001736DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001737 auto surface(SkSurface::MakeRenderTarget(
1738 ctxInfo.grContext(), SkBudgeted::kYes,
1739 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001740 test_large_blur_input(reporter, surface->getCanvas());
1741}
reedbb34a8a2016-04-23 15:19:07 -07001742
1743/*
1744 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1745 * than just scale/translate, but that other filters do.
1746 */
reed96a04f32016-04-25 09:25:15 -07001747DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001748 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reedb286bc22019-04-08 16:23:20 -04001749 sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
Michael Ludwig55edb502019-08-05 10:41:10 -04001750 sk_sp<SkImageFilter> cfif = SkImageFilters::ColorFilter(cf, nullptr); // can handle
1751 sk_sp<SkImageFilter> blif = SkImageFilters::Blur(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001752
1753 struct {
1754 sk_sp<SkImageFilter> fFilter;
1755 bool fExpectCanHandle;
1756 } recs[] = {
Michael Ludwig55edb502019-08-05 10:41:10 -04001757 { cfif, true },
1758 { SkImageFilters::ColorFilter(cf, cfif), true },
1759 { SkImageFilters::Merge(cfif, cfif), true },
1760 { SkImageFilters::Compose(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001761
Michael Ludwig55edb502019-08-05 10:41:10 -04001762 { blif, false },
1763 { SkImageFilters::Blur(3, 3, cfif), false },
1764 { SkImageFilters::ColorFilter(cf, blif), false },
1765 { SkImageFilters::Merge(cfif, blif), false },
1766 { SkImageFilters::Compose(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001767 };
liyuqianbfebe222016-11-14 11:17:16 -08001768
reedbb34a8a2016-04-23 15:19:07 -07001769 for (const auto& rec : recs) {
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001770 const bool canHandle = as_IFB(rec.fFilter)->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001771 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1772 }
1773}
Florin Malita08252ec2017-07-06 12:48:15 -04001774
Xianzhu Wangb4496662017-09-25 10:26:40 -07001775// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001776DEF_TEST(XfermodeImageFilterBounds, reporter) {
1777 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1778 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1779 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1780 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1781
1782 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1783 SkIRect expectedBounds[kModeCount];
1784 // Expect union of input rects by default.
1785 for (int i = 0; i < kModeCount; ++i) {
1786 expectedBounds[i] = background_rect;
1787 expectedBounds[i].join(foreground_rect);
1788 }
1789
1790 SkIRect intersection = background_rect;
1791 intersection.intersect(foreground_rect);
1792 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1793 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1794 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1795 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1796 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1797 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1798 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1799
1800 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1801 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1802 for (int i = 0; i < kModeCount; ++i) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001803 sk_sp<SkImageFilter> xfermode(SkImageFilters::Xfermode(static_cast<SkBlendMode>(i),
1804 background, foreground, nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001805 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1806 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001807 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1808 }
1809
1810 // Test empty intersection.
1811 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1812 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
Michael Ludwig55edb502019-08-05 10:41:10 -04001813 sk_sp<SkImageFilter> xfermode(SkImageFilters::Xfermode(
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001814 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001815 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1816 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001817 REPORTER_ASSERT(reporter, bounds.isEmpty());
1818}
1819
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001820DEF_TEST(OffsetImageFilterBounds, reporter) {
1821 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
Michael Ludwig55edb502019-08-05 10:41:10 -04001822 sk_sp<SkImageFilter> offset(SkImageFilters::Offset(-50.5f, -50.5f, nullptr));
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001823
1824 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1825 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001826 SkImageFilter::kForward_MapDirection, nullptr);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001827 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1828
1829 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1830 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001831 SkImageFilter::kReverse_MapDirection, &src);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001832 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1833}
1834
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001835static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1836 float k4, sk_sp<SkImageFilter> background,
1837 sk_sp<SkImageFilter> foreground,
Michael Ludwig55edb502019-08-05 10:41:10 -04001838 const SkIRect* crop, const SkIRect& expected) {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001839 sk_sp<SkImageFilter> arithmetic(
Michael Ludwig55edb502019-08-05 10:41:10 -04001840 SkImageFilters::Arithmetic(k1, k2, k3, k4, false, background, foreground, crop));
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001841 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1842 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001843 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001844 REPORTER_ASSERT(reporter, expected == bounds);
1845}
1846
1847static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001848 SkIRect bgRect = SkIRect::MakeXYWH(0, 0, 100, 100);
1849 SkIRect fgRect = SkIRect::MakeXYWH(50, 50, 100, 100);
1850 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(bgRect));
1851 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(fgRect));
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001852
Michael Ludwig55edb502019-08-05 10:41:10 -04001853 SkIRect unionRect = bgRect;
1854 unionRect.join(fgRect);
1855 SkIRect intersection = bgRect;
1856 intersection.intersect(fgRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001857
1858 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1859 SkIRect::MakeEmpty());
Michael Ludwig55edb502019-08-05 10:41:10 -04001860 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, unionRect);
1861 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, bgRect);
1862 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, unionRect);
1863 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, fgRect);
1864 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, unionRect);
1865 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, unionRect);
1866 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, unionRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001867 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
Michael Ludwig55edb502019-08-05 10:41:10 -04001868 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, unionRect);
1869 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, bgRect);
1870 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, unionRect);
1871 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, fgRect);
1872 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, unionRect);
1873 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, unionRect);
1874 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, unionRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001875
Michael Ludwig55edb502019-08-05 10:41:10 -04001876 // Test with crop. When k4 is non-zero, the result is expected to be cropRect
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001877 // regardless of inputs because the filter affects the whole crop area.
Michael Ludwig55edb502019-08-05 10:41:10 -04001878 SkIRect cropRect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1879 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &cropRect,
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001880 SkIRect::MakeEmpty());
Michael Ludwig55edb502019-08-05 10:41:10 -04001881 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &cropRect, cropRect);
1882 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &cropRect, bgRect);
1883 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &cropRect, cropRect);
1884 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &cropRect, fgRect);
1885 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &cropRect, cropRect);
1886 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &cropRect, unionRect);
1887 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &cropRect, cropRect);
1888 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &cropRect, intersection);
1889 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &cropRect, cropRect);
1890 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &cropRect, bgRect);
1891 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &cropRect, cropRect);
1892 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &cropRect, fgRect);
1893 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &cropRect, cropRect);
1894 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &cropRect, unionRect);
1895 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &cropRect, cropRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001896}
1897
Xianzhu Wangb4496662017-09-25 10:26:40 -07001898// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001899DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1900 test_arithmetic_combinations(reporter, 1);
1901 test_arithmetic_combinations(reporter, 0.5);
1902}
Xianzhu Wangb4496662017-09-25 10:26:40 -07001903
1904// Test SkImageSource::filterBounds.
1905DEF_TEST(ImageSourceBounds, reporter) {
1906 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
1907 // Default src and dst rects.
Michael Ludwig55edb502019-08-05 10:41:10 -04001908 sk_sp<SkImageFilter> source1(SkImageFilters::Image(image));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001909 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
1910 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
1911 REPORTER_ASSERT(reporter,
1912 imageBounds == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001913 SkImageFilter::kForward_MapDirection,
1914 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001915 REPORTER_ASSERT(reporter,
1916 input == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001917 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001918 SkMatrix scale(SkMatrix::MakeScale(2));
1919 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
1920 REPORTER_ASSERT(reporter,
1921 scaledBounds == source1->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04001922 SkImageFilter::kForward_MapDirection,
1923 nullptr));
1924 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
1925 SkImageFilter::kReverse_MapDirection,
1926 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001927
1928 // Specified src and dst rects.
1929 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
1930 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
Michael Ludwig55edb502019-08-05 10:41:10 -04001931 sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst, kMedium_SkFilterQuality));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001932 REPORTER_ASSERT(reporter,
1933 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001934 SkImageFilter::kForward_MapDirection,
1935 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001936 REPORTER_ASSERT(reporter,
1937 input == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001938 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001939 scale.mapRect(&dst);
1940 scale.mapRect(&src);
1941 REPORTER_ASSERT(reporter,
1942 dst.roundOut() == source2->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04001943 SkImageFilter::kForward_MapDirection,
1944 nullptr));
1945 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
1946 SkImageFilter::kReverse_MapDirection,
1947 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001948}
Robert Phillips12078432018-05-17 11:17:39 -04001949