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