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