blob: f8de5dcd3cfbbbc0c73044d6197777fb952b832a [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"
Robert Phillips6d344c32020-07-06 10:56:46 -040021#include "include/gpu/GrDirectContext.h"
Mike Reedb11e6272020-06-24 16:56:33 -040022#include "src/core/SkColorFilterBase.h"
Michael Ludwig8ee6cf32019-08-02 09:57:04 -040023#include "src/core/SkImageFilter_Base.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/core/SkReadBuffer.h"
25#include "src/core/SkSpecialImage.h"
26#include "src/core/SkSpecialSurface.h"
Robert Phillips6d344c32020-07-06 10:56:46 -040027#include "src/gpu/GrCaps.h"
28#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "tests/Test.h"
30#include "tools/Resources.h"
31#include "tools/ToolUtils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +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);
Brian Osman116b33e2020-02-05 13:34:09 -050092 SkScalar radius = std::min(x, y) * 0.8f;
senorblanco297f7ce2016-03-23 13:44:26 -070093 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
Brian Osmane7ad8c02020-06-22 14:51:22 -0400494static bool special_image_to_bitmap(const SkSpecialImage* src, SkBitmap* dst) {
495 sk_sp<SkImage> img = src->asImage();
496 if (!img) {
497 return false;
498 }
499
500 if (!dst->tryAllocN32Pixels(src->width(), src->height())) {
501 return false;
502 }
503
504 return img->readPixels(dst->pixmap(), src->subset().fLeft, src->subset().fTop);
505}
506
Michael Ludwig55edb502019-08-05 10:41:10 -0400507static void test_negative_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700508 // Check that SkBlurImageFilter will accept a negative sigma, either in
509 // the given arguments or after CTM application.
Michael Ludwig55edb502019-08-05 10:41:10 -0400510 static const int kWidth = 32, kHeight = 32;
511 static const SkScalar kBlurSigma = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700512
Michael Ludwig55edb502019-08-05 10:41:10 -0400513 sk_sp<SkImageFilter> positiveFilter(SkImageFilters::Blur(kBlurSigma, kBlurSigma, nullptr));
514 sk_sp<SkImageFilter> negativeFilter(SkImageFilters::Blur(-kBlurSigma, kBlurSigma, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700515
Brian Osmanfac4c0d2020-06-24 09:57:59 -0400516 sk_sp<SkImage> gradient = SkImage::MakeFromBitmap(make_gradient_circle(kWidth, kHeight));
517 sk_sp<SkSpecialImage> imgSrc(
518 SkSpecialImage::MakeFromImage(context, SkIRect::MakeWH(kWidth, kHeight), gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800519
senorblanco32673b92014-09-09 09:15:04 -0700520 SkIPoint offset;
Michael Ludwig03f9ca32019-08-14 14:35:15 -0400521 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400522 kN32_SkColorType, nullptr, imgSrc.get());
robertphillips4418dba2016-03-07 12:45:14 -0800523
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400524 sk_sp<SkSpecialImage> positiveResult1(
Michael Ludwigea071232019-08-26 10:52:15 -0400525 as_IFB(positiveFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800526 REPORTER_ASSERT(reporter, positiveResult1);
527
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400528 sk_sp<SkSpecialImage> negativeResult1(
Michael Ludwigea071232019-08-26 10:52:15 -0400529 as_IFB(negativeFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800530 REPORTER_ASSERT(reporter, negativeResult1);
531
senorblanco32673b92014-09-09 09:15:04 -0700532 SkMatrix negativeScale;
533 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400534 SkImageFilter_Base::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400535 kN32_SkColorType, nullptr, imgSrc.get());
robertphillips4418dba2016-03-07 12:45:14 -0800536
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400537 sk_sp<SkSpecialImage> negativeResult2(
Michael Ludwigea071232019-08-26 10:52:15 -0400538 as_IFB(positiveFilter)->filterImage(negativeCTX).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800539 REPORTER_ASSERT(reporter, negativeResult2);
540
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400541 sk_sp<SkSpecialImage> positiveResult2(
Michael Ludwigea071232019-08-26 10:52:15 -0400542 as_IFB(negativeFilter)->filterImage(negativeCTX).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -0800543 REPORTER_ASSERT(reporter, positiveResult2);
544
545
546 SkBitmap positiveResultBM1, positiveResultBM2;
547 SkBitmap negativeResultBM1, negativeResultBM2;
548
Brian Osmane7ad8c02020-06-22 14:51:22 -0400549 REPORTER_ASSERT(reporter, special_image_to_bitmap(positiveResult1.get(), &positiveResultBM1));
550 REPORTER_ASSERT(reporter, special_image_to_bitmap(positiveResult2.get(), &positiveResultBM2));
551 REPORTER_ASSERT(reporter, special_image_to_bitmap(negativeResult1.get(), &negativeResultBM1));
552 REPORTER_ASSERT(reporter, special_image_to_bitmap(negativeResult2.get(), &negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800553
Michael Ludwig55edb502019-08-05 10:41:10 -0400554 for (int y = 0; y < kHeight; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800555 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
556 negativeResultBM1.getAddr32(0, y),
557 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700558 REPORTER_ASSERT(reporter, !diffs);
559 if (diffs) {
560 break;
561 }
robertphillips4418dba2016-03-07 12:45:14 -0800562 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
563 negativeResultBM2.getAddr32(0, y),
564 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700565 REPORTER_ASSERT(reporter, !diffs);
566 if (diffs) {
567 break;
568 }
robertphillips4418dba2016-03-07 12:45:14 -0800569 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
570 positiveResultBM2.getAddr32(0, y),
571 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700572 REPORTER_ASSERT(reporter, !diffs);
573 if (diffs) {
574 break;
575 }
576 }
577}
578
senorblanco21a465d2016-04-11 11:58:39 -0700579DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700580 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800581}
582
bsalomon68d91342016-04-12 09:59:58 -0700583DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400584 test_negative_blur_sigma(reporter, ctxInfo.directContext());
robertphillips4418dba2016-03-07 12:45:14 -0800585}
robertphillips4418dba2016-03-07 12:45:14 -0800586
Fredrik Söderquistd1ed56e2019-10-08 14:21:14 +0200587static void test_morphology_radius_with_mirror_ctm(skiatest::Reporter* reporter, GrContext* context) {
588 // Check that SkMorphologyImageFilter maps the radius correctly when the
589 // CTM contains a mirroring transform.
590 static const int kWidth = 32, kHeight = 32;
591 static const int kRadius = 8;
592
593 sk_sp<SkImageFilter> filter(SkImageFilters::Dilate(kRadius, kRadius, nullptr));
594
595 SkBitmap bitmap;
596 bitmap.allocN32Pixels(kWidth, kHeight);
597 SkCanvas canvas(bitmap);
598 canvas.clear(SK_ColorTRANSPARENT);
599 SkPaint paint;
600 paint.setColor(SK_ColorWHITE);
601 canvas.drawRect(SkRect::MakeXYWH(kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2),
602 paint);
Brian Osmanfac4c0d2020-06-24 09:57:59 -0400603 sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
604 sk_sp<SkSpecialImage> imgSrc(
605 SkSpecialImage::MakeFromImage(context, SkIRect::MakeWH(kWidth, kHeight), image));
Fredrik Söderquistd1ed56e2019-10-08 14:21:14 +0200606
607 SkIPoint offset;
608 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
609 kN32_SkColorType, nullptr, imgSrc.get());
610
611 sk_sp<SkSpecialImage> normalResult(
612 as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
613 REPORTER_ASSERT(reporter, normalResult);
614
615 SkMatrix mirrorX;
616 mirrorX.setTranslate(0, SkIntToScalar(32));
617 mirrorX.preScale(SK_Scalar1, -SK_Scalar1);
618 SkImageFilter_Base::Context mirrorXCTX(mirrorX, SkIRect::MakeWH(32, 32), nullptr,
619 kN32_SkColorType, nullptr, imgSrc.get());
620
621 sk_sp<SkSpecialImage> mirrorXResult(
622 as_IFB(filter)->filterImage(mirrorXCTX).imageAndOffset(&offset));
623 REPORTER_ASSERT(reporter, mirrorXResult);
624
625 SkMatrix mirrorY;
626 mirrorY.setTranslate(SkIntToScalar(32), 0);
627 mirrorY.preScale(-SK_Scalar1, SK_Scalar1);
628 SkImageFilter_Base::Context mirrorYCTX(mirrorY, SkIRect::MakeWH(32, 32), nullptr,
629 kN32_SkColorType, nullptr, imgSrc.get());
630
631 sk_sp<SkSpecialImage> mirrorYResult(
632 as_IFB(filter)->filterImage(mirrorYCTX).imageAndOffset(&offset));
633 REPORTER_ASSERT(reporter, mirrorYResult);
634
635 SkBitmap normalResultBM, mirrorXResultBM, mirrorYResultBM;
636
Brian Osmane7ad8c02020-06-22 14:51:22 -0400637 REPORTER_ASSERT(reporter, special_image_to_bitmap(normalResult.get(), &normalResultBM));
638 REPORTER_ASSERT(reporter, special_image_to_bitmap(mirrorXResult.get(), &mirrorXResultBM));
639 REPORTER_ASSERT(reporter, special_image_to_bitmap(mirrorYResult.get(), &mirrorYResultBM));
Fredrik Söderquistd1ed56e2019-10-08 14:21:14 +0200640
641 for (int y = 0; y < kHeight; y++) {
642 int diffs = memcmp(normalResultBM.getAddr32(0, y),
643 mirrorXResultBM.getAddr32(0, y),
644 normalResultBM.rowBytes());
645 REPORTER_ASSERT(reporter, !diffs);
646 if (diffs) {
647 break;
648 }
649 diffs = memcmp(normalResultBM.getAddr32(0, y),
650 mirrorYResultBM.getAddr32(0, y),
651 normalResultBM.rowBytes());
652 REPORTER_ASSERT(reporter, !diffs);
653 if (diffs) {
654 break;
655 }
656 }
657}
658
659DEF_TEST(MorphologyFilterRadiusWithMirrorCTM, reporter) {
660 test_morphology_radius_with_mirror_ctm(reporter, nullptr);
661}
662
663DEF_GPUTEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400664 test_morphology_radius_with_mirror_ctm(reporter, ctxInfo.directContext());
Fredrik Söderquistd1ed56e2019-10-08 14:21:14 +0200665}
666
robertphillips3e302272016-04-20 11:48:36 -0700667static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700668 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
Michael Ludwig55edb502019-08-05 10:41:10 -0400669 SkIRect cropRect = SkIRect::MakeXYWH(5, 0, 5, 10);
670 sk_sp<SkImageFilter> input(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
671 sk_sp<SkImageFilter> filter(SkImageFilters::Blur(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700672
robertphillips3e302272016-04-20 11:48:36 -0700673 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700674 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700675 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700676
677 SkIPoint offset;
Michael Ludwig03f9ca32019-08-14 14:35:15 -0400678 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400679 kN32_SkColorType, nullptr, image.get());
senorblancobf680c32016-03-16 16:15:53 -0700680
Michael Ludwigea071232019-08-26 10:52:15 -0400681 sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
senorblancobf680c32016-03-16 16:15:53 -0700682 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
683 REPORTER_ASSERT(reporter, result);
684 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
685
686 SkBitmap resultBM;
687
Brian Osmane7ad8c02020-06-22 14:51:22 -0400688 REPORTER_ASSERT(reporter, special_image_to_bitmap(result.get(), &resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700689
senorblancobf680c32016-03-16 16:15:53 -0700690 for (int y = 0; y < resultBM.height(); y++) {
691 for (int x = 0; x < resultBM.width(); x++) {
692 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
693 REPORTER_ASSERT(reporter, !diff);
694 if (diff) {
695 break;
696 }
697 }
698 }
699}
700
senorblanco21a465d2016-04-11 11:58:39 -0700701DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700702 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700703}
704
bsalomon68d91342016-04-12 09:59:58 -0700705DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400706 test_zero_blur_sigma(reporter, ctxInfo.directContext());
senorblancobf680c32016-03-16 16:15:53 -0700707}
senorblancobf680c32016-03-16 16:15:53 -0700708
senorblanco6a93fa12016-04-05 04:43:45 -0700709
710// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
711// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700712static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700713 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700714 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400715 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -0400716 kN32_SkColorType, nullptr, source.get());
Mike Reedb286bc22019-04-08 16:23:20 -0400717 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
Mike Reedb11e6272020-06-24 16:56:33 -0400718 SkASSERT(as_CFB(green)->affectsTransparentBlack());
Michael Ludwig55edb502019-08-05 10:41:10 -0400719 sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(std::move(green),
720 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700721 SkIPoint offset;
Michael Ludwigea071232019-08-26 10:52:15 -0400722 sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(ctx).imageAndOffset(&offset));
senorblanco6a93fa12016-04-05 04:43:45 -0700723 REPORTER_ASSERT(reporter, nullptr != result.get());
724 if (result.get()) {
725 SkBitmap resultBM;
Brian Osmane7ad8c02020-06-22 14:51:22 -0400726 REPORTER_ASSERT(reporter, special_image_to_bitmap(result.get(), &resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700727 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
728 }
729}
730
731DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700732 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700733}
734
bsalomon68d91342016-04-12 09:59:58 -0700735DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -0400736 test_fail_affects_transparent_black(reporter, ctxInfo.directContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700737}
senorblanco6a93fa12016-04-05 04:43:45 -0700738
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000739DEF_TEST(ImageFilterDrawTiled, reporter) {
740 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
741 // match the same filters drawn with a single full-canvas bitmap draw.
742 // Tests pass by not asserting.
743
robertphillipsfc11b0a2016-04-05 09:09:36 -0700744 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000745
746 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700747 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000748 untiledResult.allocN32Pixels(width, height);
749 tiledResult.allocN32Pixels(width, height);
750 SkCanvas tiledCanvas(tiledResult);
751 SkCanvas untiledCanvas(untiledResult);
Robert Phillips12078432018-05-17 11:17:39 -0400752 const int tileSize = 8;
753
754 SkPaint textPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400755 textPaint.setColor(SK_ColorWHITE);
Mike Kleinea3f0142019-03-20 11:12:10 -0500756 SkFont font(ToolUtils::create_portable_typeface(), height);
Robert Phillips12078432018-05-17 11:17:39 -0400757
758 const char* text = "ABC";
759 const SkScalar yPos = SkIntToScalar(height);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000760
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000761 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700762 for (int i = 0; i < filters.count(); ++i) {
Robert Phillips12078432018-05-17 11:17:39 -0400763 SkPaint combinedPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400764 combinedPaint.setColor(SK_ColorWHITE);
765 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
766
767 untiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000768 untiledCanvas.save();
769 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500770 untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000771 untiledCanvas.restore();
Robert Phillips12078432018-05-17 11:17:39 -0400772
773 tiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000774 for (int y = 0; y < height; y += tileSize) {
775 for (int x = 0; x < width; x += tileSize) {
776 tiledCanvas.save();
Robert Phillips12078432018-05-17 11:17:39 -0400777 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
778 tiledCanvas.clipRect(clipRect);
779 if (filters.needsSaveLayer(i)) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400780 const SkRect layerBounds = SkRect::MakeIWH(width, height);
Robert Phillips12078432018-05-17 11:17:39 -0400781 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
782 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500783 tiledCanvas.drawString(text, 0, yPos, font, textPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400784 tiledCanvas.restore();
785 } else {
786 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500787 tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400788 }
789
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000790 tiledCanvas.restore();
791 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000792 }
Robert Phillips12078432018-05-17 11:17:39 -0400793
Mike Kleinea3f0142019-03-20 11:12:10 -0500794 if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500795 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400796 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000797 }
798 }
799 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000800}
801
mtklein3f3b3d02014-12-01 11:47:08 -0800802static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700803 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700804
805 SkMatrix matrix;
806 matrix.setTranslate(SkIntToScalar(50), 0);
807
Mike Reedb286bc22019-04-08 16:23:20 -0400808 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
Michael Ludwig55edb502019-08-05 10:41:10 -0400809 sk_sp<SkImageFilter> cfif(SkImageFilters::ColorFilter(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700810 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
811 kNone_SkFilterQuality,
812 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700813
814 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700815 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700816 SkPictureRecorder recorder;
817 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800818 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
819 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700820 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700821 recordingCanvas->translate(-55, 0);
822 recordingCanvas->saveLayer(&bounds, &paint);
823 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700824 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700825
826 result->allocN32Pixels(width, height);
827 SkCanvas canvas(*result);
828 canvas.clear(0);
829 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
830 canvas.drawPicture(picture1.get());
831}
832
833DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
834 // Check that matrix filter when drawn tiled with BBH exactly
835 // matches the same thing drawn without BBH.
836 // Tests pass by not asserting.
837
838 const int width = 200, height = 200;
839 const int tileSize = 100;
840 SkBitmap result1, result2;
841 SkRTreeFactory factory;
842
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700843 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700844 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700845
846 for (int y = 0; y < height; y++) {
847 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
848 REPORTER_ASSERT(reporter, !diffs);
849 if (diffs) {
850 break;
851 }
852 }
853}
854
robertphillips6e7025a2016-04-04 04:31:25 -0700855static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400856 return SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700857}
858
robertphillips6e7025a2016-04-04 04:31:25 -0700859static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400860 return SkImageFilters::DropShadow(100, 100, 10, 10, SK_ColorBLUE, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700861}
862
863DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700864 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
865 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700866
867 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000868 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400869 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
870 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700871
872 REPORTER_ASSERT(reporter, bounds == expectedBounds);
873}
874
875DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700876 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
877 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700878
879 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000880 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400881 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
882 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700883
884 REPORTER_ASSERT(reporter, bounds == expectedBounds);
885}
886
887DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400888 sk_sp<SkImageFilter> filter1(SkImageFilters::Dilate(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700889 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700890
891 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
892 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
Robert Phillips12078432018-05-17 11:17:39 -0400893 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
894 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700895
896 REPORTER_ASSERT(reporter, bounds == expectedBounds);
897}
898
jbroman203a9932016-07-11 14:07:59 -0700899DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
900 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
901 // (before the CTM). Bounds should be computed correctly in the presence of
902 // a (possibly negative) scale.
903 sk_sp<SkImageFilter> blur(make_blur(nullptr));
904 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
905 {
906 // Uniform scale by 2.
907 SkMatrix scaleMatrix;
908 scaleMatrix.setScale(2, 2);
909 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
910
Herb Derby59f8f152017-10-17 22:27:23 +0000911 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700912 SkIRect blurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400913 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700914 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
915 SkIRect reverseBlurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400916 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700917 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
918
919 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
920 SkIRect shadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400921 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700922 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
923 SkIRect expectedReverseShadowBounds =
Michael Ludwig55edb502019-08-05 10:41:10 -0400924 SkIRect::MakeLTRB(-260, -260, 200, 200);
jbroman203a9932016-07-11 14:07:59 -0700925 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400926 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
927 REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
jbroman203a9932016-07-11 14:07:59 -0700928 }
929 {
930 // Vertical flip.
931 SkMatrix scaleMatrix;
932 scaleMatrix.setScale(1, -1);
933 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
934
Herb Derby59f8f152017-10-17 22:27:23 +0000935 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700936 SkIRect blurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400937 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700938 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
939 SkIRect reverseBlurBounds = blur->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400940 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700941 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
942
943 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
944 SkIRect shadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400945 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700946 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
947 SkIRect expectedReverseShadowBounds =
Michael Ludwig55edb502019-08-05 10:41:10 -0400948 SkIRect::MakeLTRB(-130, -100, 100, 130);
jbroman203a9932016-07-11 14:07:59 -0700949 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Michael Ludwig55edb502019-08-05 10:41:10 -0400950 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
951 REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
jbroman203a9932016-07-11 14:07:59 -0700952 }
953}
954
ajuma5788faa2015-02-13 09:05:47 -0800955DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700956 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
957 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
Michael Ludwig55edb502019-08-05 10:41:10 -0400958 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(filter1),
959 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800960
Michael Ludwig55edb502019-08-05 10:41:10 -0400961 SkRect boundsSrc = SkRect::MakeIWH(100, 100);
962 SkRect expectedBounds = SkRect::MakeXYWH(-6, -6, 112, 112);
senorblancoe5e79842016-03-21 14:51:59 -0700963 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800964
965 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
966}
967
jbroman0e3129d2016-03-17 12:24:23 -0700968DEF_TEST(ImageFilterUnionBounds, reporter) {
Michael Ludwig55edb502019-08-05 10:41:10 -0400969 sk_sp<SkImageFilter> offset(SkImageFilters::Offset(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700970 // Regardless of which order they appear in, the image filter bounds should
971 // be combined correctly.
972 {
Michael Ludwig55edb502019-08-05 10:41:10 -0400973 sk_sp<SkImageFilter> composite(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, offset));
974 SkRect bounds = SkRect::MakeIWH(100, 100);
jbroman0e3129d2016-03-17 12:24:23 -0700975 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700976 bounds = composite->computeFastBounds(bounds);
Michael Ludwig55edb502019-08-05 10:41:10 -0400977 REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
jbroman0e3129d2016-03-17 12:24:23 -0700978 }
979 {
Michael Ludwig55edb502019-08-05 10:41:10 -0400980 sk_sp<SkImageFilter> composite(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, nullptr,
981 offset, nullptr));
982 SkRect bounds = SkRect::MakeIWH(100, 100);
jbroman0e3129d2016-03-17 12:24:23 -0700983 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700984 bounds = composite->computeFastBounds(bounds);
Michael Ludwig55edb502019-08-05 10:41:10 -0400985 REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
jbroman0e3129d2016-03-17 12:24:23 -0700986 }
987}
988
robertphillips3e302272016-04-20 11:48:36 -0700989static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800990 SkBitmap greenBM;
991 greenBM.allocN32Pixels(20, 20);
992 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700993 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
Michael Ludwig55edb502019-08-05 10:41:10 -0400994 sk_sp<SkImageFilter> source(SkImageFilters::Image(std::move(greenImage)));
995 sk_sp<SkImageFilter> merge(SkImageFilters::Merge(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800996
robertphillips3e302272016-04-20 11:48:36 -0700997 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800998
Michael Ludwig8ee6cf32019-08-02 09:57:04 -0400999 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001000 kN32_SkColorType, nullptr, srcImg.get());
senorblanco4a243982015-11-25 07:06:55 -08001001 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -08001002
Michael Ludwigea071232019-08-26 10:52:15 -04001003 sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -08001004 REPORTER_ASSERT(reporter, resultImg);
1005
1006 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -08001007}
1008
robertphillips4418dba2016-03-07 12:45:14 -08001009DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001010 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001011}
1012
egdanielab527a52016-06-28 08:07:26 -07001013DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001014 test_imagefilter_merge_result_size(reporter, ctxInfo.directContext());
robertphillips4418dba2016-03-07 12:45:14 -08001015}
robertphillips4418dba2016-03-07 12:45:14 -08001016
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001017static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001018 SkPaint filterPaint;
1019 filterPaint.setColor(SK_ColorWHITE);
Michael Ludwig55edb502019-08-05 10:41:10 -04001020 filterPaint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001021 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001022 SkPaint whitePaint;
1023 whitePaint.setColor(SK_ColorWHITE);
1024 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1025 canvas->restore();
1026}
1027
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001028static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001029 canvas->save();
1030 canvas->clipRect(clipRect);
1031 canvas->drawPicture(picture);
1032 canvas->restore();
1033}
1034
1035DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1036 // Check that the blur filter when recorded with RTree acceleration,
1037 // and drawn tiled (with subsequent clip rects) exactly
1038 // matches the same filter drawn with without RTree acceleration.
1039 // This tests that the "bleed" from the blur into the otherwise-blank
1040 // tiles is correctly rendered.
1041 // Tests pass by not asserting.
1042
1043 int width = 16, height = 8;
1044 SkBitmap result1, result2;
1045 result1.allocN32Pixels(width, height);
1046 result2.allocN32Pixels(width, height);
1047 SkCanvas canvas1(result1);
1048 SkCanvas canvas2(result2);
1049 int tileSize = 8;
1050
1051 canvas1.clear(0);
1052 canvas2.clear(0);
1053
1054 SkRTreeFactory factory;
1055
1056 SkPictureRecorder recorder1, recorder2;
1057 // The only difference between these two pictures is that one has RTree aceleration.
Michael Ludwig55edb502019-08-05 10:41:10 -04001058 SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height, nullptr, 0);
1059 SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory, 0);
1060
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001061 draw_blurred_rect(recordingCanvas1);
1062 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001063 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1064 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001065 for (int y = 0; y < height; y += tileSize) {
1066 for (int x = 0; x < width; x += tileSize) {
1067 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001068 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1069 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001070 }
1071 }
1072 for (int y = 0; y < height; y++) {
1073 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1074 REPORTER_ASSERT(reporter, !diffs);
1075 if (diffs) {
1076 break;
1077 }
1078 }
1079}
1080
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001081DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1082 // Check that a 1x3 filter does not cause a spurious assert.
1083 SkScalar kernel[3] = {
1084 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1085 };
1086 SkISize kernelSize = SkISize::Make(1, 3);
1087 SkScalar gain = SK_Scalar1, bias = 0;
1088 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1089
Michael Ludwig55edb502019-08-05 10:41:10 -04001090 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1091 kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kRepeat, false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001092
1093 SkBitmap result;
1094 int width = 16, height = 16;
1095 result.allocN32Pixels(width, height);
1096 SkCanvas canvas(result);
1097 canvas.clear(0);
1098
1099 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001100 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001101 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1102 canvas.drawRect(rect, paint);
1103}
1104
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001105DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1106 // Check that a filter with borders outside the target bounds
1107 // does not crash.
1108 SkScalar kernel[3] = {
1109 0, 0, 0,
1110 };
1111 SkISize kernelSize = SkISize::Make(3, 1);
1112 SkScalar gain = SK_Scalar1, bias = 0;
1113 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1114
Michael Ludwig55edb502019-08-05 10:41:10 -04001115 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1116 kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kClamp, true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001117
1118 SkBitmap result;
1119
1120 int width = 10, height = 10;
1121 result.allocN32Pixels(width, height);
1122 SkCanvas canvas(result);
1123 canvas.clear(0);
1124
1125 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001126 filterPaint.setImageFilter(std::move(filter));
Michael Ludwig55edb502019-08-05 10:41:10 -04001127 SkRect bounds = SkRect::MakeIWH(1, 10);
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001128 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1129 SkPaint rectPaint;
1130 canvas.saveLayer(&bounds, &filterPaint);
1131 canvas.drawRect(rect, rectPaint);
1132 canvas.restore();
1133}
1134
robertphillips3e302272016-04-20 11:48:36 -07001135static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001136 // Check that a kernel that is too big for the GPU still works
1137 SkScalar identityKernel[49] = {
1138 0, 0, 0, 0, 0, 0, 0,
1139 0, 0, 0, 0, 0, 0, 0,
1140 0, 0, 0, 0, 0, 0, 0,
1141 0, 0, 0, 1, 0, 0, 0,
1142 0, 0, 0, 0, 0, 0, 0,
1143 0, 0, 0, 0, 0, 0, 0,
1144 0, 0, 0, 0, 0, 0, 0
1145 };
1146 SkISize kernelSize = SkISize::Make(7, 7);
1147 SkScalar gain = SK_Scalar1, bias = 0;
1148 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1149
Michael Ludwig55edb502019-08-05 10:41:10 -04001150 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1151 kernelSize, identityKernel, gain, bias, kernelOffset,
1152 SkTileMode::kClamp, true, nullptr));
robertphillipsdada4dd2016-04-13 04:54:36 -07001153
robertphillips3e302272016-04-20 11:48:36 -07001154 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001155 SkASSERT(srcImg);
1156
1157 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001158 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001159 kN32_SkColorType, nullptr, srcImg.get());
Michael Ludwigea071232019-08-26 10:52:15 -04001160 sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
robertphillipsdada4dd2016-04-13 04:54:36 -07001161 REPORTER_ASSERT(reporter, resultImg);
1162 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1163 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1164 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1165}
1166
1167DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001168 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001169}
1170
egdanielab527a52016-06-28 08:07:26 -07001171DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1172 reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001173 test_big_kernel(reporter, ctxInfo.directContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001174}
robertphillipsdada4dd2016-04-13 04:54:36 -07001175
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001176DEF_TEST(ImageFilterCropRect, reporter) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001177 test_cropRects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001178}
1179
bsalomon68d91342016-04-12 09:59:58 -07001180DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001181 test_cropRects(reporter, ctxInfo.directContext());
robertphillips4418dba2016-03-07 12:45:14 -08001182}
robertphillips4418dba2016-03-07 12:45:14 -08001183
tfarina9ea53f92014-06-24 06:50:39 -07001184DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001185 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001186 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001187 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001188 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1189
1190 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1191
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001192 SkRTreeFactory factory;
1193 SkPictureRecorder recorder;
1194 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001195
1196 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001197 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001198 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001199 SkPaint solidPaint;
1200 solidPaint.setColor(0xFFFFFFFF);
1201 recordingCanvas->save();
1202 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1203 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1204 recordingCanvas->restore(); // scale
1205 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001206
reedca2622b2016-03-18 07:25:55 -07001207 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001208}
1209
robertphillips3e302272016-04-20 11:48:36 -07001210static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001211 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001212
robertphillips4418dba2016-03-07 12:45:14 -08001213 {
1214 SkRTreeFactory factory;
1215 SkPictureRecorder recorder;
1216 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1217
1218 // Create an SkPicture which simply draws a green 1x1 rectangle.
1219 SkPaint greenPaint;
1220 greenPaint.setColor(SK_ColorGREEN);
1221 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001222 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001223 }
1224
robertphillips3e302272016-04-20 11:48:36 -07001225 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001226
Michael Ludwig55edb502019-08-05 10:41:10 -04001227 sk_sp<SkImageFilter> imageFilter(SkImageFilters::Picture(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001228
senorblanco3d822c22014-07-30 14:49:31 -07001229 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001230 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001231 kN32_SkColorType, nullptr, srcImg.get());
robertphillips4418dba2016-03-07 12:45:14 -08001232
Michael Ludwigea071232019-08-26 10:52:15 -04001233 sk_sp<SkSpecialImage> resultImage(
1234 as_IFB(imageFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -08001235 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001236}
1237
robertphillips4418dba2016-03-07 12:45:14 -08001238DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001239 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001240}
1241
bsalomon68d91342016-04-12 09:59:58 -07001242DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001243 test_clipped_picture_imagefilter(reporter, ctxInfo.directContext());
robertphillips4418dba2016-03-07 12:45:14 -08001244}
robertphillips4418dba2016-03-07 12:45:14 -08001245
tfarina9ea53f92014-06-24 06:50:39 -07001246DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001247 // Even when there's an empty saveLayer()/restore(), ensure that an image
1248 // filter or color filter which affects transparent black still draws.
1249
1250 SkBitmap bitmap;
1251 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001252 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001253
1254 SkRTreeFactory factory;
1255 SkPictureRecorder recorder;
1256
Michael Ludwigea071232019-08-26 10:52:15 -04001257 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
Michael Ludwig55edb502019-08-05 10:41:10 -04001258 sk_sp<SkImageFilter> imageFilter(SkImageFilters::ColorFilter(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001259 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001260 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001261 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001262 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001263
Michael Ludwig55edb502019-08-05 10:41:10 -04001264 SkRect bounds = SkRect::MakeIWH(10, 10);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001265
1266 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1267 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1268 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001269 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001270
1271 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001272 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001273 uint32_t pixel = *bitmap.getAddr32(0, 0);
1274 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1275
1276 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001277 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001278 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001279 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001280
1281 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001282 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001283 pixel = *bitmap.getAddr32(0, 0);
1284 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1285
1286 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1287 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1288 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001289 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001290
1291 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001292 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001293 pixel = *bitmap.getAddr32(0, 0);
1294 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1295}
1296
robertphillips9a53fd72015-06-22 09:46:59 -07001297static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001298 SkBitmap bitmap;
1299 bitmap.allocN32Pixels(100, 100);
1300 bitmap.eraseARGB(0, 0, 0, 0);
1301
1302 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001303 SkPaint paint;
Michael Ludwig55edb502019-08-05 10:41:10 -04001304 paint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(1<<30), SkIntToScalar(1<<30), nullptr));
reedda420b92015-12-16 08:38:15 -08001305 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001306}
1307
1308DEF_TEST(HugeBlurImageFilter, reporter) {
1309 SkBitmap temp;
1310 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001311 SkCanvas canvas(temp);
1312 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001313}
1314
senorblanco21a465d2016-04-11 11:58:39 -07001315DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001316 SkScalar kernel[1] = { 0 };
1317 SkScalar gain = SK_Scalar1, bias = 0;
1318 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1319
halcanary96fcdcc2015-08-27 07:41:13 -07001320 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001321 sk_sp<SkImageFilter> conv(SkImageFilters::MatrixConvolution(
1322 SkISize::Make(1<<30, 1<<30), kernel, 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 nullptr kernel gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001328 conv = SkImageFilters::MatrixConvolution(
1329 SkISize::Make(1, 1), nullptr, 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 a kernel width < 1 gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001335 conv = SkImageFilters::MatrixConvolution(
1336 SkISize::Make(0, 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
halcanary96fcdcc2015-08-27 07:41:13 -07001341 // Check that kernel height < 1 gives a nullptr filter.
Michael Ludwig55edb502019-08-05 10:41:10 -04001342 conv = SkImageFilters::MatrixConvolution(
1343 SkISize::Make(1, -1), kernel, gain, bias, kernelOffset,
1344 SkTileMode::kRepeat, false, nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001345
halcanary96fcdcc2015-08-27 07:41:13 -07001346 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001347}
1348
Mike Reedf1942192017-07-21 14:24:29 -04001349static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1350 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001351 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001352
1353 SkBitmap bitmap;
1354 bitmap.allocN32Pixels(1, 1);
1355 bitmap.eraseARGB(255, 255, 255, 255);
1356
Mike Reedb286bc22019-04-08 16:23:20 -04001357 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
Michael Ludwig55edb502019-08-05 10:41:10 -04001358 sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(green, nullptr));
1359 SkIRect cropRect = SkIRect::MakeEmpty();
1360 sk_sp<SkImageFilter> croppedOut(SkImageFilters::ColorFilter(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001361
1362 // Check that an xfermode image filter whose input has been cropped out still draws the other
1363 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001364 SkBlendMode mode = SkBlendMode::kSrcOver;
Michael Ludwig55edb502019-08-05 10:41:10 -04001365 sk_sp<SkImageFilter> xfermodeNoFg(SkImageFilters::Xfermode(
1366 mode, greenFilter, croppedOut, nullptr));
1367 sk_sp<SkImageFilter> xfermodeNoBg(SkImageFilters::Xfermode(
1368 mode, croppedOut, greenFilter, nullptr));
1369 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkImageFilters::Xfermode(
1370 mode, croppedOut, croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001371
1372 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001373 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001374 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001375
1376 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001377 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001378 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001379 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1380
robertphillips8c0326d2016-04-05 12:48:34 -07001381 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001382 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001383 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001384 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1385
robertphillips8c0326d2016-04-05 12:48:34 -07001386 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001387 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001388 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001389 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1390}
1391
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001392DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1393 SkBitmap temp;
1394 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001395 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001396 canvas.clear(0x0);
1397
1398 SkBitmap bitmap;
1399 bitmap.allocN32Pixels(10, 10);
1400 bitmap.eraseColor(SK_ColorGREEN);
1401
1402 SkMatrix matrix;
1403 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1404 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001405 sk_sp<SkImageFilter> matrixFilter(
Michael Ludwig55edb502019-08-05 10:41:10 -04001406 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001407
1408 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1409 // correct offset to the filter matrix.
1410 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001411 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001412 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001413 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001414 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1415 canvas.saveLayer(&bounds2, &filterPaint);
1416 SkPaint greenPaint;
1417 greenPaint.setColor(SK_ColorGREEN);
1418 canvas.drawRect(bounds2, greenPaint);
1419 canvas.restore();
1420 canvas.restore();
1421 SkPaint strokePaint;
1422 strokePaint.setStyle(SkPaint::kStroke_Style);
1423 strokePaint.setColor(SK_ColorRED);
1424
kkinnunena9d9a392015-03-06 07:16:00 -08001425 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001426 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001427 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001428 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1429
1430 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1431 // correct offset to the filter matrix.
1432 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001433 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001434 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001435 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001436 canvas.restore();
1437
Mike Reedf1942192017-07-21 14:24:29 -04001438 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001439 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1440}
1441
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001442DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001443 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001444}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001445
robertphillips3e302272016-04-20 11:48:36 -07001446static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1447 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001448
Michael Ludwig55edb502019-08-05 10:41:10 -04001449 SkIRect cropRect = SkIRect::MakeXYWH(1, 0, 20, 20);
1450 sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
1451 sk_sp<SkImageFilter> blurFilter(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
robertphillips6e7025a2016-04-04 04:31:25 -07001452 nullptr, &cropRect));
Michael Ludwig55edb502019-08-05 10:41:10 -04001453 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(blurFilter),
1454 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001455 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001456 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001457 kN32_SkColorType, nullptr, srcImg.get());
robertphillips4418dba2016-03-07 12:45:14 -08001458
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001459 sk_sp<SkSpecialImage> resultImg(
Michael Ludwigea071232019-08-26 10:52:15 -04001460 as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(&offset));
robertphillips4418dba2016-03-07 12:45:14 -08001461 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001462 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1463}
1464
robertphillips4418dba2016-03-07 12:45:14 -08001465DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001466 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001467}
1468
bsalomon68d91342016-04-12 09:59:58 -07001469DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001470 test_composed_imagefilter_offset(reporter, ctxInfo.directContext());
robertphillips4418dba2016-03-07 12:45:14 -08001471}
robertphillips4418dba2016-03-07 12:45:14 -08001472
robertphillips3e302272016-04-20 11:48:36 -07001473static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001474 // The bounds passed to the inner filter must be filtered by the outer
1475 // filter, so that the inner filter produces the pixels that the outer
1476 // filter requires as input. This matters if the outer filter moves pixels.
1477 // Here, accounting for the outer offset is necessary so that the green
1478 // pixels of the picture are not clipped.
1479
1480 SkPictureRecorder recorder;
Michael Ludwig55edb502019-08-05 10:41:10 -04001481 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeIWH(200, 100));
jbroman17a65202016-03-21 08:38:58 -07001482 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1483 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001484 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
Michael Ludwig55edb502019-08-05 10:41:10 -04001485 sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(picture));
1486 SkIRect cropRect = SkIRect::MakeWH(100, 100);
1487 sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(-100, 0, nullptr, &cropRect));
1488 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(offsetFilter),
1489 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001490
robertphillips3e302272016-04-20 11:48:36 -07001491 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001492 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
Michael Ludwige30a4852019-08-14 14:35:42 -04001493 kN32_SkColorType, nullptr, sourceImage.get());
jbroman17a65202016-03-21 08:38:58 -07001494 SkIPoint offset;
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001495 sk_sp<SkSpecialImage> result(
Michael Ludwigea071232019-08-26 10:52:15 -04001496 as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(&offset));
jbroman17a65202016-03-21 08:38:58 -07001497 REPORTER_ASSERT(reporter, offset.isZero());
1498 REPORTER_ASSERT(reporter, result);
1499 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1500
1501 SkBitmap resultBM;
Brian Osmane7ad8c02020-06-22 14:51:22 -04001502 REPORTER_ASSERT(reporter, special_image_to_bitmap(result.get(), &resultBM));
jbroman17a65202016-03-21 08:38:58 -07001503 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1504}
1505
1506DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001507 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001508}
1509
egdanielab527a52016-06-28 08:07:26 -07001510DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001511 test_composed_imagefilter_bounds(reporter, ctxInfo.directContext());
jbroman17a65202016-03-21 08:38:58 -07001512}
jbroman17a65202016-03-21 08:38:58 -07001513
senorblanco0abdf762015-08-20 11:10:41 -07001514DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1515
robertphillips12fa47d2016-04-08 16:28:09 -07001516 {
1517 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
Michael Ludwig55edb502019-08-05 10:41:10 -04001518 sk_sp<SkImageFilter> lighting(SkImageFilters::PointLitDiffuse(
1519 location, SK_ColorGREEN, 0, 0, nullptr));
robertphillips12fa47d2016-04-08 16:28:09 -07001520 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1521 }
senorblanco0abdf762015-08-20 11:10:41 -07001522
senorblanco0abdf762015-08-20 11:10:41 -07001523 {
robertphillips6e7025a2016-04-04 04:31:25 -07001524 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1525 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1526 {
1527 SkColorFilter* grayCF;
1528 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
Mike Reedb11e6272020-06-24 16:56:33 -04001529 REPORTER_ASSERT(reporter, !as_CFB(grayCF)->affectsTransparentBlack());
robertphillips6e7025a2016-04-04 04:31:25 -07001530 grayCF->unref();
1531 }
1532 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1533
Michael Ludwig55edb502019-08-05 10:41:10 -04001534 sk_sp<SkImageFilter> grayBlur(SkImageFilters::Blur(
1535 SK_Scalar1, SK_Scalar1, std::move(gray)));
robertphillips6e7025a2016-04-04 04:31:25 -07001536 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001537 }
senorblanco0abdf762015-08-20 11:10:41 -07001538
robertphillips6e7025a2016-04-04 04:31:25 -07001539 {
Mike Reede869a1e2019-04-30 12:18:54 -04001540 float greenMatrix[20] = { 0, 0, 0, 0, 0,
1541 0, 0, 0, 0, 1.0f/255,
1542 0, 0, 0, 0, 0,
1543 0, 0, 0, 0, 1.0f/255
1544 };
1545 sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
Michael Ludwig55edb502019-08-05 10:41:10 -04001546 sk_sp<SkImageFilter> green(SkImageFilters::ColorFilter(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001547
Mike Reed79915942020-06-26 09:05:10 -04001548 REPORTER_ASSERT(reporter, as_CFB(greenCF)->affectsTransparentBlack());
robertphillips6e7025a2016-04-04 04:31:25 -07001549 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001550
Michael Ludwig55edb502019-08-05 10:41:10 -04001551 sk_sp<SkImageFilter> greenBlur(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
robertphillips6e7025a2016-04-04 04:31:25 -07001552 std::move(green)));
1553 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1554 }
senorblanco0abdf762015-08-20 11:10:41 -07001555
1556 uint8_t allOne[256], identity[256];
1557 for (int i = 0; i < 256; ++i) {
1558 identity[i] = i;
1559 allOne[i] = 255;
1560 }
1561
robertphillips5605b562016-04-05 11:50:42 -07001562 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1563 identity, allOne));
Michael Ludwig55edb502019-08-05 10:41:10 -04001564 sk_sp<SkImageFilter> identityFilter(SkImageFilters::ColorFilter(identityCF, nullptr));
Mike Reedb11e6272020-06-24 16:56:33 -04001565 REPORTER_ASSERT(reporter, !as_CFB(identityCF)->affectsTransparentBlack());
senorblanco0abdf762015-08-20 11:10:41 -07001566 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1567
robertphillips5605b562016-04-05 11:50:42 -07001568 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1569 identity, identity));
Michael Ludwig55edb502019-08-05 10:41:10 -04001570 sk_sp<SkImageFilter> forceOpaque(SkImageFilters::ColorFilter(forceOpaqueCF, nullptr));
Mike Reedb11e6272020-06-24 16:56:33 -04001571 REPORTER_ASSERT(reporter, as_CFB(forceOpaqueCF)->affectsTransparentBlack());
senorblanco0abdf762015-08-20 11:10:41 -07001572 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1573}
1574
fmalitacd56f812015-09-14 13:31:18 -07001575// Verify that SkImageSource survives serialization
1576DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001577 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001578 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001579 sk_sp<SkImage> image(surface->makeImageSnapshot());
Michael Ludwig55edb502019-08-05 10:41:10 -04001580 sk_sp<SkImageFilter> filter(SkImageFilters::Image(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001581
Mike Reed0331d372018-01-23 11:57:30 -05001582 sk_sp<SkData> data(filter->serialize());
1583 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001584 REPORTER_ASSERT(reporter, unflattenedFilter);
1585
1586 SkBitmap bm;
1587 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001588 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001589 SkPaint paint;
1590 paint.setColor(SK_ColorRED);
1591 paint.setImageFilter(unflattenedFilter);
1592
1593 SkCanvas canvas(bm);
Michael Ludwig55edb502019-08-05 10:41:10 -04001594 canvas.drawRect(SkRect::MakeIWH(10, 10), paint);
fmalitacd56f812015-09-14 13:31:18 -07001595 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1596}
1597
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001598DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1599 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1600 if (!data) {
1601 return;
1602 }
Mike Reed0331d372018-01-23 11:57:30 -05001603 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001604 // This will fail. More importantly, msan will verify that we did not
1605 // compare against uninitialized memory.
1606 REPORTER_ASSERT(r, !unflattenedFilter);
1607}
1608
bsalomon45eefcf2016-01-05 08:39:28 -08001609static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1610 SkBitmap largeBmp;
1611 int largeW = 5000;
1612 int largeH = 5000;
bsalomon45eefcf2016-01-05 08:39:28 -08001613 // If we're GPU-backed make the bitmap too large to be converted into a texture.
Robert Phillips6d344c32020-07-06 10:56:46 -04001614 if (auto ctx = canvas->recordingContext()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05001615 largeW = ctx->priv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001616 }
bsalomon45eefcf2016-01-05 08:39:28 -08001617
1618 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001619 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001620 if (!largeBmp.getPixels()) {
1621 ERRORF(reporter, "Failed to allocate large bmp.");
1622 return;
1623 }
1624
reed9ce9d672016-03-17 10:51:11 -07001625 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001626 if (!largeImage) {
1627 ERRORF(reporter, "Failed to create large image.");
1628 return;
1629 }
1630
Michael Ludwig55edb502019-08-05 10:41:10 -04001631 sk_sp<SkImageFilter> largeSource(SkImageFilters::Image(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001632 if (!largeSource) {
1633 ERRORF(reporter, "Failed to create large SkImageSource.");
1634 return;
1635 }
1636
Michael Ludwig55edb502019-08-05 10:41:10 -04001637 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001638 if (!blur) {
1639 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1640 return;
1641 }
1642
1643 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001644 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001645
1646 // This should not crash (http://crbug.com/570479).
1647 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1648}
1649
senorblanco21a465d2016-04-11 11:58:39 -07001650DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001651 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001652 test_large_blur_input(reporter, surface->getCanvas());
1653}
1654
senorblanco5878dbd2016-05-19 14:50:29 -07001655static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001656 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001657 surface->getCanvas()->clear(SK_ColorRED);
1658 SkPaint bluePaint;
1659 bluePaint.setColor(SK_ColorBLUE);
1660 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1661 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1662 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1663
1664 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1665 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1666 SkIRect outSubset;
1667 SkIPoint offset;
1668 sk_sp<SkImage> result;
1669
1670 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1671 REPORTER_ASSERT(reporter, !result);
1672
1673 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1674 REPORTER_ASSERT(reporter, !result);
1675
1676 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1677 REPORTER_ASSERT(reporter, !result);
1678
1679 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1680 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1681 REPORTER_ASSERT(reporter, !result);
1682
1683 SkIRect empty = SkIRect::MakeEmpty();
1684 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1685 REPORTER_ASSERT(reporter, !result);
1686
1687 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1688 REPORTER_ASSERT(reporter, !result);
1689
1690 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1691 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1692 REPORTER_ASSERT(reporter, !result);
1693
1694 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1695
1696 REPORTER_ASSERT(reporter, result);
1697 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1698 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1699 outSubset.width(), outSubset.height());
1700 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001701
1702 // In GPU-mode, this case creates a special image with a backing size that differs from
1703 // the content size
1704 {
1705 clipBounds.setXYWH(0, 0, 170, 100);
1706 subset.setXYWH(0, 0, 160, 90);
1707
Michael Ludwig55edb502019-08-05 10:41:10 -04001708 filter = SkImageFilters::Xfermode(SkBlendMode::kSrc, nullptr);
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001709 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1710 REPORTER_ASSERT(reporter, result);
1711 }
senorblanco5878dbd2016-05-19 14:50:29 -07001712}
1713
1714DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1715 test_make_with_filter(reporter, nullptr);
1716}
1717
senorblanco5878dbd2016-05-19 14:50:29 -07001718DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
Robert Phillips6d344c32020-07-06 10:56:46 -04001719 test_make_with_filter(reporter, ctxInfo.directContext());
senorblanco5878dbd2016-05-19 14:50:29 -07001720}
reed4a8126e2014-09-22 07:29:03 -07001721
bsalomon68d91342016-04-12 09:59:58 -07001722DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001723
Robert Phillips6d344c32020-07-06 10:56:46 -04001724 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.directContext(),
robertphillips3e302272016-04-20 11:48:36 -07001725 SkBudgeted::kNo,
1726 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001727
robertphillips3e302272016-04-20 11:48:36 -07001728
1729 SkCanvas* canvas = surf->getCanvas();
1730
1731 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001732}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001733
egdanielab527a52016-06-28 08:07:26 -07001734DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001735 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
Robert Phillips6d344c32020-07-06 10:56:46 -04001736 ctxInfo.directContext(),
Brian Salomon8996e182017-07-05 17:01:48 -04001737 SkBudgeted::kNo,
1738 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001739
Mike Reedf1942192017-07-21 14:24:29 -04001740 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001741}
senorblanco32673b92014-09-09 09:15:04 -07001742
egdanielab527a52016-06-28 08:07:26 -07001743DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001744 auto surface(SkSurface::MakeRenderTarget(
Robert Phillips6d344c32020-07-06 10:56:46 -04001745 ctxInfo.directContext(), SkBudgeted::kYes,
Brian Salomon8996e182017-07-05 17:01:48 -04001746 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001747 test_large_blur_input(reporter, surface->getCanvas());
1748}
reedbb34a8a2016-04-23 15:19:07 -07001749
1750/*
1751 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1752 * than just scale/translate, but that other filters do.
1753 */
reed96a04f32016-04-25 09:25:15 -07001754DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001755 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reedb286bc22019-04-08 16:23:20 -04001756 sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
Michael Ludwig55edb502019-08-05 10:41:10 -04001757 sk_sp<SkImageFilter> cfif = SkImageFilters::ColorFilter(cf, nullptr); // can handle
1758 sk_sp<SkImageFilter> blif = SkImageFilters::Blur(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001759
1760 struct {
1761 sk_sp<SkImageFilter> fFilter;
1762 bool fExpectCanHandle;
1763 } recs[] = {
Michael Ludwig55edb502019-08-05 10:41:10 -04001764 { cfif, true },
1765 { SkImageFilters::ColorFilter(cf, cfif), true },
1766 { SkImageFilters::Merge(cfif, cfif), true },
1767 { SkImageFilters::Compose(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001768
Michael Ludwig55edb502019-08-05 10:41:10 -04001769 { blif, false },
1770 { SkImageFilters::Blur(3, 3, cfif), false },
1771 { SkImageFilters::ColorFilter(cf, blif), false },
1772 { SkImageFilters::Merge(cfif, blif), false },
1773 { SkImageFilters::Compose(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001774 };
liyuqianbfebe222016-11-14 11:17:16 -08001775
reedbb34a8a2016-04-23 15:19:07 -07001776 for (const auto& rec : recs) {
Michael Ludwig8ee6cf32019-08-02 09:57:04 -04001777 const bool canHandle = as_IFB(rec.fFilter)->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001778 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1779 }
1780}
Florin Malita08252ec2017-07-06 12:48:15 -04001781
Xianzhu Wangb4496662017-09-25 10:26:40 -07001782// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001783DEF_TEST(XfermodeImageFilterBounds, reporter) {
1784 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1785 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1786 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1787 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1788
1789 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1790 SkIRect expectedBounds[kModeCount];
1791 // Expect union of input rects by default.
1792 for (int i = 0; i < kModeCount; ++i) {
1793 expectedBounds[i] = background_rect;
1794 expectedBounds[i].join(foreground_rect);
1795 }
1796
1797 SkIRect intersection = background_rect;
1798 intersection.intersect(foreground_rect);
1799 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1800 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1801 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1802 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1803 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1804 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1805 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1806
1807 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1808 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1809 for (int i = 0; i < kModeCount; ++i) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001810 sk_sp<SkImageFilter> xfermode(SkImageFilters::Xfermode(static_cast<SkBlendMode>(i),
1811 background, foreground, nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001812 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1813 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001814 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1815 }
1816
1817 // Test empty intersection.
1818 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1819 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
Michael Ludwig55edb502019-08-05 10:41:10 -04001820 sk_sp<SkImageFilter> xfermode(SkImageFilters::Xfermode(
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001821 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001822 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1823 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001824 REPORTER_ASSERT(reporter, bounds.isEmpty());
1825}
1826
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001827DEF_TEST(OffsetImageFilterBounds, reporter) {
1828 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
Michael Ludwig55edb502019-08-05 10:41:10 -04001829 sk_sp<SkImageFilter> offset(SkImageFilters::Offset(-50.5f, -50.5f, nullptr));
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001830
1831 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1832 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001833 SkImageFilter::kForward_MapDirection, nullptr);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001834 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1835
1836 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1837 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001838 SkImageFilter::kReverse_MapDirection, &src);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001839 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1840}
1841
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001842static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1843 float k4, sk_sp<SkImageFilter> background,
1844 sk_sp<SkImageFilter> foreground,
Michael Ludwig55edb502019-08-05 10:41:10 -04001845 const SkIRect* crop, const SkIRect& expected) {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001846 sk_sp<SkImageFilter> arithmetic(
Michael Ludwig55edb502019-08-05 10:41:10 -04001847 SkImageFilters::Arithmetic(k1, k2, k3, k4, false, background, foreground, crop));
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001848 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1849 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001850 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001851 REPORTER_ASSERT(reporter, expected == bounds);
1852}
1853
1854static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
Michael Ludwig55edb502019-08-05 10:41:10 -04001855 SkIRect bgRect = SkIRect::MakeXYWH(0, 0, 100, 100);
1856 SkIRect fgRect = SkIRect::MakeXYWH(50, 50, 100, 100);
1857 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(bgRect));
1858 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(fgRect));
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001859
Michael Ludwig55edb502019-08-05 10:41:10 -04001860 SkIRect unionRect = bgRect;
1861 unionRect.join(fgRect);
1862 SkIRect intersection = bgRect;
1863 intersection.intersect(fgRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001864
1865 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1866 SkIRect::MakeEmpty());
Michael Ludwig55edb502019-08-05 10:41:10 -04001867 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, unionRect);
1868 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, bgRect);
1869 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, unionRect);
1870 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, fgRect);
1871 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, unionRect);
1872 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, unionRect);
1873 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, unionRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001874 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
Michael Ludwig55edb502019-08-05 10:41:10 -04001875 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, unionRect);
1876 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, bgRect);
1877 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, unionRect);
1878 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, fgRect);
1879 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, unionRect);
1880 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, unionRect);
1881 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, unionRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001882
Michael Ludwig55edb502019-08-05 10:41:10 -04001883 // Test with crop. When k4 is non-zero, the result is expected to be cropRect
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001884 // regardless of inputs because the filter affects the whole crop area.
Michael Ludwig55edb502019-08-05 10:41:10 -04001885 SkIRect cropRect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1886 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &cropRect,
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001887 SkIRect::MakeEmpty());
Michael Ludwig55edb502019-08-05 10:41:10 -04001888 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &cropRect, cropRect);
1889 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &cropRect, bgRect);
1890 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &cropRect, cropRect);
1891 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &cropRect, fgRect);
1892 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &cropRect, cropRect);
1893 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &cropRect, unionRect);
1894 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &cropRect, cropRect);
1895 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &cropRect, intersection);
1896 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &cropRect, cropRect);
1897 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &cropRect, bgRect);
1898 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &cropRect, cropRect);
1899 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &cropRect, fgRect);
1900 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &cropRect, cropRect);
1901 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &cropRect, unionRect);
1902 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &cropRect, cropRect);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001903}
1904
Xianzhu Wangb4496662017-09-25 10:26:40 -07001905// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001906DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1907 test_arithmetic_combinations(reporter, 1);
1908 test_arithmetic_combinations(reporter, 0.5);
1909}
Xianzhu Wangb4496662017-09-25 10:26:40 -07001910
1911// Test SkImageSource::filterBounds.
1912DEF_TEST(ImageSourceBounds, reporter) {
1913 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
1914 // Default src and dst rects.
Michael Ludwig55edb502019-08-05 10:41:10 -04001915 sk_sp<SkImageFilter> source1(SkImageFilters::Image(image));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001916 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
1917 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
1918 REPORTER_ASSERT(reporter,
1919 imageBounds == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001920 SkImageFilter::kForward_MapDirection,
1921 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001922 REPORTER_ASSERT(reporter,
1923 input == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001924 SkImageFilter::kReverse_MapDirection, &input));
Mike Reed1f607332020-05-21 12:11:27 -04001925 SkMatrix scale(SkMatrix::Scale(2, 2));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001926 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
1927 REPORTER_ASSERT(reporter,
1928 scaledBounds == source1->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04001929 SkImageFilter::kForward_MapDirection,
1930 nullptr));
1931 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
1932 SkImageFilter::kReverse_MapDirection,
1933 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001934
1935 // Specified src and dst rects.
1936 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
1937 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
Michael Ludwig55edb502019-08-05 10:41:10 -04001938 sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst, kMedium_SkFilterQuality));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001939 REPORTER_ASSERT(reporter,
1940 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001941 SkImageFilter::kForward_MapDirection,
1942 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001943 REPORTER_ASSERT(reporter,
1944 input == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001945 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001946 scale.mapRect(&dst);
1947 scale.mapRect(&src);
1948 REPORTER_ASSERT(reporter,
1949 dst.roundOut() == source2->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04001950 SkImageFilter::kForward_MapDirection,
1951 nullptr));
1952 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
1953 SkImageFilter::kReverse_MapDirection,
1954 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001955}
Robert Phillips12078432018-05-17 11:17:39 -04001956