blob: db269f00e83981b70a54c77b6c2a3bb24df8cf3b [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
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07008#include "SkArithmeticImageFilter.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +00009#include "SkBitmap.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000010#include "SkBlurImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000011#include "SkCanvas.h"
12#include "SkColorFilterImageFilter.h"
13#include "SkColorMatrixFilter.h"
Florin Malita08252ec2017-07-06 12:48:15 -040014#include "SkColorSpaceXformer.h"
ajuma5788faa2015-02-13 09:05:47 -080015#include "SkComposeImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000016#include "SkDisplacementMapEffect.h"
17#include "SkDropShadowImageFilter.h"
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +000018#include "SkFlattenableSerialization.h"
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +000019#include "SkGradientShader.h"
fmalita5598b632015-09-15 11:26:13 -070020#include "SkImage.h"
fmalitacd56f812015-09-14 13:31:18 -070021#include "SkImageSource.h"
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +000022#include "SkLightingImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000023#include "SkMatrixConvolutionImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000024#include "SkMergeImageFilter.h"
25#include "SkMorphologyImageFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000026#include "SkOffsetImageFilter.h"
ajuma77b6ba32016-01-08 14:58:35 -080027#include "SkPaintImageFilter.h"
senorblanco8f3937d2014-10-29 12:36:32 -070028#include "SkPerlinNoiseShader.h"
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000029#include "SkPicture.h"
senorblanco@chromium.org910702b2014-05-30 20:36:15 +000030#include "SkPictureImageFilter.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000031#include "SkPictureRecorder.h"
robertphillips3d32d762015-07-13 13:16:44 -070032#include "SkPoint3.h"
halcanary97d2c0a2014-08-19 06:27:53 -070033#include "SkReadBuffer.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000034#include "SkRect.h"
robertphillips4418dba2016-03-07 12:45:14 -080035#include "SkSpecialImage.h"
36#include "SkSpecialSurface.h"
fmalitacd56f812015-09-14 13:31:18 -070037#include "SkSurface.h"
senorblanco0abdf762015-08-20 11:10:41 -070038#include "SkTableColorFilter.h"
senorblanco@chromium.org6776b822014-01-03 21:48:22 +000039#include "SkTileImageFilter.h"
40#include "SkXfermodeImageFilter.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000041#include "Test.h"
Mike Reed5a625e02017-08-08 15:48:54 -040042#include "sk_tool_utils.h"
senorblanco@chromium.org194d7752013-07-24 22:19:24 +000043
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000044#if SK_SUPPORT_GPU
kkinnunen15302832015-12-01 04:35:26 -080045#include "GrContext.h"
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +000046#endif
47
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
robertphillipsf3f5bad2014-12-19 13:49:15 -080059 SK_TO_STRING_OVERRIDE()
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000060 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
61
62protected:
robertphillips4ba94e22016-04-04 12:07:47 -070063 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source, const Context& ctx,
64 SkIPoint* offset) const override {
robertphillips43c2ad42016-04-04 05:05:11 -070065 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
robertphillips4ba94e22016-04-04 12:07:47 -070066 offset->fX = offset->fY = 0;
67 return sk_ref_sp<SkSpecialImage>(source);
robertphillips43c2ad42016-04-04 05:05:11 -070068 }
Matt Sarett62745a82017-04-17 11:57:29 -040069 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
70 return sk_ref_sp(const_cast<MatrixTestImageFilter*>(this));
71 }
robertphillips43c2ad42016-04-04 05:05:11 -070072
mtklein36352bf2015-03-25 18:17:31 -070073 void flatten(SkWriteBuffer& buffer) const override {
brianosman18f13f32016-05-02 07:51:08 -070074 SkDEBUGFAIL("Should never get here");
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000075 }
76
77private:
robertphillips43c2ad42016-04-04 05:05:11 -070078 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
79 : INHERITED(nullptr, 0, nullptr)
80 , fReporter(reporter)
81 , fExpectedMatrix(expectedMatrix) {
82 }
83
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000084 skiatest::Reporter* fReporter;
85 SkMatrix fExpectedMatrix;
mtklein3f3b3d02014-12-01 11:47:08 -080086
reed9fa60da2014-08-21 07:59:51 -070087 typedef SkImageFilter INHERITED;
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +000088};
89
senorblanco6a93fa12016-04-05 04:43:45 -070090class FailImageFilter : public SkImageFilter {
91public:
robertphillips6b134732016-04-15 09:58:37 -070092 FailImageFilter() : SkImageFilter(nullptr, 0, nullptr) { }
senorblanco6a93fa12016-04-05 04:43:45 -070093
94 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* source,
95 const Context& ctx,
96 SkIPoint* offset) const override {
97 return nullptr;
98 }
Matt Sarett62745a82017-04-17 11:57:29 -040099 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
100 return nullptr;
101 }
senorblanco6a93fa12016-04-05 04:43:45 -0700102
103 SK_TO_STRING_OVERRIDE()
104 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(FailImageFilter)
105
106private:
107 typedef SkImageFilter INHERITED;
108};
109
110sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
111 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
112 return sk_sp<SkFlattenable>(new FailImageFilter());
113}
114
115#ifndef SK_IGNORE_TO_STRING
116void FailImageFilter::toString(SkString* str) const {
117 str->appendf("FailImageFilter: (");
118 str->append(")");
119}
120#endif
121
senorblanco297f7ce2016-03-23 13:44:26 -0700122void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
123 SkScalar x = SkIntToScalar(width / 2);
124 SkScalar y = SkIntToScalar(height / 2);
125 SkScalar radius = SkMinScalar(x, y) * 0.8f;
126 canvas->clear(0x00000000);
127 SkColor colors[2];
128 colors[0] = SK_ColorWHITE;
129 colors[1] = SK_ColorBLACK;
130 sk_sp<SkShader> shader(
131 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
132 SkShader::kClamp_TileMode)
133 );
134 SkPaint paint;
135 paint.setShader(shader);
136 canvas->drawCircle(x, y, radius, paint);
137}
138
139SkBitmap make_gradient_circle(int width, int height) {
140 SkBitmap bitmap;
141 bitmap.allocN32Pixels(width, height);
142 SkCanvas canvas(bitmap);
143 draw_gradient_circle(&canvas, width, height);
144 return bitmap;
145}
146
147class FilterList {
148public:
robertphillipsfc11b0a2016-04-05 09:09:36 -0700149 FilterList(sk_sp<SkImageFilter> input, const SkImageFilter::CropRect* cropRect = nullptr) {
senorblanco297f7ce2016-03-23 13:44:26 -0700150 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
senorblanco297f7ce2016-03-23 13:44:26 -0700151 const SkScalar five = SkIntToScalar(5);
152
robertphillips6e7025a2016-04-04 04:31:25 -0700153 {
154 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorRED,
Mike Reed7d954ad2016-10-28 15:42:34 -0400155 SkBlendMode::kSrcIn));
senorblanco297f7ce2016-03-23 13:44:26 -0700156
robertphillips6e7025a2016-04-04 04:31:25 -0700157 this->addFilter("color filter",
robertphillips12fa47d2016-04-08 16:28:09 -0700158 SkColorFilterImageFilter::Make(std::move(cf), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700159 }
senorblanco297f7ce2016-03-23 13:44:26 -0700160
robertphillips6e7025a2016-04-04 04:31:25 -0700161 {
162 sk_sp<SkImage> gradientImage(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
163 sk_sp<SkImageFilter> gradientSource(SkImageSource::Make(std::move(gradientImage)));
senorblanco297f7ce2016-03-23 13:44:26 -0700164
liyuqianbfebe222016-11-14 11:17:16 -0800165 this->addFilter("displacement map",
robertphillipsbfe11fc2016-04-15 07:17:36 -0700166 SkDisplacementMapEffect::Make(SkDisplacementMapEffect::kR_ChannelSelectorType,
167 SkDisplacementMapEffect::kB_ChannelSelectorType,
168 20.0f,
169 std::move(gradientSource), input, cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700170 }
senorblanco297f7ce2016-03-23 13:44:26 -0700171
robertphillips6e7025a2016-04-04 04:31:25 -0700172 this->addFilter("blur", SkBlurImageFilter::Make(SK_Scalar1,
173 SK_Scalar1,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700174 input,
robertphillips12fa47d2016-04-08 16:28:09 -0700175 cropRect));
robertphillipsc4169122016-04-06 08:40:59 -0700176 this->addFilter("drop shadow", SkDropShadowImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700177 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN,
robertphillipsfc11b0a2016-04-05 09:09:36 -0700178 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillips12fa47d2016-04-08 16:28:09 -0700179 input, cropRect));
180 this->addFilter("diffuse lighting",
181 SkLightingImageFilter::MakePointLitDiffuse(location, SK_ColorGREEN, 0, 0,
182 input, cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700183 this->addFilter("specular lighting",
robertphillips12fa47d2016-04-08 16:28:09 -0700184 SkLightingImageFilter::MakePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0,
185 input, cropRect));
186 {
187 SkScalar kernel[9] = {
188 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
189 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
190 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
191 };
192 const SkISize kernelSize = SkISize::Make(3, 3);
193 const SkScalar gain = SK_Scalar1, bias = 0;
194
195 this->addFilter("matrix convolution",
robertphillipsef6a47b2016-04-08 08:01:20 -0700196 SkMatrixConvolutionImageFilter::Make(
senorblanco297f7ce2016-03-23 13:44:26 -0700197 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
robertphillipsfc11b0a2016-04-05 09:09:36 -0700198 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false,
robertphillips12fa47d2016-04-08 16:28:09 -0700199 input, cropRect));
200 }
201
Mike Reed0bdaf052017-06-18 23:35:57 -0400202 this->addFilter("merge", SkMergeImageFilter::Make(input, input, cropRect));
robertphillips12fa47d2016-04-08 16:28:09 -0700203
robertphillips6e7025a2016-04-04 04:31:25 -0700204 {
205 SkPaint greenColorShaderPaint;
206 greenColorShaderPaint.setShader(SkShader::MakeColorShader(SK_ColorGREEN));
207
208 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64));
209 sk_sp<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Make(greenColorShaderPaint,
210 &leftSideCropRect));
211 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64));
212 sk_sp<SkImageFilter> paintFilterRight(SkPaintImageFilter::Make(greenColorShaderPaint,
213 &rightSideCropRect));
214
215
216 this->addFilter("merge with disjoint inputs", SkMergeImageFilter::Make(
Mike Reed0bdaf052017-06-18 23:35:57 -0400217 std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700218 }
219
senorblanco297f7ce2016-03-23 13:44:26 -0700220 this->addFilter("offset",
robertphillipsfc11b0a2016-04-05 09:09:36 -0700221 SkOffsetImageFilter::Make(SK_Scalar1, SK_Scalar1, input,
robertphillips12fa47d2016-04-08 16:28:09 -0700222 cropRect));
223 this->addFilter("dilate", SkDilateImageFilter::Make(3, 2, input, cropRect));
224 this->addFilter("erode", SkErodeImageFilter::Make(2, 3, input, cropRect));
robertphillips534c2702016-04-15 07:57:40 -0700225 this->addFilter("tile", SkTileImageFilter::Make(
226 SkRect::MakeXYWH(0, 0, 50, 50),
227 cropRect ? cropRect->rect() : SkRect::MakeXYWH(0, 0, 100, 100),
228 input));
robertphillips6e7025a2016-04-04 04:31:25 -0700229
robertphillips12fa47d2016-04-08 16:28:09 -0700230 if (!cropRect) {
231 SkMatrix matrix;
232
233 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
234 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
235
236 this->addFilter("matrix",
237 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, input));
238 }
robertphillips6e7025a2016-04-04 04:31:25 -0700239 {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700240 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(five, five, input));
robertphillips6e7025a2016-04-04 04:31:25 -0700241
242 this->addFilter("blur and offset", SkOffsetImageFilter::Make(five, five,
243 std::move(blur),
robertphillips12fa47d2016-04-08 16:28:09 -0700244 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700245 }
246 {
robertphillips6e7025a2016-04-04 04:31:25 -0700247 SkPictureRecorder recorder;
Mike Klein26eb16f2017-04-10 09:50:25 -0400248 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
robertphillips6e7025a2016-04-04 04:31:25 -0700249
250 SkPaint greenPaint;
251 greenPaint.setColor(SK_ColorGREEN);
252 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
253 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
254 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(std::move(picture)));
255
256 this->addFilter("picture and blur", SkBlurImageFilter::Make(five, five,
257 std::move(pictureFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700258 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700259 }
260 {
261 SkPaint paint;
262 paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
263 sk_sp<SkImageFilter> paintFilter(SkPaintImageFilter::Make(paint));
264
265 this->addFilter("paint and blur", SkBlurImageFilter::Make(five, five,
266 std::move(paintFilter),
robertphillips12fa47d2016-04-08 16:28:09 -0700267 cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700268 }
reed374772b2016-10-05 17:33:02 -0700269 this->addFilter("xfermode", SkXfermodeImageFilter::Make(SkBlendMode::kSrc, input, input,
270 cropRect));
senorblanco297f7ce2016-03-23 13:44:26 -0700271 }
272 int count() const { return fFilters.count(); }
273 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
274 const char* getName(int index) const { return fFilters[index].fName; }
275private:
276 struct Filter {
robertphillips12fa47d2016-04-08 16:28:09 -0700277 Filter() : fName(nullptr) {}
278 Filter(const char* name, sk_sp<SkImageFilter> filter)
279 : fName(name)
280 , fFilter(std::move(filter)) {
281 }
senorblanco297f7ce2016-03-23 13:44:26 -0700282 const char* fName;
283 sk_sp<SkImageFilter> fFilter;
284 };
robertphillips12fa47d2016-04-08 16:28:09 -0700285 void addFilter(const char* name, sk_sp<SkImageFilter> filter) {
286 fFilters.push_back(Filter(name, std::move(filter)));
senorblanco297f7ce2016-03-23 13:44:26 -0700287 }
288
289 SkTArray<Filter> fFilters;
290};
291
Xianzhu Wang0fa353c2017-08-25 16:27:04 -0700292class FixedBoundsImageFilter : public SkImageFilter {
293public:
294 FixedBoundsImageFilter(const SkIRect& bounds)
295 : SkImageFilter(nullptr, 0, nullptr), fBounds(bounds) {}
296
297private:
298#ifndef SK_IGNORE_TO_STRING
299 void toString(SkString*) const override {}
300#endif
301 Factory getFactory() const override { return nullptr; }
302
303 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
304 SkIPoint* offset) const override {
305 return nullptr;
306 }
307 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override { return nullptr; }
308
309 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&, MapDirection) const override {
310 return fBounds;
311 }
312
313 SkIRect fBounds;
314};
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +0000315}
316
reed60c9b582016-04-03 09:11:13 -0700317sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
brianosman18f13f32016-05-02 07:51:08 -0700318 SkDEBUGFAIL("Should never get here");
319 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700320}
321
robertphillipsf3f5bad2014-12-19 13:49:15 -0800322#ifndef SK_IGNORE_TO_STRING
323void MatrixTestImageFilter::toString(SkString* str) const {
324 str->appendf("MatrixTestImageFilter: (");
325 str->append(")");
326}
327#endif
328
reed9ce9d672016-03-17 10:51:11 -0700329static sk_sp<SkImage> make_small_image() {
reede8f30622016-03-23 18:59:25 -0700330 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
fmalita5598b632015-09-15 11:26:13 -0700331 SkCanvas* canvas = surface->getCanvas();
332 canvas->clear(0x00000000);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000333 SkPaint darkPaint;
334 darkPaint.setColor(0xFF804020);
335 SkPaint lightPaint;
336 lightPaint.setColor(0xFF244484);
337 const int i = kBitmapSize / 4;
338 for (int y = 0; y < kBitmapSize; y += i) {
339 for (int x = 0; x < kBitmapSize; x += i) {
fmalita5598b632015-09-15 11:26:13 -0700340 canvas->save();
341 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
342 canvas->drawRect(SkRect::MakeXYWH(0, 0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000343 SkIntToScalar(i),
344 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700345 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000346 0,
347 SkIntToScalar(i),
348 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700349 canvas->drawRect(SkRect::MakeXYWH(0,
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000350 SkIntToScalar(i),
351 SkIntToScalar(i),
352 SkIntToScalar(i)), lightPaint);
fmalita5598b632015-09-15 11:26:13 -0700353 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000354 SkIntToScalar(i),
355 SkIntToScalar(i),
356 SkIntToScalar(i)), darkPaint);
fmalita5598b632015-09-15 11:26:13 -0700357 canvas->restore();
commit-bot@chromium.org4b681bc2013-09-13 12:40:02 +0000358 }
359 }
fmalita5598b632015-09-15 11:26:13 -0700360
reed9ce9d672016-03-17 10:51:11 -0700361 return surface->makeImageSnapshot();
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000362}
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000363
robertphillips5605b562016-04-05 11:50:42 -0700364static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000365 SkScalar s = amount;
366 SkScalar matrix[20] = { s, 0, 0, 0, 0,
367 0, s, 0, 0, 0,
368 0, 0, s, 0, 0,
369 0, 0, 0, s, 0 };
robertphillips5605b562016-04-05 11:50:42 -0700370 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
371 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000372}
373
robertphillips5605b562016-04-05 11:50:42 -0700374static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
375 const SkImageFilter::CropRect* cropRect) {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000376 SkScalar matrix[20];
377 memset(matrix, 0, 20 * sizeof(SkScalar));
378 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
379 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
380 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
381 matrix[18] = 1.0f;
robertphillips5605b562016-04-05 11:50:42 -0700382 sk_sp<SkColorFilter> filter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
383 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000384}
385
robertphillips5605b562016-04-05 11:50:42 -0700386static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input,
387 const SkImageFilter::CropRect* cropRect) {
388 sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
Mike Reed7d954ad2016-10-28 15:42:34 -0400389 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -0700390 return SkColorFilterImageFilter::Make(std::move(filter), std::move(input), cropRect);
reedcedc36f2015-03-08 04:42:52 -0700391}
392
robertphillips3e302272016-04-20 11:48:36 -0700393static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
robertphillipsc91fd342016-04-25 12:32:54 -0700394#if SK_SUPPORT_GPU
robertphillips4418dba2016-03-07 12:45:14 -0800395 if (context) {
robertphillips4df16562016-04-28 15:09:34 -0700396 return SkSpecialSurface::MakeRenderTarget(context,
397 widthHeight, widthHeight,
Brian Osman777b5632016-10-14 09:16:21 -0400398 kRGBA_8888_GrPixelConfig, nullptr);
robertphillipsc91fd342016-04-25 12:32:54 -0700399 } else
400#endif
401 {
robertphillips4418dba2016-03-07 12:45:14 -0800402 const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
403 kOpaque_SkAlphaType);
robertphillips3e302272016-04-20 11:48:36 -0700404 return SkSpecialSurface::MakeRaster(info);
robertphillips4418dba2016-03-07 12:45:14 -0800405 }
senorblancobf680c32016-03-16 16:15:53 -0700406}
407
senorblanco5878dbd2016-05-19 14:50:29 -0700408static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
409 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
410#if SK_SUPPORT_GPU
411 if (context) {
412 return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
413 } else
414#endif
415 {
416 return SkSurface::MakeRaster(info);
417 }
418}
419
robertphillips3e302272016-04-20 11:48:36 -0700420static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
421 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
robertphillips4418dba2016-03-07 12:45:14 -0800422
423 SkASSERT(surf);
424
425 SkCanvas* canvas = surf->getCanvas();
426 SkASSERT(canvas);
427
428 canvas->clear(0x0);
429
robertphillips37bd7c32016-03-17 14:31:39 -0700430 return surf->makeImageSnapshot();
robertphillips4418dba2016-03-07 12:45:14 -0800431}
432
433
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000434DEF_TEST(ImageFilter, reporter) {
435 {
reedcedc36f2015-03-08 04:42:52 -0700436 // Check that two non-clipping color-matrice-filters concatenate into a single filter.
robertphillips5605b562016-04-05 11:50:42 -0700437 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, nullptr));
438 sk_sp<SkImageFilter> quarterBrightness(make_scale(0.5f, std::move(halfBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700439 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700440 SkColorFilter* cf;
441 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700442 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700443 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000444 }
445
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000446 {
reedcedc36f2015-03-08 04:42:52 -0700447 // Check that a clipping color-matrice-filter followed by a color-matrice-filters
448 // concatenates into a single filter, but not a matrixfilter (due to clamping).
robertphillips5605b562016-04-05 11:50:42 -0700449 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
450 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
halcanary96fcdcc2015-08-27 07:41:13 -0700451 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
reedcedc36f2015-03-08 04:42:52 -0700452 SkColorFilter* cf;
453 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
halcanary96fcdcc2015-08-27 07:41:13 -0700454 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700455 cf->unref();
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000456 }
457
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000458 {
459 // Check that a color filter image filter without a crop rect can be
460 // expressed as a color filter.
robertphillips5605b562016-04-05 11:50:42 -0700461 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700462 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000463 }
mtklein2afbe232016-02-07 12:23:10 -0800464
reedcedc36f2015-03-08 04:42:52 -0700465 {
466 // Check that a colorfilterimage filter without a crop rect but with an input
467 // that is another colorfilterimage can be expressed as a colorfilter (composed).
robertphillips5605b562016-04-05 11:50:42 -0700468 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
469 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -0700470 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
reedcedc36f2015-03-08 04:42:52 -0700471 }
472
473 {
474 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
475 // can build the DAG and won't assert if we call asColorFilter.
robertphillips5605b562016-04-05 11:50:42 -0700476 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
reedcedc36f2015-03-08 04:42:52 -0700477 const int kWayTooManyForComposeColorFilter = 100;
478 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
robertphillips5605b562016-04-05 11:50:42 -0700479 filter = make_blue(filter, nullptr);
reedcedc36f2015-03-08 04:42:52 -0700480 // the first few of these will succeed, but after we hit the internal limit,
481 // it will then return false.
halcanary96fcdcc2015-08-27 07:41:13 -0700482 (void)filter->asColorFilter(nullptr);
reedcedc36f2015-03-08 04:42:52 -0700483 }
484 }
reed5c518a82015-03-05 14:47:29 -0800485
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000486 {
487 // Check that a color filter image filter with a crop rect cannot
488 // be expressed as a color filter.
489 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
robertphillips5605b562016-04-05 11:50:42 -0700490 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
halcanary96fcdcc2015-08-27 07:41:13 -0700491 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000492 }
493
494 {
senorblanco3df05012014-07-03 11:13:09 -0700495 // Check that two non-commutative matrices are concatenated in
496 // the correct order.
497 SkScalar blueToRedMatrix[20] = { 0 };
498 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
499 SkScalar redToGreenMatrix[20] = { 0 };
500 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
robertphillips5605b562016-04-05 11:50:42 -0700501 sk_sp<SkColorFilter> blueToRed(SkColorFilter::MakeMatrixFilterRowMajor255(blueToRedMatrix));
502 sk_sp<SkImageFilter> filter1(SkColorFilterImageFilter::Make(std::move(blueToRed),
503 nullptr));
504 sk_sp<SkColorFilter> redToGreen(SkColorFilter::MakeMatrixFilterRowMajor255(redToGreenMatrix));
505 sk_sp<SkImageFilter> filter2(SkColorFilterImageFilter::Make(std::move(redToGreen),
506 std::move(filter1)));
senorblanco3df05012014-07-03 11:13:09 -0700507
508 SkBitmap result;
509 result.allocN32Pixels(kBitmapSize, kBitmapSize);
510
511 SkPaint paint;
512 paint.setColor(SK_ColorBLUE);
robertphillips5605b562016-04-05 11:50:42 -0700513 paint.setImageFilter(std::move(filter2));
senorblanco3df05012014-07-03 11:13:09 -0700514 SkCanvas canvas(result);
515 canvas.clear(0x0);
516 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
517 canvas.drawRect(rect, paint);
518 uint32_t pixel = *result.getAddr32(0, 0);
519 // The result here should be green, since we have effectively shifted blue to green.
520 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
521 }
522
523 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000524 // Tests pass by not asserting
reed9ce9d672016-03-17 10:51:11 -0700525 sk_sp<SkImage> image(make_small_image());
fmalita5598b632015-09-15 11:26:13 -0700526 SkBitmap result;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +0000527 result.allocN32Pixels(kBitmapSize, kBitmapSize);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000528
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000529 {
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000530 // This tests for :
531 // 1 ) location at (0,0,1)
robertphillips3d32d762015-07-13 13:16:44 -0700532 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000533 // 2 ) location and target at same value
robertphillips3d32d762015-07-13 13:16:44 -0700534 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000535 // 3 ) large negative specular exponent value
536 SkScalar specularExponent = -1000;
537
robertphillips549c8992016-04-01 09:28:51 -0700538 sk_sp<SkImageFilter> bmSrc(SkImageSource::Make(std::move(image)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000539 SkPaint paint;
robertphillips12fa47d2016-04-08 16:28:09 -0700540 paint.setImageFilter(SkLightingImageFilter::MakeSpotLitSpecular(
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000541 location, target, specularExponent, 180,
542 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
robertphillips12fa47d2016-04-08 16:28:09 -0700543 std::move(bmSrc)));
tfarina@chromium.org9f9d5822013-12-18 22:15:12 +0000544 SkCanvas canvas(result);
545 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
546 SkIntToScalar(kBitmapSize));
547 canvas.drawRect(r, paint);
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000548 }
senorblanco@chromium.org194d7752013-07-24 22:19:24 +0000549 }
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000550}
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000551
robertphillips3e302272016-04-20 11:48:36 -0700552static void test_crop_rects(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800553 GrContext* context) {
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000554 // Check that all filters offset to their absolute crop rect,
555 // unaffected by the input crop rect.
556 // Tests pass by not asserting.
robertphillips3e302272016-04-20 11:48:36 -0700557 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillips4418dba2016-03-07 12:45:14 -0800558 SkASSERT(srcImg);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000559
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000560 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
561 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
robertphillipsfc11b0a2016-04-05 09:09:36 -0700562 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000563
robertphillipsfc11b0a2016-04-05 09:09:36 -0700564 FilterList filters(input, &cropRect);
senorblanco@chromium.org6776b822014-01-03 21:48:22 +0000565
senorblanco297f7ce2016-03-23 13:44:26 -0700566 for (int i = 0; i < filters.count(); ++i) {
567 SkImageFilter* filter = filters.getFilter(i);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000568 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700569 SkImageFilter::OutputProperties noColorSpace(nullptr);
570 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips2302de92016-03-24 07:26:32 -0700571 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
senorblanco297f7ce2016-03-23 13:44:26 -0700572 REPORTER_ASSERT_MESSAGE(reporter, resultImg, filters.getName(i));
573 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +0000574 }
575}
576
robertphillips3e302272016-04-20 11:48:36 -0700577static void test_negative_blur_sigma(skiatest::Reporter* reporter,
robertphillips4418dba2016-03-07 12:45:14 -0800578 GrContext* context) {
senorblanco32673b92014-09-09 09:15:04 -0700579 // Check that SkBlurImageFilter will accept a negative sigma, either in
580 // the given arguments or after CTM application.
reed5ea95df2015-10-06 14:05:32 -0700581 const int width = 32, height = 32;
582 const SkScalar five = SkIntToScalar(5);
senorblanco32673b92014-09-09 09:15:04 -0700583
robertphillips6e7025a2016-04-04 04:31:25 -0700584 sk_sp<SkImageFilter> positiveFilter(SkBlurImageFilter::Make(five, five, nullptr));
585 sk_sp<SkImageFilter> negativeFilter(SkBlurImageFilter::Make(-five, five, nullptr));
senorblanco32673b92014-09-09 09:15:04 -0700586
587 SkBitmap gradient = make_gradient_circle(width, height);
robertphillips3e302272016-04-20 11:48:36 -0700588 sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(width, height),
robertphillips37bd7c32016-03-17 14:31:39 -0700589 gradient));
robertphillips4418dba2016-03-07 12:45:14 -0800590
senorblanco32673b92014-09-09 09:15:04 -0700591 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700592 SkImageFilter::OutputProperties noColorSpace(nullptr);
593 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800594
robertphillips2302de92016-03-24 07:26:32 -0700595 sk_sp<SkSpecialImage> positiveResult1(positiveFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800596 REPORTER_ASSERT(reporter, positiveResult1);
597
robertphillips2302de92016-03-24 07:26:32 -0700598 sk_sp<SkSpecialImage> negativeResult1(negativeFilter->filterImage(imgSrc.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800599 REPORTER_ASSERT(reporter, negativeResult1);
600
senorblanco32673b92014-09-09 09:15:04 -0700601 SkMatrix negativeScale;
602 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
brianosman2a75e5d2016-09-22 07:15:37 -0700603 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
604 noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -0800605
robertphillips2302de92016-03-24 07:26:32 -0700606 sk_sp<SkSpecialImage> negativeResult2(positiveFilter->filterImage(imgSrc.get(),
607 negativeCTX,
608 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800609 REPORTER_ASSERT(reporter, negativeResult2);
610
robertphillips2302de92016-03-24 07:26:32 -0700611 sk_sp<SkSpecialImage> positiveResult2(negativeFilter->filterImage(imgSrc.get(),
612 negativeCTX,
613 &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800614 REPORTER_ASSERT(reporter, positiveResult2);
615
616
617 SkBitmap positiveResultBM1, positiveResultBM2;
618 SkBitmap negativeResultBM1, negativeResultBM2;
619
robertphillips64612512016-04-08 12:10:42 -0700620 REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
621 REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
622 REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
623 REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
robertphillips4418dba2016-03-07 12:45:14 -0800624
senorblanco32673b92014-09-09 09:15:04 -0700625 for (int y = 0; y < height; y++) {
robertphillips4418dba2016-03-07 12:45:14 -0800626 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
627 negativeResultBM1.getAddr32(0, y),
628 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700629 REPORTER_ASSERT(reporter, !diffs);
630 if (diffs) {
631 break;
632 }
robertphillips4418dba2016-03-07 12:45:14 -0800633 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
634 negativeResultBM2.getAddr32(0, y),
635 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700636 REPORTER_ASSERT(reporter, !diffs);
637 if (diffs) {
638 break;
639 }
robertphillips4418dba2016-03-07 12:45:14 -0800640 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
641 positiveResultBM2.getAddr32(0, y),
642 positiveResultBM1.rowBytes());
senorblanco32673b92014-09-09 09:15:04 -0700643 REPORTER_ASSERT(reporter, !diffs);
644 if (diffs) {
645 break;
646 }
647 }
648}
649
senorblanco21a465d2016-04-11 11:58:39 -0700650DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700651 test_negative_blur_sigma(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800652}
653
654#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700655DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700656 test_negative_blur_sigma(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -0800657}
658#endif
659
robertphillips3e302272016-04-20 11:48:36 -0700660static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
senorblancobf680c32016-03-16 16:15:53 -0700661 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
662 SkImageFilter::CropRect cropRect(SkRect::Make(SkIRect::MakeXYWH(5, 0, 5, 10)));
robertphillips51a315e2016-03-31 09:05:49 -0700663 sk_sp<SkImageFilter> input(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -0700664 sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(0, 0, std::move(input), &cropRect));
senorblancobf680c32016-03-16 16:15:53 -0700665
robertphillips3e302272016-04-20 11:48:36 -0700666 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
senorblancobf680c32016-03-16 16:15:53 -0700667 surf->getCanvas()->clear(SK_ColorGREEN);
robertphillips37bd7c32016-03-17 14:31:39 -0700668 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
senorblancobf680c32016-03-16 16:15:53 -0700669
670 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -0700671 SkImageFilter::OutputProperties noColorSpace(nullptr);
672 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr, noColorSpace);
senorblancobf680c32016-03-16 16:15:53 -0700673
robertphillips2302de92016-03-24 07:26:32 -0700674 sk_sp<SkSpecialImage> result(filter->filterImage(image.get(), ctx, &offset));
senorblancobf680c32016-03-16 16:15:53 -0700675 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
676 REPORTER_ASSERT(reporter, result);
677 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
678
679 SkBitmap resultBM;
680
robertphillips64612512016-04-08 12:10:42 -0700681 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblancobf680c32016-03-16 16:15:53 -0700682
senorblancobf680c32016-03-16 16:15:53 -0700683 for (int y = 0; y < resultBM.height(); y++) {
684 for (int x = 0; x < resultBM.width(); x++) {
685 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
686 REPORTER_ASSERT(reporter, !diff);
687 if (diff) {
688 break;
689 }
690 }
691 }
692}
693
senorblanco21a465d2016-04-11 11:58:39 -0700694DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700695 test_zero_blur_sigma(reporter, nullptr);
senorblancobf680c32016-03-16 16:15:53 -0700696}
697
698#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700699DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700700 test_zero_blur_sigma(reporter, ctxInfo.grContext());
senorblancobf680c32016-03-16 16:15:53 -0700701}
702#endif
703
senorblanco6a93fa12016-04-05 04:43:45 -0700704
705// Tests that, even when an upstream filter has returned null (due to failure or clipping), a
706// downstream filter that affects transparent black still does so even with a nullptr input.
robertphillips3e302272016-04-20 11:48:36 -0700707static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
senorblanco6a93fa12016-04-05 04:43:45 -0700708 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
robertphillips3e302272016-04-20 11:48:36 -0700709 sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
brianosman2a75e5d2016-09-22 07:15:37 -0700710 SkImageFilter::OutputProperties noColorSpace(nullptr);
711 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr, noColorSpace);
Mike Reed7d954ad2016-10-28 15:42:34 -0400712 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN, SkBlendMode::kSrc));
senorblanco6a93fa12016-04-05 04:43:45 -0700713 SkASSERT(green->affectsTransparentBlack());
robertphillips5605b562016-04-05 11:50:42 -0700714 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(std::move(green),
715 std::move(failFilter)));
senorblanco6a93fa12016-04-05 04:43:45 -0700716 SkIPoint offset;
717 sk_sp<SkSpecialImage> result(greenFilter->filterImage(source.get(), ctx, &offset));
718 REPORTER_ASSERT(reporter, nullptr != result.get());
719 if (result.get()) {
720 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -0700721 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
senorblanco6a93fa12016-04-05 04:43:45 -0700722 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
723 }
724}
725
726DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700727 test_fail_affects_transparent_black(reporter, nullptr);
senorblanco6a93fa12016-04-05 04:43:45 -0700728}
729
730#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -0700731DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -0700732 test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
senorblanco6a93fa12016-04-05 04:43:45 -0700733}
734#endif
735
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000736DEF_TEST(ImageFilterDrawTiled, reporter) {
737 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
738 // match the same filters drawn with a single full-canvas bitmap draw.
739 // Tests pass by not asserting.
740
robertphillipsfc11b0a2016-04-05 09:09:36 -0700741 FilterList filters(nullptr);
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000742
743 SkBitmap untiledResult, tiledResult;
reed5ea95df2015-10-06 14:05:32 -0700744 const int width = 64, height = 64;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000745 untiledResult.allocN32Pixels(width, height);
746 tiledResult.allocN32Pixels(width, height);
747 SkCanvas tiledCanvas(tiledResult);
748 SkCanvas untiledCanvas(untiledResult);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000749 int tileSize = 8;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000750
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000751 for (int scale = 1; scale <= 2; ++scale) {
senorblanco297f7ce2016-03-23 13:44:26 -0700752 for (int i = 0; i < filters.count(); ++i) {
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000753 tiledCanvas.clear(0);
754 untiledCanvas.clear(0);
755 SkPaint paint;
Mike Reed5e257172016-11-01 11:22:05 -0400756 paint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000757 paint.setTextSize(SkIntToScalar(height));
758 paint.setColor(SK_ColorWHITE);
759 SkString str;
760 const char* text = "ABC";
761 SkScalar ypos = SkIntToScalar(height);
762 untiledCanvas.save();
763 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400764 untiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000765 untiledCanvas.restore();
766 for (int y = 0; y < height; y += tileSize) {
767 for (int x = 0; x < width; x += tileSize) {
768 tiledCanvas.save();
769 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
770 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
Cary Clark2a475ea2017-04-28 15:35:12 -0400771 tiledCanvas.drawString(text, 0, ypos, paint);
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000772 tiledCanvas.restore();
773 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000774 }
senorblanco@chromium.orgd4db6572014-05-07 20:00:04 +0000775 untiledCanvas.flush();
776 tiledCanvas.flush();
Mike Reed34042072017-08-08 16:29:22 -0400777 if (!sk_tool_utils::equal_pixels(untiledResult, tiledResult, 1)) {
Mike Reed5a625e02017-08-08 15:48:54 -0400778 REPORTER_ASSERT_MESSAGE(reporter, false, filters.getName(i));
779 break;
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000780 }
781 }
782 }
senorblanco@chromium.org0a5c2332014-04-29 15:20:39 +0000783}
784
mtklein3f3b3d02014-12-01 11:47:08 -0800785static void draw_saveLayer_picture(int width, int height, int tileSize,
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700786 SkBBHFactory* factory, SkBitmap* result) {
mtkleind910f542014-08-22 09:06:34 -0700787
788 SkMatrix matrix;
789 matrix.setTranslate(SkIntToScalar(50), 0);
790
Mike Reed7d954ad2016-10-28 15:42:34 -0400791 sk_sp<SkColorFilter> cf(SkColorFilter::MakeModeFilter(SK_ColorWHITE, SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -0700792 sk_sp<SkImageFilter> cfif(SkColorFilterImageFilter::Make(std::move(cf), nullptr));
robertphillipsae8c9332016-04-05 15:09:00 -0700793 sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
794 kNone_SkFilterQuality,
795 std::move(cfif)));
mtkleind910f542014-08-22 09:06:34 -0700796
797 SkPaint paint;
robertphillips5605b562016-04-05 11:50:42 -0700798 paint.setImageFilter(std::move(imageFilter));
mtkleind910f542014-08-22 09:06:34 -0700799 SkPictureRecorder recorder;
800 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
mtklein3f3b3d02014-12-01 11:47:08 -0800801 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
802 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700803 factory, 0);
mtkleind910f542014-08-22 09:06:34 -0700804 recordingCanvas->translate(-55, 0);
805 recordingCanvas->saveLayer(&bounds, &paint);
806 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -0700807 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
mtkleind910f542014-08-22 09:06:34 -0700808
809 result->allocN32Pixels(width, height);
810 SkCanvas canvas(*result);
811 canvas.clear(0);
812 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
813 canvas.drawPicture(picture1.get());
814}
815
816DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
817 // Check that matrix filter when drawn tiled with BBH exactly
818 // matches the same thing drawn without BBH.
819 // Tests pass by not asserting.
820
821 const int width = 200, height = 200;
822 const int tileSize = 100;
823 SkBitmap result1, result2;
824 SkRTreeFactory factory;
825
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700826 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
halcanary96fcdcc2015-08-27 07:41:13 -0700827 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
mtkleind910f542014-08-22 09:06:34 -0700828
829 for (int y = 0; y < height; y++) {
830 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
831 REPORTER_ASSERT(reporter, !diffs);
832 if (diffs) {
833 break;
834 }
835 }
836}
837
robertphillips6e7025a2016-04-04 04:31:25 -0700838static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
839 return SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1, std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700840}
841
robertphillips6e7025a2016-04-04 04:31:25 -0700842static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
robertphillipsc4169122016-04-06 08:40:59 -0700843 return SkDropShadowImageFilter::Make(
senorblanco1150a6d2014-08-25 12:46:58 -0700844 SkIntToScalar(100), SkIntToScalar(100),
845 SkIntToScalar(10), SkIntToScalar(10),
sugoi234f0362014-10-23 13:59:52 -0700846 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
robertphillipsc4169122016-04-06 08:40:59 -0700847 std::move(input));
senorblanco1150a6d2014-08-25 12:46:58 -0700848}
849
850DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700851 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
852 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700853
854 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
855 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700856 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700857
858 REPORTER_ASSERT(reporter, bounds == expectedBounds);
859}
860
861DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700862 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
863 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700864
865 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
866 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
senorblancoe5e79842016-03-21 14:51:59 -0700867 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700868
869 REPORTER_ASSERT(reporter, bounds == expectedBounds);
870}
871
872DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
robertphillipsfc11b0a2016-04-05 09:09:36 -0700873 sk_sp<SkImageFilter> filter1(SkDilateImageFilter::Make(2, 2, nullptr));
robertphillips6e7025a2016-04-04 04:31:25 -0700874 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
senorblanco1150a6d2014-08-25 12:46:58 -0700875
876 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
877 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
senorblancoe5e79842016-03-21 14:51:59 -0700878 bounds = filter2->filterBounds(bounds, SkMatrix::I());
senorblanco1150a6d2014-08-25 12:46:58 -0700879
880 REPORTER_ASSERT(reporter, bounds == expectedBounds);
881}
882
jbroman203a9932016-07-11 14:07:59 -0700883DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
884 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
885 // (before the CTM). Bounds should be computed correctly in the presence of
886 // a (possibly negative) scale.
887 sk_sp<SkImageFilter> blur(make_blur(nullptr));
888 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
889 {
890 // Uniform scale by 2.
891 SkMatrix scaleMatrix;
892 scaleMatrix.setScale(2, 2);
893 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
894
895 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
896 SkIRect blurBounds = blur->filterBounds(
897 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
898 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
899 SkIRect reverseBlurBounds = blur->filterBounds(
900 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
901 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
902
903 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
904 SkIRect shadowBounds = dropShadow->filterBounds(
905 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
906 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
907 SkIRect expectedReverseShadowBounds =
908 SkIRect::MakeLTRB(-260, -260, 200, 200);
909 SkIRect reverseShadowBounds = dropShadow->filterBounds(
910 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
911 REPORTER_ASSERT(reporter,
912 reverseShadowBounds == expectedReverseShadowBounds);
913 }
914 {
915 // Vertical flip.
916 SkMatrix scaleMatrix;
917 scaleMatrix.setScale(1, -1);
918 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
919
920 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
921 SkIRect blurBounds = blur->filterBounds(
922 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
923 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
924 SkIRect reverseBlurBounds = blur->filterBounds(
925 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
926 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
927
928 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
929 SkIRect shadowBounds = dropShadow->filterBounds(
930 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection);
931 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
932 SkIRect expectedReverseShadowBounds =
933 SkIRect::MakeLTRB(-130, -100, 100, 130);
934 SkIRect reverseShadowBounds = dropShadow->filterBounds(
935 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection);
936 REPORTER_ASSERT(reporter,
937 reverseShadowBounds == expectedReverseShadowBounds);
938 }
939}
940
ajuma5788faa2015-02-13 09:05:47 -0800941DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
robertphillips6e7025a2016-04-04 04:31:25 -0700942 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
943 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
robertphillips491fb172016-03-30 12:32:58 -0700944 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(filter1),
945 std::move(filter2)));
ajuma5788faa2015-02-13 09:05:47 -0800946
947 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
948 SkRect expectedBounds = SkRect::MakeXYWH(
949 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112));
senorblancoe5e79842016-03-21 14:51:59 -0700950 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
ajuma5788faa2015-02-13 09:05:47 -0800951
952 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
953}
954
jbroman0e3129d2016-03-17 12:24:23 -0700955DEF_TEST(ImageFilterUnionBounds, reporter) {
robertphillips51a315e2016-03-31 09:05:49 -0700956 sk_sp<SkImageFilter> offset(SkOffsetImageFilter::Make(50, 0, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700957 // Regardless of which order they appear in, the image filter bounds should
958 // be combined correctly.
959 {
reed374772b2016-10-05 17:33:02 -0700960 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, offset));
jbroman0e3129d2016-03-17 12:24:23 -0700961 SkRect bounds = SkRect::MakeWH(100, 100);
962 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700963 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700964 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
965 }
966 {
reed374772b2016-10-05 17:33:02 -0700967 sk_sp<SkImageFilter> composite(SkXfermodeImageFilter::Make(SkBlendMode::kSrcOver, nullptr,
robertphillips8c0326d2016-04-05 12:48:34 -0700968 offset, nullptr));
jbroman0e3129d2016-03-17 12:24:23 -0700969 SkRect bounds = SkRect::MakeWH(100, 100);
970 // Intentionally aliasing here, as that's what the real callers do.
senorblancoe5e79842016-03-21 14:51:59 -0700971 bounds = composite->computeFastBounds(bounds);
jbroman0e3129d2016-03-17 12:24:23 -0700972 REPORTER_ASSERT(reporter, bounds == SkRect::MakeWH(150, 100));
973 }
974}
975
robertphillips3e302272016-04-20 11:48:36 -0700976static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
senorblanco4a243982015-11-25 07:06:55 -0800977 SkBitmap greenBM;
978 greenBM.allocN32Pixels(20, 20);
979 greenBM.eraseColor(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -0700980 sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
robertphillips549c8992016-04-01 09:28:51 -0700981 sk_sp<SkImageFilter> source(SkImageSource::Make(std::move(greenImage)));
Mike Reed0bdaf052017-06-18 23:35:57 -0400982 sk_sp<SkImageFilter> merge(SkMergeImageFilter::Make(source, source));
senorblanco4a243982015-11-25 07:06:55 -0800983
robertphillips3e302272016-04-20 11:48:36 -0700984 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
robertphillips4418dba2016-03-07 12:45:14 -0800985
brianosman2a75e5d2016-09-22 07:15:37 -0700986 SkImageFilter::OutputProperties noColorSpace(nullptr);
987 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
988 noColorSpace);
senorblanco4a243982015-11-25 07:06:55 -0800989 SkIPoint offset;
robertphillips4418dba2016-03-07 12:45:14 -0800990
robertphillips2302de92016-03-24 07:26:32 -0700991 sk_sp<SkSpecialImage> resultImg(merge->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -0800992 REPORTER_ASSERT(reporter, resultImg);
993
994 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
senorblanco4a243982015-11-25 07:06:55 -0800995}
996
robertphillips4418dba2016-03-07 12:45:14 -0800997DEF_TEST(ImageFilterMergeResultSize, reporter) {
robertphillips3e302272016-04-20 11:48:36 -0700998 test_imagefilter_merge_result_size(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -0800999}
1000
1001#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001002DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001003 test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001004}
1005#endif
1006
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001007static void draw_blurred_rect(SkCanvas* canvas) {
senorblanco837f5322014-07-14 10:19:54 -07001008 SkPaint filterPaint;
1009 filterPaint.setColor(SK_ColorWHITE);
robertphillips6e7025a2016-04-04 04:31:25 -07001010 filterPaint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(8), 0, nullptr));
halcanary96fcdcc2015-08-27 07:41:13 -07001011 canvas->saveLayer(nullptr, &filterPaint);
senorblanco837f5322014-07-14 10:19:54 -07001012 SkPaint whitePaint;
1013 whitePaint.setColor(SK_ColorWHITE);
1014 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1015 canvas->restore();
1016}
1017
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001018static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
senorblanco837f5322014-07-14 10:19:54 -07001019 canvas->save();
1020 canvas->clipRect(clipRect);
1021 canvas->drawPicture(picture);
1022 canvas->restore();
1023}
1024
1025DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1026 // Check that the blur filter when recorded with RTree acceleration,
1027 // and drawn tiled (with subsequent clip rects) exactly
1028 // matches the same filter drawn with without RTree acceleration.
1029 // This tests that the "bleed" from the blur into the otherwise-blank
1030 // tiles is correctly rendered.
1031 // Tests pass by not asserting.
1032
1033 int width = 16, height = 8;
1034 SkBitmap result1, result2;
1035 result1.allocN32Pixels(width, height);
1036 result2.allocN32Pixels(width, height);
1037 SkCanvas canvas1(result1);
1038 SkCanvas canvas2(result2);
1039 int tileSize = 8;
1040
1041 canvas1.clear(0);
1042 canvas2.clear(0);
1043
1044 SkRTreeFactory factory;
1045
1046 SkPictureRecorder recorder1, recorder2;
1047 // The only difference between these two pictures is that one has RTree aceleration.
mtklein3f3b3d02014-12-01 11:47:08 -08001048 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width),
1049 SkIntToScalar(height),
halcanary96fcdcc2015-08-27 07:41:13 -07001050 nullptr, 0);
mtklein3f3b3d02014-12-01 11:47:08 -08001051 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width),
1052 SkIntToScalar(height),
robertphillipsa8d7f0b2014-08-29 08:03:56 -07001053 &factory, 0);
1054 draw_blurred_rect(recordingCanvas1);
1055 draw_blurred_rect(recordingCanvas2);
reedca2622b2016-03-18 07:25:55 -07001056 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1057 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
senorblanco837f5322014-07-14 10:19:54 -07001058 for (int y = 0; y < height; y += tileSize) {
1059 for (int x = 0; x < width; x += tileSize) {
1060 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
reedca2622b2016-03-18 07:25:55 -07001061 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1062 draw_picture_clipped(&canvas2, tileRect, picture2.get());
senorblanco837f5322014-07-14 10:19:54 -07001063 }
1064 }
1065 for (int y = 0; y < height; y++) {
1066 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1067 REPORTER_ASSERT(reporter, !diffs);
1068 if (diffs) {
1069 break;
1070 }
1071 }
1072}
1073
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001074DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1075 // Check that a 1x3 filter does not cause a spurious assert.
1076 SkScalar kernel[3] = {
1077 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1078 };
1079 SkISize kernelSize = SkISize::Make(1, 3);
1080 SkScalar gain = SK_Scalar1, bias = 0;
1081 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1082
robertphillipsef6a47b2016-04-08 08:01:20 -07001083 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1084 kernelSize, kernel,
1085 gain, bias, kernelOffset,
1086 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
1087 false, nullptr));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001088
1089 SkBitmap result;
1090 int width = 16, height = 16;
1091 result.allocN32Pixels(width, height);
1092 SkCanvas canvas(result);
1093 canvas.clear(0);
1094
1095 SkPaint paint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001096 paint.setImageFilter(std::move(filter));
senorblanco@chromium.org91957432014-05-01 14:03:41 +00001097 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1098 canvas.drawRect(rect, paint);
1099}
1100
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001101DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1102 // Check that a filter with borders outside the target bounds
1103 // does not crash.
1104 SkScalar kernel[3] = {
1105 0, 0, 0,
1106 };
1107 SkISize kernelSize = SkISize::Make(3, 1);
1108 SkScalar gain = SK_Scalar1, bias = 0;
1109 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1110
robertphillipsef6a47b2016-04-08 08:01:20 -07001111 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1112 kernelSize, kernel, gain, bias, kernelOffset,
1113 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1114 true, nullptr));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001115
1116 SkBitmap result;
1117
1118 int width = 10, height = 10;
1119 result.allocN32Pixels(width, height);
1120 SkCanvas canvas(result);
1121 canvas.clear(0);
1122
1123 SkPaint filterPaint;
robertphillipsef6a47b2016-04-08 08:01:20 -07001124 filterPaint.setImageFilter(std::move(filter));
senorblanco@chromium.org8c7372b2014-05-02 19:13:11 +00001125 SkRect bounds = SkRect::MakeWH(1, 10);
1126 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1127 SkPaint rectPaint;
1128 canvas.saveLayer(&bounds, &filterPaint);
1129 canvas.drawRect(rect, rectPaint);
1130 canvas.restore();
1131}
1132
robertphillips3e302272016-04-20 11:48:36 -07001133static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
robertphillipsdada4dd2016-04-13 04:54:36 -07001134 // Check that a kernel that is too big for the GPU still works
1135 SkScalar identityKernel[49] = {
1136 0, 0, 0, 0, 0, 0, 0,
1137 0, 0, 0, 0, 0, 0, 0,
1138 0, 0, 0, 0, 0, 0, 0,
1139 0, 0, 0, 1, 0, 0, 0,
1140 0, 0, 0, 0, 0, 0, 0,
1141 0, 0, 0, 0, 0, 0, 0,
1142 0, 0, 0, 0, 0, 0, 0
1143 };
1144 SkISize kernelSize = SkISize::Make(7, 7);
1145 SkScalar gain = SK_Scalar1, bias = 0;
1146 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1147
1148 sk_sp<SkImageFilter> filter(SkMatrixConvolutionImageFilter::Make(
1149 kernelSize, identityKernel, gain, bias, kernelOffset,
1150 SkMatrixConvolutionImageFilter::kClamp_TileMode,
1151 true, nullptr));
1152
robertphillips3e302272016-04-20 11:48:36 -07001153 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
robertphillipsdada4dd2016-04-13 04:54:36 -07001154 SkASSERT(srcImg);
1155
1156 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001157 SkImageFilter::OutputProperties noColorSpace(nullptr);
1158 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillipsdada4dd2016-04-13 04:54:36 -07001159 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
1160 REPORTER_ASSERT(reporter, resultImg);
1161 REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1162 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1163 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1164}
1165
1166DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001167 test_big_kernel(reporter, nullptr);
robertphillipsdada4dd2016-04-13 04:54:36 -07001168}
1169
1170#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001171DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1172 reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001173 test_big_kernel(reporter, ctxInfo.grContext());
robertphillipsdada4dd2016-04-13 04:54:36 -07001174}
1175#endif
1176
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001177DEF_TEST(ImageFilterCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001178 test_crop_rects(reporter, nullptr);
senorblanco@chromium.orgaba651c2014-02-03 22:22:16 +00001179}
1180
robertphillips4418dba2016-03-07 12:45:14 -08001181#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001182DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001183 test_crop_rects(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001184}
1185#endif
1186
tfarina9ea53f92014-06-24 06:50:39 -07001187DEF_TEST(ImageFilterMatrix, reporter) {
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001188 SkBitmap temp;
mike@reedtribe.orgdeee4962014-02-13 14:41:43 +00001189 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001190 SkCanvas canvas(temp);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001191 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1192
1193 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1194
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +00001195 SkRTreeFactory factory;
1196 SkPictureRecorder recorder;
1197 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001198
1199 SkPaint paint;
robertphillips43c2ad42016-04-04 05:05:11 -07001200 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
halcanary96fcdcc2015-08-27 07:41:13 -07001201 recordingCanvas->saveLayer(nullptr, &paint);
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001202 SkPaint solidPaint;
1203 solidPaint.setColor(0xFFFFFFFF);
1204 recordingCanvas->save();
1205 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1206 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1207 recordingCanvas->restore(); // scale
1208 recordingCanvas->restore(); // saveLayer
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001209
reedca2622b2016-03-18 07:25:55 -07001210 canvas.drawPicture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org5251e2b2014-02-05 22:36:31 +00001211}
1212
senorblanco3d822c22014-07-30 14:49:31 -07001213DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001214 SkRTreeFactory factory;
1215 SkPictureRecorder recorder;
1216 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1217
1218 // Create an SkPicture which simply draws a green 1x1 rectangle.
1219 SkPaint greenPaint;
1220 greenPaint.setColor(SK_ColorGREEN);
1221 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001222 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001223
1224 // Wrap that SkPicture in an SkPictureImageFilter.
robertphillips5ff17b12016-03-28 13:13:42 -07001225 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001226
1227 // Check that SkPictureImageFilter successfully serializes its contained
1228 // SkPicture when not in cross-process mode.
1229 SkPaint paint;
robertphillips5ff17b12016-03-28 13:13:42 -07001230 paint.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001231 SkPictureRecorder outerRecorder;
1232 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
1233 SkPaint redPaintWithFilter;
1234 redPaintWithFilter.setColor(SK_ColorRED);
robertphillips5ff17b12016-03-28 13:13:42 -07001235 redPaintWithFilter.setImageFilter(imageFilter);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001236 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001237 sk_sp<SkPicture> outerPicture(outerRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001238
1239 SkBitmap bitmap;
1240 bitmap.allocN32Pixels(1, 1);
robertphillips9a53fd72015-06-22 09:46:59 -07001241 SkCanvas canvas(bitmap);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001242
1243 // The result here should be green, since the filter replaces the primitive's red interior.
1244 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001245 canvas.drawPicture(outerPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001246 uint32_t pixel = *bitmap.getAddr32(0, 0);
1247 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1248
1249 // Check that, for now, SkPictureImageFilter does not serialize or
1250 // deserialize its contained picture when the filter is serialized
1251 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
robertphillips12fa47d2016-04-08 16:28:09 -07001252 sk_sp<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001253 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1254 data->size());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001255
1256 redPaintWithFilter.setImageFilter(unflattenedFilter);
1257 SkPictureRecorder crossProcessRecorder;
1258 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
1259 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
reedca2622b2016-03-18 07:25:55 -07001260 sk_sp<SkPicture> crossProcessPicture(crossProcessRecorder.finishRecordingAsPicture());
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001261
1262 canvas.clear(0x0);
robertphillips9b14f262014-06-04 05:40:44 -07001263 canvas.drawPicture(crossProcessPicture);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001264 pixel = *bitmap.getAddr32(0, 0);
hendrikw446ee672015-06-16 09:28:37 -07001265 // If the security precautions are enabled, the result here should not be green, since the
1266 // filter draws nothing.
mtklein2afbe232016-02-07 12:23:10 -08001267 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled()
hendrikw446ee672015-06-16 09:28:37 -07001268 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN);
senorblanco@chromium.org97f5fc62014-05-30 20:50:56 +00001269}
1270
robertphillips3e302272016-04-20 11:48:36 -07001271static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
reedca2622b2016-03-18 07:25:55 -07001272 sk_sp<SkPicture> picture;
senorblanco3d822c22014-07-30 14:49:31 -07001273
robertphillips4418dba2016-03-07 12:45:14 -08001274 {
1275 SkRTreeFactory factory;
1276 SkPictureRecorder recorder;
1277 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1278
1279 // Create an SkPicture which simply draws a green 1x1 rectangle.
1280 SkPaint greenPaint;
1281 greenPaint.setColor(SK_ColorGREEN);
1282 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
reedca2622b2016-03-18 07:25:55 -07001283 picture = recorder.finishRecordingAsPicture();
robertphillips4418dba2016-03-07 12:45:14 -08001284 }
1285
robertphillips3e302272016-04-20 11:48:36 -07001286 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
senorblanco3d822c22014-07-30 14:49:31 -07001287
robertphillips5ff17b12016-03-28 13:13:42 -07001288 sk_sp<SkImageFilter> imageFilter(SkPictureImageFilter::Make(picture));
senorblanco3d822c22014-07-30 14:49:31 -07001289
senorblanco3d822c22014-07-30 14:49:31 -07001290 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001291 SkImageFilter::OutputProperties noColorSpace(nullptr);
1292 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001293
robertphillips2302de92016-03-24 07:26:32 -07001294 sk_sp<SkSpecialImage> resultImage(imageFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001295 REPORTER_ASSERT(reporter, !resultImage);
senorblanco3d822c22014-07-30 14:49:31 -07001296}
1297
robertphillips4418dba2016-03-07 12:45:14 -08001298DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001299 test_clipped_picture_imagefilter(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001300}
1301
1302#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001303DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001304 test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001305}
1306#endif
1307
tfarina9ea53f92014-06-24 06:50:39 -07001308DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001309 // Even when there's an empty saveLayer()/restore(), ensure that an image
1310 // filter or color filter which affects transparent black still draws.
1311
1312 SkBitmap bitmap;
1313 bitmap.allocN32Pixels(10, 10);
robertphillips9a53fd72015-06-22 09:46:59 -07001314 SkCanvas canvas(bitmap);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001315
1316 SkRTreeFactory factory;
1317 SkPictureRecorder recorder;
1318
robertphillips5605b562016-04-05 11:50:42 -07001319 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001320 SkBlendMode::kSrc));
robertphillips5605b562016-04-05 11:50:42 -07001321 sk_sp<SkImageFilter> imageFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001322 SkPaint imageFilterPaint;
robertphillips5605b562016-04-05 11:50:42 -07001323 imageFilterPaint.setImageFilter(std::move(imageFilter));
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001324 SkPaint colorFilterPaint;
reedd053ce92016-03-22 10:17:23 -07001325 colorFilterPaint.setColorFilter(green);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001326
1327 SkRect bounds = SkRect::MakeWH(10, 10);
1328
1329 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1330 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1331 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001332 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001333
1334 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001335 canvas.drawPicture(picture);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001336 uint32_t pixel = *bitmap.getAddr32(0, 0);
1337 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1338
1339 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
halcanary96fcdcc2015-08-27 07:41:13 -07001340 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001341 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001342 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001343
1344 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001345 canvas.drawPicture(picture2);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001346 pixel = *bitmap.getAddr32(0, 0);
1347 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1348
1349 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1350 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1351 recordingCanvas->restore();
reedca2622b2016-03-18 07:25:55 -07001352 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001353
1354 canvas.clear(0);
robertphillips9b14f262014-06-04 05:40:44 -07001355 canvas.drawPicture(picture3);
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001356 pixel = *bitmap.getAddr32(0, 0);
1357 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1358}
1359
robertphillips9a53fd72015-06-22 09:46:59 -07001360static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001361 SkBitmap bitmap;
1362 bitmap.allocN32Pixels(100, 100);
1363 bitmap.eraseARGB(0, 0, 0, 0);
1364
1365 // Check that a blur with an insane radius does not crash or assert.
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001366 SkPaint paint;
robertphillips6e7025a2016-04-04 04:31:25 -07001367 paint.setImageFilter(SkBlurImageFilter::Make(SkIntToScalar(1<<30),
1368 SkIntToScalar(1<<30),
1369 nullptr));
reedda420b92015-12-16 08:38:15 -08001370 canvas->drawBitmap(bitmap, 0, 0, &paint);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001371}
1372
1373DEF_TEST(HugeBlurImageFilter, reporter) {
1374 SkBitmap temp;
1375 temp.allocN32Pixels(100, 100);
robertphillips9a53fd72015-06-22 09:46:59 -07001376 SkCanvas canvas(temp);
1377 test_huge_blur(&canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001378}
1379
senorblanco21a465d2016-04-11 11:58:39 -07001380DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
senorblanco3a495202014-09-29 07:57:20 -07001381 SkScalar kernel[1] = { 0 };
1382 SkScalar gain = SK_Scalar1, bias = 0;
1383 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1384
halcanary96fcdcc2015-08-27 07:41:13 -07001385 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001386 sk_sp<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001387 SkISize::Make(1<<30, 1<<30),
1388 kernel,
1389 gain,
1390 bias,
1391 kernelOffset,
1392 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001393 false,
1394 nullptr));
senorblanco3a495202014-09-29 07:57:20 -07001395
halcanary96fcdcc2015-08-27 07:41:13 -07001396 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001397
halcanary96fcdcc2015-08-27 07:41:13 -07001398 // Check that a nullptr kernel gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001399 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001400 SkISize::Make(1, 1),
halcanary96fcdcc2015-08-27 07:41:13 -07001401 nullptr,
senorblanco3a495202014-09-29 07:57:20 -07001402 gain,
1403 bias,
1404 kernelOffset,
1405 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001406 false,
1407 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001408
halcanary96fcdcc2015-08-27 07:41:13 -07001409 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001410
halcanary96fcdcc2015-08-27 07:41:13 -07001411 // Check that a kernel width < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001412 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001413 SkISize::Make(0, 1),
1414 kernel,
1415 gain,
1416 bias,
1417 kernelOffset,
1418 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001419 false,
1420 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001421
halcanary96fcdcc2015-08-27 07:41:13 -07001422 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001423
halcanary96fcdcc2015-08-27 07:41:13 -07001424 // Check that kernel height < 1 gives a nullptr filter.
robertphillipsef6a47b2016-04-08 08:01:20 -07001425 conv = SkMatrixConvolutionImageFilter::Make(
senorblanco3a495202014-09-29 07:57:20 -07001426 SkISize::Make(1, -1),
1427 kernel,
1428 gain,
1429 bias,
1430 kernelOffset,
1431 SkMatrixConvolutionImageFilter::kRepeat_TileMode,
robertphillipsef6a47b2016-04-08 08:01:20 -07001432 false,
1433 nullptr);
senorblanco3a495202014-09-29 07:57:20 -07001434
halcanary96fcdcc2015-08-27 07:41:13 -07001435 REPORTER_ASSERT(reporter, nullptr == conv.get());
senorblanco3a495202014-09-29 07:57:20 -07001436}
1437
Mike Reedf1942192017-07-21 14:24:29 -04001438static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1439 auto canvas = surf->getCanvas();
robertphillips9a53fd72015-06-22 09:46:59 -07001440 canvas->clear(0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001441
1442 SkBitmap bitmap;
1443 bitmap.allocN32Pixels(1, 1);
1444 bitmap.eraseARGB(255, 255, 255, 255);
1445
robertphillips5605b562016-04-05 11:50:42 -07001446 sk_sp<SkColorFilter> green(SkColorFilter::MakeModeFilter(SK_ColorGREEN,
Mike Reed7d954ad2016-10-28 15:42:34 -04001447 SkBlendMode::kSrcIn));
robertphillips5605b562016-04-05 11:50:42 -07001448 sk_sp<SkImageFilter> greenFilter(SkColorFilterImageFilter::Make(green, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001449 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
robertphillips5605b562016-04-05 11:50:42 -07001450 sk_sp<SkImageFilter> croppedOut(SkColorFilterImageFilter::Make(green, nullptr, &cropRect));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001451
1452 // Check that an xfermode image filter whose input has been cropped out still draws the other
1453 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
reed374772b2016-10-05 17:33:02 -07001454 SkBlendMode mode = SkBlendMode::kSrcOver;
robertphillips8c0326d2016-04-05 12:48:34 -07001455 sk_sp<SkImageFilter> xfermodeNoFg(SkXfermodeImageFilter::Make(mode, greenFilter,
1456 croppedOut, nullptr));
1457 sk_sp<SkImageFilter> xfermodeNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1458 greenFilter, nullptr));
1459 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkXfermodeImageFilter::Make(mode, croppedOut,
1460 croppedOut, nullptr));
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001461
1462 SkPaint paint;
robertphillips8c0326d2016-04-05 12:48:34 -07001463 paint.setImageFilter(std::move(xfermodeNoFg));
reedda420b92015-12-16 08:38:15 -08001464 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001465
1466 uint32_t pixel;
kkinnunena9d9a392015-03-06 07:16:00 -08001467 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
Mike Reedf1942192017-07-21 14:24:29 -04001468 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001469 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1470
robertphillips8c0326d2016-04-05 12:48:34 -07001471 paint.setImageFilter(std::move(xfermodeNoBg));
reedda420b92015-12-16 08:38:15 -08001472 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001473 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001474 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1475
robertphillips8c0326d2016-04-05 12:48:34 -07001476 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
reedda420b92015-12-16 08:38:15 -08001477 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite
Mike Reedf1942192017-07-21 14:24:29 -04001478 surf->readPixels(info, &pixel, 4, 0, 0);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001479 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1480}
1481
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001482DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1483 SkBitmap temp;
1484 temp.allocN32Pixels(50, 50);
robertphillips9a53fd72015-06-22 09:46:59 -07001485 SkCanvas canvas(temp);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001486 canvas.clear(0x0);
1487
1488 SkBitmap bitmap;
1489 bitmap.allocN32Pixels(10, 10);
1490 bitmap.eraseColor(SK_ColorGREEN);
1491
1492 SkMatrix matrix;
1493 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1494 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
robertphillipsae8c9332016-04-05 15:09:00 -07001495 sk_sp<SkImageFilter> matrixFilter(
1496 SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001497
1498 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1499 // correct offset to the filter matrix.
1500 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
halcanary96fcdcc2015-08-27 07:41:13 -07001501 canvas.saveLayer(&bounds1, nullptr);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001502 SkPaint filterPaint;
robertphillipsae8c9332016-04-05 15:09:00 -07001503 filterPaint.setImageFilter(std::move(matrixFilter));
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001504 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1505 canvas.saveLayer(&bounds2, &filterPaint);
1506 SkPaint greenPaint;
1507 greenPaint.setColor(SK_ColorGREEN);
1508 canvas.drawRect(bounds2, greenPaint);
1509 canvas.restore();
1510 canvas.restore();
1511 SkPaint strokePaint;
1512 strokePaint.setStyle(SkPaint::kStroke_Style);
1513 strokePaint.setColor(SK_ColorRED);
1514
kkinnunena9d9a392015-03-06 07:16:00 -08001515 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001516 uint32_t pixel;
Mike Reedf1942192017-07-21 14:24:29 -04001517 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001518 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1519
1520 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1521 // correct offset to the filter matrix.
1522 canvas.clear(0x0);
Mike Reedf1942192017-07-21 14:24:29 -04001523 temp.readPixels(info, &pixel, 4, 25, 25);
halcanary96fcdcc2015-08-27 07:41:13 -07001524 canvas.saveLayer(&bounds1, nullptr);
reedda420b92015-12-16 08:38:15 -08001525 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001526 canvas.restore();
1527
Mike Reedf1942192017-07-21 14:24:29 -04001528 temp.readPixels(info, &pixel, 4, 25, 25);
senorblanco@chromium.orgd5424a42014-04-02 19:20:05 +00001529 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1530}
1531
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001532DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
Mike Reedf1942192017-07-21 14:24:29 -04001533 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001534}
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001535
robertphillips3e302272016-04-20 11:48:36 -07001536static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1537 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
ajuma5788faa2015-02-13 09:05:47 -08001538
1539 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20));
robertphillips51a315e2016-03-31 09:05:49 -07001540 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(0, 0, nullptr, &cropRect));
robertphillips6e7025a2016-04-04 04:31:25 -07001541 sk_sp<SkImageFilter> blurFilter(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1542 nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001543 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(blurFilter),
1544 std::move(offsetFilter)));
ajuma5788faa2015-02-13 09:05:47 -08001545 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001546 SkImageFilter::OutputProperties noColorSpace(nullptr);
1547 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001548
robertphillips2302de92016-03-24 07:26:32 -07001549 sk_sp<SkSpecialImage> resultImg(composedFilter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001550 REPORTER_ASSERT(reporter, resultImg);
ajuma5788faa2015-02-13 09:05:47 -08001551 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1552}
1553
robertphillips4418dba2016-03-07 12:45:14 -08001554DEF_TEST(ComposedImageFilterOffset, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001555 test_composed_imagefilter_offset(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001556}
1557
1558#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001559DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001560 test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001561}
1562#endif
1563
robertphillips3e302272016-04-20 11:48:36 -07001564static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
jbroman17a65202016-03-21 08:38:58 -07001565 // The bounds passed to the inner filter must be filtered by the outer
1566 // filter, so that the inner filter produces the pixels that the outer
1567 // filter requires as input. This matters if the outer filter moves pixels.
1568 // Here, accounting for the outer offset is necessary so that the green
1569 // pixels of the picture are not clipped.
1570
1571 SkPictureRecorder recorder;
1572 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeWH(200, 100));
1573 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1574 recordingCanvas->clear(SK_ColorGREEN);
robertphillips491fb172016-03-30 12:32:58 -07001575 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
robertphillips5ff17b12016-03-28 13:13:42 -07001576 sk_sp<SkImageFilter> pictureFilter(SkPictureImageFilter::Make(picture));
jbroman17a65202016-03-21 08:38:58 -07001577 SkImageFilter::CropRect cropRect(SkRect::MakeWH(100, 100));
robertphillips51a315e2016-03-31 09:05:49 -07001578 sk_sp<SkImageFilter> offsetFilter(SkOffsetImageFilter::Make(-100, 0, nullptr, &cropRect));
robertphillips491fb172016-03-30 12:32:58 -07001579 sk_sp<SkImageFilter> composedFilter(SkComposeImageFilter::Make(std::move(offsetFilter),
1580 std::move(pictureFilter)));
jbroman17a65202016-03-21 08:38:58 -07001581
robertphillips3e302272016-04-20 11:48:36 -07001582 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
brianosman2a75e5d2016-09-22 07:15:37 -07001583 SkImageFilter::OutputProperties noColorSpace(nullptr);
1584 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
jbroman17a65202016-03-21 08:38:58 -07001585 SkIPoint offset;
1586 sk_sp<SkSpecialImage> result(composedFilter->filterImage(sourceImage.get(), ctx, &offset));
1587 REPORTER_ASSERT(reporter, offset.isZero());
1588 REPORTER_ASSERT(reporter, result);
1589 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1590
1591 SkBitmap resultBM;
robertphillips64612512016-04-08 12:10:42 -07001592 REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
jbroman17a65202016-03-21 08:38:58 -07001593 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1594}
1595
1596DEF_TEST(ComposedImageFilterBounds, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001597 test_composed_imagefilter_bounds(reporter, nullptr);
jbroman17a65202016-03-21 08:38:58 -07001598}
1599
1600#if SK_SUPPORT_GPU
egdanielab527a52016-06-28 08:07:26 -07001601DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001602 test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
jbroman17a65202016-03-21 08:38:58 -07001603}
1604#endif
1605
robertphillips3e302272016-04-20 11:48:36 -07001606static void test_partial_crop_rect(skiatest::Reporter* reporter, GrContext* context) {
1607 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
senorblanco24d2a7b2015-07-13 10:27:05 -07001608
1609 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30),
senorblancoed7cf272015-07-16 15:19:11 -07001610 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge);
robertphillips5605b562016-04-05 11:50:42 -07001611 sk_sp<SkImageFilter> filter(make_grayscale(nullptr, &cropRect));
senorblanco24d2a7b2015-07-13 10:27:05 -07001612 SkIPoint offset;
brianosman2a75e5d2016-09-22 07:15:37 -07001613 SkImageFilter::OutputProperties noColorSpace(nullptr);
1614 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr, noColorSpace);
robertphillips4418dba2016-03-07 12:45:14 -08001615
robertphillips2302de92016-03-24 07:26:32 -07001616 sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg.get(), ctx, &offset));
robertphillips4418dba2016-03-07 12:45:14 -08001617 REPORTER_ASSERT(reporter, resultImg);
1618
senorblanco24d2a7b2015-07-13 10:27:05 -07001619 REPORTER_ASSERT(reporter, offset.fX == 0);
1620 REPORTER_ASSERT(reporter, offset.fY == 0);
robertphillips4418dba2016-03-07 12:45:14 -08001621 REPORTER_ASSERT(reporter, resultImg->width() == 20);
1622 REPORTER_ASSERT(reporter, resultImg->height() == 30);
senorblanco24d2a7b2015-07-13 10:27:05 -07001623}
1624
senorblanco21a465d2016-04-11 11:58:39 -07001625DEF_TEST(ImageFilterPartialCropRect, reporter) {
robertphillips3e302272016-04-20 11:48:36 -07001626 test_partial_crop_rect(reporter, nullptr);
robertphillips4418dba2016-03-07 12:45:14 -08001627}
1628
1629#if SK_SUPPORT_GPU
bsalomon68d91342016-04-12 09:59:58 -07001630DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterPartialCropRect_Gpu, reporter, ctxInfo) {
bsalomon8b7451a2016-05-11 06:33:06 -07001631 test_partial_crop_rect(reporter, ctxInfo.grContext());
robertphillips4418dba2016-03-07 12:45:14 -08001632}
1633#endif
1634
senorblanco0abdf762015-08-20 11:10:41 -07001635DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1636
robertphillips12fa47d2016-04-08 16:28:09 -07001637 {
1638 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1639 sk_sp<SkImageFilter> lighting(SkLightingImageFilter::MakePointLitDiffuse(location,
1640 SK_ColorGREEN,
1641 0, 0, nullptr));
1642 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1643 }
senorblanco0abdf762015-08-20 11:10:41 -07001644
senorblanco0abdf762015-08-20 11:10:41 -07001645 {
robertphillips6e7025a2016-04-04 04:31:25 -07001646 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1647 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1648 {
1649 SkColorFilter* grayCF;
1650 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1651 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1652 grayCF->unref();
1653 }
1654 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1655
1656 sk_sp<SkImageFilter> grayBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1657 std::move(gray)));
1658 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001659 }
senorblanco0abdf762015-08-20 11:10:41 -07001660
robertphillips6e7025a2016-04-04 04:31:25 -07001661 {
1662 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0,
1663 0, 0, 0, 0, 1,
1664 0, 0, 0, 0, 0,
1665 0, 0, 0, 0, 1 };
1666 sk_sp<SkColorFilter> greenCF(SkColorFilter::MakeMatrixFilterRowMajor255(greenMatrix));
robertphillips5605b562016-04-05 11:50:42 -07001667 sk_sp<SkImageFilter> green(SkColorFilterImageFilter::Make(greenCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001668
robertphillips6e7025a2016-04-04 04:31:25 -07001669 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1670 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
senorblanco0abdf762015-08-20 11:10:41 -07001671
robertphillips6e7025a2016-04-04 04:31:25 -07001672 sk_sp<SkImageFilter> greenBlur(SkBlurImageFilter::Make(SK_Scalar1, SK_Scalar1,
1673 std::move(green)));
1674 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1675 }
senorblanco0abdf762015-08-20 11:10:41 -07001676
1677 uint8_t allOne[256], identity[256];
1678 for (int i = 0; i < 256; ++i) {
1679 identity[i] = i;
1680 allOne[i] = 255;
1681 }
1682
robertphillips5605b562016-04-05 11:50:42 -07001683 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1684 identity, allOne));
1685 sk_sp<SkImageFilter> identityFilter(SkColorFilterImageFilter::Make(identityCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001686 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1687 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1688
robertphillips5605b562016-04-05 11:50:42 -07001689 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1690 identity, identity));
1691 sk_sp<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Make(forceOpaqueCF, nullptr));
senorblanco0abdf762015-08-20 11:10:41 -07001692 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1693 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1694}
1695
fmalitacd56f812015-09-14 13:31:18 -07001696// Verify that SkImageSource survives serialization
1697DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
reede8f30622016-03-23 18:59:25 -07001698 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
fmalitacd56f812015-09-14 13:31:18 -07001699 surface->getCanvas()->clear(SK_ColorGREEN);
reed9ce9d672016-03-17 10:51:11 -07001700 sk_sp<SkImage> image(surface->makeImageSnapshot());
robertphillips549c8992016-04-01 09:28:51 -07001701 sk_sp<SkImageFilter> filter(SkImageSource::Make(std::move(image)));
fmalitacd56f812015-09-14 13:31:18 -07001702
robertphillips549c8992016-04-01 09:28:51 -07001703 sk_sp<SkData> data(SkValidatingSerializeFlattenable(filter.get()));
Mike Reed5e257172016-11-01 11:22:05 -04001704 sk_sp<SkImageFilter> unflattenedFilter = SkValidatingDeserializeImageFilter(data->data(),
1705 data->size());
fmalitacd56f812015-09-14 13:31:18 -07001706 REPORTER_ASSERT(reporter, unflattenedFilter);
1707
1708 SkBitmap bm;
1709 bm.allocN32Pixels(10, 10);
fmalita23cb88c2015-09-15 06:56:23 -07001710 bm.eraseColor(SK_ColorBLUE);
fmalitacd56f812015-09-14 13:31:18 -07001711 SkPaint paint;
1712 paint.setColor(SK_ColorRED);
1713 paint.setImageFilter(unflattenedFilter);
1714
1715 SkCanvas canvas(bm);
1716 canvas.drawRect(SkRect::MakeWH(10, 10), paint);
1717 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1718}
1719
bsalomon45eefcf2016-01-05 08:39:28 -08001720static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1721 SkBitmap largeBmp;
1722 int largeW = 5000;
1723 int largeH = 5000;
1724#if SK_SUPPORT_GPU
1725 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1726 if (GrContext* ctx = canvas->getGrContext()) {
1727 largeW = ctx->caps()->maxTextureSize() + 1;
1728 }
1729#endif
1730
1731 largeBmp.allocN32Pixels(largeW, largeH);
mtklein2afbe232016-02-07 12:23:10 -08001732 largeBmp.eraseColor(0);
bsalomon45eefcf2016-01-05 08:39:28 -08001733 if (!largeBmp.getPixels()) {
1734 ERRORF(reporter, "Failed to allocate large bmp.");
1735 return;
1736 }
1737
reed9ce9d672016-03-17 10:51:11 -07001738 sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
bsalomon45eefcf2016-01-05 08:39:28 -08001739 if (!largeImage) {
1740 ERRORF(reporter, "Failed to create large image.");
1741 return;
1742 }
1743
robertphillips549c8992016-04-01 09:28:51 -07001744 sk_sp<SkImageFilter> largeSource(SkImageSource::Make(std::move(largeImage)));
bsalomon45eefcf2016-01-05 08:39:28 -08001745 if (!largeSource) {
1746 ERRORF(reporter, "Failed to create large SkImageSource.");
1747 return;
1748 }
1749
robertphillips6e7025a2016-04-04 04:31:25 -07001750 sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(10.f, 10.f, std::move(largeSource)));
bsalomon45eefcf2016-01-05 08:39:28 -08001751 if (!blur) {
1752 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1753 return;
1754 }
1755
1756 SkPaint paint;
robertphillips549c8992016-04-01 09:28:51 -07001757 paint.setImageFilter(std::move(blur));
bsalomon45eefcf2016-01-05 08:39:28 -08001758
1759 // This should not crash (http://crbug.com/570479).
1760 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1761}
1762
senorblanco21a465d2016-04-11 11:58:39 -07001763DEF_TEST(ImageFilterBlurLargeImage, reporter) {
reede8f30622016-03-23 18:59:25 -07001764 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
bsalomon45eefcf2016-01-05 08:39:28 -08001765 test_large_blur_input(reporter, surface->getCanvas());
1766}
1767
senorblanco5878dbd2016-05-19 14:50:29 -07001768static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001769 sk_sp<SkSurface> surface(create_surface(context, 192, 128));
senorblanco5878dbd2016-05-19 14:50:29 -07001770 surface->getCanvas()->clear(SK_ColorRED);
1771 SkPaint bluePaint;
1772 bluePaint.setColor(SK_ColorBLUE);
1773 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1774 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1775 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1776
1777 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1778 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1779 SkIRect outSubset;
1780 SkIPoint offset;
1781 sk_sp<SkImage> result;
1782
1783 result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1784 REPORTER_ASSERT(reporter, !result);
1785
1786 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1787 REPORTER_ASSERT(reporter, !result);
1788
1789 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1790 REPORTER_ASSERT(reporter, !result);
1791
1792 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1793 result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1794 REPORTER_ASSERT(reporter, !result);
1795
1796 SkIRect empty = SkIRect::MakeEmpty();
1797 result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1798 REPORTER_ASSERT(reporter, !result);
1799
1800 result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1801 REPORTER_ASSERT(reporter, !result);
1802
1803 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1804 result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1805 REPORTER_ASSERT(reporter, !result);
1806
1807 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1808
1809 REPORTER_ASSERT(reporter, result);
1810 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1811 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1812 outSubset.width(), outSubset.height());
1813 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
Robert Phillipsa5fdc972017-02-18 16:58:09 -05001814
1815 // In GPU-mode, this case creates a special image with a backing size that differs from
1816 // the content size
1817 {
1818 clipBounds.setXYWH(0, 0, 170, 100);
1819 subset.setXYWH(0, 0, 160, 90);
1820
1821 filter = SkXfermodeImageFilter::Make(SkBlendMode::kSrc, nullptr);
1822 result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1823 REPORTER_ASSERT(reporter, result);
1824 }
senorblanco5878dbd2016-05-19 14:50:29 -07001825}
1826
1827DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1828 test_make_with_filter(reporter, nullptr);
1829}
1830
1831#if SK_SUPPORT_GPU
1832DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1833 test_make_with_filter(reporter, ctxInfo.grContext());
1834}
1835#endif
1836
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001837#if SK_SUPPORT_GPU
reed4a8126e2014-09-22 07:29:03 -07001838
bsalomon68d91342016-04-12 09:59:58 -07001839DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
robertphillipsefbffed2015-06-22 12:06:08 -07001840
bsalomon8b7451a2016-05-11 06:33:06 -07001841 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
robertphillips3e302272016-04-20 11:48:36 -07001842 SkBudgeted::kNo,
1843 SkImageInfo::MakeN32Premul(100, 100)));
robertphillips9a53fd72015-06-22 09:46:59 -07001844
robertphillips3e302272016-04-20 11:48:36 -07001845
1846 SkCanvas* canvas = surf->getCanvas();
1847
1848 test_huge_blur(canvas, reporter);
senorblanco@chromium.org09843fd2014-03-24 20:50:59 +00001849}
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001850
egdanielab527a52016-06-28 08:07:26 -07001851DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001852 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1853 ctxInfo.grContext(),
1854 SkBudgeted::kNo,
1855 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
robertphillips3e302272016-04-20 11:48:36 -07001856
Mike Reedf1942192017-07-21 14:24:29 -04001857 test_xfermode_cropped_input(surf.get(), reporter);
senorblanco@chromium.orgee845ae2014-04-01 19:15:23 +00001858}
senorblanco32673b92014-09-09 09:15:04 -07001859
egdanielab527a52016-06-28 08:07:26 -07001860DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
Brian Salomon8996e182017-07-05 17:01:48 -04001861 auto surface(SkSurface::MakeRenderTarget(
1862 ctxInfo.grContext(), SkBudgeted::kYes,
1863 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
bsalomon45eefcf2016-01-05 08:39:28 -08001864 test_large_blur_input(reporter, surface->getCanvas());
1865}
senorblanco@chromium.org58d14662014-02-03 22:36:39 +00001866#endif
reedbb34a8a2016-04-23 15:19:07 -07001867
1868/*
1869 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1870 * than just scale/translate, but that other filters do.
1871 */
reed96a04f32016-04-25 09:25:15 -07001872DEF_TEST(ImageFilterComplexCTM, reporter) {
reedbb34a8a2016-04-23 15:19:07 -07001873 // just need a colorfilter to exercise the corresponding imagefilter
Mike Reed7d954ad2016-10-28 15:42:34 -04001874 sk_sp<SkColorFilter> cf = SkColorFilter::MakeModeFilter(SK_ColorRED, SkBlendMode::kSrcATop);
reed96a04f32016-04-25 09:25:15 -07001875 sk_sp<SkImageFilter> cfif = SkColorFilterImageFilter::Make(cf, nullptr); // can handle
1876 sk_sp<SkImageFilter> blif = SkBlurImageFilter::Make(3, 3, nullptr); // cannot handle
reedbb34a8a2016-04-23 15:19:07 -07001877
1878 struct {
1879 sk_sp<SkImageFilter> fFilter;
1880 bool fExpectCanHandle;
1881 } recs[] = {
1882 { cfif, true },
1883 { SkColorFilterImageFilter::Make(cf, cfif), true },
Mike Reed0bdaf052017-06-18 23:35:57 -04001884 { SkMergeImageFilter::Make(cfif, cfif), true },
reed96a04f32016-04-25 09:25:15 -07001885 { SkComposeImageFilter::Make(cfif, cfif), true },
1886
reedbb34a8a2016-04-23 15:19:07 -07001887 { blif, false },
reed96a04f32016-04-25 09:25:15 -07001888 { SkBlurImageFilter::Make(3, 3, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001889 { SkColorFilterImageFilter::Make(cf, blif), false },
Mike Reed0bdaf052017-06-18 23:35:57 -04001890 { SkMergeImageFilter::Make(cfif, blif), false },
reed96a04f32016-04-25 09:25:15 -07001891 { SkComposeImageFilter::Make(blif, cfif), false },
reedbb34a8a2016-04-23 15:19:07 -07001892 };
liyuqianbfebe222016-11-14 11:17:16 -08001893
reedbb34a8a2016-04-23 15:19:07 -07001894 for (const auto& rec : recs) {
reed96a04f32016-04-25 09:25:15 -07001895 const bool canHandle = rec.fFilter->canHandleComplexCTM();
reedbb34a8a2016-04-23 15:19:07 -07001896 REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1897 }
1898}
Florin Malita08252ec2017-07-06 12:48:15 -04001899
1900// Test that transforming the filter DAG doesn't clone shared nodes multiple times.
1901DEF_TEST(ImageFilterColorSpaceDAG, reporter) {
1902
1903 // Helper for counting makeColorSpace() clones.
1904 class TestFilter final : public SkImageFilter {
1905 public:
1906 TestFilter() : INHERITED(nullptr, 0, nullptr) {}
1907
1908#ifndef SK_IGNORE_TO_STRING
1909 void toString(SkString*) const override {}
1910#endif
1911 Factory getFactory() const override { return nullptr; }
1912
1913 size_t cloneCount() const { return fCloneCount; }
1914
1915 protected:
1916 sk_sp<SkSpecialImage> onFilterImage(SkSpecialImage* src, const Context&,
1917 SkIPoint* offset) const override {
1918 return nullptr;
1919 }
1920 sk_sp<SkImageFilter> onMakeColorSpace(SkColorSpaceXformer*) const override {
1921 fCloneCount++;
1922 return sk_ref_sp(const_cast<TestFilter*>(this));
1923 }
1924
1925 private:
1926 typedef SkImageFilter INHERITED;
1927
1928 mutable size_t fCloneCount = 0;
1929 };
1930
1931 auto filter = sk_make_sp<TestFilter>();
1932 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1933
1934 // Build a DAG referencing the filter twice.
1935 auto complexFilter = SkMergeImageFilter::Make(filter, SkOffsetImageFilter::Make(1, 1, filter));
1936 REPORTER_ASSERT(reporter, filter->cloneCount() == 0u);
1937
1938 auto xformer = SkColorSpaceXformer::Make(SkColorSpace::MakeSRGB());
1939 auto xformedFilter = xformer->apply(complexFilter.get());
1940
Florin Malita39e08552017-07-06 14:16:18 -04001941 REPORTER_ASSERT(reporter, filter->cloneCount() == 1u);
Florin Malita08252ec2017-07-06 12:48:15 -04001942}
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001943
Xianzhu Wangb4496662017-09-25 10:26:40 -07001944// Test SkXfermodeImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07001945DEF_TEST(XfermodeImageFilterBounds, reporter) {
1946 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1947 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1948 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1949 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1950
1951 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1952 SkIRect expectedBounds[kModeCount];
1953 // Expect union of input rects by default.
1954 for (int i = 0; i < kModeCount; ++i) {
1955 expectedBounds[i] = background_rect;
1956 expectedBounds[i].join(foreground_rect);
1957 }
1958
1959 SkIRect intersection = background_rect;
1960 intersection.intersect(foreground_rect);
1961 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1962 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1963 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1964 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1965 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1966 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1967 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1968
1969 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1970 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1971 for (int i = 0; i < kModeCount; ++i) {
1972 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(static_cast<SkBlendMode>(i),
1973 background, foreground, nullptr));
1974 auto bounds =
1975 xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1976 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1977 }
1978
1979 // Test empty intersection.
1980 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1981 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1982 sk_sp<SkImageFilter> xfermode(SkXfermodeImageFilter::Make(
1983 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
1984 auto bounds = xfermode->filterBounds(src, SkMatrix::I(), SkImageFilter::kForward_MapDirection);
1985 REPORTER_ASSERT(reporter, bounds.isEmpty());
1986}
1987
1988static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1989 float k4, sk_sp<SkImageFilter> background,
1990 sk_sp<SkImageFilter> foreground,
1991 const SkImageFilter::CropRect* crop, const SkIRect& expected) {
1992 sk_sp<SkImageFilter> arithmetic(
1993 SkArithmeticImageFilter::Make(k1, k2, k3, k4, false, background, foreground, crop));
1994 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1995 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
1996 SkImageFilter::kForward_MapDirection);
1997 REPORTER_ASSERT(reporter, expected == bounds);
1998}
1999
2000static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
2001 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
2002 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
2003 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
2004 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
2005
2006 SkIRect union_rect = background_rect;
2007 union_rect.join(foreground_rect);
2008 SkIRect intersection = background_rect;
2009 intersection.intersect(foreground_rect);
2010
2011 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
2012 SkIRect::MakeEmpty());
2013 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, union_rect);
2014 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, background_rect);
2015 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, union_rect);
2016 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, foreground_rect);
2017 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, union_rect);
2018 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, union_rect);
2019 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, union_rect);
2020 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
2021 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, union_rect);
2022 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, background_rect);
2023 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, union_rect);
2024 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, foreground_rect);
2025 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, union_rect);
2026 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, union_rect);
2027 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, union_rect);
2028
2029 // Test with crop. When k4 is non-zero, the result is expected to be crop_rect
2030 // regardless of inputs because the filter affects the whole crop area.
2031 SkIRect crop_rect = SkIRect::MakeXYWH(-111, -222, 333, 444);
2032 SkImageFilter::CropRect crop(SkRect::Make(crop_rect));
2033 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &crop,
2034 SkIRect::MakeEmpty());
2035 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &crop, crop_rect);
2036 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &crop, background_rect);
2037 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &crop, crop_rect);
2038 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &crop, foreground_rect);
2039 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &crop, crop_rect);
2040 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &crop, union_rect);
2041 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &crop, crop_rect);
2042 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &crop, intersection);
2043 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &crop, crop_rect);
2044 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &crop, background_rect);
2045 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &crop, crop_rect);
2046 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &crop, foreground_rect);
2047 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &crop, crop_rect);
2048 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &crop, union_rect);
2049 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &crop, crop_rect);
2050}
2051
Xianzhu Wangb4496662017-09-25 10:26:40 -07002052// Test SkArithmeticImageFilter::filterBounds with different blending modes.
Xianzhu Wang0fa353c2017-08-25 16:27:04 -07002053DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2054 test_arithmetic_combinations(reporter, 1);
2055 test_arithmetic_combinations(reporter, 0.5);
2056}
Xianzhu Wangb4496662017-09-25 10:26:40 -07002057
2058// Test SkImageSource::filterBounds.
2059DEF_TEST(ImageSourceBounds, reporter) {
2060 sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
2061 // Default src and dst rects.
2062 sk_sp<SkImageFilter> source1(SkImageSource::Make(image));
2063 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2064 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2065 REPORTER_ASSERT(reporter,
2066 imageBounds == source1->filterBounds(input, SkMatrix::I(),
2067 SkImageFilter::kForward_MapDirection));
2068 REPORTER_ASSERT(reporter,
2069 input == source1->filterBounds(input, SkMatrix::I(),
2070 SkImageFilter::kReverse_MapDirection));
2071 SkMatrix scale(SkMatrix::MakeScale(2));
2072 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2073 REPORTER_ASSERT(reporter,
2074 scaledBounds == source1->filterBounds(input, scale,
2075 SkImageFilter::kForward_MapDirection));
2076 REPORTER_ASSERT(
2077 reporter,
2078 input == source1->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2079
2080 // Specified src and dst rects.
2081 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2082 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2083 sk_sp<SkImageFilter> source2(SkImageSource::Make(image, src, dst, kMedium_SkFilterQuality));
2084 REPORTER_ASSERT(reporter,
2085 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2086 SkImageFilter::kForward_MapDirection));
2087 REPORTER_ASSERT(reporter,
2088 input == source2->filterBounds(input, SkMatrix::I(),
2089 SkImageFilter::kReverse_MapDirection));
2090 scale.mapRect(&dst);
2091 scale.mapRect(&src);
2092 REPORTER_ASSERT(reporter,
2093 dst.roundOut() == source2->filterBounds(input, scale,
2094 SkImageFilter::kForward_MapDirection));
2095 REPORTER_ASSERT(
2096 reporter,
2097 input == source2->filterBounds(input, scale, SkImageFilter::kReverse_MapDirection));
2098}