• 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__anon2251612f0111::FilterList::Filter229          Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
Filter__anon2251612f0111::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