• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "src/core/SkImageFilter_Base.h"
22 #include "src/core/SkReadBuffer.h"
23 #include "src/core/SkSpecialImage.h"
24 #include "src/core/SkSpecialSurface.h"
25 #include "tests/Test.h"
26 #include "tools/Resources.h"
27 #include "tools/ToolUtils.h"
28 
29 #include "include/gpu/GrContext.h"
30 #include "src/gpu/GrCaps.h"
31 #include "src/gpu/GrContextPriv.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     typedef SkImageFilter_Base INHERITED;
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     typedef SkImageFilter_Base INHERITED;
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 = SkMinScalar(x, y) * 0.8f;
93     canvas->clear(0x00000000);
94     SkColor colors[2];
95     colors[0] = SK_ColorWHITE;
96     colors[1] = SK_ColorBLACK;
97     sk_sp<SkShader> shader(
98         SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
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(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
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             SkPaint greenColorShaderPaint;
162             greenColorShaderPaint.setShader(SkShaders::Color(SK_ColorGREEN));
163 
164             SkIRect leftSideCropRect = SkIRect::MakeXYWH(0, 0, 32, 64);
165             sk_sp<SkImageFilter> paintFilterLeft(SkImageFilters::Paint(greenColorShaderPaint,
166                                                                        &leftSideCropRect));
167             SkIRect rightSideCropRect = SkIRect::MakeXYWH(32, 0, 32, 64);
168             sk_sp<SkImageFilter> paintFilterRight(SkImageFilters::Paint(greenColorShaderPaint,
169                                                                         &rightSideCropRect));
170 
171 
172             this->addFilter("merge with disjoint inputs", SkImageFilters::Merge(
173                     std::move(paintFilterLeft), std::move(paintFilterRight), cropRect));
174         }
175 
176         this->addFilter("offset", SkImageFilters::Offset(SK_Scalar1, SK_Scalar1, input, cropRect));
177         this->addFilter("dilate", SkImageFilters::Dilate(3, 2, input, cropRect));
178         this->addFilter("erode", SkImageFilters::Erode(2, 3, input, cropRect));
179         this->addFilter("tile", SkImageFilters::Tile(SkRect::MakeXYWH(0, 0, 50, 50),
180                                                      cropRect ? SkRect::Make(*cropRect)
181                                                               : SkRect::MakeXYWH(0, 0, 100, 100),
182                                                      input));
183 
184         if (!cropRect) {
185             SkMatrix matrix;
186 
187             matrix.setTranslate(SK_Scalar1, SK_Scalar1);
188             matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
189 
190             this->addFilter("matrix",
191                     SkImageFilters::MatrixTransform(matrix, kLow_SkFilterQuality, input));
192         }
193         {
194             sk_sp<SkImageFilter> blur(SkImageFilters::Blur(kBlurSigma, kBlurSigma, input));
195 
196             this->addFilter("blur and offset", SkImageFilters::Offset(
197                     kBlurSigma, kBlurSigma, std::move(blur), cropRect));
198         }
199         {
200             SkPictureRecorder recorder;
201             SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
202 
203             SkPaint greenPaint;
204             greenPaint.setColor(SK_ColorGREEN);
205             recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
206             sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
207             sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(std::move(picture)));
208 
209             this->addFilter("picture and blur", SkImageFilters::Blur(
210                     kBlurSigma, kBlurSigma, std::move(pictureFilter), cropRect));
211         }
212         {
213             SkPaint paint;
214             paint.setShader(SkPerlinNoiseShader::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0));
215             sk_sp<SkImageFilter> paintFilter(SkImageFilters::Paint(paint));
216 
217             this->addFilter("paint and blur", SkImageFilters::Blur(
218                     kBlurSigma, kBlurSigma,  std::move(paintFilter), cropRect));
219         }
220         this->addFilter("xfermode", SkImageFilters::Xfermode(
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__anon00d16c8a0111::FilterList::Filter229         Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
Filter__anon00d16c8a0111::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     typedef SkImageFilter_Base INHERITED;
267 };
268 }
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(GrContext * context,int widthHeight)332 static sk_sp<SkSpecialSurface> create_empty_special_surface(GrContext* context, int widthHeight) {
333     if (context) {
334         return SkSpecialSurface::MakeRenderTarget(context, widthHeight, widthHeight,
335                                                   GrColorType::kRGBA_8888, nullptr);
336     } else {
337         const SkImageInfo info = SkImageInfo::MakeN32(widthHeight, widthHeight,
338                                                       kOpaque_SkAlphaType);
339         return SkSpecialSurface::MakeRaster(info);
340     }
341 }
342 
create_surface(GrContext * context,int width,int height)343 static sk_sp<SkSurface> create_surface(GrContext* context, int width, int height) {
344     const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
345     if (context) {
346         return SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info);
347     } else {
348         return SkSurface::MakeRaster(info);
349     }
350 }
351 
create_empty_special_image(GrContext * context,int widthHeight)352 static sk_sp<SkSpecialImage> create_empty_special_image(GrContext* context, int widthHeight) {
353     sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, widthHeight));
354 
355     SkASSERT(surf);
356 
357     SkCanvas* canvas = surf->getCanvas();
358     SkASSERT(canvas);
359 
360     canvas->clear(0x0);
361 
362     return surf->makeImageSnapshot();
363 }
364 
365 
DEF_TEST(ImageFilter,reporter)366 DEF_TEST(ImageFilter, reporter) {
367     {
368         // Check that a color matrix filter followed by a color matrix filter
369         // concatenates into a single filter.
370         sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
371         sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
372         REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
373         SkColorFilter* cf;
374         REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
375         cf->unref();
376     }
377 
378     {
379         // Check that a color filter image filter without a crop rect can be
380         // expressed as a color filter.
381         sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
382         REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
383     }
384 
385     {
386         // Check that a colorfilterimage filter without a crop rect but with an input
387         // that is another colorfilterimage can be expressed as a colorfilter (composed).
388         sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
389         sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
390         REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
391     }
392 
393     {
394         // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
395         // can build the DAG and won't assert if we call asColorFilter.
396         sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
397         const int kWayTooManyForComposeColorFilter = 100;
398         for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
399             filter = make_blue(filter, nullptr);
400             // the first few of these will succeed, but after we hit the internal limit,
401             // it will then return false.
402             (void)filter->asColorFilter(nullptr);
403         }
404     }
405 
406     {
407         // Check that a color filter image filter with a crop rect cannot
408         // be expressed as a color filter.
409         SkIRect cropRect = SkIRect::MakeWH(100, 100);
410         sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
411         REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
412     }
413 
414     {
415         // Check that two non-commutative matrices are concatenated in
416         // the correct order.
417         float blueToRedMatrix[20] = { 0 };
418         blueToRedMatrix[2] = blueToRedMatrix[18] = 1;
419         float redToGreenMatrix[20] = { 0 };
420         redToGreenMatrix[5] = redToGreenMatrix[18] = 1;
421         sk_sp<SkColorFilter> blueToRed(SkColorFilters::Matrix(blueToRedMatrix));
422         sk_sp<SkImageFilter> filter1(SkImageFilters::ColorFilter(std::move(blueToRed), nullptr));
423         sk_sp<SkColorFilter> redToGreen(SkColorFilters::Matrix(redToGreenMatrix));
424         sk_sp<SkImageFilter> filter2(SkImageFilters::ColorFilter(std::move(redToGreen),
425                                                                  std::move(filter1)));
426 
427         SkBitmap result;
428         result.allocN32Pixels(kBitmapSize, kBitmapSize);
429 
430         SkPaint paint;
431         paint.setColor(SK_ColorBLUE);
432         paint.setImageFilter(std::move(filter2));
433         SkCanvas canvas(result);
434         canvas.clear(0x0);
435         SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
436         canvas.drawRect(rect, paint);
437         uint32_t pixel = *result.getAddr32(0, 0);
438         // The result here should be green, since we have effectively shifted blue to green.
439         REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
440     }
441 
442     {
443         // Tests pass by not asserting
444         sk_sp<SkImage> image(make_small_image());
445         SkBitmap result;
446         result.allocN32Pixels(kBitmapSize, kBitmapSize);
447 
448         {
449             // This tests for :
450             // 1 ) location at (0,0,1)
451             SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
452             // 2 ) location and target at same value
453             SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
454             // 3 ) large negative specular exponent value
455             SkScalar specularExponent = -1000;
456 
457             sk_sp<SkImageFilter> bmSrc(SkImageFilters::Image(std::move(image)));
458             SkPaint paint;
459             paint.setImageFilter(SkImageFilters::SpotLitSpecular(
460                     location, target, specularExponent, 180,
461                     0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
462                     std::move(bmSrc)));
463             SkCanvas canvas(result);
464             SkRect r = SkRect::MakeIWH(kBitmapSize, kBitmapSize);
465             canvas.drawRect(r, paint);
466         }
467     }
468 }
469 
test_cropRects(skiatest::Reporter * reporter,GrContext * context)470 static void test_cropRects(skiatest::Reporter* reporter, GrContext* context) {
471     // Check that all filters offset to their absolute crop rect,
472     // unaffected by the input crop rect.
473     // Tests pass by not asserting.
474     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
475     SkASSERT(srcImg);
476 
477     SkIRect inputCropRect = SkIRect::MakeXYWH(8, 13, 80, 80);
478     SkIRect cropRect = SkIRect::MakeXYWH(20, 30, 60, 60);
479     sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
480 
481     FilterList filters(input, &cropRect);
482 
483     for (int i = 0; i < filters.count(); ++i) {
484         SkImageFilter* filter = filters.getFilter(i);
485         SkIPoint offset;
486         SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
487                                         kN32_SkColorType, nullptr, srcImg.get());
488         sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx, &offset));
489         REPORTER_ASSERT(reporter, resultImg, filters.getName(i));
490         REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, filters.getName(i));
491     }
492 }
493 
test_negative_blur_sigma(skiatest::Reporter * reporter,GrContext * context)494 static void test_negative_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
495     // Check that SkBlurImageFilter will accept a negative sigma, either in
496     // the given arguments or after CTM application.
497     static const int kWidth = 32, kHeight = 32;
498     static const SkScalar kBlurSigma = SkIntToScalar(5);
499 
500     sk_sp<SkImageFilter> positiveFilter(SkImageFilters::Blur(kBlurSigma, kBlurSigma, nullptr));
501     sk_sp<SkImageFilter> negativeFilter(SkImageFilters::Blur(-kBlurSigma, kBlurSigma, nullptr));
502 
503     SkBitmap gradient = make_gradient_circle(kWidth, kHeight);
504     sk_sp<SkSpecialImage> imgSrc(SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(kWidth, kHeight),
505                                                                 gradient));
506 
507     SkIPoint offset;
508     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
509                                     kN32_SkColorType, nullptr, imgSrc.get());
510 
511     sk_sp<SkSpecialImage> positiveResult1(
512             as_IFB(positiveFilter)->filterImage(ctx, &offset));
513     REPORTER_ASSERT(reporter, positiveResult1);
514 
515     sk_sp<SkSpecialImage> negativeResult1(
516             as_IFB(negativeFilter)->filterImage(ctx, &offset));
517     REPORTER_ASSERT(reporter, negativeResult1);
518 
519     SkMatrix negativeScale;
520     negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
521     SkImageFilter_Base::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr,
522                                             kN32_SkColorType, nullptr, imgSrc.get());
523 
524     sk_sp<SkSpecialImage> negativeResult2(
525             as_IFB(positiveFilter)->filterImage(negativeCTX, &offset));
526     REPORTER_ASSERT(reporter, negativeResult2);
527 
528     sk_sp<SkSpecialImage> positiveResult2(
529             as_IFB(negativeFilter)->filterImage(negativeCTX, &offset));
530     REPORTER_ASSERT(reporter, positiveResult2);
531 
532 
533     SkBitmap positiveResultBM1, positiveResultBM2;
534     SkBitmap negativeResultBM1, negativeResultBM2;
535 
536     REPORTER_ASSERT(reporter, positiveResult1->getROPixels(&positiveResultBM1));
537     REPORTER_ASSERT(reporter, positiveResult2->getROPixels(&positiveResultBM2));
538     REPORTER_ASSERT(reporter, negativeResult1->getROPixels(&negativeResultBM1));
539     REPORTER_ASSERT(reporter, negativeResult2->getROPixels(&negativeResultBM2));
540 
541     for (int y = 0; y < kHeight; y++) {
542         int diffs = memcmp(positiveResultBM1.getAddr32(0, y),
543                            negativeResultBM1.getAddr32(0, y),
544                            positiveResultBM1.rowBytes());
545         REPORTER_ASSERT(reporter, !diffs);
546         if (diffs) {
547             break;
548         }
549         diffs = memcmp(positiveResultBM1.getAddr32(0, y),
550                        negativeResultBM2.getAddr32(0, y),
551                        positiveResultBM1.rowBytes());
552         REPORTER_ASSERT(reporter, !diffs);
553         if (diffs) {
554             break;
555         }
556         diffs = memcmp(positiveResultBM1.getAddr32(0, y),
557                        positiveResultBM2.getAddr32(0, y),
558                        positiveResultBM1.rowBytes());
559         REPORTER_ASSERT(reporter, !diffs);
560         if (diffs) {
561             break;
562         }
563     }
564 }
565 
DEF_TEST(ImageFilterNegativeBlurSigma,reporter)566 DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
567     test_negative_blur_sigma(reporter, nullptr);
568 }
569 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu,reporter,ctxInfo)570 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu, reporter, ctxInfo) {
571     test_negative_blur_sigma(reporter, ctxInfo.grContext());
572 }
573 
test_zero_blur_sigma(skiatest::Reporter * reporter,GrContext * context)574 static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrContext* context) {
575     // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
576     SkIRect cropRect = SkIRect::MakeXYWH(5, 0, 5, 10);
577     sk_sp<SkImageFilter> input(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
578     sk_sp<SkImageFilter> filter(SkImageFilters::Blur(0, 0, std::move(input), &cropRect));
579 
580     sk_sp<SkSpecialSurface> surf(create_empty_special_surface(context, 10));
581     surf->getCanvas()->clear(SK_ColorGREEN);
582     sk_sp<SkSpecialImage> image(surf->makeImageSnapshot());
583 
584     SkIPoint offset;
585     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr,
586                                     kN32_SkColorType, nullptr, image.get());
587 
588     sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(ctx, &offset));
589     REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
590     REPORTER_ASSERT(reporter, result);
591     REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
592 
593     SkBitmap resultBM;
594 
595     REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
596 
597     for (int y = 0; y < resultBM.height(); y++) {
598         for (int x = 0; x < resultBM.width(); x++) {
599             bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
600             REPORTER_ASSERT(reporter, !diff);
601             if (diff) {
602                 break;
603             }
604         }
605     }
606 }
607 
DEF_TEST(ImageFilterZeroBlurSigma,reporter)608 DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
609     test_zero_blur_sigma(reporter, nullptr);
610 }
611 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu,reporter,ctxInfo)612 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu, reporter, ctxInfo) {
613     test_zero_blur_sigma(reporter, ctxInfo.grContext());
614 }
615 
616 
617 // Tests that, even when an upstream filter has returned null (due to failure or clipping), a
618 // downstream filter that affects transparent black still does so even with a nullptr input.
test_fail_affects_transparent_black(skiatest::Reporter * reporter,GrContext * context)619 static void test_fail_affects_transparent_black(skiatest::Reporter* reporter, GrContext* context) {
620     sk_sp<FailImageFilter> failFilter(new FailImageFilter());
621     sk_sp<SkSpecialImage> source(create_empty_special_image(context, 5));
622     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 1, 1), nullptr,
623                                     kN32_SkColorType, nullptr, source.get());
624     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
625     SkASSERT(green->affectsTransparentBlack());
626     sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(std::move(green),
627                                                                  std::move(failFilter)));
628     SkIPoint offset;
629     sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(ctx, &offset));
630     REPORTER_ASSERT(reporter, nullptr != result.get());
631     if (result.get()) {
632         SkBitmap resultBM;
633         REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
634         REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
635     }
636 }
637 
DEF_TEST(ImageFilterFailAffectsTransparentBlack,reporter)638 DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
639     test_fail_affects_transparent_black(reporter, nullptr);
640 }
641 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu,reporter,ctxInfo)642 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu, reporter, ctxInfo) {
643     test_fail_affects_transparent_black(reporter, ctxInfo.grContext());
644 }
645 
DEF_TEST(ImageFilterDrawTiled,reporter)646 DEF_TEST(ImageFilterDrawTiled, reporter) {
647     // Check that all filters when drawn tiled (with subsequent clip rects) exactly
648     // match the same filters drawn with a single full-canvas bitmap draw.
649     // Tests pass by not asserting.
650 
651     FilterList filters(nullptr);
652 
653     SkBitmap untiledResult, tiledResult;
654     const int width = 64, height = 64;
655     untiledResult.allocN32Pixels(width, height);
656     tiledResult.allocN32Pixels(width, height);
657     SkCanvas tiledCanvas(tiledResult);
658     SkCanvas untiledCanvas(untiledResult);
659     const int tileSize = 8;
660 
661     SkPaint textPaint;
662     textPaint.setColor(SK_ColorWHITE);
663     SkFont font(ToolUtils::create_portable_typeface(), height);
664 
665     const char* text = "ABC";
666     const SkScalar yPos = SkIntToScalar(height);
667 
668     for (int scale = 1; scale <= 2; ++scale) {
669         for (int i = 0; i < filters.count(); ++i) {
670             SkPaint combinedPaint;
671             combinedPaint.setColor(SK_ColorWHITE);
672             combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
673 
674             untiledCanvas.clear(SK_ColorTRANSPARENT);
675             untiledCanvas.save();
676             untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
677             untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
678             untiledCanvas.restore();
679 
680             tiledCanvas.clear(SK_ColorTRANSPARENT);
681             for (int y = 0; y < height; y += tileSize) {
682                 for (int x = 0; x < width; x += tileSize) {
683                     tiledCanvas.save();
684                     const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
685                     tiledCanvas.clipRect(clipRect);
686                     if (filters.needsSaveLayer(i)) {
687                         const SkRect layerBounds = SkRect::MakeIWH(width, height);
688                         tiledCanvas.saveLayer(&layerBounds, &combinedPaint);
689                             tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
690                             tiledCanvas.drawString(text, 0, yPos, font, textPaint);
691                         tiledCanvas.restore();
692                     } else {
693                         tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
694                         tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
695                     }
696 
697                     tiledCanvas.restore();
698                 }
699             }
700 
701             if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
702                 REPORTER_ASSERT(reporter, false, filters.getName(i));
703                 break;
704             }
705         }
706     }
707 }
708 
draw_saveLayer_picture(int width,int height,int tileSize,SkBBHFactory * factory,SkBitmap * result)709 static void draw_saveLayer_picture(int width, int height, int tileSize,
710                                    SkBBHFactory* factory, SkBitmap* result) {
711 
712     SkMatrix matrix;
713     matrix.setTranslate(SkIntToScalar(50), 0);
714 
715     sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
716     sk_sp<SkImageFilter> cfif(SkImageFilters::ColorFilter(std::move(cf), nullptr));
717     sk_sp<SkImageFilter> imageFilter(SkImageFilter::MakeMatrixFilter(matrix,
718                                                                      kNone_SkFilterQuality,
719                                                                      std::move(cfif)));
720 
721     SkPaint paint;
722     paint.setImageFilter(std::move(imageFilter));
723     SkPictureRecorder recorder;
724     SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
725     SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
726                                                         SkIntToScalar(height),
727                                                         factory, 0);
728     recordingCanvas->translate(-55, 0);
729     recordingCanvas->saveLayer(&bounds, &paint);
730     recordingCanvas->restore();
731     sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
732 
733     result->allocN32Pixels(width, height);
734     SkCanvas canvas(*result);
735     canvas.clear(0);
736     canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
737     canvas.drawPicture(picture1.get());
738 }
739 
DEF_TEST(ImageFilterDrawMatrixBBH,reporter)740 DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
741     // Check that matrix filter when drawn tiled with BBH exactly
742     // matches the same thing drawn without BBH.
743     // Tests pass by not asserting.
744 
745     const int width = 200, height = 200;
746     const int tileSize = 100;
747     SkBitmap result1, result2;
748     SkRTreeFactory factory;
749 
750     draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
751     draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
752 
753     for (int y = 0; y < height; y++) {
754         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
755         REPORTER_ASSERT(reporter, !diffs);
756         if (diffs) {
757             break;
758         }
759     }
760 }
761 
make_blur(sk_sp<SkImageFilter> input)762 static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
763     return SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, std::move(input));
764 }
765 
make_drop_shadow(sk_sp<SkImageFilter> input)766 static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
767     return SkImageFilters::DropShadow(100, 100, 10, 10, SK_ColorBLUE, std::move(input));
768 }
769 
DEF_TEST(ImageFilterBlurThenShadowBounds,reporter)770 DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
771     sk_sp<SkImageFilter> filter1(make_blur(nullptr));
772     sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
773 
774     SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
775     SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
776     bounds = filter2->filterBounds(bounds, SkMatrix::I(),
777                                    SkImageFilter::kReverse_MapDirection, &bounds);
778 
779     REPORTER_ASSERT(reporter, bounds == expectedBounds);
780 }
781 
DEF_TEST(ImageFilterShadowThenBlurBounds,reporter)782 DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
783     sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
784     sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
785 
786     SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
787     SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236);
788     bounds = filter2->filterBounds(bounds, SkMatrix::I(),
789                                    SkImageFilter::kReverse_MapDirection, &bounds);
790 
791     REPORTER_ASSERT(reporter, bounds == expectedBounds);
792 }
793 
DEF_TEST(ImageFilterDilateThenBlurBounds,reporter)794 DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
795     sk_sp<SkImageFilter> filter1(SkImageFilters::Dilate(2, 2, nullptr));
796     sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
797 
798     SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100);
799     SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234);
800     bounds = filter2->filterBounds(bounds, SkMatrix::I(),
801                                    SkImageFilter::kReverse_MapDirection, &bounds);
802 
803     REPORTER_ASSERT(reporter, bounds == expectedBounds);
804 }
805 
DEF_TEST(ImageFilterScaledBlurRadius,reporter)806 DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
807     // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
808     // (before the CTM). Bounds should be computed correctly in the presence of
809     // a (possibly negative) scale.
810     sk_sp<SkImageFilter> blur(make_blur(nullptr));
811     sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
812     {
813         // Uniform scale by 2.
814         SkMatrix scaleMatrix;
815         scaleMatrix.setScale(2, 2);
816         SkIRect bounds = SkIRect::MakeLTRB(0, 0, 200, 200);
817 
818         SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
819         SkIRect blurBounds = blur->filterBounds(
820                 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
821         REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
822         SkIRect reverseBlurBounds = blur->filterBounds(
823                 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
824         REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
825 
826         SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
827         SkIRect shadowBounds = dropShadow->filterBounds(
828                 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
829         REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
830         SkIRect expectedReverseShadowBounds =
831                 SkIRect::MakeLTRB(-260, -260, 200, 200);
832         SkIRect reverseShadowBounds = dropShadow->filterBounds(
833                 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
834         REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
835     }
836     {
837         // Vertical flip.
838         SkMatrix scaleMatrix;
839         scaleMatrix.setScale(1, -1);
840         SkIRect bounds = SkIRect::MakeLTRB(0, -100, 100, 0);
841 
842         SkIRect expectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
843         SkIRect blurBounds = blur->filterBounds(
844                 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
845         REPORTER_ASSERT(reporter, blurBounds == expectedBlurBounds);
846         SkIRect reverseBlurBounds = blur->filterBounds(
847                 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
848         REPORTER_ASSERT(reporter, reverseBlurBounds == expectedBlurBounds);
849 
850         SkIRect expectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
851         SkIRect shadowBounds = dropShadow->filterBounds(
852                 bounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
853         REPORTER_ASSERT(reporter, shadowBounds == expectedShadowBounds);
854         SkIRect expectedReverseShadowBounds =
855                 SkIRect::MakeLTRB(-130, -100, 100, 130);
856         SkIRect reverseShadowBounds = dropShadow->filterBounds(
857                 bounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &bounds);
858         REPORTER_ASSERT(reporter, reverseShadowBounds == expectedReverseShadowBounds);
859     }
860 }
861 
DEF_TEST(ImageFilterComposedBlurFastBounds,reporter)862 DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
863     sk_sp<SkImageFilter> filter1(make_blur(nullptr));
864     sk_sp<SkImageFilter> filter2(make_blur(nullptr));
865     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(filter1),
866                                                                 std::move(filter2)));
867 
868     SkRect boundsSrc = SkRect::MakeIWH(100, 100);
869     SkRect expectedBounds = SkRect::MakeXYWH(-6, -6, 112, 112);
870     SkRect boundsDst = composedFilter->computeFastBounds(boundsSrc);
871 
872     REPORTER_ASSERT(reporter, boundsDst == expectedBounds);
873 }
874 
DEF_TEST(ImageFilterUnionBounds,reporter)875 DEF_TEST(ImageFilterUnionBounds, reporter) {
876     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(50, 0, nullptr));
877     // Regardless of which order they appear in, the image filter bounds should
878     // be combined correctly.
879     {
880         sk_sp<SkImageFilter> composite(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, offset));
881         SkRect bounds = SkRect::MakeIWH(100, 100);
882         // Intentionally aliasing here, as that's what the real callers do.
883         bounds = composite->computeFastBounds(bounds);
884         REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
885     }
886     {
887         sk_sp<SkImageFilter> composite(SkImageFilters::Xfermode(SkBlendMode::kSrcOver, nullptr,
888                                                                 offset, nullptr));
889         SkRect bounds = SkRect::MakeIWH(100, 100);
890         // Intentionally aliasing here, as that's what the real callers do.
891         bounds = composite->computeFastBounds(bounds);
892         REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
893     }
894 }
895 
test_imagefilter_merge_result_size(skiatest::Reporter * reporter,GrContext * context)896 static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter, GrContext* context) {
897     SkBitmap greenBM;
898     greenBM.allocN32Pixels(20, 20);
899     greenBM.eraseColor(SK_ColorGREEN);
900     sk_sp<SkImage> greenImage(SkImage::MakeFromBitmap(greenBM));
901     sk_sp<SkImageFilter> source(SkImageFilters::Image(std::move(greenImage)));
902     sk_sp<SkImageFilter> merge(SkImageFilters::Merge(source, source));
903 
904     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 1));
905 
906     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr,
907                                     kN32_SkColorType, nullptr, srcImg.get());
908     SkIPoint offset;
909 
910     sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(ctx, &offset));
911     REPORTER_ASSERT(reporter, resultImg);
912 
913     REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
914 }
915 
DEF_TEST(ImageFilterMergeResultSize,reporter)916 DEF_TEST(ImageFilterMergeResultSize, reporter) {
917     test_imagefilter_merge_result_size(reporter, nullptr);
918 }
919 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu,reporter,ctxInfo)920 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu, reporter, ctxInfo) {
921     test_imagefilter_merge_result_size(reporter, ctxInfo.grContext());
922 }
923 
draw_blurred_rect(SkCanvas * canvas)924 static void draw_blurred_rect(SkCanvas* canvas) {
925     SkPaint filterPaint;
926     filterPaint.setColor(SK_ColorWHITE);
927     filterPaint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(8), 0, nullptr));
928     canvas->saveLayer(nullptr, &filterPaint);
929     SkPaint whitePaint;
930     whitePaint.setColor(SK_ColorWHITE);
931     canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
932     canvas->restore();
933 }
934 
draw_picture_clipped(SkCanvas * canvas,const SkRect & clipRect,const SkPicture * picture)935 static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
936     canvas->save();
937     canvas->clipRect(clipRect);
938     canvas->drawPicture(picture);
939     canvas->restore();
940 }
941 
DEF_TEST(ImageFilterDrawTiledBlurRTree,reporter)942 DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
943     // Check that the blur filter when recorded with RTree acceleration,
944     // and drawn tiled (with subsequent clip rects) exactly
945     // matches the same filter drawn with without RTree acceleration.
946     // This tests that the "bleed" from the blur into the otherwise-blank
947     // tiles is correctly rendered.
948     // Tests pass by not asserting.
949 
950     int width = 16, height = 8;
951     SkBitmap result1, result2;
952     result1.allocN32Pixels(width, height);
953     result2.allocN32Pixels(width, height);
954     SkCanvas canvas1(result1);
955     SkCanvas canvas2(result2);
956     int tileSize = 8;
957 
958     canvas1.clear(0);
959     canvas2.clear(0);
960 
961     SkRTreeFactory factory;
962 
963     SkPictureRecorder recorder1, recorder2;
964     // The only difference between these two pictures is that one has RTree aceleration.
965     SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height, nullptr, 0);
966     SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory, 0);
967 
968     draw_blurred_rect(recordingCanvas1);
969     draw_blurred_rect(recordingCanvas2);
970     sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
971     sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
972     for (int y = 0; y < height; y += tileSize) {
973         for (int x = 0; x < width; x += tileSize) {
974             SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
975             draw_picture_clipped(&canvas1, tileRect, picture1.get());
976             draw_picture_clipped(&canvas2, tileRect, picture2.get());
977         }
978     }
979     for (int y = 0; y < height; y++) {
980         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
981         REPORTER_ASSERT(reporter, !diffs);
982         if (diffs) {
983             break;
984         }
985     }
986 }
987 
DEF_TEST(ImageFilterMatrixConvolution,reporter)988 DEF_TEST(ImageFilterMatrixConvolution, reporter) {
989     // Check that a 1x3 filter does not cause a spurious assert.
990     SkScalar kernel[3] = {
991         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
992     };
993     SkISize kernelSize = SkISize::Make(1, 3);
994     SkScalar gain = SK_Scalar1, bias = 0;
995     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
996 
997     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
998             kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kRepeat, false, nullptr));
999 
1000     SkBitmap result;
1001     int width = 16, height = 16;
1002     result.allocN32Pixels(width, height);
1003     SkCanvas canvas(result);
1004     canvas.clear(0);
1005 
1006     SkPaint paint;
1007     paint.setImageFilter(std::move(filter));
1008     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1009     canvas.drawRect(rect, paint);
1010 }
1011 
DEF_TEST(ImageFilterMatrixConvolutionBorder,reporter)1012 DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1013     // Check that a filter with borders outside the target bounds
1014     // does not crash.
1015     SkScalar kernel[3] = {
1016         0, 0, 0,
1017     };
1018     SkISize kernelSize = SkISize::Make(3, 1);
1019     SkScalar gain = SK_Scalar1, bias = 0;
1020     SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1021 
1022     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1023             kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kClamp, true, nullptr));
1024 
1025     SkBitmap result;
1026 
1027     int width = 10, height = 10;
1028     result.allocN32Pixels(width, height);
1029     SkCanvas canvas(result);
1030     canvas.clear(0);
1031 
1032     SkPaint filterPaint;
1033     filterPaint.setImageFilter(std::move(filter));
1034     SkRect bounds = SkRect::MakeIWH(1, 10);
1035     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1036     SkPaint rectPaint;
1037     canvas.saveLayer(&bounds, &filterPaint);
1038     canvas.drawRect(rect, rectPaint);
1039     canvas.restore();
1040 }
1041 
test_big_kernel(skiatest::Reporter * reporter,GrContext * context)1042 static void test_big_kernel(skiatest::Reporter* reporter, GrContext* context) {
1043     // Check that a kernel that is too big for the GPU still works
1044     SkScalar identityKernel[49] = {
1045         0, 0, 0, 0, 0, 0, 0,
1046         0, 0, 0, 0, 0, 0, 0,
1047         0, 0, 0, 0, 0, 0, 0,
1048         0, 0, 0, 1, 0, 0, 0,
1049         0, 0, 0, 0, 0, 0, 0,
1050         0, 0, 0, 0, 0, 0, 0,
1051         0, 0, 0, 0, 0, 0, 0
1052     };
1053     SkISize kernelSize = SkISize::Make(7, 7);
1054     SkScalar gain = SK_Scalar1, bias = 0;
1055     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1056 
1057     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1058             kernelSize, identityKernel, gain, bias, kernelOffset,
1059             SkTileMode::kClamp, true, nullptr));
1060 
1061     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
1062     SkASSERT(srcImg);
1063 
1064     SkIPoint offset;
1065     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
1066                                     kN32_SkColorType, nullptr, srcImg.get());
1067     sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx, &offset));
1068     REPORTER_ASSERT(reporter, resultImg);
1069     REPORTER_ASSERT(reporter, SkToBool(context) == resultImg->isTextureBacked());
1070     REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1071     REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1072 }
1073 
DEF_TEST(ImageFilterMatrixConvolutionBigKernel,reporter)1074 DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
1075     test_big_kernel(reporter, nullptr);
1076 }
1077 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,reporter,ctxInfo)1078 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1079                                    reporter, ctxInfo) {
1080     test_big_kernel(reporter, ctxInfo.grContext());
1081 }
1082 
DEF_TEST(ImageFilterCropRect,reporter)1083 DEF_TEST(ImageFilterCropRect, reporter) {
1084     test_cropRects(reporter, nullptr);
1085 }
1086 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu,reporter,ctxInfo)1087 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu, reporter, ctxInfo) {
1088     test_cropRects(reporter, ctxInfo.grContext());
1089 }
1090 
DEF_TEST(ImageFilterMatrix,reporter)1091 DEF_TEST(ImageFilterMatrix, reporter) {
1092     SkBitmap temp;
1093     temp.allocN32Pixels(100, 100);
1094     SkCanvas canvas(temp);
1095     canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1096 
1097     SkMatrix expectedMatrix = canvas.getTotalMatrix();
1098 
1099     SkRTreeFactory factory;
1100     SkPictureRecorder recorder;
1101     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
1102 
1103     SkPaint paint;
1104     paint.setImageFilter(MatrixTestImageFilter::Make(reporter, expectedMatrix));
1105     recordingCanvas->saveLayer(nullptr, &paint);
1106     SkPaint solidPaint;
1107     solidPaint.setColor(0xFFFFFFFF);
1108     recordingCanvas->save();
1109     recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1110     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1111     recordingCanvas->restore(); // scale
1112     recordingCanvas->restore(); // saveLayer
1113 
1114     canvas.drawPicture(recorder.finishRecordingAsPicture());
1115 }
1116 
test_clipped_picture_imagefilter(skiatest::Reporter * reporter,GrContext * context)1117 static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter, GrContext* context) {
1118     sk_sp<SkPicture> picture;
1119 
1120     {
1121         SkRTreeFactory factory;
1122         SkPictureRecorder recorder;
1123         SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
1124 
1125         // Create an SkPicture which simply draws a green 1x1 rectangle.
1126         SkPaint greenPaint;
1127         greenPaint.setColor(SK_ColorGREEN);
1128         recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
1129         picture = recorder.finishRecordingAsPicture();
1130     }
1131 
1132     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 2));
1133 
1134     sk_sp<SkImageFilter> imageFilter(SkImageFilters::Picture(picture));
1135 
1136     SkIPoint offset;
1137     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr,
1138                                     kN32_SkColorType, nullptr, srcImg.get());
1139 
1140     sk_sp<SkSpecialImage> resultImage(as_IFB(imageFilter)->filterImage(ctx, &offset));
1141     REPORTER_ASSERT(reporter, !resultImage);
1142 }
1143 
DEF_TEST(ImageFilterClippedPictureImageFilter,reporter)1144 DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
1145     test_clipped_picture_imagefilter(reporter, nullptr);
1146 }
1147 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu,reporter,ctxInfo)1148 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu, reporter, ctxInfo) {
1149     test_clipped_picture_imagefilter(reporter, ctxInfo.grContext());
1150 }
1151 
DEF_TEST(ImageFilterEmptySaveLayer,reporter)1152 DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
1153     // Even when there's an empty saveLayer()/restore(), ensure that an image
1154     // filter or color filter which affects transparent black still draws.
1155 
1156     SkBitmap bitmap;
1157     bitmap.allocN32Pixels(10, 10);
1158     SkCanvas canvas(bitmap);
1159 
1160     SkRTreeFactory factory;
1161     SkPictureRecorder recorder;
1162 
1163     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN,
1164                                                              SkBlendMode::kSrc));
1165     sk_sp<SkImageFilter> imageFilter(SkImageFilters::ColorFilter(green, nullptr));
1166     SkPaint imageFilterPaint;
1167     imageFilterPaint.setImageFilter(std::move(imageFilter));
1168     SkPaint colorFilterPaint;
1169     colorFilterPaint.setColorFilter(green);
1170 
1171     SkRect bounds = SkRect::MakeIWH(10, 10);
1172 
1173     SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1174     recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1175     recordingCanvas->restore();
1176     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1177 
1178     canvas.clear(0);
1179     canvas.drawPicture(picture);
1180     uint32_t pixel = *bitmap.getAddr32(0, 0);
1181     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1182 
1183     recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1184     recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
1185     recordingCanvas->restore();
1186     sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
1187 
1188     canvas.clear(0);
1189     canvas.drawPicture(picture2);
1190     pixel = *bitmap.getAddr32(0, 0);
1191     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1192 
1193     recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
1194     recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1195     recordingCanvas->restore();
1196     sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
1197 
1198     canvas.clear(0);
1199     canvas.drawPicture(picture3);
1200     pixel = *bitmap.getAddr32(0, 0);
1201     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1202 }
1203 
test_huge_blur(SkCanvas * canvas,skiatest::Reporter * reporter)1204 static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
1205     SkBitmap bitmap;
1206     bitmap.allocN32Pixels(100, 100);
1207     bitmap.eraseARGB(0, 0, 0, 0);
1208 
1209     // Check that a blur with an insane radius does not crash or assert.
1210     SkPaint paint;
1211     paint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(1<<30), SkIntToScalar(1<<30), nullptr));
1212     canvas->drawBitmap(bitmap, 0, 0, &paint);
1213 }
1214 
DEF_TEST(HugeBlurImageFilter,reporter)1215 DEF_TEST(HugeBlurImageFilter, reporter) {
1216     SkBitmap temp;
1217     temp.allocN32Pixels(100, 100);
1218     SkCanvas canvas(temp);
1219     test_huge_blur(&canvas, reporter);
1220 }
1221 
DEF_TEST(ImageFilterMatrixConvolutionSanityTest,reporter)1222 DEF_TEST(ImageFilterMatrixConvolutionSanityTest, reporter) {
1223     SkScalar kernel[1] = { 0 };
1224     SkScalar gain = SK_Scalar1, bias = 0;
1225     SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1226 
1227     // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
1228     sk_sp<SkImageFilter> conv(SkImageFilters::MatrixConvolution(
1229             SkISize::Make(1<<30, 1<<30), kernel, gain, bias, kernelOffset,
1230             SkTileMode::kRepeat, false, nullptr));
1231 
1232     REPORTER_ASSERT(reporter, nullptr == conv.get());
1233 
1234     // Check that a nullptr kernel gives a nullptr filter.
1235     conv = SkImageFilters::MatrixConvolution(
1236             SkISize::Make(1, 1), nullptr, gain, bias, kernelOffset,
1237             SkTileMode::kRepeat, false, nullptr);
1238 
1239     REPORTER_ASSERT(reporter, nullptr == conv.get());
1240 
1241     // Check that a kernel width < 1 gives a nullptr filter.
1242     conv = SkImageFilters::MatrixConvolution(
1243             SkISize::Make(0, 1), kernel, gain, bias, kernelOffset,
1244             SkTileMode::kRepeat, false, nullptr);
1245 
1246     REPORTER_ASSERT(reporter, nullptr == conv.get());
1247 
1248     // Check that kernel height < 1 gives a nullptr filter.
1249     conv = SkImageFilters::MatrixConvolution(
1250             SkISize::Make(1, -1), kernel, gain, bias, kernelOffset,
1251             SkTileMode::kRepeat, false, nullptr);
1252 
1253     REPORTER_ASSERT(reporter, nullptr == conv.get());
1254 }
1255 
test_xfermode_cropped_input(SkSurface * surf,skiatest::Reporter * reporter)1256 static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1257     auto canvas = surf->getCanvas();
1258     canvas->clear(0);
1259 
1260     SkBitmap bitmap;
1261     bitmap.allocN32Pixels(1, 1);
1262     bitmap.eraseARGB(255, 255, 255, 255);
1263 
1264     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
1265     sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(green, nullptr));
1266     SkIRect cropRect = SkIRect::MakeEmpty();
1267     sk_sp<SkImageFilter> croppedOut(SkImageFilters::ColorFilter(green, nullptr, &cropRect));
1268 
1269     // Check that an xfermode image filter whose input has been cropped out still draws the other
1270     // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1271     SkBlendMode mode = SkBlendMode::kSrcOver;
1272     sk_sp<SkImageFilter> xfermodeNoFg(SkImageFilters::Xfermode(
1273             mode, greenFilter, croppedOut, nullptr));
1274     sk_sp<SkImageFilter> xfermodeNoBg(SkImageFilters::Xfermode(
1275             mode, croppedOut, greenFilter, nullptr));
1276     sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkImageFilters::Xfermode(
1277             mode, croppedOut,  croppedOut, nullptr));
1278 
1279     SkPaint paint;
1280     paint.setImageFilter(std::move(xfermodeNoFg));
1281     canvas->drawBitmap(bitmap, 0, 0, &paint);   // drawSprite
1282 
1283     uint32_t pixel;
1284     SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1285     surf->readPixels(info, &pixel, 4, 0, 0);
1286     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1287 
1288     paint.setImageFilter(std::move(xfermodeNoBg));
1289     canvas->drawBitmap(bitmap, 0, 0, &paint);   // drawSprite
1290     surf->readPixels(info, &pixel, 4, 0, 0);
1291     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1292 
1293     paint.setImageFilter(std::move(xfermodeNoFgNoBg));
1294     canvas->drawBitmap(bitmap, 0, 0, &paint);   // drawSprite
1295     surf->readPixels(info, &pixel, 4, 0, 0);
1296     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1297 }
1298 
DEF_TEST(ImageFilterNestedSaveLayer,reporter)1299 DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1300     SkBitmap temp;
1301     temp.allocN32Pixels(50, 50);
1302     SkCanvas canvas(temp);
1303     canvas.clear(0x0);
1304 
1305     SkBitmap bitmap;
1306     bitmap.allocN32Pixels(10, 10);
1307     bitmap.eraseColor(SK_ColorGREEN);
1308 
1309     SkMatrix matrix;
1310     matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1311     matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1312     sk_sp<SkImageFilter> matrixFilter(
1313             SkImageFilter::MakeMatrixFilter(matrix, kLow_SkFilterQuality, nullptr));
1314 
1315     // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1316     // correct offset to the filter matrix.
1317     SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1318     canvas.saveLayer(&bounds1, nullptr);
1319     SkPaint filterPaint;
1320     filterPaint.setImageFilter(std::move(matrixFilter));
1321     SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1322     canvas.saveLayer(&bounds2, &filterPaint);
1323     SkPaint greenPaint;
1324     greenPaint.setColor(SK_ColorGREEN);
1325     canvas.drawRect(bounds2, greenPaint);
1326     canvas.restore();
1327     canvas.restore();
1328     SkPaint strokePaint;
1329     strokePaint.setStyle(SkPaint::kStroke_Style);
1330     strokePaint.setColor(SK_ColorRED);
1331 
1332     SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1333     uint32_t pixel;
1334     temp.readPixels(info, &pixel, 4, 25, 25);
1335     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1336 
1337     // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1338     // correct offset to the filter matrix.
1339     canvas.clear(0x0);
1340     temp.readPixels(info, &pixel, 4, 25, 25);
1341     canvas.saveLayer(&bounds1, nullptr);
1342     canvas.drawBitmap(bitmap, 20, 20, &filterPaint);    // drawSprite
1343     canvas.restore();
1344 
1345     temp.readPixels(info, &pixel, 4, 25, 25);
1346     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1347 }
1348 
DEF_TEST(XfermodeImageFilterCroppedInput,reporter)1349 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1350     test_xfermode_cropped_input(SkSurface::MakeRasterN32Premul(100, 100).get(), reporter);
1351 }
1352 
test_composed_imagefilter_offset(skiatest::Reporter * reporter,GrContext * context)1353 static void test_composed_imagefilter_offset(skiatest::Reporter* reporter, GrContext* context) {
1354     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(context, 100));
1355 
1356     SkIRect cropRect = SkIRect::MakeXYWH(1, 0, 20, 20);
1357     sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
1358     sk_sp<SkImageFilter> blurFilter(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1359                                                             nullptr, &cropRect));
1360     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(blurFilter),
1361                                                                 std::move(offsetFilter)));
1362     SkIPoint offset;
1363     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
1364                                     kN32_SkColorType, nullptr, srcImg.get());
1365 
1366     sk_sp<SkSpecialImage> resultImg(
1367             as_IFB(composedFilter)->filterImage(ctx, &offset));
1368     REPORTER_ASSERT(reporter, resultImg);
1369     REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1370 }
1371 
DEF_TEST(ComposedImageFilterOffset,reporter)1372 DEF_TEST(ComposedImageFilterOffset, reporter) {
1373     test_composed_imagefilter_offset(reporter, nullptr);
1374 }
1375 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu,reporter,ctxInfo)1376 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu, reporter, ctxInfo) {
1377     test_composed_imagefilter_offset(reporter, ctxInfo.grContext());
1378 }
1379 
test_composed_imagefilter_bounds(skiatest::Reporter * reporter,GrContext * context)1380 static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter, GrContext* context) {
1381     // The bounds passed to the inner filter must be filtered by the outer
1382     // filter, so that the inner filter produces the pixels that the outer
1383     // filter requires as input. This matters if the outer filter moves pixels.
1384     // Here, accounting for the outer offset is necessary so that the green
1385     // pixels of the picture are not clipped.
1386 
1387     SkPictureRecorder recorder;
1388     SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeIWH(200, 100));
1389     recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1390     recordingCanvas->clear(SK_ColorGREEN);
1391     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1392     sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(picture));
1393     SkIRect cropRect = SkIRect::MakeWH(100, 100);
1394     sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(-100, 0, nullptr, &cropRect));
1395     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(offsetFilter),
1396                                                                 std::move(pictureFilter)));
1397 
1398     sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(context, 100));
1399     SkImageFilter_Base::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr,
1400                                     kN32_SkColorType, nullptr, sourceImage.get());
1401     SkIPoint offset;
1402     sk_sp<SkSpecialImage> result(
1403             as_IFB(composedFilter)->filterImage(ctx, &offset));
1404     REPORTER_ASSERT(reporter, offset.isZero());
1405     REPORTER_ASSERT(reporter, result);
1406     REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1407 
1408     SkBitmap resultBM;
1409     REPORTER_ASSERT(reporter, result->getROPixels(&resultBM));
1410     REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1411 }
1412 
DEF_TEST(ComposedImageFilterBounds,reporter)1413 DEF_TEST(ComposedImageFilterBounds, reporter) {
1414     test_composed_imagefilter_bounds(reporter, nullptr);
1415 }
1416 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu,reporter,ctxInfo)1417 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu, reporter, ctxInfo) {
1418     test_composed_imagefilter_bounds(reporter, ctxInfo.grContext());
1419 }
1420 
DEF_TEST(ImageFilterCanComputeFastBounds,reporter)1421 DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1422 
1423     {
1424         SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1425         sk_sp<SkImageFilter> lighting(SkImageFilters::PointLitDiffuse(
1426                 location,  SK_ColorGREEN, 0, 0, nullptr));
1427         REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1428     }
1429 
1430     {
1431         sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1432         REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1433         {
1434             SkColorFilter* grayCF;
1435             REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1436             REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack());
1437             grayCF->unref();
1438         }
1439         REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1440 
1441         sk_sp<SkImageFilter> grayBlur(SkImageFilters::Blur(
1442                 SK_Scalar1, SK_Scalar1, std::move(gray)));
1443         REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1444     }
1445 
1446     {
1447         float greenMatrix[20] = { 0, 0, 0, 0, 0,
1448                                   0, 0, 0, 0, 1.0f/255,
1449                                   0, 0, 0, 0, 0,
1450                                   0, 0, 0, 0, 1.0f/255
1451         };
1452         sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
1453         sk_sp<SkImageFilter> green(SkImageFilters::ColorFilter(greenCF, nullptr));
1454 
1455         REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack());
1456         REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1457 
1458         sk_sp<SkImageFilter> greenBlur(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1459                                                                std::move(green)));
1460         REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1461     }
1462 
1463     uint8_t allOne[256], identity[256];
1464     for (int i = 0; i < 256; ++i) {
1465         identity[i] = i;
1466         allOne[i] = 255;
1467     }
1468 
1469     sk_sp<SkColorFilter> identityCF(SkTableColorFilter::MakeARGB(identity, identity,
1470                                                                  identity, allOne));
1471     sk_sp<SkImageFilter> identityFilter(SkImageFilters::ColorFilter(identityCF, nullptr));
1472     REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack());
1473     REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1474 
1475     sk_sp<SkColorFilter> forceOpaqueCF(SkTableColorFilter::MakeARGB(allOne, identity,
1476                                                                     identity, identity));
1477     sk_sp<SkImageFilter> forceOpaque(SkImageFilters::ColorFilter(forceOpaqueCF, nullptr));
1478     REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack());
1479     REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1480 }
1481 
1482 // Verify that SkImageSource survives serialization
DEF_TEST(ImageFilterImageSourceSerialization,reporter)1483 DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
1484     auto surface(SkSurface::MakeRasterN32Premul(10, 10));
1485     surface->getCanvas()->clear(SK_ColorGREEN);
1486     sk_sp<SkImage> image(surface->makeImageSnapshot());
1487     sk_sp<SkImageFilter> filter(SkImageFilters::Image(std::move(image)));
1488 
1489     sk_sp<SkData> data(filter->serialize());
1490     sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1491     REPORTER_ASSERT(reporter, unflattenedFilter);
1492 
1493     SkBitmap bm;
1494     bm.allocN32Pixels(10, 10);
1495     bm.eraseColor(SK_ColorBLUE);
1496     SkPaint paint;
1497     paint.setColor(SK_ColorRED);
1498     paint.setImageFilter(unflattenedFilter);
1499 
1500     SkCanvas canvas(bm);
1501     canvas.drawRect(SkRect::MakeIWH(10, 10), paint);
1502     REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1503 }
1504 
DEF_TEST(ImageFilterImageSourceUninitialized,r)1505 DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1506     sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1507     if (!data) {
1508         return;
1509     }
1510     sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1511     // This will fail. More importantly, msan will verify that we did not
1512     // compare against uninitialized memory.
1513     REPORTER_ASSERT(r, !unflattenedFilter);
1514 }
1515 
test_large_blur_input(skiatest::Reporter * reporter,SkCanvas * canvas)1516 static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1517     SkBitmap largeBmp;
1518     int largeW = 5000;
1519     int largeH = 5000;
1520     // If we're GPU-backed make the bitmap too large to be converted into a texture.
1521     if (GrContext* ctx = canvas->getGrContext()) {
1522         largeW = ctx->priv().caps()->maxTextureSize() + 1;
1523     }
1524 
1525     largeBmp.allocN32Pixels(largeW, largeH);
1526     largeBmp.eraseColor(0);
1527     if (!largeBmp.getPixels()) {
1528         ERRORF(reporter, "Failed to allocate large bmp.");
1529         return;
1530     }
1531 
1532     sk_sp<SkImage> largeImage(SkImage::MakeFromBitmap(largeBmp));
1533     if (!largeImage) {
1534         ERRORF(reporter, "Failed to create large image.");
1535         return;
1536     }
1537 
1538     sk_sp<SkImageFilter> largeSource(SkImageFilters::Image(std::move(largeImage)));
1539     if (!largeSource) {
1540         ERRORF(reporter, "Failed to create large SkImageSource.");
1541         return;
1542     }
1543 
1544     sk_sp<SkImageFilter> blur(SkImageFilters::Blur(10.f, 10.f, std::move(largeSource)));
1545     if (!blur) {
1546         ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1547         return;
1548     }
1549 
1550     SkPaint paint;
1551     paint.setImageFilter(std::move(blur));
1552 
1553     // This should not crash (http://crbug.com/570479).
1554     canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1555 }
1556 
DEF_TEST(ImageFilterBlurLargeImage,reporter)1557 DEF_TEST(ImageFilterBlurLargeImage, reporter) {
1558     auto surface(SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(100, 100)));
1559     test_large_blur_input(reporter, surface->getCanvas());
1560 }
1561 
test_make_with_filter(skiatest::Reporter * reporter,GrContext * context)1562 static void test_make_with_filter(skiatest::Reporter* reporter, GrContext* context) {
1563     sk_sp<SkSurface> surface(create_surface(context, 192, 128));
1564     surface->getCanvas()->clear(SK_ColorRED);
1565     SkPaint bluePaint;
1566     bluePaint.setColor(SK_ColorBLUE);
1567     SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1568     surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1569     sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1570 
1571     sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1572     SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1573     SkIRect outSubset;
1574     SkIPoint offset;
1575     sk_sp<SkImage> result;
1576 
1577     result = sourceImage->makeWithFilter(nullptr, subset, clipBounds, &outSubset, &offset);
1578     REPORTER_ASSERT(reporter, !result);
1579 
1580     result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, nullptr, &offset);
1581     REPORTER_ASSERT(reporter, !result);
1582 
1583     result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, nullptr);
1584     REPORTER_ASSERT(reporter, !result);
1585 
1586     SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1587     result = sourceImage->makeWithFilter(filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1588     REPORTER_ASSERT(reporter, !result);
1589 
1590     SkIRect empty = SkIRect::MakeEmpty();
1591     result = sourceImage->makeWithFilter(filter.get(), empty, clipBounds, &outSubset, &offset);
1592     REPORTER_ASSERT(reporter, !result);
1593 
1594     result = sourceImage->makeWithFilter(filter.get(), subset, empty, &outSubset, &offset);
1595     REPORTER_ASSERT(reporter, !result);
1596 
1597     SkIRect leftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1598     result = sourceImage->makeWithFilter(filter.get(), subset, leftField, &outSubset, &offset);
1599     REPORTER_ASSERT(reporter, !result);
1600 
1601     result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1602 
1603     REPORTER_ASSERT(reporter, result);
1604     REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1605     SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1606                                           outSubset.width(), outSubset.height());
1607     REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1608 
1609     // In GPU-mode, this case creates a special image with a backing size that differs from
1610     // the content size
1611     {
1612         clipBounds.setXYWH(0, 0, 170, 100);
1613         subset.setXYWH(0, 0, 160, 90);
1614 
1615         filter = SkImageFilters::Xfermode(SkBlendMode::kSrc, nullptr);
1616         result = sourceImage->makeWithFilter(filter.get(), subset, clipBounds, &outSubset, &offset);
1617         REPORTER_ASSERT(reporter, result);
1618     }
1619 }
1620 
DEF_TEST(ImageFilterMakeWithFilter,reporter)1621 DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1622     test_make_with_filter(reporter, nullptr);
1623 }
1624 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu,reporter,ctxInfo)1625 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Gpu, reporter, ctxInfo) {
1626     test_make_with_filter(reporter, ctxInfo.grContext());
1627 }
1628 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu,reporter,ctxInfo)1629 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu, reporter, ctxInfo) {
1630 
1631     sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(ctxInfo.grContext(),
1632                                                       SkBudgeted::kNo,
1633                                                       SkImageInfo::MakeN32Premul(100, 100)));
1634 
1635 
1636     SkCanvas* canvas = surf->getCanvas();
1637 
1638     test_huge_blur(canvas, reporter);
1639 }
1640 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu,reporter,ctxInfo)1641 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu, reporter, ctxInfo) {
1642     sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(
1643             ctxInfo.grContext(),
1644             SkBudgeted::kNo,
1645             SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1646 
1647     test_xfermode_cropped_input(surf.get(), reporter);
1648 }
1649 
DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu,reporter,ctxInfo)1650 DEF_GPUTEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu, reporter, ctxInfo) {
1651     auto surface(SkSurface::MakeRenderTarget(
1652             ctxInfo.grContext(), SkBudgeted::kYes,
1653             SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1654     test_large_blur_input(reporter, surface->getCanvas());
1655 }
1656 
1657 /*
1658  *  Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1659  *  than just scale/translate, but that other filters do.
1660  */
DEF_TEST(ImageFilterComplexCTM,reporter)1661 DEF_TEST(ImageFilterComplexCTM, reporter) {
1662     // just need a colorfilter to exercise the corresponding imagefilter
1663     sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
1664     sk_sp<SkImageFilter> cfif = SkImageFilters::ColorFilter(cf, nullptr);    // can handle
1665     sk_sp<SkImageFilter> blif = SkImageFilters::Blur(3, 3, nullptr);         // cannot handle
1666 
1667     struct {
1668         sk_sp<SkImageFilter> fFilter;
1669         bool                 fExpectCanHandle;
1670     } recs[] = {
1671         { cfif,                                  true  },
1672         { SkImageFilters::ColorFilter(cf, cfif), true  },
1673         { SkImageFilters::Merge(cfif, cfif),     true  },
1674         { SkImageFilters::Compose(cfif, cfif),   true  },
1675 
1676         { blif,                                  false },
1677         { SkImageFilters::Blur(3, 3, cfif),      false },
1678         { SkImageFilters::ColorFilter(cf, blif), false },
1679         { SkImageFilters::Merge(cfif, blif),     false },
1680         { SkImageFilters::Compose(blif, cfif),   false },
1681     };
1682 
1683     for (const auto& rec : recs) {
1684         const bool canHandle = as_IFB(rec.fFilter)->canHandleComplexCTM();
1685         REPORTER_ASSERT(reporter, canHandle == rec.fExpectCanHandle);
1686     }
1687 }
1688 
1689 // Test SkXfermodeImageFilter::filterBounds with different blending modes.
DEF_TEST(XfermodeImageFilterBounds,reporter)1690 DEF_TEST(XfermodeImageFilterBounds, reporter) {
1691     SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
1692     SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
1693     sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(background_rect));
1694     sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(foreground_rect));
1695 
1696     const int kModeCount = static_cast<int>(SkBlendMode::kLastMode) + 1;
1697     SkIRect expectedBounds[kModeCount];
1698     // Expect union of input rects by default.
1699     for (int i = 0; i < kModeCount; ++i) {
1700         expectedBounds[i] = background_rect;
1701         expectedBounds[i].join(foreground_rect);
1702     }
1703 
1704     SkIRect intersection = background_rect;
1705     intersection.intersect(foreground_rect);
1706     expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
1707     expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
1708     expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
1709     expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
1710     expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
1711     expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
1712     expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
1713 
1714     // The value of this variable doesn't matter because we use inputs with fixed bounds.
1715     SkIRect src = SkIRect::MakeXYWH(11, 22, 33, 44);
1716     for (int i = 0; i < kModeCount; ++i) {
1717         sk_sp<SkImageFilter> xfermode(SkImageFilters::Xfermode(static_cast<SkBlendMode>(i),
1718                                                                background, foreground, nullptr));
1719         auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1720                                              SkImageFilter::kForward_MapDirection, nullptr);
1721         REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
1722     }
1723 
1724     // Test empty intersection.
1725     sk_sp<SkImageFilter> background2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(0, 0, 20, 20)));
1726     sk_sp<SkImageFilter> foreground2(new FixedBoundsImageFilter(SkIRect::MakeXYWH(40, 40, 50, 50)));
1727     sk_sp<SkImageFilter> xfermode(SkImageFilters::Xfermode(
1728             SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
1729     auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
1730                                          SkImageFilter::kForward_MapDirection, nullptr);
1731     REPORTER_ASSERT(reporter, bounds.isEmpty());
1732 }
1733 
DEF_TEST(OffsetImageFilterBounds,reporter)1734 DEF_TEST(OffsetImageFilterBounds, reporter) {
1735     SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
1736     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(-50.5f, -50.5f, nullptr));
1737 
1738     SkIRect expectedForward = SkIRect::MakeXYWH(-50, -50, 100, 100);
1739     SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
1740                                                  SkImageFilter::kForward_MapDirection, nullptr);
1741     REPORTER_ASSERT(reporter, boundsForward == expectedForward);
1742 
1743     SkIRect expectedReverse = SkIRect::MakeXYWH(50, 50, 100, 100);
1744     SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
1745                                                  SkImageFilter::kReverse_MapDirection, &src);
1746     REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
1747 }
1748 
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)1749 static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
1750                                    float k4, sk_sp<SkImageFilter> background,
1751                                    sk_sp<SkImageFilter> foreground,
1752                                    const SkIRect* crop, const SkIRect& expected) {
1753     sk_sp<SkImageFilter> arithmetic(
1754             SkImageFilters::Arithmetic(k1, k2, k3, k4, false, background, foreground, crop));
1755     // The value of the input rect doesn't matter because we use inputs with fixed bounds.
1756     SkIRect bounds = arithmetic->filterBounds(SkIRect::MakeXYWH(11, 22, 33, 44), SkMatrix::I(),
1757                                               SkImageFilter::kForward_MapDirection, nullptr);
1758     REPORTER_ASSERT(reporter, expected == bounds);
1759 }
1760 
test_arithmetic_combinations(skiatest::Reporter * reporter,float v)1761 static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
1762     SkIRect bgRect = SkIRect::MakeXYWH(0, 0, 100, 100);
1763     SkIRect fgRect = SkIRect::MakeXYWH(50, 50, 100, 100);
1764     sk_sp<SkImageFilter> background(new FixedBoundsImageFilter(bgRect));
1765     sk_sp<SkImageFilter> foreground(new FixedBoundsImageFilter(fgRect));
1766 
1767     SkIRect unionRect = bgRect;
1768     unionRect.join(fgRect);
1769     SkIRect intersection = bgRect;
1770     intersection.intersect(fgRect);
1771 
1772     test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
1773                            SkIRect::MakeEmpty());
1774     test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, unionRect);
1775     test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, bgRect);
1776     test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, unionRect);
1777     test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, fgRect);
1778     test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, unionRect);
1779     test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, unionRect);
1780     test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, unionRect);
1781     test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
1782     test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, unionRect);
1783     test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, bgRect);
1784     test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, unionRect);
1785     test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, fgRect);
1786     test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, unionRect);
1787     test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, unionRect);
1788     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, unionRect);
1789 
1790     // Test with crop. When k4 is non-zero, the result is expected to be cropRect
1791     // regardless of inputs because the filter affects the whole crop area.
1792     SkIRect cropRect = SkIRect::MakeXYWH(-111, -222, 333, 444);
1793     test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &cropRect,
1794                            SkIRect::MakeEmpty());
1795     test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &cropRect, cropRect);
1796     test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &cropRect, bgRect);
1797     test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &cropRect, cropRect);
1798     test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &cropRect, fgRect);
1799     test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &cropRect, cropRect);
1800     test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &cropRect, unionRect);
1801     test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &cropRect, cropRect);
1802     test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &cropRect, intersection);
1803     test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &cropRect, cropRect);
1804     test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &cropRect, bgRect);
1805     test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &cropRect, cropRect);
1806     test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &cropRect, fgRect);
1807     test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &cropRect, cropRect);
1808     test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &cropRect, unionRect);
1809     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &cropRect, cropRect);
1810 }
1811 
1812 // Test SkArithmeticImageFilter::filterBounds with different blending modes.
DEF_TEST(ArithmeticImageFilterBounds,reporter)1813 DEF_TEST(ArithmeticImageFilterBounds, reporter) {
1814     test_arithmetic_combinations(reporter, 1);
1815     test_arithmetic_combinations(reporter, 0.5);
1816 }
1817 
1818 // Test SkImageSource::filterBounds.
DEF_TEST(ImageSourceBounds,reporter)1819 DEF_TEST(ImageSourceBounds, reporter) {
1820     sk_sp<SkImage> image(SkImage::MakeFromBitmap(make_gradient_circle(64, 64)));
1821     // Default src and dst rects.
1822     sk_sp<SkImageFilter> source1(SkImageFilters::Image(image));
1823     SkIRect imageBounds = SkIRect::MakeWH(64, 64);
1824     SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
1825     REPORTER_ASSERT(reporter,
1826                     imageBounds == source1->filterBounds(input, SkMatrix::I(),
1827                                                          SkImageFilter::kForward_MapDirection,
1828                                                          nullptr));
1829     REPORTER_ASSERT(reporter,
1830                     input == source1->filterBounds(input, SkMatrix::I(),
1831                                                    SkImageFilter::kReverse_MapDirection, &input));
1832     SkMatrix scale(SkMatrix::MakeScale(2));
1833     SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
1834     REPORTER_ASSERT(reporter,
1835                     scaledBounds == source1->filterBounds(input, scale,
1836                                                           SkImageFilter::kForward_MapDirection,
1837                                                           nullptr));
1838     REPORTER_ASSERT(reporter, input == source1->filterBounds(input, scale,
1839                                                              SkImageFilter::kReverse_MapDirection,
1840                                                              &input));
1841 
1842     // Specified src and dst rects.
1843     SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
1844     SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
1845     sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst, kMedium_SkFilterQuality));
1846     REPORTER_ASSERT(reporter,
1847                     dst.roundOut() == source2->filterBounds(input, SkMatrix::I(),
1848                                                             SkImageFilter::kForward_MapDirection,
1849                                                             nullptr));
1850     REPORTER_ASSERT(reporter,
1851                     input == source2->filterBounds(input, SkMatrix::I(),
1852                                                    SkImageFilter::kReverse_MapDirection, &input));
1853     scale.mapRect(&dst);
1854     scale.mapRect(&src);
1855     REPORTER_ASSERT(reporter,
1856                     dst.roundOut() == source2->filterBounds(input, scale,
1857                                                             SkImageFilter::kForward_MapDirection,
1858                                                             nullptr));
1859     REPORTER_ASSERT(reporter, input == source2->filterBounds(input, scale,
1860                                                              SkImageFilter::kReverse_MapDirection,
1861                                                              &input));
1862 }
1863 
1864