blob: e1427b1001c7f5ab31aefcef3e5e84c55b5cef92 [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"
16#include "include/effects/SkArithmeticImageFilter.h"
17#include "include/effects/SkBlurImageFilter.h"
18#include "include/effects/SkColorFilterImageFilter.h"
19#include "include/effects/SkColorMatrixFilter.h"
20#include "include/effects/SkComposeImageFilter.h"
21#include "include/effects/SkDisplacementMapEffect.h"
22#include "include/effects/SkDropShadowImageFilter.h"
23#include "include/effects/SkGradientShader.h"
24#include "include/effects/SkImageSource.h"
25#include "include/effects/SkLightingImageFilter.h"
26#include "include/effects/SkMatrixConvolutionImageFilter.h"
27#include "include/effects/SkMergeImageFilter.h"
28#include "include/effects/SkMorphologyImageFilter.h"
29#include "include/effects/SkOffsetImageFilter.h"
30#include "include/effects/SkPaintImageFilter.h"
31#include "include/effects/SkPerlinNoiseShader.h"
32#include "include/effects/SkPictureImageFilter.h"
33#include "include/effects/SkTableColorFilter.h"
34#include "include/effects/SkTileImageFilter.h"
35#include "include/effects/SkXfermodeImageFilter.h"
36#include "src/core/SkImageFilterPriv.h"
37#include "src/core/SkReadBuffer.h"
38#include "src/core/SkSpecialImage.h"
39#include "src/core/SkSpecialSurface.h"
40#include "tests/Test.h"
41#include "tools/Resources.h"
42#include "tools/ToolUtils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000043
Mike Kleinc0bd9f92019-04-23 12:05:21 -050044#include "include/gpu/GrContext.h"
45#include "src/gpu/GrCaps.h"
46#include "src/gpu/GrContextPriv.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000047
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +000048static const int kBitmapSize = 4;
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000049
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000050namespace {
51
52class MatrixTestImageFilter : public SkImageFilter {
53public:
robertphillips43c2ad42016-04-04 05:05:11 -070054 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
55 const SkMatrix& expectedMatrix) {
56 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000057 }
58
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000059protected:
robertphillips4ba94e22016-04-04 12:07:47 -070060 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
61 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070062 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070063 offset->fX = offset->fY = 0;
64 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070065 }
66
mtklein36352bf2015-03-25 18:17:31 -070067 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070068 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000069 }
70
71private:
Mike Klein4fee3232018-10-18 17:27:16 -040072 SK_FLATTENABLE_HOOKS(MatrixTestImageFilter)
73
robertphillips43c2ad42016-04-04 05:05:11 -070074 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
75 : INHERITED(nullptr, 0, nullptr)
76 , fReporter(reporter)
77 , fExpectedMatrix(expectedMatrix) {
78 }
79
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000080 skiatest::Reporter* fReporter;
81 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080082
reed9fa60da2014-08-21 07:59:51 -070083 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000084};
85
senorblanco6a93fa12016-04-05 04:43:45 -070086class FailImageFilter : public SkImageFilter {
87public:
robertphillips6b134732016-04-15 09:58:37 -070088 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070089
90 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
91 const Context& ctx,
92 SkIPoint* offset) const override {
93 return nullptr;
94 }
95
Mike Klein4fee3232018-10-18 17:27:16 -040096 SK_FLATTENABLE_HOOKS(FailImageFilter)
senorblanco6a93fa12016-04-05 04:43:45 -070097
98private:
99 typedef SkImageFilter INHERITED;
100};
101
102sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
103 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
104 return sk_sp<SkFlattenable>(new FailImageFilter());
105}
106
senorblanco297f7ce2016-03-23 13:44:26 -0700107void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
108 SkScalar x = SkIntToScalar(width / 2);
109 SkScalar y = SkIntToScalar(height / 2);
110 SkScalar radius = SkMinScalar(x, y) * 0.8f;
111 canvas->clear(0x00000000);
112 SkColor colors[2];
113 colors[0] = SK_ColorWHITE;
114 colors[1] = SK_ColorBLACK;
115 sk_sp<SkShader> shader(
116 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
Mike Reedfae8fce2019-04-03 10:27:45 -0400117 SkTileMode::kClamp)
senorblanco297f7ce2016-03-23 13:44:26 -0700118 );
119 SkPaint paint;
120 paint.setShader(shader);
121 canvas->drawCircle(x, y, radius, paint);
122}
123
124SkBitmap make_gradient_circle(int width, int height) {
125 SkBitmap bitmap;
126 bitmap.allocN32Pixels(width, height);
127 SkCanvas canvas(bitmap);
128 draw_gradient_circle(&canvas, width, height);
129 return bitmap;
130}
131
132class FilterList {
133public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700134 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700135 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700136 const SkScalar five = SkIntToScalar(5);
robertphillips6e7025a2016-04-04 04:31:25 -0700137 {
Mike Reedb286bc22019-04-08 16:23:20 -0400138 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400139 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700140
robertphillips6e7025a2016-04-04 04:31:25 -0700141 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700142 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700143 }
robertphillips6e7025a2016-04-04 04:31:25 -0700144 {
145 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
146 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700147
liyuqianbfebe222016-11-14 11:17:16 -0800148 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700149 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
150 SkDisplacementMapEffect::kB_ChannelSelectorType,
151 20.0f,
152 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700153 }
robertphillips6e7025a2016-04-04 04:31:25 -0700154 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
155 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700156 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700157 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700158 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700159 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700160 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700161 input, cropRect));
162 this->addFilter("diffuse lighting",
163 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
164 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700165 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700166 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
167 input, cropRect));
168 {
169 SkScalar kernel[9] = {
170 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
171 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
172 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
173 };
174 const SkISize kernelSize = SkISize::Make(3, 3);
175 const SkScalar gain = SK_Scalar1, bias = 0;
176
Robert Phillips12078432018-05-17 11:17:39 -0400177 // This filter needs a saveLayer bc it is in repeat mode
robertphillips12fa47d2016-04-08 16:28:09 -0700178 this->addFilter("matrix convolution",
Robert Phillips12078432018-05-17 11:17:39 -0400179 SkMatrixConvolutionImageFilter::Make(
180 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
181 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
182 input, cropRect),
183 true);
robertphillips12fa47d2016-04-08 16:28:09 -0700184 }
Mike Reed0bdaf052017-06-18 23:35:57 -0400185 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700186
robertphillips6e7025a2016-04-04 04:31:25 -0700187 {
188 SkPaint greenColorShaderPaint;
Mike Reedc8bea7d2019-04-09 13:55:36 -0400189 greenColorShaderPaint.setShader(SkShaders::Color(SK_ColorGREEN));
robertphillips6e7025a2016-04-04 04:31:25 -0700190
191 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
192 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
193 &leftSideCropRect));
194 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
195 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
196 &rightSideCropRect));
197
198
199 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400200 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700201 }
202
senorblanco297f7ce2016-03-23 13:44:26 -0700203 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700204 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700205 cropRect));
206 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
207 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700208 this->addFilter("tile", SkTileImageFilter::Make(
209 SkRect::MakeXYWH(0, 0, 50, 50),
210 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
211 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700212
robertphillips12fa47d2016-04-08 16:28:09 -0700213 if (!cropRect) {
214 SkMatrix matrix;
215
216 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
217 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
218
219 this->addFilter("matrix",
220 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
221 }
robertphillips6e7025a2016-04-04 04:31:25 -0700222 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700223 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700224
225 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
226 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700227 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700228 }
229 {
robertphillips6e7025a2016-04-04 04:31:25 -0700230 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400231 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700232
233 SkPaint greenPaint;
234 greenPaint.setColor(SK_ColorGREEN);
235 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
236 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
237 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
238
239 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
240 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700241 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700242 }
243 {
244 SkPaint paint;
245 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
246 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
247
248 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
249 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700250 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700251 }
reed374772b2016-10-05 17:33:02 -0700252 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
253 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700254 }
255 int count() const { return fFilters.count(); }
256 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
257 const char* getName(int index) const { return fFilters[index].fName; }
Robert Phillips12078432018-05-17 11:17:39 -0400258 bool needsSaveLayer(int index) const { return fFilters[index].fNeedsSaveLayer; }
senorblanco297f7ce2016-03-23 13:44:26 -0700259private:
260 struct Filter {
Robert Phillips12078432018-05-17 11:17:39 -0400261 Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
262 Filter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer)
robertphillips12fa47d2016-04-08 16:28:09 -0700263 : fName(name)
Robert Phillips12078432018-05-17 11:17:39 -0400264 , fFilter(std::move(filter))
265 , fNeedsSaveLayer(needsSaveLayer) {
robertphillips12fa47d2016-04-08 16:28:09 -0700266 }
senorblanco297f7ce2016-03-23 13:44:26 -0700267 const char* fName;
268 sk_sp<SkImageFilter> fFilter;
Robert Phillips12078432018-05-17 11:17:39 -0400269 bool fNeedsSaveLayer;
senorblanco297f7ce2016-03-23 13:44:26 -0700270 };
Robert Phillips12078432018-05-17 11:17:39 -0400271 void addFilter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer = false) {
272 fFilters.push_back(Filter(name, std::move(filter), needsSaveLayer));
senorblanco297f7ce2016-03-23 13:44:26 -0700273 }
274
275 SkTArray<Filter> fFilters;
276};
277
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700278class FixedBoundsImageFilter : public SkImageFilter {
279public:
280 FixedBoundsImageFilter(const SkIRect& bounds)
281 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
282
283private:
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700284 Factory getFactory() const override { return nullptr; }
Mike Klein4fee3232018-10-18 17:27:16 -0400285 const char* getTypeName() const override { return nullptr; }
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700286
287 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
288 SkIPoint* offset) const override {
289 return nullptr;
290 }
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700291
Robert Phillips12078432018-05-17 11:17:39 -0400292 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&,
293 MapDirection, const SkIRect*) const override {
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700294 return fBounds;
295 }
296
297 SkIRect fBounds;
298};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000299}
300
reed60c9b582016-04-03 09:11:13 -0700301sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700302 SkDEBUGFAIL("Should never get here");
303 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700304}
305
reed9ce9d672016-03-17 10:51:11 -0700306static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700307 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700308 SkCanvas* canvas = surface->getCanvas();
309 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000310 SkPaint darkPaint;
311 darkPaint.setColor(0xFF804020);
312 SkPaint lightPaint;
313 lightPaint.setColor(0xFF244484);
314 const int i = kBitmapSize / 4;
315 for (int y = 0; y < kBitmapSize; y += i) {
316 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700317 canvas->save();
318 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
319 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000320 SkIntToScalar(i),
321 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700322 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000323 0,
324 SkIntToScalar(i),
325 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700326 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000327 SkIntToScalar(i),
328 SkIntToScalar(i),
329 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700330 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000331 SkIntToScalar(i),
332 SkIntToScalar(i),
333 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700334 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000335 }
336 }
fmalita5598b632015-09-15 11:26:13 -0700337
reed9ce9d672016-03-17 10:51:11 -0700338 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000339}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000340
robertphillips5605b562016-04-05 11:50:42 -0700341static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
Mike Reede869a1e2019-04-30 12:18:54 -0400342 float s = amount;
343 float matrix[20] = { s, 0, 0, 0, 0,
344 0, s, 0, 0, 0,
345 0, 0, s, 0, 0,
346 0, 0, 0, s, 0 };
347 sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
robertphillips5605b562016-04-05 11:50:42 -0700348 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000349}
350
robertphillips5605b562016-04-05 11:50:42 -0700351static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
352 const SkImageFilter::CropRect* cropRect) {
Mike Reede869a1e2019-04-30 12:18:54 -0400353 float matrix[20];
354 memset(matrix, 0, 20 * sizeof(float));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000355 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
356 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
357 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
358 matrix[18] = 1.0f;
Mike Reede869a1e2019-04-30 12:18:54 -0400359 sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
robertphillips5605b562016-04-05 11:50:42 -0700360 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000361}
362
robertphillips5605b562016-04-05 11:50:42 -0700363static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
364 const SkImageFilter::CropRect* cropRect) {
Mike Reedb286bc22019-04-08 16:23:20 -0400365 sk_sp<SkColorFilter> filter(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700366 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700367}
368
robertphillips3e302272016-04-20 11:48:36 -0700369static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillips4418dba2016-03-07 12:45:14 -0800370 if (context) {
Brian Salomon27ae52c2019-07-03 11:27:44 -0400371 return SkSpecialSurface::MakeRenderTarget(context, widthHeight, widthHeight,
372 GrColorType::kRGBA_8888, nullptr);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400373 } else {
robertphillips4418dba2016-03-07 12:45:14 -0800374 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
375 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700376 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800377 }
senorblancobf680c32016-03-16 16:15:53 -0700378}
379
senorblanco5878dbd2016-05-19 14:50:29 -0700380static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
381 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
senorblanco5878dbd2016-05-19 14:50:29 -0700382 if (context) {
383 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
Brian Osmanc7ad40f2018-05-31 14:27:17 -0400384 } else {
senorblanco5878dbd2016-05-19 14:50:29 -0700385 return SkSurface::MakeRaster(info);
386 }
387}
388
robertphillips3e302272016-04-20 11:48:36 -0700389static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
390 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800391
392 SkASSERT(surf);
393
394 SkCanvas* canvas = surf->getCanvas();
395 SkASSERT(canvas);
396
397 canvas->clear(0x0);
398
robertphillips37bd7c32016-03-17 14:31:39 -0700399 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800400}
401
402
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000403DEF_TEST(ImageFilter, reporter) {
404 {
Mike Kleindadac552019-03-12 10:01:28 -0500405 // Check that a color matrix filter followed by a color matrix filter
406 // concatenates into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700407 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
408 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700409 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700410 SkColorFilter* cf;
411 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
reedcedc36f2015-03-08 04:42:52 -0700412 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000413 }
414
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000415 {
416 // Check that a color filter image filter without a crop rect can be
417 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700418 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700419 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000420 }
mtklein2afbe232016-02-07 12:23:10 -0800421
reedcedc36f2015-03-08 04:42:52 -0700422 {
423 // Check that a colorfilterimage filter without a crop rect but with an input
424 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700425 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
426 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700427 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700428 }
429
430 {
431 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
432 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700433 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700434 const int kWayTooManyForComposeColorFilter = 100;
435 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700436 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700437 // the first few of these will succeed, but after we hit the internal limit,
438 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700439 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700440 }
441 }
reed5c518a82015-03-05 14:47:29 -0800442
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000443 {
444 // Check that a color filter image filter with a crop rect cannot
445 // be expressed as a color filter.
446 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700447 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700448 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000449 }
450
451 {
senorblanco3df05012014-07-03 11:13:09 -0700452 // Check that two non-commutative matrices are concatenated in
453 // the correct order.
Mike Reede869a1e2019-04-30 12:18:54 -0400454 float blueToRedMatrix[20] = { 0 };
455 blueToRedMatrix[2] = blueToRedMatrix[18] = 1;
456 float redToGreenMatrix[20] = { 0 };
457 redToGreenMatrix[5] = redToGreenMatrix[18] = 1;
458 sk_sp<SkColorFilter> blueToRed(SkColorFilters::Matrix(blueToRedMatrix));
robertphillips5605b562016-04-05 11:50:42 -0700459 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
460 nullptr));
Mike Reede869a1e2019-04-30 12:18:54 -0400461 sk_sp<SkColorFilter> redToGreen(SkColorFilters::Matrix(redToGreenMatrix));
robertphillips5605b562016-04-05 11:50:42 -0700462 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
463 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700464
465 SkBitmap result;
466 result.allocN32Pixels(kBitmapSize, kBitmapSize);
467
468 SkPaint paint;
469 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700470 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700471 SkCanvas canvas(result);
472 canvas.clear(0x0);
473 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
474 canvas.drawRect(rect, paint);
475 uint32_t pixel = *result.getAddr32(0, 0);
476 // The result here should be green, since we have effectively shifted blue to green.
477 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
478 }
479
480 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000481 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700482 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700483 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000484 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000485
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000486 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000487 // This tests for :
488 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700489 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000490 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700491 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000492 // 3 ) large negative specular exponent value
493 SkScalar specularExponent = -1000;
494
robertphillips549c8992016-04-01 09:28:51 -0700495 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000496 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700497 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000498 location, target, specularExponent, 180,
499 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700500 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000501 SkCanvas canvas(result);
502 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
503 SkIntToScalar(kBitmapSize));
504 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000505 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000506 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000507}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000508
robertphillips3e302272016-04-20 11:48:36 -0700509static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800510 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000511 // Check that all filters offset to their absolute crop rect,
512 // unaffected by the input crop rect.
513 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700514 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800515 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000516
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000517 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
518 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700519 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000520
robertphillipsfc11b0a2016-04-05 09:09:36 -0700521 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000522
senorblanco297f7ce2016-03-23 13:44:26 -0700523 for (int i = 0; i < filters.count(); ++i) {
524 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000525 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400526 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700527 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700528 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
Brian Salomon1c80e992018-01-29 09:50:47 -0500529 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
530 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000531 }
532}
533
robertphillips3e302272016-04-20 11:48:36 -0700534static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800535 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700536 // Check that SkBlurImageFilter will accept a negative sigma, either in
537 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700538 const int width = 32, height = 32;
539 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700540
robertphillips6e7025a2016-04-04 04:31:25 -0700541 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
542 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700543
544 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700545 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700546 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800547
senorblanco32673b92014-09-09 09:15:04 -0700548 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400549 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700550 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800551
robertphillips2302de92016-03-24 07:26:32 -0700552 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800553 REPORTER_ASSERT(reporter, positiveResult1);
554
robertphillips2302de92016-03-24 07:26:32 -0700555 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800556 REPORTER_ASSERT(reporter, negativeResult1);
557
senorblanco32673b92014-09-09 09:15:04 -0700558 SkMatrix negativeScale;
559 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700560 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
561 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800562
robertphillips2302de92016-03-24 07:26:32 -0700563 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
564 negativeCTX,
565 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800566 REPORTER_ASSERT(reporter, negativeResult2);
567
robertphillips2302de92016-03-24 07:26:32 -0700568 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
569 negativeCTX,
570 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800571 REPORTER_ASSERT(reporter, positiveResult2);
572
573
574 SkBitmap positiveResultBM1, positiveResultBM2;
575 SkBitmap negativeResultBM1, negativeResultBM2;
576
robertphillips64612512016-04-08 12:10:42 -0700577 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
578 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
579 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
580 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800581
senorblanco32673b92014-09-09 09:15:04 -0700582 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800583 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
584 negativeResultBM1.getAddr32(0, y),
585 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700586 REPORTER_ASSERT(reporter, !diffs);
587 if (diffs) {
588 break;
589 }
robertphillips4418dba2016-03-07 12:45:14 -0800590 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
591 negativeResultBM2.getAddr32(0, y),
592 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700593 REPORTER_ASSERT(reporter, !diffs);
594 if (diffs) {
595 break;
596 }
robertphillips4418dba2016-03-07 12:45:14 -0800597 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
598 positiveResultBM2.getAddr32(0, y),
599 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700600 REPORTER_ASSERT(reporter, !diffs);
601 if (diffs) {
602 break;
603 }
604 }
605}
606
senorblanco21a465d2016-04-11 11:58:39 -0700607DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700608 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800609}
610
bsalomon68d91342016-04-12 09:59:58 -0700611DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700612 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800613}
robertphillips4418dba2016-03-07 12:45:14 -0800614
robertphillips3e302272016-04-20 11:48:36 -0700615static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700616 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
617 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700618 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700619 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700620
robertphillips3e302272016-04-20 11:48:36 -0700621 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700622 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700623 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700624
625 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -0400626 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700627 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700628
robertphillips2302de92016-03-24 07:26:32 -0700629 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700630 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
631 REPORTER_ASSERT(reporter, result);
632 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
633
634 SkBitmap resultBM;
635
robertphillips64612512016-04-08 12:10:42 -0700636 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700637
senorblancobf680c32016-03-16 16:15:53 -0700638 for (int y = 0; y < resultBM.height(); y++) {
639 for (int x = 0; x < resultBM.width(); x++) {
640 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
641 REPORTER_ASSERT(reporter, !diff);
642 if (diff) {
643 break;
644 }
645 }
646 }
647}
648
senorblanco21a465d2016-04-11 11:58:39 -0700649DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700650 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700651}
652
bsalomon68d91342016-04-12 09:59:58 -0700653DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700654 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700655}
senorblancobf680c32016-03-16 16:15:53 -0700656
senorblanco6a93fa12016-04-05 04:43:45 -0700657
658// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
659// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700660static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700661 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700662 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
Brian Osmana50205f2018-07-06 13:57:01 -0400663 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700664 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reedb286bc22019-04-08 16:23:20 -0400665 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700666 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700667 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
668 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700669 SkIPoint offset;
670 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
671 REPORTER_ASSERT(reporter, nullptr != result.get());
672 if (result.get()) {
673 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700674 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700675 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
676 }
677}
678
679DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700680 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700681}
682
bsalomon68d91342016-04-12 09:59:58 -0700683DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700684 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700685}
senorblanco6a93fa12016-04-05 04:43:45 -0700686
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000687DEF_TEST(ImageFilterDrawTiled, reporter) {
688 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
689 // match the same filters drawn with a single full-canvas bitmap draw.
690 // Tests pass by not asserting.
691
robertphillipsfc11b0a2016-04-05 09:09:36 -0700692 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000693
694 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700695 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000696 untiledResult.allocN32Pixels(width, height);
697 tiledResult.allocN32Pixels(width, height);
698 SkCanvas tiledCanvas(tiledResult);
699 SkCanvas untiledCanvas(untiledResult);
Robert Phillips12078432018-05-17 11:17:39 -0400700 const int tileSize = 8;
701
702 SkPaint textPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400703 textPaint.setColor(SK_ColorWHITE);
Mike Kleinea3f0142019-03-20 11:12:10 -0500704 SkFont font(ToolUtils::create_portable_typeface(), height);
Robert Phillips12078432018-05-17 11:17:39 -0400705
706 const char* text = "ABC";
707 const SkScalar yPos = SkIntToScalar(height);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000708
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000709 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700710 for (int i = 0; i < filters.count(); ++i) {
Robert Phillips12078432018-05-17 11:17:39 -0400711 SkPaint combinedPaint;
Robert Phillips12078432018-05-17 11:17:39 -0400712 combinedPaint.setColor(SK_ColorWHITE);
713 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
714
715 untiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000716 untiledCanvas.save();
717 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500718 untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000719 untiledCanvas.restore();
Robert Phillips12078432018-05-17 11:17:39 -0400720
721 tiledCanvas.clear(SK_ColorTRANSPARENT);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000722 for (int y = 0; y < height; y += tileSize) {
723 for (int x = 0; x < width; x += tileSize) {
724 tiledCanvas.save();
Robert Phillips12078432018-05-17 11:17:39 -0400725 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
726 tiledCanvas.clipRect(clipRect);
727 if (filters.needsSaveLayer(i)) {
728 const SkRect layerBounds = SkRect::MakeWH(width, height);
729 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
730 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500731 tiledCanvas.drawString(text, 0, yPos, font, textPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400732 tiledCanvas.restore();
733 } else {
734 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Mike Reed1af9b482019-01-07 11:01:57 -0500735 tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
Robert Phillips12078432018-05-17 11:17:39 -0400736 }
737
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000738 tiledCanvas.restore();
739 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000740 }
Robert Phillips12078432018-05-17 11:17:39 -0400741
Mike Kleinea3f0142019-03-20 11:12:10 -0500742 if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
Brian Salomon1c80e992018-01-29 09:50:47 -0500743 REPORTER_ASSERT(reporter, false, filters.getName(i));
Mike Reed5a625e02017-08-08 15:48:54 -0400744 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000745 }
746 }
747 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000748}
749
mtklein3f3b3d02014-12-01 11:47:08 -0800750static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700751 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700752
753 SkMatrix matrix;
754 matrix.setTranslate(SkIntToScalar(50), 0);
755
Mike Reedb286bc22019-04-08 16:23:20 -0400756 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700757 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700758 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
759 kNone_SkFilterQuality,
760 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700761
762 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700763 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700764 SkPictureRecorder recorder;
765 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800766 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
767 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700768 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700769 recordingCanvas->translate(-55, 0);
770 recordingCanvas->saveLayer(&bounds, &paint);
771 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700772 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700773
774 result->allocN32Pixels(width, height);
775 SkCanvas canvas(*result);
776 canvas.clear(0);
777 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
778 canvas.drawPicture(picture1.get());
779}
780
781DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
782 // Check that matrix filter when drawn tiled with BBH exactly
783 // matches the same thing drawn without BBH.
784 // Tests pass by not asserting.
785
786 const int width = 200, height = 200;
787 const int tileSize = 100;
788 SkBitmap result1, result2;
789 SkRTreeFactory factory;
790
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700791 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700792 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700793
794 for (int y = 0; y < height; y++) {
795 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
796 REPORTER_ASSERT(reporter, !diffs);
797 if (diffs) {
798 break;
799 }
800 }
801}
802
robertphillips6e7025a2016-04-04 04:31:25 -0700803static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
804 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700805}
806
robertphillips6e7025a2016-04-04 04:31:25 -0700807static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700808 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700809 SkIntToScalar(100), SkIntToScalar(100),
810 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700811 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700812 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700813}
814
815DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700816 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
817 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700818
819 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000820 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400821 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
822 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700823
824 REPORTER_ASSERT(reporter, bounds == expectedBounds);
825}
826
827DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700828 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
829 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700830
831 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
Herb Derby59f8f152017-10-17 22:27:23 +0000832 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
Robert Phillips12078432018-05-17 11:17:39 -0400833 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
834 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700835
836 REPORTER_ASSERT(reporter, bounds == expectedBounds);
837}
838
839DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700840 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700841 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700842
843 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
844 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
Robert Phillips12078432018-05-17 11:17:39 -0400845 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
846 SkImageFilter::kReverse_MapDirection, &bounds);
senorblanco1150a6d2014-08-25 12:46:58 -0700847
848 REPORTER_ASSERT(reporter, bounds == expectedBounds);
849}
850
jbroman203a9932016-07-11 14:07:59 -0700851DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
852 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
853 // (before the CTM). Bounds should be computed correctly in the presence of
854 // a (possibly negative) scale.
855 sk_sp<SkImageFilter> blur(make_blur(nullptr));
856 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
857 {
858 // Uniform scale by 2.
859 SkMatrix scaleMatrix;
860 scaleMatrix.setScale(2, 2);
861 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
862
Herb Derby59f8f152017-10-17 22:27:23 +0000863 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
jbroman203a9932016-07-11 14:07:59 -0700864 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400865 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700866 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
867 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400868 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700869 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
870
871 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
872 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400873 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700874 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
875 SkIRect expectedReverseShadowBounds =
876 SkIRect::MakeLTRB(-260, -260, 200, 200);
877 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400878 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700879 REPORTER_ASSERT(reporter,
880 reverseShadowBounds == expectedReverseShadowBounds);
881 }
882 {
883 // Vertical flip.
884 SkMatrix scaleMatrix;
885 scaleMatrix.setScale(1, -1);
886 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
887
Herb Derby59f8f152017-10-17 22:27:23 +0000888 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
jbroman203a9932016-07-11 14:07:59 -0700889 SkIRect blurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400890 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700891 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
892 SkIRect reverseBlurBounds = blur->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400893 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700894 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
895
896 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
897 SkIRect shadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400898 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
jbroman203a9932016-07-11 14:07:59 -0700899 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
900 SkIRect expectedReverseShadowBounds =
901 SkIRect::MakeLTRB(-130, -100, 100, 130);
902 SkIRect reverseShadowBounds = dropShadow->filterBounds(
Robert Phillips12078432018-05-17 11:17:39 -0400903 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
jbroman203a9932016-07-11 14:07:59 -0700904 REPORTER_ASSERT(reporter,
905 reverseShadowBounds == expectedReverseShadowBounds);
906 }
907}
908
ajuma5788faa2015-02-13 09:05:47 -0800909DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700910 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
911 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700912 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
913 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800914
915 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
916 SkRect expectedBounds = SkRect::MakeXYWH(
Herb Derby59f8f152017-10-17 22:27:23 +0000917 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700918 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800919
920 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
921}
922
jbroman0e3129d2016-03-17 12:24:23 -0700923DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700924 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700925 // Regardless of which order they appear in, the image filter bounds should
926 // be combined correctly.
927 {
reed374772b2016-10-05 17:33:02 -0700928 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700929 SkRect bounds = SkRect::MakeWH(100, 100);
930 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700931 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700932 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
933 }
934 {
reed374772b2016-10-05 17:33:02 -0700935 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700936 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700937 SkRect bounds = SkRect::MakeWH(100, 100);
938 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700939 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700940 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
941 }
942}
943
robertphillips3e302272016-04-20 11:48:36 -0700944static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800945 SkBitmap greenBM;
946 greenBM.allocN32Pixels(20, 20);
947 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700948 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700949 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400950 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800951
robertphillips3e302272016-04-20 11:48:36 -0700952 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800953
Brian Osmana50205f2018-07-06 13:57:01 -0400954 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -0700955 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
956 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800957 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800958
robertphillips2302de92016-03-24 07:26:32 -0700959 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800960 REPORTER_ASSERT(reporter, resultImg);
961
962 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800963}
964
robertphillips4418dba2016-03-07 12:45:14 -0800965DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700966 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800967}
968
egdanielab527a52016-06-28 08:07:26 -0700969DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700970 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800971}
robertphillips4418dba2016-03-07 12:45:14 -0800972
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700973static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -0700974 SkPaint filterPaint;
975 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -0700976 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700977 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -0700978 SkPaint whitePaint;
979 whitePaint.setColor(SK_ColorWHITE);
980 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
981 canvas->restore();
982}
983
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700984static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -0700985 canvas->save();
986 canvas->clipRect(clipRect);
987 canvas->drawPicture(picture);
988 canvas->restore();
989}
990
991DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
992 // Check that the blur filter when recorded with RTree acceleration,
993 // and drawn tiled (with subsequent clip rects) exactly
994 // matches the same filter drawn with without RTree acceleration.
995 // This tests that the "bleed" from the blur into the otherwise-blank
996 // tiles is correctly rendered.
997 // Tests pass by not asserting.
998
999 int width = 16, height = 8;
1000 SkBitmap result1, result2;
1001 result1.allocN32Pixels(width, height);
1002 result2.allocN32Pixels(width, height);
1003 SkCanvas canvas1(result1);
1004 SkCanvas canvas2(result2);
1005 int tileSize = 8;
1006
1007 canvas1.clear(0);
1008 canvas2.clear(0);
1009
1010 SkRTreeFactory factory;
1011
1012 SkPictureRecorder recorder1, recorder2;
1013 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001014 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1015 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001016 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001017 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1018 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001019 &factory, 0);
1020 draw_blurred_rect(recordingCanvas1);
1021 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001022 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1023 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001024 for (int y = 0; y < height; y += tileSize) {
1025 for (int x = 0; x < width; x += tileSize) {
1026 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001027 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1028 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001029 }
1030 }
1031 for (int y = 0; y < height; y++) {
1032 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1033 REPORTER_ASSERT(reporter, !diffs);
1034 if (diffs) {
1035 break;
1036 }
1037 }
1038}
1039
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001040DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1041 // Check that a 1x3 filter does not cause a spurious assert.
1042 SkScalar kernel[3] = {
1043 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1044 };
1045 SkISize kernelSize = SkISize::Make(1, 3);
1046 SkScalar gain = SK_Scalar1, bias = 0;
1047 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1048
robertphillipsef6a47b2016-04-08 08:01:20 -07001049 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1050 kernelSize, kernel,
1051 gain, bias, kernelOffset,
1052 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1053 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001054
1055 SkBitmap result;
1056 int width = 16, height = 16;
1057 result.allocN32Pixels(width, height);
1058 SkCanvas canvas(result);
1059 canvas.clear(0);
1060
1061 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001062 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001063 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1064 canvas.drawRect(rect, paint);
1065}
1066
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001067DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1068 // Check that a filter with borders outside the target bounds
1069 // does not crash.
1070 SkScalar kernel[3] = {
1071 0, 0, 0,
1072 };
1073 SkISize kernelSize = SkISize::Make(3, 1);
1074 SkScalar gain = SK_Scalar1, bias = 0;
1075 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1076
robertphillipsef6a47b2016-04-08 08:01:20 -07001077 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1078 kernelSize, kernel, gain, bias, kernelOffset,
1079 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1080 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001081
1082 SkBitmap result;
1083
1084 int width = 10, height = 10;
1085 result.allocN32Pixels(width, height);
1086 SkCanvas canvas(result);
1087 canvas.clear(0);
1088
1089 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001090 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001091 SkRect bounds = SkRect::MakeWH(1, 10);
1092 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1093 SkPaint rectPaint;
1094 canvas.saveLayer(&bounds, &filterPaint);
1095 canvas.drawRect(rect, rectPaint);
1096 canvas.restore();
1097}
1098
robertphillips3e302272016-04-20 11:48:36 -07001099static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001100 // Check that a kernel that is too big for the GPU still works
1101 SkScalar identityKernel[49] = {
1102 0, 0, 0, 0, 0, 0, 0,
1103 0, 0, 0, 0, 0, 0, 0,
1104 0, 0, 0, 0, 0, 0, 0,
1105 0, 0, 0, 1, 0, 0, 0,
1106 0, 0, 0, 0, 0, 0, 0,
1107 0, 0, 0, 0, 0, 0, 0,
1108 0, 0, 0, 0, 0, 0, 0
1109 };
1110 SkISize kernelSize = SkISize::Make(7, 7);
1111 SkScalar gain = SK_Scalar1, bias = 0;
1112 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1113
1114 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1115 kernelSize, identityKernel, gain, bias, kernelOffset,
1116 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1117 true, nullptr));
1118
robertphillips3e302272016-04-20 11:48:36 -07001119 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001120 SkASSERT(srcImg);
1121
1122 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001123 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001124 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001125 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1126 REPORTER_ASSERT(reporter, resultImg);
1127 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1128 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1129 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1130}
1131
1132DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001133 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001134}
1135
egdanielab527a52016-06-28 08:07:26 -07001136DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1137 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001138 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001139}
robertphillipsdada4dd2016-04-13 04:54:36 -07001140
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001141DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001142 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001143}
1144
bsalomon68d91342016-04-12 09:59:58 -07001145DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001146 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001147}
robertphillips4418dba2016-03-07 12:45:14 -08001148
tfarina9ea53f92014-06-24 06:50:39 -07001149DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001150 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001151 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001152 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001153 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1154
1155 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1156
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001157 SkRTreeFactory factory;
1158 SkPictureRecorder recorder;
1159 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001160
1161 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001162 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001163 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001164 SkPaint solidPaint;
1165 solidPaint.setColor(0xFFFFFFFF);
1166 recordingCanvas->save();
1167 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1168 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1169 recordingCanvas->restore(); // scale
1170 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001171
reedca2622b2016-03-18 07:25:55 -07001172 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001173}
1174
robertphillips3e302272016-04-20 11:48:36 -07001175static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001176 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001177
robertphillips4418dba2016-03-07 12:45:14 -08001178 {
1179 SkRTreeFactory factory;
1180 SkPictureRecorder recorder;
1181 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1182
1183 // Create an SkPicture which simply draws a green 1x1 rectangle.
1184 SkPaint greenPaint;
1185 greenPaint.setColor(SK_ColorGREEN);
1186 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001187 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001188 }
1189
robertphillips3e302272016-04-20 11:48:36 -07001190 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001191
robertphillips5ff17b12016-03-28 13:13:42 -07001192 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001193
senorblanco3d822c22014-07-30 14:49:31 -07001194 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001195 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001196 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001197
robertphillips2302de92016-03-24 07:26:32 -07001198 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001199 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001200}
1201
robertphillips4418dba2016-03-07 12:45:14 -08001202DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001203 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001204}
1205
bsalomon68d91342016-04-12 09:59:58 -07001206DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001207 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001208}
robertphillips4418dba2016-03-07 12:45:14 -08001209
tfarina9ea53f92014-06-24 06:50:39 -07001210DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001211 // Even when there's an empty saveLayer()/restore(), ensure that an image
1212 // filter or color filter which affects transparent black still draws.
1213
1214 SkBitmap bitmap;
1215 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001216 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001217
1218 SkRTreeFactory factory;
1219 SkPictureRecorder recorder;
1220
Mike Reedb286bc22019-04-08 16:23:20 -04001221 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001222 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001223 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001224 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001225 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001226 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001227 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001228
1229 SkRect bounds = SkRect::MakeWH(10, 10);
1230
1231 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1232 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1233 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001234 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001235
1236 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001237 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001238 uint32_t pixel = *bitmap.getAddr32(0, 0);
1239 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1240
1241 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001242 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001243 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001244 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001245
1246 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001247 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001248 pixel = *bitmap.getAddr32(0, 0);
1249 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1250
1251 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1252 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1253 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001254 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001255
1256 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001257 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001258 pixel = *bitmap.getAddr32(0, 0);
1259 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1260}
1261
robertphillips9a53fd72015-06-22 09:46:59 -07001262static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001263 SkBitmap bitmap;
1264 bitmap.allocN32Pixels(100, 100);
1265 bitmap.eraseARGB(0, 0, 0, 0);
1266
1267 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001268 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001269 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1270 SkIntToScalar(1<<30),
1271 nullptr));
reedda420b92015-12-16 08:38:15 -08001272 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001273}
1274
1275DEF_TEST(HugeBlurImageFilter, reporter) {
1276 SkBitmap temp;
1277 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001278 SkCanvas canvas(temp);
1279 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001280}
1281
senorblanco21a465d2016-04-11 11:58:39 -07001282DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001283 SkScalar kernel[1] = { 0 };
1284 SkScalar gain = SK_Scalar1, bias = 0;
1285 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1286
halcanary96fcdcc2015-08-27 07:41:13 -07001287 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001288 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001289 SkISize::Make(1<<30, 1<<30),
1290 kernel,
1291 gain,
1292 bias,
1293 kernelOffset,
1294 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001295 false,
1296 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001297
halcanary96fcdcc2015-08-27 07:41:13 -07001298 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001299
halcanary96fcdcc2015-08-27 07:41:13 -07001300 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001301 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001302 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001303 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001304 gain,
1305 bias,
1306 kernelOffset,
1307 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001308 false,
1309 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001310
halcanary96fcdcc2015-08-27 07:41:13 -07001311 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001312
halcanary96fcdcc2015-08-27 07:41:13 -07001313 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001314 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001315 SkISize::Make(0, 1),
1316 kernel,
1317 gain,
1318 bias,
1319 kernelOffset,
1320 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001321 false,
1322 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001323
halcanary96fcdcc2015-08-27 07:41:13 -07001324 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001325
halcanary96fcdcc2015-08-27 07:41:13 -07001326 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001327 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001328 SkISize::Make(1, -1),
1329 kernel,
1330 gain,
1331 bias,
1332 kernelOffset,
1333 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001334 false,
1335 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001336
halcanary96fcdcc2015-08-27 07:41:13 -07001337 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001338}
1339
Mike Reedf1942192017-07-21 14:24:29 -04001340static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1341 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001342 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001343
1344 SkBitmap bitmap;
1345 bitmap.allocN32Pixels(1, 1);
1346 bitmap.eraseARGB(255, 255, 255, 255);
1347
Mike Reedb286bc22019-04-08 16:23:20 -04001348 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001349 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001350 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001351 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001352
1353 // Check that an xfermode image filter whose input has been cropped out still draws the other
1354 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001355 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001356 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1357 croppedOut, nullptr));
1358 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1359 greenFilter, nullptr));
1360 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1361 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001362
1363 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001364 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001365 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001366
1367 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001368 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001369 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001370 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1371
robertphillips8c0326d2016-04-05 12:48:34 -07001372 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001373 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001374 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001375 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1376
robertphillips8c0326d2016-04-05 12:48:34 -07001377 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001378 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001379 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001380 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1381}
1382
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001383DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1384 SkBitmap temp;
1385 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001386 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001387 canvas.clear(0x0);
1388
1389 SkBitmap bitmap;
1390 bitmap.allocN32Pixels(10, 10);
1391 bitmap.eraseColor(SK_ColorGREEN);
1392
1393 SkMatrix matrix;
1394 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1395 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001396 sk_sp<SkImageFilter> matrixFilter(
1397 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001398
1399 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1400 // correct offset to the filter matrix.
1401 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001402 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001403 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001404 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001405 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1406 canvas.saveLayer(&bounds2, &filterPaint);
1407 SkPaint greenPaint;
1408 greenPaint.setColor(SK_ColorGREEN);
1409 canvas.drawRect(bounds2, greenPaint);
1410 canvas.restore();
1411 canvas.restore();
1412 SkPaint strokePaint;
1413 strokePaint.setStyle(SkPaint::kStroke_Style);
1414 strokePaint.setColor(SK_ColorRED);
1415
kkinnunena9d9a392015-03-06 07:16:00 -08001416 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001417 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001418 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001419 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1420
1421 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1422 // correct offset to the filter matrix.
1423 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001424 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001425 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001426 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001427 canvas.restore();
1428
Mike Reedf1942192017-07-21 14:24:29 -04001429 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001430 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1431}
1432
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001433DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001434 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001435}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001436
robertphillips3e302272016-04-20 11:48:36 -07001437static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1438 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001439
1440 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001441 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001442 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1443 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001444 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1445 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001446 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001447 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001448 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001449
robertphillips2302de92016-03-24 07:26:32 -07001450 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001451 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001452 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1453}
1454
robertphillips4418dba2016-03-07 12:45:14 -08001455DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001456 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001457}
1458
bsalomon68d91342016-04-12 09:59:58 -07001459DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001460 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001461}
robertphillips4418dba2016-03-07 12:45:14 -08001462
robertphillips3e302272016-04-20 11:48:36 -07001463static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001464 // The bounds passed to the inner filter must be filtered by the outer
1465 // filter, so that the inner filter produces the pixels that the outer
1466 // filter requires as input. This matters if the outer filter moves pixels.
1467 // Here, accounting for the outer offset is necessary so that the green
1468 // pixels of the picture are not clipped.
1469
1470 SkPictureRecorder recorder;
1471 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1472 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1473 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001474 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001475 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001476 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001477 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001478 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1479 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001480
robertphillips3e302272016-04-20 11:48:36 -07001481 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
Brian Osmana50205f2018-07-06 13:57:01 -04001482 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001483 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001484 SkIPoint offset;
1485 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1486 REPORTER_ASSERT(reporter, offset.isZero());
1487 REPORTER_ASSERT(reporter, result);
1488 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1489
1490 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001491 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001492 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1493}
1494
1495DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001496 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001497}
1498
egdanielab527a52016-06-28 08:07:26 -07001499DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001500 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001501}
jbroman17a65202016-03-21 08:38:58 -07001502
robertphillips3e302272016-04-20 11:48:36 -07001503static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1504 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001505
1506 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001507 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001508 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001509 SkIPoint offset;
Brian Osmana50205f2018-07-06 13:57:01 -04001510 SkImageFilter::OutputProperties noColorSpace(kN32_SkColorType, nullptr);
brianosman2a75e5d2016-09-22 07:15:37 -07001511 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001512
robertphillips2302de92016-03-24 07:26:32 -07001513 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001514 REPORTER_ASSERT(reporter, resultImg);
1515
senorblanco24d2a7b2015-07-13 10:27:05 -07001516 REPORTER_ASSERT(reporter, offset.fX == 0);
1517 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001518 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1519 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001520}
1521
senorblanco21a465d2016-04-11 11:58:39 -07001522DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001523 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001524}
1525
bsalomon68d91342016-04-12 09:59:58 -07001526DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001527 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001528}
robertphillips4418dba2016-03-07 12:45:14 -08001529
senorblanco0abdf762015-08-20 11:10:41 -07001530DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1531
robertphillips12fa47d2016-04-08 16:28:09 -07001532 {
1533 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1534 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1535 SK_ColorGREEN,
1536 0, 0, nullptr));
1537 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1538 }
senorblanco0abdf762015-08-20 11:10:41 -07001539
senorblanco0abdf762015-08-20 11:10:41 -07001540 {
robertphillips6e7025a2016-04-04 04:31:25 -07001541 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1542 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1543 {
1544 SkColorFilter* grayCF;
1545 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1546 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1547 grayCF->unref();
1548 }
1549 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1550
1551 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1552 std::move(gray)));
1553 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001554 }
senorblanco0abdf762015-08-20 11:10:41 -07001555
robertphillips6e7025a2016-04-04 04:31:25 -07001556 {
Mike Reede869a1e2019-04-30 12:18:54 -04001557 float greenMatrix[20] = { 0, 0, 0, 0, 0,
1558 0, 0, 0, 0, 1.0f/255,
1559 0, 0, 0, 0, 0,
1560 0, 0, 0, 0, 1.0f/255
1561 };
1562 sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001563 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001564
robertphillips6e7025a2016-04-04 04:31:25 -07001565 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1566 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001567
robertphillips6e7025a2016-04-04 04:31:25 -07001568 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1569 std::move(green)));
1570 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1571 }
senorblanco0abdf762015-08-20 11:10:41 -07001572
1573 uint8_t allOne[256], identity[256];
1574 for (int i = 0; i < 256; ++i) {
1575 identity[i] = i;
1576 allOne[i] = 255;
1577 }
1578
robertphillips5605b562016-04-05 11:50:42 -07001579 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1580 identity, allOne));
1581 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001582 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1583 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1584
robertphillips5605b562016-04-05 11:50:42 -07001585 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1586 identity, identity));
1587 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001588 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1589 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1590}
1591
fmalitacd56f812015-09-14 13:31:18 -07001592// Verify that SkImageSource survives serialization
1593DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001594 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001595 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001596 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001597 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001598
Mike Reed0331d372018-01-23 11:57:30 -05001599 sk_sp<SkData> data(filter->serialize());
1600 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
fmalitacd56f812015-09-14 13:31:18 -07001601 REPORTER_ASSERT(reporter, unflattenedFilter);
1602
1603 SkBitmap bm;
1604 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001605 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001606 SkPaint paint;
1607 paint.setColor(SK_ColorRED);
1608 paint.setImageFilter(unflattenedFilter);
1609
1610 SkCanvas canvas(bm);
1611 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1612 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1613}
1614
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001615DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1616 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1617 if (!data) {
1618 return;
1619 }
Mike Reed0331d372018-01-23 11:57:30 -05001620 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
Leon Scroggins III4cdbf602017-09-28 14:33:57 -04001621 // This will fail. More importantly, msan will verify that we did not
1622 // compare against uninitialized memory.
1623 REPORTER_ASSERT(r, !unflattenedFilter);
1624}
1625
bsalomon45eefcf2016-01-05 08:39:28 -08001626static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1627 SkBitmap largeBmp;
1628 int largeW = 5000;
1629 int largeH = 5000;
bsalomon45eefcf2016-01-05 08:39:28 -08001630 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1631 if (GrContext* ctx = canvas->getGrContext()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05001632 largeW = ctx->priv().caps()->maxTextureSize() + 1;
bsalomon45eefcf2016-01-05 08:39:28 -08001633 }
bsalomon45eefcf2016-01-05 08:39:28 -08001634
1635 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001636 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001637 if (!largeBmp.getPixels()) {
1638 ERRORF(reporter, "Failed to allocate large bmp.");
1639 return;
1640 }
1641
reed9ce9d672016-03-17 10:51:11 -07001642 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001643 if (!largeImage) {
1644 ERRORF(reporter, "Failed to create large image.");
1645 return;
1646 }
1647
robertphillips549c8992016-04-01 09:28:51 -07001648 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001649 if (!largeSource) {
1650 ERRORF(reporter, "Failed to create large SkImageSource.");
1651 return;
1652 }
1653
robertphillips6e7025a2016-04-04 04:31:25 -07001654 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001655 if (!blur) {
1656 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1657 return;
1658 }
1659
1660 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001661 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001662
1663 // This should not crash (http://crbug.com/570479).
1664 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1665}
1666
senorblanco21a465d2016-04-11 11:58:39 -07001667DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001668 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001669 test_large_blur_input(reporter, surface->getCanvas());
1670}
1671
senorblanco5878dbd2016-05-19 14:50:29 -07001672static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001673 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001674 surface->getCanvas()->clear(SK_ColorRED);
1675 SkPaint bluePaint;
1676 bluePaint.setColor(SK_ColorBLUE);
1677 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1678 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1679 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1680
1681 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1682 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1683 SkIRect outSubset;
1684 SkIPoint offset;
1685 sk_sp<SkImage> result;
1686
1687 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1688 REPORTER_ASSERT(reporter, !result);
1689
1690 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1691 REPORTER_ASSERT(reporter, !result);
1692
1693 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1694 REPORTER_ASSERT(reporter, !result);
1695
1696 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1697 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1698 REPORTER_ASSERT(reporter, !result);
1699
1700 SkIRect empty = SkIRect::MakeEmpty();
1701 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1702 REPORTER_ASSERT(reporter, !result);
1703
1704 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1705 REPORTER_ASSERT(reporter, !result);
1706
1707 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1708 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1709 REPORTER_ASSERT(reporter, !result);
1710
1711 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1712
1713 REPORTER_ASSERT(reporter, result);
1714 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1715 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1716 outSubset.width(), outSubset.height());
1717 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001718
1719 // In GPU-mode, this case creates a special image with a backing size that differs from
1720 // the content size
1721 {
1722 clipBounds.setXYWH(0, 0, 170, 100);
1723 subset.setXYWH(0, 0, 160, 90);
1724
1725 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1726 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1727 REPORTER_ASSERT(reporter, result);
1728 }
senorblanco5878dbd2016-05-19 14:50:29 -07001729}
1730
1731DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1732 test_make_with_filter(reporter, nullptr);
1733}
1734
senorblanco5878dbd2016-05-19 14:50:29 -07001735DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1736 test_make_with_filter(reporter, ctxInfo.grContext());
1737}
reed4a8126e2014-09-22 07:29:03 -07001738
bsalomon68d91342016-04-12 09:59:58 -07001739DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001740
bsalomon8b7451a2016-05-11 06:33:06 -07001741 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001742 SkBudgeted::kNo,
1743 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001744
robertphillips3e302272016-04-20 11:48:36 -07001745
1746 SkCanvas* canvas = surf->getCanvas();
1747
1748 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001749}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001750
egdanielab527a52016-06-28 08:07:26 -07001751DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001752 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1753 ctxInfo.grContext(),
1754 SkBudgeted::kNo,
1755 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001756
Mike Reedf1942192017-07-21 14:24:29 -04001757 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001758}
senorblanco32673b92014-09-09 09:15:04 -07001759
egdanielab527a52016-06-28 08:07:26 -07001760DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001761 auto surface(SkSurface::MakeRenderTarget(
1762 ctxInfo.grContext(), SkBudgeted::kYes,
1763 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001764 test_large_blur_input(reporter, surface->getCanvas());
1765}
reedbb34a8a2016-04-23 15:19:07 -07001766
1767/*
1768 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1769 * than just scale/translate, but that other filters do.
1770 */
reed96a04f32016-04-25 09:25:15 -07001771DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001772 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reedb286bc22019-04-08 16:23:20 -04001773 sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001774 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1775 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001776
1777 struct {
1778 sk_sp<SkImageFilter> fFilter;
1779 bool fExpectCanHandle;
1780 } recs[] = {
1781 { cfif, true },
1782 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001783 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001784 { SkComposeImageFilter::Make(cfif, cfif), true },
1785
reedbb34a8a2016-04-23 15:19:07 -07001786 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001787 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001788 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001789 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001790 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001791 };
liyuqianbfebe222016-11-14 11:17:16 -08001792
reedbb34a8a2016-04-23 15:19:07 -07001793 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001794 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001795 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1796 }
1797}
Florin Malita08252ec2017-07-06 12:48:15 -04001798
Xianzhu Wangb4496662017-09-25 10:26:40 -07001799// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001800DEF_TEST(XfermodeImageFilterBounds, reporter) {
1801 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1802 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1803 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1804 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1805
1806 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1807 SkIRect expectedBounds[kModeCount];
1808 // Expect union of input rects by default.
1809 for (int i = 0; i < kModeCount; ++i) {
1810 expectedBounds[i] = background_rect;
1811 expectedBounds[i].join(foreground_rect);
1812 }
1813
1814 SkIRect intersection = background_rect;
1815 intersection.intersect(foreground_rect);
1816 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1817 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1818 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1819 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1820 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1821 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1822 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1823
1824 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1825 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1826 for (int i = 0; i < kModeCount; ++i) {
1827 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1828 background, foreground, nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001829 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1830 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001831 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1832 }
1833
1834 // Test empty intersection.
1835 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1836 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1837 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1838 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
Robert Phillips12078432018-05-17 11:17:39 -04001839 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1840 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001841 REPORTER_ASSERT(reporter, bounds.isEmpty());
1842}
1843
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001844DEF_TEST(OffsetImageFilterBounds, reporter) {
1845 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1846 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(-50.5f, -50.5f, nullptr));
1847
1848 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1849 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001850 SkImageFilter::kForward_MapDirection, nullptr);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001851 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1852
1853 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1854 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001855 SkImageFilter::kReverse_MapDirection, &src);
Fredrik Söderquistb87f7982017-10-26 13:54:16 +02001856 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1857}
1858
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001859static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1860 float k4, sk_sp<SkImageFilter> background,
1861 sk_sp<SkImageFilter> foreground,
1862 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
1863 sk_sp<SkImageFilter> arithmetic(
1864 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
1865 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1866 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001867 SkImageFilter::kForward_MapDirection, nullptr);
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001868 REPORTER_ASSERT(reporter, expected == bounds);
1869}
1870
1871static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1872 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1873 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1874 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1875 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1876
1877 SkIRect union_rect = background_rect;
1878 union_rect.join(foreground_rect);
1879 SkIRect intersection = background_rect;
1880 intersection.intersect(foreground_rect);
1881
1882 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1883 SkIRect::MakeEmpty());
1884 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
1885 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
1886 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
1887 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
1888 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
1889 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
1890 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
1891 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1892 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
1893 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
1894 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
1895 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
1896 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
1897 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
1898 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
1899
1900 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
1901 // regardless of inputs because the filter affects the whole crop area.
1902 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1903 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
1904 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
1905 SkIRect::MakeEmpty());
1906 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
1907 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
1908 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
1909 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
1910 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
1911 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
1912 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
1913 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
1914 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
1915 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
1916 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
1917 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
1918 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
1919 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
1920 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
1921}
1922
Xianzhu Wangb4496662017-09-25 10:26:40 -07001923// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001924DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1925 test_arithmetic_combinations(reporter, 1);
1926 test_arithmetic_combinations(reporter, 0.5);
1927}
Xianzhu Wangb4496662017-09-25 10:26:40 -07001928
1929// Test SkImageSource::filterBounds.
1930DEF_TEST(ImageSourceBounds, reporter) {
1931 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
1932 // Default src and dst rects.
1933 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
1934 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
1935 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
1936 REPORTER_ASSERT(reporter,
1937 imageBounds == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001938 SkImageFilter::kForward_MapDirection,
1939 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001940 REPORTER_ASSERT(reporter,
1941 input == source1->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001942 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001943 SkMatrix scale(SkMatrix::MakeScale(2));
1944 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
1945 REPORTER_ASSERT(reporter,
1946 scaledBounds == source1->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04001947 SkImageFilter::kForward_MapDirection,
1948 nullptr));
1949 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
1950 SkImageFilter::kReverse_MapDirection,
1951 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001952
1953 // Specified src and dst rects.
1954 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
1955 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
1956 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
1957 REPORTER_ASSERT(reporter,
1958 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001959 SkImageFilter::kForward_MapDirection,
1960 nullptr));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001961 REPORTER_ASSERT(reporter,
1962 input == source2->filterBounds(input, SkMatrix::I(),
Robert Phillips12078432018-05-17 11:17:39 -04001963 SkImageFilter::kReverse_MapDirection, &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001964 scale.mapRect(&dst);
1965 scale.mapRect(&src);
1966 REPORTER_ASSERT(reporter,
1967 dst.roundOut() == source2->filterBounds(input, scale,
Robert Phillips12078432018-05-17 11:17:39 -04001968 SkImageFilter::kForward_MapDirection,
1969 nullptr));
1970 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
1971 SkImageFilter::kReverse_MapDirection,
1972 &input));
Xianzhu Wangb4496662017-09-25 10:26:40 -07001973}
Robert Phillips12078432018-05-17 11:17:39 -04001974