1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkBitmap.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkImage.h"
11 #include "include/core/SkPicture.h"
12 #include "include/core/SkPictureRecorder.h"
13 #include "include/core/SkPoint3.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkSurface.h"
16 #include "include/effects/SkColorMatrixFilter.h"
17 #include "include/effects/SkGradientShader.h"
18 #include "include/effects/SkImageFilters.h"
19 #include "include/effects/SkPerlinNoiseShader.h"
20 #include "include/effects/SkTableColorFilter.h"
21 #include "include/gpu/GrDirectContext.h"
22 #include "src/core/SkColorFilterBase.h"
23 #include "src/core/SkImageFilter_Base.h"
24 #include "src/core/SkReadBuffer.h"
25 #include "src/core/SkSpecialImage.h"
26 #include "src/core/SkSpecialSurface.h"
27 #include "src/gpu/GrCaps.h"
28 #include "src/gpu/GrRecordingContextPriv.h"
29 #include "tests/Test.h"
30 #include "tools/Resources.h"
31 #include "tools/ToolUtils.h"
32
33 static const int kBitmapSize = 4;
34
35 namespace {
36
37 class MatrixTestImageFilter : public SkImageFilter_Base {
38 public:
Make(skiatest::Reporter * reporter,const SkMatrix & expectedMatrix)39 static sk_sp<SkImageFilter> Make(skiatest::Reporter* reporter,
40 const SkMatrix& expectedMatrix) {
41 return sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix));
42 }
43
44 protected:
onFilterImage(const Context & ctx,SkIPoint * offset) const45 sk_sp<SkSpecialImage> onFilterImage(const Context& ctx, SkIPoint* offset) const override {
46 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
47 offset->fX = offset->fY = 0;
48 return sk_ref_sp<SkSpecialImage>(ctx.sourceImage());
49 }
50
flatten(SkWriteBuffer & buffer) const51 void flatten(SkWriteBuffer& buffer) const override {
52 SkDEBUGFAIL("Should never get here");
53 }
54
55 private:
56 SK_FLATTENABLE_HOOKS(MatrixTestImageFilter)
57
MatrixTestImageFilter(skiatest::Reporter * reporter,const SkMatrix & expectedMatrix)58 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
59 : INHERITED(nullptr, 0, nullptr)
60 , fReporter(reporter)
61 , fExpectedMatrix(expectedMatrix) {
62 }
63
64 skiatest::Reporter* fReporter;
65 SkMatrix fExpectedMatrix;
66
67 using INHERITED = SkImageFilter_Base;
68 };
69
70 class FailImageFilter : public SkImageFilter_Base {
71 public:
FailImageFilter()72 FailImageFilter() : INHERITED(nullptr, 0, nullptr) { }
73
onFilterImage(const Context & ctx,SkIPoint * offset) const74 sk_sp<SkSpecialImage> onFilterImage(const Context& ctx, SkIPoint* offset) const override {
75 return nullptr;
76 }
77
78 SK_FLATTENABLE_HOOKS(FailImageFilter)
79
80 private:
81 using INHERITED = SkImageFilter_Base;
82 };
83
CreateProc(SkReadBuffer & buffer)84 sk_sp<SkFlattenable> FailImageFilter::CreateProc(SkReadBuffer& buffer) {
85 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 0);
86 return sk_sp<SkFlattenable>(new FailImageFilter());
87 }
88
draw_gradient_circle(SkCanvas * canvas,int width,int height)89 void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
90 SkScalar x = SkIntToScalar(width / 2);
91 SkScalar y = SkIntToScalar(height / 2);
92 SkScalar radius = std::min(x, y) * 0.8f;
93 canvas->clear(0x00000000);
94 SkColor colors[2];
95 colors[0] = SK_ColorWHITE;
96 colors[1] = SK_ColorBLACK;
97 sk_sp<SkShader> shader(
98 SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
99 SkTileMode::kClamp)
100 );
101 SkPaint paint;
102 paint.setShader(shader);
103 canvas->drawCircle(x, y, radius, paint);
104 }
105
make_gradient_circle(int width,int height)106 SkBitmap make_gradient_circle(int width, int height) {
107 SkBitmap bitmap;
108 bitmap.allocN32Pixels(width, height);
109 SkCanvas canvas(bitmap);
110 draw_gradient_circle(&canvas, width, height);
111 return bitmap;
112 }
113
114 class FilterList {
115 public:
FilterList(sk_sp<SkImageFilter> input,const SkIRect * cropRect=nullptr)116 FilterList(sk_sp<SkImageFilter> input, const SkIRect* cropRect = nullptr) {
117 static const SkScalar kBlurSigma = SkIntToScalar(5);
118
119 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
120 {
121 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcIn));
122
123 this->addFilter("color filter",
124 SkImageFilters::ColorFilter(std::move(cf), input, cropRect));
125 }
126 {
127 sk_sp<SkImage> gradientImage(make_gradient_circle(64, 64).asImage());
128 sk_sp<SkImageFilter> gradientSource(SkImageFilters::Image(std::move(gradientImage)));
129
130 this->addFilter("displacement map",
131 SkImageFilters::DisplacementMap(SkColorChannel::kR, SkColorChannel::kB, 20.0f,
132 std::move(gradientSource), input, cropRect));
133 }
134 this->addFilter("blur", SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, input, cropRect));
135 this->addFilter("drop shadow", SkImageFilters::DropShadow(
136 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input, cropRect));
137 this->addFilter("diffuse lighting",
138 SkImageFilters::PointLitDiffuse(location, SK_ColorGREEN, 0, 0, input, cropRect));
139 this->addFilter("specular lighting",
140 SkImageFilters::PointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input,
141 cropRect));
142 {
143 SkScalar kernel[9] = {
144 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
145 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
146 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
147 };
148 const SkISize kernelSize = SkISize::Make(3, 3);
149 const SkScalar gain = SK_Scalar1, bias = 0;
150
151 // This filter needs a saveLayer bc it is in repeat mode
152 this->addFilter("matrix convolution",
153 SkImageFilters::MatrixConvolution(
154 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
155 SkTileMode::kRepeat, false, input, cropRect),
156 true);
157 }
158 this->addFilter("merge", SkImageFilters::Merge(input, input, cropRect));
159
160 {
161 sk_sp<SkShader> greenColorShader = SkShaders::Color(SK_ColorGREEN);
162
163 SkIRect leftSideCropRect = SkIRect::MakeXYWH(0, 0, 32, 64);
164 sk_sp<SkImageFilter> shaderFilterLeft(SkImageFilters::Shader(greenColorShader,
165 &leftSideCropRect));
166 SkIRect rightSideCropRect = SkIRect::MakeXYWH(32, 0, 32, 64);
167 sk_sp<SkImageFilter> shaderFilterRight(SkImageFilters::Shader(greenColorShader,
168 &rightSideCropRect));
169
170
171 this->addFilter("merge with disjoint inputs", SkImageFilters::Merge(
172 std::move(shaderFilterLeft), std::move(shaderFilterRight), cropRect));
173 }
174
175 this->addFilter("offset", SkImageFilters::Offset(SK_Scalar1, SK_Scalar1, input, cropRect));
176 this->addFilter("dilate", SkImageFilters::Dilate(3, 2, input, cropRect));
177 this->addFilter("erode", SkImageFilters::Erode(2, 3, input, cropRect));
178 this->addFilter("tile", SkImageFilters::Tile(SkRect::MakeXYWH(0, 0, 50, 50),
179 cropRect ? SkRect::Make(*cropRect)
180 : SkRect::MakeXYWH(0, 0, 100, 100),
181 input));
182
183 if (!cropRect) {
184 SkMatrix matrix;
185
186 matrix.setTranslate(SK_Scalar1, SK_Scalar1);
187 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
188
189 this->addFilter("matrix",
190 SkImageFilters::MatrixTransform(matrix,
191 SkSamplingOptions(SkFilterMode::kLinear),
192 input));
193 }
194 {
195 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(kBlurSigma, kBlurSigma, input));
196
197 this->addFilter("blur and offset", SkImageFilters::Offset(
198 kBlurSigma, kBlurSigma, std::move(blur), cropRect));
199 }
200 {
201 SkPictureRecorder recorder;
202 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
203
204 SkPaint greenPaint;
205 greenPaint.setColor(SK_ColorGREEN);
206 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
207 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
208 sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(std::move(picture)));
209
210 this->addFilter("picture and blur", SkImageFilters::Blur(
211 kBlurSigma, kBlurSigma, std::move(pictureFilter), cropRect));
212 }
213 {
214 sk_sp<SkImageFilter> paintFilter(SkImageFilters::Shader(
215 SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0)));
216
217 this->addFilter("paint and blur", SkImageFilters::Blur(
218 kBlurSigma, kBlurSigma, std::move(paintFilter), cropRect));
219 }
220 this->addFilter("blend", SkImageFilters::Blend(
221 SkBlendMode::kSrc, input, input, cropRect));
222 }
count() const223 int count() const { return fFilters.count(); }
getFilter(int index) const224 SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
getName(int index) const225 const char* getName(int index) const { return fFilters[index].fName; }
needsSaveLayer(int index) const226 bool needsSaveLayer(int index) const { return fFilters[index].fNeedsSaveLayer; }
227 private:
228 struct Filter {
Filter__anon0a89c7da0111::FilterList::Filter229 Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
Filter__anon0a89c7da0111::FilterList::Filter230 Filter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer)
231 : fName(name)
232 , fFilter(std::move(filter))
233 , fNeedsSaveLayer(needsSaveLayer) {
234 }
235 const char* fName;
236 sk_sp<SkImageFilter> fFilter;
237 bool fNeedsSaveLayer;
238 };
addFilter(const char * name,sk_sp<SkImageFilter> filter,bool needsSaveLayer=false)239 void addFilter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer = false) {
240 fFilters.push_back(Filter(name, std::move(filter), needsSaveLayer));
241 }
242
243 SkTArray<Filter> fFilters;
244 };
245
246 class FixedBoundsImageFilter : public SkImageFilter_Base {
247 public:
FixedBoundsImageFilter(const SkIRect & bounds)248 FixedBoundsImageFilter(const SkIRect& bounds)
249 : INHERITED(nullptr, 0, nullptr), fBounds(bounds) {}
250
251 private:
getFactory() const252 Factory getFactory() const override { return nullptr; }
getTypeName() const253 const char* getTypeName() const override { return nullptr; }
254
onFilterImage(const Context &,SkIPoint * offset) const255 sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override {
256 return nullptr;
257 }
258
onFilterBounds(const SkIRect &,const SkMatrix &,MapDirection,const SkIRect *) const259 SkIRect onFilterBounds(const SkIRect&, const SkMatrix&,
260 MapDirection, const SkIRect*) const override {
261 return fBounds;
262 }
263
264 SkIRect fBounds;
265
266 using INHERITED = SkImageFilter_Base;
267 };
268 } // namespace
269
CreateProc(SkReadBuffer & buffer)270 sk_sp<SkFlattenable> MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) {
271 SkDEBUGFAIL("Should never get here");
272 return nullptr;
273 }
274
make_small_image()275 static sk_sp<SkImage> make_small_image() {
276 auto surface(SkSurface::MakeRasterN32Premul(kBitmapSize, kBitmapSize));
277 SkCanvas* canvas = surface->getCanvas();
278 canvas->clear(0x00000000);
279 SkPaint darkPaint;
280 darkPaint.setColor(0xFF804020);
281 SkPaint lightPaint;
282 lightPaint.setColor(0xFF244484);
283 const int kRectSize = kBitmapSize / 4;
284 static_assert(kBitmapSize % 4 == 0, "bitmap size not multiple of 4");
285
286 for (int y = 0; y < kBitmapSize; y += kRectSize) {
287 for (int x = 0; x < kBitmapSize; x += kRectSize) {
288 canvas->save();
289 canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
290 canvas->drawRect(
291 SkRect::MakeXYWH(0, 0, kRectSize, kRectSize), darkPaint);
292 canvas->drawRect(
293 SkRect::MakeXYWH(kRectSize, 0, kRectSize, kRectSize), lightPaint);
294 canvas->drawRect(
295 SkRect::MakeXYWH(0, kRectSize, kRectSize, kRectSize), lightPaint);
296 canvas->drawRect(
297 SkRect::MakeXYWH(kRectSize, kRectSize, kRectSize, kRectSize), darkPaint);
298 canvas->restore();
299 }
300 }
301
302 return surface->makeImageSnapshot();
303 }
304
make_scale(float amount,sk_sp<SkImageFilter> input)305 static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
306 float s = amount;
307 float matrix[20] = { s, 0, 0, 0, 0,
308 0, s, 0, 0, 0,
309 0, 0, s, 0, 0,
310 0, 0, 0, s, 0 };
311 sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
312 return SkImageFilters::ColorFilter(std::move(filter), std::move(input));
313 }
314
make_grayscale(sk_sp<SkImageFilter> input,const SkIRect * cropRect)315 static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
316 const SkIRect* cropRect) {
317 float matrix[20];
318 memset(matrix, 0, 20 * sizeof(float));
319 matrix[0] = matrix[5] = matrix[10] = 0.2126f;
320 matrix[1] = matrix[6] = matrix[11] = 0.7152f;
321 matrix[2] = matrix[7] = matrix[12] = 0.0722f;
322 matrix[18] = 1.0f;
323 sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
324 return SkImageFilters::ColorFilter(std::move(filter), std::move(input), cropRect);
325 }
326
make_blue(sk_sp<SkImageFilter> input,const SkIRect * cropRect)327 static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input, const SkIRect* cropRect) {
328 sk_sp<SkColorFilter> filter(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn));
329 return SkImageFilters::ColorFilter(std::move(filter), std::move(input), cropRect);
330 }
331
create_empty_special_surface(GrRecordingContext * rContext,int widthHeight)332 static sk_sp<SkSpecialSurface> create_empty_special_surface(GrRecordingContext* rContext,
333 int widthHeight) {
334
335 const SkImageInfo ii = SkImageInfo::Make({ widthHeight, widthHeight },
336 kRGBA_8888_SkColorType,
337 kPremul_SkAlphaType);
338
339 if (rContext) {
340 return SkSpecialSurface::MakeRenderTarget(rContext, ii, SkSurfaceProps());
341 } else {
342 return SkSpecialSurface::MakeRaster(ii, SkSurfaceProps());
343 }
344 }
345
create_surface(GrRecordingContext * rContext,int width,int height)346 static sk_sp<SkSurface> create_surface(GrRecordingContext* rContext, int width, int height) {
347 const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
348 if (rContext) {
349 return SkSurface::MakeRenderTarget(rContext, SkBudgeted::kNo, info);
350 } else {
351 return SkSurface::MakeRaster(info);
352 }
353 }
354
create_empty_special_image(GrRecordingContext * rContext,int widthHeight)355 static sk_sp<SkSpecialImage> create_empty_special_image(GrRecordingContext* rContext,
356 int widthHeight) {
357 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(rContext, widthHeight));
358
359 SkASSERT(surf);
360
361 SkCanvas* canvas = surf->getCanvas();
362 SkASSERT(canvas);
363
364 canvas->clear(0x0);
365
366 return surf->makeImageSnapshot();
367 }
368
369
DEF_TEST(ImageFilter,reporter)370 DEF_TEST(ImageFilter, reporter) {
371 {
372 // Check that a color matrix filter followed by a color matrix filter
373 // concatenates into a single filter.
374 sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
375 sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
376 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
377 SkColorFilter* cf;
378 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
379 cf->unref();
380 }
381
382 {
383 // Check that a color filter image filter without a crop rect can be
384 // expressed as a color filter.
385 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
386 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
387 }
388
389 {
390 // Check that a colorfilterimage filter without a crop rect but with an input
391 // that is another colorfilterimage can be expressed as a colorfilter (composed).
392 sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
393 sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
394 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
395 }
396
397 {
398 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
399 // can build the DAG and won't assert if we call asColorFilter.
400 sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
401 const int kWayTooManyForComposeColorFilter = 100;
402 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
403 filter = make_blue(filter, nullptr);
404 // the first few of these will succeed, but after we hit the internal limit,
405 // it will then return false.
406 (void)filter->asColorFilter(nullptr);
407 }
408 }
409
410 {
411 // Check that a color filter image filter with a crop rect cannot
412 // be expressed as a color filter.
413 SkIRect cropRect = SkIRect::MakeWH(100, 100);
414 sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
415 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
416 }
417
418 {
419 // Check that two non-commutative matrices are concatenated in
420 // the correct order.
421 float blueToRedMatrix[20] = { 0 };
422 blueToRedMatrix[2] = blueToRedMatrix[18] = 1;
423 float redToGreenMatrix[20] = { 0 };
424 redToGreenMatrix[5] = redToGreenMatrix[18] = 1;
425 sk_sp<SkColorFilter> blueToRed(SkColorFilters::Matrix(blueToRedMatrix));
426 sk_sp<SkImageFilter> filter1(SkImageFilters::ColorFilter(std::move(blueToRed), nullptr));
427 sk_sp<SkColorFilter> redToGreen(SkColorFilters::Matrix(redToGreenMatrix));
428 sk_sp<SkImageFilter> filter2(SkImageFilters::ColorFilter(std::move(redToGreen),
429 std::move(filter1)));
430
431 SkBitmap result;
432 result.allocN32Pixels(kBitmapSize, kBitmapSize);
433
434 SkPaint paint;
435 paint.setColor(SK_ColorBLUE);
436 paint.setImageFilter(std::move(filter2));
437 SkCanvas canvas(result);
438 canvas.clear(0x0);
439 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
440 canvas.drawRect(rect, paint);
441 uint32_t pixel = *result.getAddr32(0, 0);
442 // The result here should be green, since we have effectively shifted blue to green.
443 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
444 }
445
446 {
447 // Tests pass by not asserting
448 sk_sp<SkImage> image(make_small_image());
449 SkBitmap result;
450 result.allocN32Pixels(kBitmapSize, kBitmapSize);
451
452 {
453 // This tests for :
454 // 1 ) location at (0,0,1)
455 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
456 // 2 ) location and target at same value
457 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
458 // 3 ) large negative specular exponent value
459 SkScalar specularExponent = -1000;
460
461 sk_sp<SkImageFilter> bmSrc(SkImageFilters::Image(std::move(image)));
462 SkPaint paint;
463 paint.setImageFilter(SkImageFilters::SpotLitSpecular(
464 location, target, specularExponent, 180,
465 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
466 std::move(bmSrc)));
467 SkCanvas canvas(result);
468 SkRect r = SkRect::MakeIWH(kBitmapSize, kBitmapSize);
469 canvas.drawRect(r, paint);
470 }
471 }
472 }
473
test_cropRects(skiatest::Reporter * reporter,GrRecordingContext * rContext)474 static void test_cropRects(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
475 // Check that all filters offset to their absolute crop rect,
476 // unaffected by the input crop rect.
477 // Tests pass by not asserting.
478 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
479 SkASSERT(srcImg);
480
481 SkIRect inputCropRect = SkIRect::MakeXYWH(8, 13, 80, 80);
482 SkIRect cropRect = SkIRect::MakeXYWH(20, 30, 60, 60);
483 sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
484
485 FilterList filters(input, &cropRect);
486
487 for (int i = 0; i < filters.count(); ++i) {
488 SkImageFilter* filter = filters.getFilter(i);
489 SkIPoint offset;
490 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
491 kN32_SkColorType, nullptr, srcImg.get());
492 sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
493 REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
494 REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
495 }
496 }
497
special_image_to_bitmap(GrDirectContext * dContext,const SkSpecialImage * src,SkBitmap * dst)498 static bool special_image_to_bitmap(GrDirectContext* dContext, const SkSpecialImage* src,
499 SkBitmap* dst) {
500 sk_sp<SkImage> img = src->asImage();
501 if (!img) {
502 return false;
503 }
504
505 if (!dst->tryAllocN32Pixels(src->width(), src->height())) {
506 return false;
507 }
508
509 return img->readPixels(dContext, dst->pixmap(), src->subset().fLeft, src->subset().fTop);
510 }
511
test_negative_blur_sigma(skiatest::Reporter * reporter,GrDirectContext * dContext)512 static void test_negative_blur_sigma(skiatest::Reporter* reporter,
513 GrDirectContext* dContext) {
514 // Check that SkBlurImageFilter will accept a negative sigma, either in
515 // the given arguments or after CTM application.
516 static const int kWidth = 32, kHeight = 32;
517 static const SkScalar kBlurSigma = SkIntToScalar(5);
518
519 sk_sp<SkImageFilter> positiveFilter(SkImageFilters::Blur(kBlurSigma, kBlurSigma, nullptr));
520 sk_sp<SkImageFilter> negativeFilter(SkImageFilters::Blur(-kBlurSigma, kBlurSigma, nullptr));
521
522 sk_sp<SkImage> gradient = make_gradient_circle(kWidth, kHeight).asImage();
523 sk_sp<SkSpecialImage> imgSrc(
524 SkSpecialImage::MakeFromImage(dContext, SkIRect::MakeWH(kWidth, kHeight), gradient,
525 SkSurfaceProps()));
526
527 SkIPoint offset;
528 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
529 kN32_SkColorType, nullptr, imgSrc.get());
530
531 sk_sp<SkSpecialImage> positiveResult1(
532 as_IFB(positiveFilter)->filterImage(ctx).imageAndOffset(&offset));
533 REPORTER_ASSERT(reporter, positiveResult1);
534
535 sk_sp<SkSpecialImage> negativeResult1(
536 as_IFB(negativeFilter)->filterImage(ctx).imageAndOffset(&offset));
537 REPORTER_ASSERT(reporter, negativeResult1);
538
539 SkMatrix negativeScale;
540 negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
541 SkImageFilter_Base::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
542 kN32_SkColorType, nullptr, imgSrc.get());
543
544 sk_sp<SkSpecialImage> negativeResult2(
545 as_IFB(positiveFilter)->filterImage(negativeCTX).imageAndOffset(&offset));
546 REPORTER_ASSERT(reporter, negativeResult2);
547
548 sk_sp<SkSpecialImage> positiveResult2(
549 as_IFB(negativeFilter)->filterImage(negativeCTX).imageAndOffset(&offset));
550 REPORTER_ASSERT(reporter, positiveResult2);
551
552
553 SkBitmap positiveResultBM1, positiveResultBM2;
554 SkBitmap negativeResultBM1, negativeResultBM2;
555
556 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, positiveResult1.get(),
557 &positiveResultBM1));
558 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, positiveResult2.get(),
559 &positiveResultBM2));
560 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, negativeResult1.get(),
561 &negativeResultBM1));
562 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, negativeResult2.get(),
563 &negativeResultBM2));
564
565 for (int y = 0; y < kHeight; y++) {
566 int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
567 negativeResultBM1.getAddr32(0, y),
568 positiveResultBM1.rowBytes());
569 REPORTER_ASSERT(reporter, !diffs);
570 if (diffs) {
571 break;
572 }
573 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
574 negativeResultBM2.getAddr32(0, y),
575 positiveResultBM1.rowBytes());
576 REPORTER_ASSERT(reporter, !diffs);
577 if (diffs) {
578 break;
579 }
580 diffs = memcmp(positiveResultBM1.getAddr32(0, y),
581 positiveResultBM2.getAddr32(0, y),
582 positiveResultBM1.rowBytes());
583 REPORTER_ASSERT(reporter, !diffs);
584 if (diffs) {
585 break;
586 }
587 }
588 }
589
DEF_TEST(ImageFilterNegativeBlurSigma,reporter)590 DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
591 test_negative_blur_sigma(reporter, nullptr);
592 }
593
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu,reporter,ctxInfo)594 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
595 test_negative_blur_sigma(reporter, ctxInfo.directContext());
596 }
597
test_morphology_radius_with_mirror_ctm(skiatest::Reporter * reporter,GrDirectContext * dContext)598 static void test_morphology_radius_with_mirror_ctm(skiatest::Reporter* reporter,
599 GrDirectContext* dContext) {
600 // Check that SkMorphologyImageFilter maps the radius correctly when the
601 // CTM contains a mirroring transform.
602 static const int kWidth = 32, kHeight = 32;
603 static const int kRadius = 8;
604
605 sk_sp<SkImageFilter> filter(SkImageFilters::Dilate(kRadius, kRadius, nullptr));
606
607 SkBitmap bitmap;
608 bitmap.allocN32Pixels(kWidth, kHeight);
609 SkCanvas canvas(bitmap);
610 canvas.clear(SK_ColorTRANSPARENT);
611 SkPaint paint;
612 paint.setColor(SK_ColorWHITE);
613 canvas.drawRect(SkRect::MakeXYWH(kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2),
614 paint);
615 sk_sp<SkImage> image = bitmap.asImage();
616 sk_sp<SkSpecialImage> imgSrc(
617 SkSpecialImage::MakeFromImage(dContext, SkIRect::MakeWH(kWidth, kHeight), image,
618 SkSurfaceProps()));
619
620 SkIPoint offset;
621 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
622 kN32_SkColorType, nullptr, imgSrc.get());
623
624 sk_sp<SkSpecialImage> normalResult(
625 as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
626 REPORTER_ASSERT(reporter, normalResult);
627
628 SkMatrix mirrorX;
629 mirrorX.setTranslate(0, SkIntToScalar(32));
630 mirrorX.preScale(SK_Scalar1, -SK_Scalar1);
631 SkImageFilter_Base::Context mirrorXCTX(mirrorX, SkIRect::MakeWH(32, 32), nullptr,
632 kN32_SkColorType, nullptr, imgSrc.get());
633
634 sk_sp<SkSpecialImage> mirrorXResult(
635 as_IFB(filter)->filterImage(mirrorXCTX).imageAndOffset(&offset));
636 REPORTER_ASSERT(reporter, mirrorXResult);
637
638 SkMatrix mirrorY;
639 mirrorY.setTranslate(SkIntToScalar(32), 0);
640 mirrorY.preScale(-SK_Scalar1, SK_Scalar1);
641 SkImageFilter_Base::Context mirrorYCTX(mirrorY, SkIRect::MakeWH(32, 32), nullptr,
642 kN32_SkColorType, nullptr, imgSrc.get());
643
644 sk_sp<SkSpecialImage> mirrorYResult(
645 as_IFB(filter)->filterImage(mirrorYCTX).imageAndOffset(&offset));
646 REPORTER_ASSERT(reporter, mirrorYResult);
647
648 SkBitmap normalResultBM, mirrorXResultBM, mirrorYResultBM;
649
650 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, normalResult.get(),
651 &normalResultBM));
652 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, mirrorXResult.get(),
653 &mirrorXResultBM));
654 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, mirrorYResult.get(),
655 &mirrorYResultBM));
656
657 for (int y = 0; y < kHeight; y++) {
658 int diffs = memcmp(normalResultBM.getAddr32(0, y),
659 mirrorXResultBM.getAddr32(0, y),
660 normalResultBM.rowBytes());
661 REPORTER_ASSERT(reporter, !diffs);
662 if (diffs) {
663 break;
664 }
665 diffs = memcmp(normalResultBM.getAddr32(0, y),
666 mirrorYResultBM.getAddr32(0, y),
667 normalResultBM.rowBytes());
668 REPORTER_ASSERT(reporter, !diffs);
669 if (diffs) {
670 break;
671 }
672 }
673 }
674
DEF_TEST(MorphologyFilterRadiusWithMirrorCTM,reporter)675 DEF_TEST(MorphologyFilterRadiusWithMirrorCTM, reporter) {
676 test_morphology_radius_with_mirror_ctm(reporter, nullptr);
677 }
678
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu,reporter,ctxInfo)679 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu, reporter, ctxInfo) {
680 test_morphology_radius_with_mirror_ctm(reporter, ctxInfo.directContext());
681 }
682
test_zero_blur_sigma(skiatest::Reporter * reporter,GrDirectContext * dContext)683 static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrDirectContext* dContext) {
684 // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
685 SkIRect cropRect = SkIRect::MakeXYWH(5, 0, 5, 10);
686 sk_sp<SkImageFilter> input(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
687 sk_sp<SkImageFilter> filter(SkImageFilters::Blur(0, 0, std::move(input), &cropRect));
688
689 sk_sp<SkSpecialSurface> surf(create_empty_special_surface(dContext, 10));
690 surf->getCanvas()->clear(SK_ColorGREEN);
691 sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
692
693 SkIPoint offset;
694 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
695 kN32_SkColorType, nullptr, image.get());
696
697 sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
698 REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
699 REPORTER_ASSERT(reporter, result);
700 REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
701
702 SkBitmap resultBM;
703
704 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
705
706 for (int y = 0; y < resultBM.height(); y++) {
707 for (int x = 0; x < resultBM.width(); x++) {
708 bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
709 REPORTER_ASSERT(reporter, !diff);
710 if (diff) {
711 break;
712 }
713 }
714 }
715 }
716
DEF_TEST(ImageFilterZeroBlurSigma,reporter)717 DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
718 test_zero_blur_sigma(reporter, nullptr);
719 }
720
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu,reporter,ctxInfo)721 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
722 test_zero_blur_sigma(reporter, ctxInfo.directContext());
723 }
724
725
726 // Tests that, even when an upstream filter has returned null (due to failure or clipping), a
727 // downstream filter that affects transparent black still does so even with a nullptr input.
test_fail_affects_transparent_black(skiatest::Reporter * reporter,GrDirectContext * dContext)728 static void test_fail_affects_transparent_black(skiatest::Reporter* reporter,
729 GrDirectContext* dContext) {
730 sk_sp<FailImageFilter> failFilter(new FailImageFilter());
731 sk_sp<SkSpecialImage> source(create_empty_special_image(dContext, 5));
732 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr,
733 kN32_SkColorType, nullptr, source.get());
734 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
735 SkASSERT(as_CFB(green)->affectsTransparentBlack());
736 sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(std::move(green),
737 std::move(failFilter)));
738 SkIPoint offset;
739 sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(ctx).imageAndOffset(&offset));
740 REPORTER_ASSERT(reporter, nullptr != result.get());
741 if (result) {
742 SkBitmap resultBM;
743 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
744 REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
745 }
746 }
747
DEF_TEST(ImageFilterFailAffectsTransparentBlack,reporter)748 DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
749 test_fail_affects_transparent_black(reporter, nullptr);
750 }
751
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu,reporter,ctxInfo)752 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
753 test_fail_affects_transparent_black(reporter, ctxInfo.directContext());
754 }
755
DEF_TEST(ImageFilterDrawTiled,reporter)756 DEF_TEST(ImageFilterDrawTiled, reporter) {
757 // Check that all filters when drawn tiled (with subsequent clip rects) exactly
758 // match the same filters drawn with a single full-canvas bitmap draw.
759 // Tests pass by not asserting.
760
761 FilterList filters(nullptr);
762
763 SkBitmap untiledResult, tiledResult;
764 const int width = 64, height = 64;
765 untiledResult.allocN32Pixels(width, height);
766 tiledResult.allocN32Pixels(width, height);
767 SkCanvas tiledCanvas(tiledResult);
768 SkCanvas untiledCanvas(untiledResult);
769 const int tileSize = 8;
770
771 SkPaint textPaint;
772 textPaint.setColor(SK_ColorWHITE);
773 SkFont font(ToolUtils::create_portable_typeface(), height);
774
775 const char* text = "ABC";
776 const SkScalar yPos = SkIntToScalar(height);
777
778 for (int scale = 1; scale <= 2; ++scale) {
779 for (int i = 0; i < filters.count(); ++i) {
780 SkPaint combinedPaint;
781 combinedPaint.setColor(SK_ColorWHITE);
782 combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
783
784 untiledCanvas.clear(SK_ColorTRANSPARENT);
785 untiledCanvas.save();
786 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
787 untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
788 untiledCanvas.restore();
789
790 tiledCanvas.clear(SK_ColorTRANSPARENT);
791 for (int y = 0; y < height; y += tileSize) {
792 for (int x = 0; x < width; x += tileSize) {
793 tiledCanvas.save();
794 const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
795 tiledCanvas.clipRect(clipRect);
796 if (filters.needsSaveLayer(i)) {
797 const SkRect layerBounds = SkRect::MakeIWH(width, height);
798 tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
799 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
800 tiledCanvas.drawString(text, 0, yPos, font, textPaint);
801 tiledCanvas.restore();
802 } else {
803 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
804 tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
805 }
806
807 tiledCanvas.restore();
808 }
809 }
810
811 if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
812 REPORTER_ASSERT(reporter, false, filters.getName(i));
813 break;
814 }
815 }
816 }
817 }
818
draw_saveLayer_picture(int width,int height,int tileSize,SkBBHFactory * factory,SkBitmap * result)819 static void draw_saveLayer_picture(int width, int height, int tileSize,
820 SkBBHFactory* factory, SkBitmap* result) {
821
822 SkMatrix matrix;
823 matrix.setTranslate(SkIntToScalar(50), 0);
824
825 sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
826 sk_sp<SkImageFilter> cfif(SkImageFilters::ColorFilter(std::move(cf), nullptr));
827 sk_sp<SkImageFilter> imageFilter(SkImageFilters::MatrixTransform(matrix,
828 SkSamplingOptions(),
829 std::move(cfif)));
830
831 SkPaint paint;
832 paint.setImageFilter(std::move(imageFilter));
833 SkPictureRecorder recorder;
834 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
835 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
836 SkIntToScalar(height),
837 factory);
838 recordingCanvas->translate(-55, 0);
839 recordingCanvas->saveLayer(&bounds, &paint);
840 recordingCanvas->restore();
841 sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
842
843 result->allocN32Pixels(width, height);
844 SkCanvas canvas(*result);
845 canvas.clear(0);
846 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
847 canvas.drawPicture(picture1.get());
848 }
849
DEF_TEST(ImageFilterDrawMatrixBBH,reporter)850 DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
851 // Check that matrix filter when drawn tiled with BBH exactly
852 // matches the same thing drawn without BBH.
853 // Tests pass by not asserting.
854
855 const int width = 200, height = 200;
856 const int tileSize = 100;
857 SkBitmap result1, result2;
858 SkRTreeFactory factory;
859
860 draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
861 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
862
863 for (int y = 0; y < height; y++) {
864 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
865 REPORTER_ASSERT(reporter, !diffs);
866 if (diffs) {
867 break;
868 }
869 }
870 }
871
make_blur(sk_sp<SkImageFilter> input)872 static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
873 return SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, std::move(input));
874 }
875
make_drop_shadow(sk_sp<SkImageFilter> input)876 static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
877 return SkImageFilters::DropShadow(100, 100, 10, 10, SK_ColorBLUE, std::move(input));
878 }
879
DEF_TEST(ImageFilterBlurThenShadowBounds,reporter)880 DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
881 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
882 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
883
884 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
885 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
886 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
887 SkImageFilter::kReverse_MapDirection, &bounds);
888
889 REPORTER_ASSERT(reporter, bounds == expectedBounds);
890 }
891
DEF_TEST(ImageFilterShadowThenBlurBounds,reporter)892 DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
893 sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
894 sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
895
896 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
897 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
898 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
899 SkImageFilter::kReverse_MapDirection, &bounds);
900
901 REPORTER_ASSERT(reporter, bounds == expectedBounds);
902 }
903
DEF_TEST(ImageFilterDilateThenBlurBounds,reporter)904 DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
905 sk_sp<SkImageFilter> filter1(SkImageFilters::Dilate(2, 2, nullptr));
906 sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
907
908 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
909 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
910 bounds = filter2->filterBounds(bounds, SkMatrix::I(),
911 SkImageFilter::kReverse_MapDirection, &bounds);
912
913 REPORTER_ASSERT(reporter, bounds == expectedBounds);
914 }
915
DEF_TEST(ImageFilterScaledBlurRadius,reporter)916 DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
917 // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
918 // (before the CTM). Bounds should be computed correctly in the presence of
919 // a (possibly negative) scale.
920 sk_sp<SkImageFilter> blur(make_blur(nullptr));
921 sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
922 {
923 // Uniform scale by 2.
924 SkMatrix scaleMatrix;
925 scaleMatrix.setScale(2, 2);
926 SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
927
928 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
929 SkIRect blurBounds = blur->filterBounds(
930 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
931 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
932 SkIRect reverseBlurBounds = blur->filterBounds(
933 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
934 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
935
936 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
937 SkIRect shadowBounds = dropShadow->filterBounds(
938 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
939 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
940 SkIRect expectedReverseShadowBounds =
941 SkIRect::MakeLTRB(-260, -260, 200, 200);
942 SkIRect reverseShadowBounds = dropShadow->filterBounds(
943 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
944 REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
945 }
946 {
947 // Vertical flip.
948 SkMatrix scaleMatrix;
949 scaleMatrix.setScale(1, -1);
950 SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
951
952 SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
953 SkIRect blurBounds = blur->filterBounds(
954 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
955 REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
956 SkIRect reverseBlurBounds = blur->filterBounds(
957 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
958 REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
959
960 SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
961 SkIRect shadowBounds = dropShadow->filterBounds(
962 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
963 REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
964 SkIRect expectedReverseShadowBounds =
965 SkIRect::MakeLTRB(-130, -100, 100, 130);
966 SkIRect reverseShadowBounds = dropShadow->filterBounds(
967 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
968 REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
969 }
970 }
971
DEF_TEST(ImageFilterComposedBlurFastBounds,reporter)972 DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
973 sk_sp<SkImageFilter> filter1(make_blur(nullptr));
974 sk_sp<SkImageFilter> filter2(make_blur(nullptr));
975 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(filter1),
976 std::move(filter2)));
977
978 SkRect boundsSrc = SkRect::MakeIWH(100, 100);
979 SkRect expectedBounds = SkRect::MakeXYWH(-6, -6, 112, 112);
980 SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
981
982 REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
983 }
984
DEF_TEST(ImageFilterUnionBounds,reporter)985 DEF_TEST(ImageFilterUnionBounds, reporter) {
986 sk_sp<SkImageFilter> offset(SkImageFilters::Offset(50, 0, nullptr));
987 // Regardless of which order they appear in, the image filter bounds should
988 // be combined correctly.
989 {
990 sk_sp<SkImageFilter> composite(SkImageFilters::Blend(SkBlendMode::kSrcOver, offset));
991 SkRect bounds = SkRect::MakeIWH(100, 100);
992 // Intentionally aliasing here, as that's what the real callers do.
993 bounds = composite->computeFastBounds(bounds);
994 REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
995 }
996 {
997 sk_sp<SkImageFilter> composite(SkImageFilters::Blend(SkBlendMode::kSrcOver, nullptr,
998 offset, nullptr));
999 SkRect bounds = SkRect::MakeIWH(100, 100);
1000 // Intentionally aliasing here, as that's what the real callers do.
1001 bounds = composite->computeFastBounds(bounds);
1002 REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
1003 }
1004 }
1005
test_imagefilter_merge_result_size(skiatest::Reporter * reporter,GrRecordingContext * rContext)1006 static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter,
1007 GrRecordingContext* rContext) {
1008 SkBitmap greenBM;
1009 greenBM.allocN32Pixels(20, 20);
1010 greenBM.eraseColor(SK_ColorGREEN);
1011 sk_sp<SkImage> greenImage(greenBM.asImage());
1012 sk_sp<SkImageFilter> source(SkImageFilters::Image(std::move(greenImage)));
1013 sk_sp<SkImageFilter> merge(SkImageFilters::Merge(source, source));
1014
1015 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 1));
1016
1017 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
1018 kN32_SkColorType, nullptr, srcImg.get());
1019 SkIPoint offset;
1020
1021 sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(ctx).imageAndOffset(&offset));
1022 REPORTER_ASSERT(reporter, resultImg);
1023
1024 REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
1025 }
1026
DEF_TEST(ImageFilterMergeResultSize,reporter)1027 DEF_TEST(ImageFilterMergeResultSize, reporter) {
1028 test_imagefilter_merge_result_size(reporter, nullptr);
1029 }
1030
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu,reporter,ctxInfo)1031 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
1032 test_imagefilter_merge_result_size(reporter, ctxInfo.directContext());
1033 }
1034
draw_blurred_rect(SkCanvas * canvas)1035 static void draw_blurred_rect(SkCanvas* canvas) {
1036 SkPaint filterPaint;
1037 filterPaint.setColor(SK_ColorWHITE);
1038 filterPaint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(8), 0, nullptr));
1039 canvas->saveLayer(nullptr, &filterPaint);
1040 SkPaint whitePaint;
1041 whitePaint.setColor(SK_ColorWHITE);
1042 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1043 canvas->restore();
1044 }
1045
draw_picture_clipped(SkCanvas * canvas,const SkRect & clipRect,const SkPicture * picture)1046 static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
1047 canvas->save();
1048 canvas->clipRect(clipRect);
1049 canvas->drawPicture(picture);
1050 canvas->restore();
1051 }
1052
DEF_TEST(ImageFilterDrawTiledBlurRTree,reporter)1053 DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1054 // Check that the blur filter when recorded with RTree acceleration,
1055 // and drawn tiled (with subsequent clip rects) exactly
1056 // matches the same filter drawn with without RTree acceleration.
1057 // This tests that the "bleed" from the blur into the otherwise-blank
1058 // tiles is correctly rendered.
1059 // Tests pass by not asserting.
1060
1061 int width = 16, height = 8;
1062 SkBitmap result1, result2;
1063 result1.allocN32Pixels(width, height);
1064 result2.allocN32Pixels(width, height);
1065 SkCanvas canvas1(result1);
1066 SkCanvas canvas2(result2);
1067 int tileSize = 8;
1068
1069 canvas1.clear(0);
1070 canvas2.clear(0);
1071
1072 SkRTreeFactory factory;
1073
1074 SkPictureRecorder recorder1, recorder2;
1075 // The only difference between these two pictures is that one has RTree aceleration.
1076 SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height);
1077 SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory);
1078
1079 draw_blurred_rect(recordingCanvas1);
1080 draw_blurred_rect(recordingCanvas2);
1081 sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1082 sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
1083 for (int y = 0; y < height; y += tileSize) {
1084 for (int x = 0; x < width; x += tileSize) {
1085 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
1086 draw_picture_clipped(&canvas1, tileRect, picture1.get());
1087 draw_picture_clipped(&canvas2, tileRect, picture2.get());
1088 }
1089 }
1090 for (int y = 0; y < height; y++) {
1091 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1092 REPORTER_ASSERT(reporter, !diffs);
1093 if (diffs) {
1094 break;
1095 }
1096 }
1097 }
1098
DEF_TEST(ImageFilterMatrixConvolution,reporter)1099 DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1100 // Check that a 1x3 filter does not cause a spurious assert.
1101 SkScalar kernel[3] = {
1102 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1103 };
1104 SkISize kernelSize = SkISize::Make(1, 3);
1105 SkScalar gain = SK_Scalar1, bias = 0;
1106 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1107
1108 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1109 kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kRepeat, false, nullptr));
1110
1111 SkBitmap result;
1112 int width = 16, height = 16;
1113 result.allocN32Pixels(width, height);
1114 SkCanvas canvas(result);
1115 canvas.clear(0);
1116
1117 SkPaint paint;
1118 paint.setImageFilter(std::move(filter));
1119 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1120 canvas.drawRect(rect, paint);
1121 }
1122
DEF_TEST(ImageFilterMatrixConvolutionBorder,reporter)1123 DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1124 // Check that a filter with borders outside the target bounds
1125 // does not crash.
1126 SkScalar kernel[3] = {
1127 0, 0, 0,
1128 };
1129 SkISize kernelSize = SkISize::Make(3, 1);
1130 SkScalar gain = SK_Scalar1, bias = 0;
1131 SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1132
1133 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1134 kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kClamp, true, nullptr));
1135
1136 SkBitmap result;
1137
1138 int width = 10, height = 10;
1139 result.allocN32Pixels(width, height);
1140 SkCanvas canvas(result);
1141 canvas.clear(0);
1142
1143 SkPaint filterPaint;
1144 filterPaint.setImageFilter(std::move(filter));
1145 SkRect bounds = SkRect::MakeIWH(1, 10);
1146 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1147 SkPaint rectPaint;
1148 canvas.saveLayer(&bounds, &filterPaint);
1149 canvas.drawRect(rect, rectPaint);
1150 canvas.restore();
1151 }
1152
test_big_kernel(skiatest::Reporter * reporter,GrRecordingContext * rContext)1153 static void test_big_kernel(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
1154 // Check that a kernel that is too big for the GPU still works
1155 SkScalar identityKernel[49] = {
1156 0, 0, 0, 0, 0, 0, 0,
1157 0, 0, 0, 0, 0, 0, 0,
1158 0, 0, 0, 0, 0, 0, 0,
1159 0, 0, 0, 1, 0, 0, 0,
1160 0, 0, 0, 0, 0, 0, 0,
1161 0, 0, 0, 0, 0, 0, 0,
1162 0, 0, 0, 0, 0, 0, 0
1163 };
1164 SkISize kernelSize = SkISize::Make(7, 7);
1165 SkScalar gain = SK_Scalar1, bias = 0;
1166 SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1167
1168 sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1169 kernelSize, identityKernel, gain, bias, kernelOffset,
1170 SkTileMode::kClamp, true, nullptr));
1171
1172 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
1173 SkASSERT(srcImg);
1174
1175 SkIPoint offset;
1176 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
1177 kN32_SkColorType, nullptr, srcImg.get());
1178 sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(&offset));
1179 REPORTER_ASSERT(reporter, resultImg);
1180 REPORTER_ASSERT(reporter, SkToBool(rContext) == resultImg->isTextureBacked());
1181 REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1182 REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1183 }
1184
DEF_TEST(ImageFilterMatrixConvolutionBigKernel,reporter)1185 DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
1186 test_big_kernel(reporter, nullptr);
1187 }
1188
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,reporter,ctxInfo)1189 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1190 reporter, ctxInfo) {
1191 test_big_kernel(reporter, ctxInfo.directContext());
1192 }
1193
DEF_TEST(ImageFilterCropRect,reporter)1194 DEF_TEST(ImageFilterCropRect, reporter) {
1195 test_cropRects(reporter, nullptr);
1196 }
1197
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu,reporter,ctxInfo)1198 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
1199 test_cropRects(reporter, ctxInfo.directContext());
1200 }
1201
DEF_TEST(ImageFilterMatrix,reporter)1202 DEF_TEST(ImageFilterMatrix, reporter) {
1203 SkBitmap temp;
1204 temp.allocN32Pixels(100, 100);
1205 SkCanvas canvas(temp);
1206 canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1207
1208 SkMatrix expectedMatrix = canvas.getTotalMatrix();
1209
1210 SkRTreeFactory factory;
1211 SkPictureRecorder recorder;
1212 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory);
1213
1214 SkPaint paint;
1215 paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
1216 recordingCanvas->saveLayer(nullptr, &paint);
1217 SkPaint solidPaint;
1218 solidPaint.setColor(0xFFFFFFFF);
1219 recordingCanvas->save();
1220 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1221 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1222 recordingCanvas->restore(); // scale
1223 recordingCanvas->restore(); // saveLayer
1224
1225 canvas.drawPicture(recorder.finishRecordingAsPicture());
1226 }
1227
test_clipped_picture_imagefilter(skiatest::Reporter * reporter,GrRecordingContext * rContext)1228 static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter,
1229 GrRecordingContext* rContext) {
1230 sk_sp<SkPicture> picture;
1231
1232 {
1233 SkRTreeFactory factory;
1234 SkPictureRecorder recorder;
1235 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory);
1236
1237 // Create an SkPicture which simply draws a green 1x1 rectangle.
1238 SkPaint greenPaint;
1239 greenPaint.setColor(SK_ColorGREEN);
1240 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
1241 picture = recorder.finishRecordingAsPicture();
1242 }
1243
1244 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 2));
1245
1246 sk_sp<SkImageFilter> imageFilter(SkImageFilters::Picture(picture));
1247
1248 SkIPoint offset;
1249 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr,
1250 kN32_SkColorType, nullptr, srcImg.get());
1251
1252 sk_sp<SkSpecialImage> resultImage(
1253 as_IFB(imageFilter)->filterImage(ctx).imageAndOffset(&offset));
1254 REPORTER_ASSERT(reporter, !resultImage);
1255 }
1256
DEF_TEST(ImageFilterClippedPictureImageFilter,reporter)1257 DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
1258 test_clipped_picture_imagefilter(reporter, nullptr);
1259 }
1260
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu,reporter,ctxInfo)1261 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
1262 test_clipped_picture_imagefilter(reporter, ctxInfo.directContext());
1263 }
1264
DEF_TEST(ImageFilterEmptySaveLayer,reporter)1265 DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
1266 // Even when there's an empty saveLayer()/restore(), ensure that an image
1267 // filter or color filter which affects transparent black still draws.
1268
1269 SkBitmap bitmap;
1270 bitmap.allocN32Pixels(10, 10);
1271 SkCanvas canvas(bitmap);
1272
1273 SkRTreeFactory factory;
1274 SkPictureRecorder recorder;
1275
1276 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
1277 sk_sp<SkImageFilter> imageFilter(SkImageFilters::ColorFilter(green, nullptr));
1278 SkPaint imageFilterPaint;
1279 imageFilterPaint.setImageFilter(std::move(imageFilter));
1280 SkPaint colorFilterPaint;
1281 colorFilterPaint.setColorFilter(green);
1282
1283 SkRect bounds = SkRect::MakeIWH(10, 10);
1284
1285 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory);
1286 recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1287 recordingCanvas->restore();
1288 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1289
1290 canvas.clear(0);
1291 canvas.drawPicture(picture);
1292 uint32_t pixel = *bitmap.getAddr32(0, 0);
1293 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1294
1295 recordingCanvas = recorder.beginRecording(10, 10, &factory);
1296 recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
1297 recordingCanvas->restore();
1298 sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
1299
1300 canvas.clear(0);
1301 canvas.drawPicture(picture2);
1302 pixel = *bitmap.getAddr32(0, 0);
1303 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1304
1305 recordingCanvas = recorder.beginRecording(10, 10, &factory);
1306 recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1307 recordingCanvas->restore();
1308 sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
1309
1310 canvas.clear(0);
1311 canvas.drawPicture(picture3);
1312 pixel = *bitmap.getAddr32(0, 0);
1313 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1314 }
1315
test_huge_blur(SkCanvas * canvas,skiatest::Reporter * reporter)1316 static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
1317 SkBitmap bitmap;
1318 bitmap.allocN32Pixels(100, 100);
1319 bitmap.eraseARGB(0, 0, 0, 0);
1320
1321 // Check that a blur with a very large radius does not crash or assert.
1322 SkPaint paint;
1323 paint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(1<<30), SkIntToScalar(1<<30), nullptr));
1324 canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
1325 }
1326
DEF_TEST(HugeBlurImageFilter,reporter)1327 DEF_TEST(HugeBlurImageFilter, reporter) {
1328 SkBitmap temp;
1329 temp.allocN32Pixels(100, 100);
1330 SkCanvas canvas(temp);
1331 test_huge_blur(&canvas, reporter);
1332 }
1333
DEF_TEST(ImageFilterMatrixConvolutionTest,reporter)1334 DEF_TEST(ImageFilterMatrixConvolutionTest, reporter) {
1335 SkScalar kernel[1] = { 0 };
1336 SkScalar gain = SK_Scalar1, bias = 0;
1337 SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1338
1339 // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
1340 sk_sp<SkImageFilter> conv(SkImageFilters::MatrixConvolution(
1341 SkISize::Make(1<<30, 1<<30), kernel, gain, bias, kernelOffset,
1342 SkTileMode::kRepeat, false, nullptr));
1343
1344 REPORTER_ASSERT(reporter, nullptr == conv.get());
1345
1346 // Check that a nullptr kernel gives a nullptr filter.
1347 conv = SkImageFilters::MatrixConvolution(
1348 SkISize::Make(1, 1), nullptr, gain, bias, kernelOffset,
1349 SkTileMode::kRepeat, false, nullptr);
1350
1351 REPORTER_ASSERT(reporter, nullptr == conv.get());
1352
1353 // Check that a kernel width < 1 gives a nullptr filter.
1354 conv = SkImageFilters::MatrixConvolution(
1355 SkISize::Make(0, 1), kernel, gain, bias, kernelOffset,
1356 SkTileMode::kRepeat, false, nullptr);
1357
1358 REPORTER_ASSERT(reporter, nullptr == conv.get());
1359
1360 // Check that kernel height < 1 gives a nullptr filter.
1361 conv = SkImageFilters::MatrixConvolution(
1362 SkISize::Make(1, -1), kernel, gain, bias, kernelOffset,
1363 SkTileMode::kRepeat, false, nullptr);
1364
1365 REPORTER_ASSERT(reporter, nullptr == conv.get());
1366 }
1367
test_xfermode_cropped_input(SkSurface * surf,skiatest::Reporter * reporter)1368 static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1369 auto canvas = surf->getCanvas();
1370 canvas->clear(0);
1371
1372 SkBitmap bitmap;
1373 bitmap.allocN32Pixels(1, 1);
1374 bitmap.eraseARGB(255, 255, 255, 255);
1375
1376 sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
1377 sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(green, nullptr));
1378 SkIRect cropRect = SkIRect::MakeEmpty();
1379 sk_sp<SkImageFilter> croppedOut(SkImageFilters::ColorFilter(green, nullptr, &cropRect));
1380
1381 // Check that an blend image filter whose input has been cropped out still draws the other
1382 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1383 SkBlendMode mode = SkBlendMode::kSrcOver;
1384 sk_sp<SkImageFilter> xfermodeNoFg(SkImageFilters::Blend(
1385 mode, greenFilter, croppedOut, nullptr));
1386 sk_sp<SkImageFilter> xfermodeNoBg(SkImageFilters::Blend(
1387 mode, croppedOut, greenFilter, nullptr));
1388 sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkImageFilters::Blend(
1389 mode, croppedOut, croppedOut, nullptr));
1390
1391 SkPaint paint;
1392 paint.setImageFilter(std::move(xfermodeNoFg));
1393 canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint); // drawSprite
1394
1395 uint32_t pixel;
1396 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1397 surf->readPixels(info, &pixel, 4, 0, 0);
1398 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1399
1400 paint.setImageFilter(std::move(xfermodeNoBg));
1401 canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint); // drawSprite
1402 surf->readPixels(info, &pixel, 4, 0, 0);
1403 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1404
1405 paint.setImageFilter(std::move(xfermodeNoFgNoBg));
1406 canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint); // drawSprite
1407 surf->readPixels(info, &pixel, 4, 0, 0);
1408 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1409 }
1410
DEF_TEST(ImageFilterNestedSaveLayer,reporter)1411 DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1412 SkBitmap temp;
1413 temp.allocN32Pixels(50, 50);
1414 SkCanvas canvas(temp);
1415 canvas.clear(0x0);
1416
1417 SkBitmap bitmap;
1418 bitmap.allocN32Pixels(10, 10);
1419 bitmap.eraseColor(SK_ColorGREEN);
1420
1421 SkMatrix matrix;
1422 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1423 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1424 sk_sp<SkImageFilter> matrixFilter(
1425 SkImageFilters::MatrixTransform(matrix, SkSamplingOptions(SkFilterMode::kLinear), nullptr));
1426
1427 // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1428 // correct offset to the filter matrix.
1429 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1430 canvas.saveLayer(&bounds1, nullptr);
1431 SkPaint filterPaint;
1432 filterPaint.setImageFilter(std::move(matrixFilter));
1433 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1434 canvas.saveLayer(&bounds2, &filterPaint);
1435 SkPaint greenPaint;
1436 greenPaint.setColor(SK_ColorGREEN);
1437 canvas.drawRect(bounds2, greenPaint);
1438 canvas.restore();
1439 canvas.restore();
1440 SkPaint strokePaint;
1441 strokePaint.setStyle(SkPaint::kStroke_Style);
1442 strokePaint.setColor(SK_ColorRED);
1443
1444 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1445 uint32_t pixel;
1446 temp.readPixels(info, &pixel, 4, 25, 25);
1447 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1448
1449 // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1450 // correct offset to the filter matrix.
1451 canvas.clear(0x0);
1452 temp.readPixels(info, &pixel, 4, 25, 25);
1453 canvas.saveLayer(&bounds1, nullptr);
1454 canvas.drawImage(bitmap.asImage(), 20, 20, SkSamplingOptions(), &filterPaint); // drawSprite
1455 canvas.restore();
1456
1457 temp.readPixels(info, &pixel, 4, 25, 25);
1458 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1459 }
1460
DEF_TEST(XfermodeImageFilterCroppedInput,reporter)1461 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1462 test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
1463 }
1464
test_composed_imagefilter_offset(skiatest::Reporter * reporter,GrRecordingContext * rContext)1465 static void test_composed_imagefilter_offset(skiatest::Reporter* reporter,
1466 GrRecordingContext* rContext) {
1467 sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
1468
1469 SkIRect cropRect = SkIRect::MakeXYWH(1, 0, 20, 20);
1470 sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
1471 sk_sp<SkImageFilter> blurFilter(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1472 nullptr, &cropRect));
1473 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(blurFilter),
1474 std::move(offsetFilter)));
1475 SkIPoint offset;
1476 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
1477 kN32_SkColorType, nullptr, srcImg.get());
1478
1479 sk_sp<SkSpecialImage> resultImg(
1480 as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(&offset));
1481 REPORTER_ASSERT(reporter, resultImg);
1482 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1483 }
1484
DEF_TEST(ComposedImageFilterOffset,reporter)1485 DEF_TEST(ComposedImageFilterOffset, reporter) {
1486 test_composed_imagefilter_offset(reporter, nullptr);
1487 }
1488
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu,reporter,ctxInfo)1489 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
1490 test_composed_imagefilter_offset(reporter, ctxInfo.directContext());
1491 }
1492
test_composed_imagefilter_bounds(skiatest::Reporter * reporter,GrDirectContext * dContext)1493 static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter,
1494 GrDirectContext* dContext) {
1495 // The bounds passed to the inner filter must be filtered by the outer
1496 // filter, so that the inner filter produces the pixels that the outer
1497 // filter requires as input. This matters if the outer filter moves pixels.
1498 // Here, accounting for the outer offset is necessary so that the green
1499 // pixels of the picture are not clipped.
1500
1501 SkPictureRecorder recorder;
1502 SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeIWH(200, 100));
1503 recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1504 recordingCanvas->clear(SK_ColorGREEN);
1505 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1506 sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(picture));
1507 SkIRect cropRect = SkIRect::MakeWH(100, 100);
1508 sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(-100, 0, nullptr, &cropRect));
1509 sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(offsetFilter),
1510 std::move(pictureFilter)));
1511
1512 sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(dContext, 100));
1513 SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
1514 kN32_SkColorType, nullptr, sourceImage.get());
1515 SkIPoint offset;
1516 sk_sp<SkSpecialImage> result(
1517 as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(&offset));
1518 REPORTER_ASSERT(reporter, offset.isZero());
1519 REPORTER_ASSERT(reporter, result);
1520 REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1521
1522 SkBitmap resultBM;
1523 REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
1524 REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1525 }
1526
DEF_TEST(ComposedImageFilterBounds,reporter)1527 DEF_TEST(ComposedImageFilterBounds, reporter) {
1528 test_composed_imagefilter_bounds(reporter, nullptr);
1529 }
1530
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu,reporter,ctxInfo)1531 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
1532 test_composed_imagefilter_bounds(reporter, ctxInfo.directContext());
1533 }
1534
DEF_TEST(ImageFilterCanComputeFastBounds,reporter)1535 DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1536
1537 {
1538 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1539 sk_sp<SkImageFilter> lighting(SkImageFilters::PointLitDiffuse(
1540 location, SK_ColorGREEN, 0, 0, nullptr));
1541 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1542 }
1543
1544 {
1545 sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1546 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1547 {
1548 SkColorFilter* grayCF;
1549 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1550 REPORTER_ASSERT(reporter, !as_CFB(grayCF)->affectsTransparentBlack());
1551 grayCF->unref();
1552 }
1553 REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1554
1555 sk_sp<SkImageFilter> grayBlur(SkImageFilters::Blur(
1556 SK_Scalar1, SK_Scalar1, std::move(gray)));
1557 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1558 }
1559
1560 {
1561 float greenMatrix[20] = { 0, 0, 0, 0, 0,
1562 0, 0, 0, 0, 1.0f/255,
1563 0, 0, 0, 0, 0,
1564 0, 0, 0, 0, 1.0f/255
1565 };
1566 sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
1567 sk_sp<SkImageFilter> green(SkImageFilters::ColorFilter(greenCF, nullptr));
1568
1569 REPORTER_ASSERT(reporter, as_CFB(greenCF)->affectsTransparentBlack());
1570 REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1571
1572 sk_sp<SkImageFilter> greenBlur(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1573 std::move(green)));
1574 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1575 }
1576
1577 uint8_t allOne[256], identity[256];
1578 for (int i = 0; i < 256; ++i) {
1579 identity[i] = i;
1580 allOne[i] = 255;
1581 }
1582
1583 sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1584 identity, allOne));
1585 sk_sp<SkImageFilter> identityFilter(SkImageFilters::ColorFilter(identityCF, nullptr));
1586 REPORTER_ASSERT(reporter, !as_CFB(identityCF)->affectsTransparentBlack());
1587 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1588
1589 sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1590 identity, identity));
1591 sk_sp<SkImageFilter> forceOpaque(SkImageFilters::ColorFilter(forceOpaqueCF, nullptr));
1592 REPORTER_ASSERT(reporter, as_CFB(forceOpaqueCF)->affectsTransparentBlack());
1593 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1594 }
1595
1596 // Verify that SkImageSource survives serialization
DEF_TEST(ImageFilterImageSourceSerialization,reporter)1597 DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
1598 auto surface(SkSurface::MakeRasterN32Premul(10, 10));
1599 surface->getCanvas()->clear(SK_ColorGREEN);
1600 sk_sp<SkImage> image(surface->makeImageSnapshot());
1601 sk_sp<SkImageFilter> filter(SkImageFilters::Image(std::move(image)));
1602
1603 sk_sp<SkData> data(filter->serialize());
1604 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1605 REPORTER_ASSERT(reporter, unflattenedFilter);
1606
1607 SkBitmap bm;
1608 bm.allocN32Pixels(10, 10);
1609 bm.eraseColor(SK_ColorBLUE);
1610 SkPaint paint;
1611 paint.setColor(SK_ColorRED);
1612 paint.setImageFilter(unflattenedFilter);
1613
1614 SkCanvas canvas(bm);
1615 canvas.drawRect(SkRect::MakeIWH(10, 10), paint);
1616 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1617 }
1618
DEF_TEST(ImageFilterImageSourceUninitialized,r)1619 DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1620 sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1621 if (!data) {
1622 return;
1623 }
1624 sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1625 // This will fail. More importantly, msan will verify that we did not
1626 // compare against uninitialized memory.
1627 REPORTER_ASSERT(r, !unflattenedFilter);
1628 }
1629
test_large_blur_input(skiatest::Reporter * reporter,SkCanvas * canvas)1630 static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1631 SkBitmap largeBmp;
1632 int largeW = 5000;
1633 int largeH = 5000;
1634 // If we're GPU-backed make the bitmap too large to be converted into a texture.
1635 if (auto ctx = canvas->recordingContext()) {
1636 largeW = ctx->priv().caps()->maxTextureSize() + 1;
1637 }
1638
1639 largeBmp.allocN32Pixels(largeW, largeH);
1640 largeBmp.eraseColor(0);
1641 if (!largeBmp.getPixels()) {
1642 ERRORF(reporter, "Failed to allocate large bmp.");
1643 return;
1644 }
1645
1646 sk_sp<SkImage> largeImage(largeBmp.asImage());
1647 if (!largeImage) {
1648 ERRORF(reporter, "Failed to create large image.");
1649 return;
1650 }
1651
1652 sk_sp<SkImageFilter> largeSource(SkImageFilters::Image(std::move(largeImage)));
1653 if (!largeSource) {
1654 ERRORF(reporter, "Failed to create large SkImageSource.");
1655 return;
1656 }
1657
1658 sk_sp<SkImageFilter> blur(SkImageFilters::Blur(10.f, 10.f, std::move(largeSource)));
1659 if (!blur) {
1660 ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1661 return;
1662 }
1663
1664 SkPaint paint;
1665 paint.setImageFilter(std::move(blur));
1666
1667 // This should not crash (http://crbug.com/570479).
1668 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1669 }
1670
DEF_TEST(ImageFilterBlurLargeImage,reporter)1671 DEF_TEST(ImageFilterBlurLargeImage, reporter) {
1672 auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
1673 test_large_blur_input(reporter, surface->getCanvas());
1674 }
1675
test_make_with_filter(skiatest::Reporter * reporter,GrRecordingContext * rContext)1676 static void test_make_with_filter(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
1677 sk_sp<SkSurface> surface(create_surface(rContext, 192, 128));
1678 surface->getCanvas()->clear(SK_ColorRED);
1679 SkPaint bluePaint;
1680 bluePaint.setColor(SK_ColorBLUE);
1681 SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1682 surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1683 sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1684
1685 sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1686 SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1687 SkIRect outSubset;
1688 SkIPoint offset;
1689 sk_sp<SkImage> result;
1690
1691 result = sourceImage->makeWithFilter(rContext, nullptr, subset, clipBounds,
1692 &outSubset, &offset);
1693 REPORTER_ASSERT(reporter, !result);
1694
1695 result = sourceImage->makeWithFilter(rContext, filter.get(), subset, clipBounds,
1696 nullptr, &offset);
1697 REPORTER_ASSERT(reporter, !result);
1698
1699 result = sourceImage->makeWithFilter(rContext, filter.get(), subset, clipBounds,
1700 &outSubset, nullptr);
1701 REPORTER_ASSERT(reporter, !result);
1702
1703 SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1704 result = sourceImage->makeWithFilter(rContext, filter.get(), bigSubset, clipBounds,
1705 &outSubset, &offset);
1706 REPORTER_ASSERT(reporter, !result);
1707
1708 SkIRect empty = SkIRect::MakeEmpty();
1709 result = sourceImage->makeWithFilter(rContext, filter.get(), empty, clipBounds,
1710 &outSubset, &offset);
1711 REPORTER_ASSERT(reporter, !result);
1712
1713 result = sourceImage->makeWithFilter(rContext, filter.get(), subset, empty,
1714 &outSubset, &offset);
1715 REPORTER_ASSERT(reporter, !result);
1716
1717 SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1718 result = sourceImage->makeWithFilter(rContext, filter.get(), subset, leftField,
1719 &outSubset, &offset);
1720 REPORTER_ASSERT(reporter, !result);
1721
1722 result = sourceImage->makeWithFilter(rContext, filter.get(), subset, clipBounds,
1723 &outSubset, &offset);
1724
1725 REPORTER_ASSERT(reporter, result);
1726 REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1727 SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1728 outSubset.width(), outSubset.height());
1729 REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1730
1731 // In GPU-mode, this case creates a special image with a backing size that differs from
1732 // the content size
1733 {
1734 clipBounds.setXYWH(0, 0, 170, 100);
1735 subset.setXYWH(0, 0, 160, 90);
1736
1737 filter = SkImageFilters::Blend(SkBlendMode::kSrc, nullptr);
1738 result = sourceImage->makeWithFilter(rContext, filter.get(), subset, clipBounds,
1739 &outSubset, &offset);
1740 REPORTER_ASSERT(reporter, result);
1741 }
1742 }
1743
DEF_TEST(ImageFilterMakeWithFilter,reporter)1744 DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1745 test_make_with_filter(reporter, nullptr);
1746 }
1747
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu,reporter,ctxInfo)1748 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1749 test_make_with_filter(reporter, ctxInfo.directContext());
1750 }
1751
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu,reporter,ctxInfo)1752 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
1753
1754 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.directContext(),
1755 SkBudgeted::kNo,
1756 SkImageInfo::MakeN32Premul(100, 100)));
1757
1758
1759 SkCanvas* canvas = surf->getCanvas();
1760
1761 test_huge_blur(canvas, reporter);
1762 }
1763
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu,reporter,ctxInfo)1764 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
1765 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1766 ctxInfo.directContext(),
1767 SkBudgeted::kNo,
1768 SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1769
1770 test_xfermode_cropped_input(surf.get(), reporter);
1771 }
1772
DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu,reporter,ctxInfo)1773 DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
1774 auto surface(SkSurface::MakeRenderTarget(
1775 ctxInfo.directContext(), SkBudgeted::kYes,
1776 SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1777 test_large_blur_input(reporter, surface->getCanvas());
1778 }
1779
1780 /*
1781 * Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1782 * than just scale/translate, but that other filters do.
1783 */
DEF_TEST(ImageFilterComplexCTM,reporter)1784 DEF_TEST(ImageFilterComplexCTM, reporter) {
1785 // just need a colorfilter to exercise the corresponding imagefilter
1786 sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
1787 sk_sp<SkImageFilter> cfif = SkImageFilters::ColorFilter(cf, nullptr); // can handle
1788 sk_sp<SkImageFilter> blif = SkImageFilters::Blur(3, 3, nullptr); // cannot handle
1789 using MatrixCapability = SkImageFilter_Base::MatrixCapability;
1790
1791 struct {
1792 sk_sp<SkImageFilter> fFilter;
1793 MatrixCapability fExpectCapability;
1794 } recs[] = {
1795 { cfif, MatrixCapability::kComplex },
1796 { SkImageFilters::ColorFilter(cf, cfif), MatrixCapability::kComplex },
1797 { SkImageFilters::Merge(cfif, cfif), MatrixCapability::kComplex },
1798 { SkImageFilters::Compose(cfif, cfif), MatrixCapability::kComplex },
1799
1800 { blif, MatrixCapability::kScaleTranslate },
1801 { SkImageFilters::Blur(3, 3, cfif), MatrixCapability::kScaleTranslate },
1802 { SkImageFilters::ColorFilter(cf, blif), MatrixCapability::kScaleTranslate },
1803 { SkImageFilters::Merge(cfif, blif), MatrixCapability::kScaleTranslate },
1804 { SkImageFilters::Compose(blif, cfif), MatrixCapability::kScaleTranslate },
1805 };
1806
1807 for (const auto& rec : recs) {
1808 const MatrixCapability capability = as_IFB(rec.fFilter)->getCTMCapability();
1809 REPORTER_ASSERT(reporter, capability == rec.fExpectCapability);
1810 }
1811 }
1812
1813 // Test SkXfermodeImageFilter::filterBounds with different blending modes.
DEF_TEST(XfermodeImageFilterBounds,reporter)1814 DEF_TEST(XfermodeImageFilterBounds, reporter) {
1815 SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1816 SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1817 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1818 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1819
1820 const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1821 SkIRect expectedBounds[kModeCount];
1822 // Expect union of input rects by default.
1823 for (int i = 0; i < kModeCount; ++i) {
1824 expectedBounds[i] = background_rect;
1825 expectedBounds[i].join(foreground_rect);
1826 }
1827
1828 SkIRect intersection = background_rect;
1829 intersection.intersect(foreground_rect);
1830 expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1831 expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1832 expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1833 expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1834 expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1835 expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1836 expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1837
1838 // The value of this variable doesn't matter because we use inputs with fixed bounds.
1839 SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1840 for (int i = 0; i < kModeCount; ++i) {
1841 sk_sp<SkImageFilter> xfermode(SkImageFilters::Blend(static_cast<SkBlendMode>(i),
1842 background, foreground, nullptr));
1843 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1844 SkImageFilter::kForward_MapDirection, nullptr);
1845 REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1846 }
1847
1848 // Test empty intersection.
1849 sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1850 sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1851 sk_sp<SkImageFilter> xfermode(SkImageFilters::Blend(
1852 SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
1853 auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1854 SkImageFilter::kForward_MapDirection, nullptr);
1855 REPORTER_ASSERT(reporter, bounds.isEmpty());
1856 }
1857
DEF_TEST(OffsetImageFilterBounds,reporter)1858 DEF_TEST(OffsetImageFilterBounds, reporter) {
1859 SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1860 sk_sp<SkImageFilter> offset(SkImageFilters::Offset(-50.5f, -50.5f, nullptr));
1861
1862 SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1863 SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
1864 SkImageFilter::kForward_MapDirection, nullptr);
1865 REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1866
1867 SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1868 SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
1869 SkImageFilter::kReverse_MapDirection, &src);
1870 REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1871 }
1872
test_arithmetic_bounds(skiatest::Reporter * reporter,float k1,float k2,float k3,float k4,sk_sp<SkImageFilter> background,sk_sp<SkImageFilter> foreground,const SkIRect * crop,const SkIRect & expected)1873 static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1874 float k4, sk_sp<SkImageFilter> background,
1875 sk_sp<SkImageFilter> foreground,
1876 const SkIRect* crop, const SkIRect& expected) {
1877 sk_sp<SkImageFilter> arithmetic(
1878 SkImageFilters::Arithmetic(k1, k2, k3, k4, false, background, foreground, crop));
1879 // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1880 SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
1881 SkImageFilter::kForward_MapDirection, nullptr);
1882 REPORTER_ASSERT(reporter, expected == bounds);
1883 }
1884
test_arithmetic_combinations(skiatest::Reporter * reporter,float v)1885 static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1886 SkIRect bgRect = SkIRect::MakeXYWH(0, 0, 100, 100);
1887 SkIRect fgRect = SkIRect::MakeXYWH(50, 50, 100, 100);
1888 sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(bgRect));
1889 sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(fgRect));
1890
1891 SkIRect unionRect = bgRect;
1892 unionRect.join(fgRect);
1893 SkIRect intersection = bgRect;
1894 intersection.intersect(fgRect);
1895
1896 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1897 SkIRect::MakeEmpty());
1898 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, unionRect);
1899 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, bgRect);
1900 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, unionRect);
1901 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, fgRect);
1902 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, unionRect);
1903 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, unionRect);
1904 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, unionRect);
1905 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1906 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, unionRect);
1907 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, bgRect);
1908 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, unionRect);
1909 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, fgRect);
1910 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, unionRect);
1911 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, unionRect);
1912 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, unionRect);
1913
1914 // Test with crop. When k4 is non-zero, the result is expected to be cropRect
1915 // regardless of inputs because the filter affects the whole crop area.
1916 SkIRect cropRect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1917 test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &cropRect,
1918 SkIRect::MakeEmpty());
1919 test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &cropRect, cropRect);
1920 test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &cropRect, bgRect);
1921 test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &cropRect, cropRect);
1922 test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &cropRect, fgRect);
1923 test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &cropRect, cropRect);
1924 test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &cropRect, unionRect);
1925 test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &cropRect, cropRect);
1926 test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &cropRect, intersection);
1927 test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &cropRect, cropRect);
1928 test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &cropRect, bgRect);
1929 test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &cropRect, cropRect);
1930 test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &cropRect, fgRect);
1931 test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &cropRect, cropRect);
1932 test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &cropRect, unionRect);
1933 test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &cropRect, cropRect);
1934 }
1935
1936 // Test SkArithmeticImageFilter::filterBounds with different blending modes.
DEF_TEST(ArithmeticImageFilterBounds,reporter)1937 DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1938 test_arithmetic_combinations(reporter, 1);
1939 test_arithmetic_combinations(reporter, 0.5);
1940 }
1941
1942 // Test SkDisplacementMapEffect::filterBounds.
DEF_TEST(DisplacementMapBounds,reporter)1943 DEF_TEST(DisplacementMapBounds, reporter) {
1944 SkIRect floodBounds(SkIRect::MakeXYWH(20, 30, 10, 10));
1945 sk_sp<SkImageFilter> flood(SkImageFilters::Shader(SkShaders::Color(SK_ColorGREEN),
1946 &floodBounds));
1947 SkIRect tilingBounds(SkIRect::MakeXYWH(0, 0, 200, 100));
1948 sk_sp<SkImageFilter> tiling(SkImageFilters::Tile(SkRect::Make(floodBounds),
1949 SkRect::Make(tilingBounds),
1950 flood));
1951 sk_sp<SkImageFilter> displace(SkImageFilters::DisplacementMap(SkColorChannel::kR,
1952 SkColorChannel::kB,
1953 20.0f, nullptr, tiling));
1954 SkIRect input(SkIRect::MakeXYWH(20, 30, 40, 50));
1955 // Expected: union(floodBounds, outset(input, 10))
1956 SkIRect expected(SkIRect::MakeXYWH(10, 20, 60, 70));
1957 REPORTER_ASSERT(reporter,
1958 expected == displace->filterBounds(input, SkMatrix::I(),
1959 SkImageFilter::kReverse_MapDirection));
1960 }
1961
1962 // Test SkImageSource::filterBounds.
DEF_TEST(ImageSourceBounds,reporter)1963 DEF_TEST(ImageSourceBounds, reporter) {
1964 sk_sp<SkImage> image(make_gradient_circle(64, 64).asImage());
1965 // Default src and dst rects.
1966 sk_sp<SkImageFilter> source1(SkImageFilters::Image(image));
1967 SkIRect imageBounds = SkIRect::MakeWH(64, 64);
1968 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
1969 REPORTER_ASSERT(reporter,
1970 imageBounds == source1->filterBounds(input, SkMatrix::I(),
1971 SkImageFilter::kForward_MapDirection,
1972 nullptr));
1973 REPORTER_ASSERT(reporter,
1974 input == source1->filterBounds(input, SkMatrix::I(),
1975 SkImageFilter::kReverse_MapDirection, &input));
1976 SkMatrix scale(SkMatrix::Scale(2, 2));
1977 SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
1978 REPORTER_ASSERT(reporter,
1979 scaledBounds == source1->filterBounds(input, scale,
1980 SkImageFilter::kForward_MapDirection,
1981 nullptr));
1982 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
1983 SkImageFilter::kReverse_MapDirection,
1984 &input));
1985
1986 // Specified src and dst rects.
1987 SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
1988 SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
1989 sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst,
1990 SkSamplingOptions(SkFilterMode::kLinear,
1991 SkMipmapMode::kLinear)));
1992 REPORTER_ASSERT(reporter,
1993 dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
1994 SkImageFilter::kForward_MapDirection,
1995 nullptr));
1996 REPORTER_ASSERT(reporter,
1997 input == source2->filterBounds(input, SkMatrix::I(),
1998 SkImageFilter::kReverse_MapDirection, &input));
1999 scale.mapRect(&dst);
2000 scale.mapRect(&src);
2001 REPORTER_ASSERT(reporter,
2002 dst.roundOut() == source2->filterBounds(input, scale,
2003 SkImageFilter::kForward_MapDirection,
2004 nullptr));
2005 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
2006 SkImageFilter::kReverse_MapDirection,
2007 &input));
2008 }
2009
2010 // Test SkPictureImageFilter::filterBounds.
DEF_TEST(PictureImageSourceBounds,reporter)2011 DEF_TEST(PictureImageSourceBounds, reporter) {
2012 SkPictureRecorder recorder;
2013 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
2014
2015 SkPaint greenPaint;
2016 greenPaint.setColor(SK_ColorGREEN);
2017 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
2018 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
2019
2020 // Default target rect.
2021 sk_sp<SkImageFilter> source1(SkImageFilters::Picture(picture));
2022 SkIRect pictureBounds = SkIRect::MakeWH(64, 64);
2023 SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2024 REPORTER_ASSERT(reporter,
2025 pictureBounds == source1->filterBounds(input, SkMatrix::I(),
2026 SkImageFilter::kForward_MapDirection,
2027 nullptr));
2028 REPORTER_ASSERT(reporter,
2029 input == source1->filterBounds(input, SkMatrix::I(),
2030 SkImageFilter::kReverse_MapDirection, &input));
2031 SkMatrix scale(SkMatrix::Scale(2, 2));
2032 SkIRect scaledPictureBounds = SkIRect::MakeWH(128, 128);
2033 REPORTER_ASSERT(reporter,
2034 scaledPictureBounds == source1->filterBounds(input, scale,
2035 SkImageFilter::kForward_MapDirection,
2036 nullptr));
2037 REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
2038 SkImageFilter::kReverse_MapDirection,
2039 &input));
2040
2041 // Specified target rect.
2042 SkRect targetRect(SkRect::MakeXYWH(9.5, 9.5, 31, 21));
2043 sk_sp<SkImageFilter> source2(SkImageFilters::Picture(picture, targetRect));
2044 REPORTER_ASSERT(reporter,
2045 targetRect.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2046 SkImageFilter::kForward_MapDirection,
2047 nullptr));
2048 REPORTER_ASSERT(reporter,
2049 input == source2->filterBounds(input, SkMatrix::I(),
2050 SkImageFilter::kReverse_MapDirection, &input));
2051 scale.mapRect(&targetRect);
2052 REPORTER_ASSERT(reporter,
2053 targetRect.roundOut() == source2->filterBounds(input, scale,
2054 SkImageFilter::kForward_MapDirection,
2055 nullptr));
2056 REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
2057 SkImageFilter::kReverse_MapDirection,
2058 &input));
2059 }
2060
DEF_TEST(DropShadowImageFilter_Huge,reporter)2061 DEF_TEST(DropShadowImageFilter_Huge, reporter) {
2062 // Successful if it doesn't crash or trigger ASAN. (crbug.com/1264705)
2063 auto surf = SkSurface::MakeRasterN32Premul(300, 150);
2064
2065 SkPaint paint;
2066 paint.setImageFilter(SkImageFilters::DropShadowOnly(
2067 0.0f, 0.437009f, 14129.6f, 14129.6f, SK_ColorGRAY, nullptr));
2068
2069 surf->getCanvas()->saveLayer(nullptr, &paint);
2070 surf->getCanvas()->restore();
2071 }
2072