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