xref: /aosp_15_r20/external/skia/tests/ImageFilterTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkAlphaType.h"
9 #include "include/core/SkBBHFactory.h"
10 #include "include/core/SkBitmap.h"
11 #include "include/core/SkBlendMode.h"
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkColor.h"
14 #include "include/core/SkColorFilter.h"
15 #include "include/core/SkColorType.h"
16 #include "include/core/SkData.h"
17 #include "include/core/SkFlattenable.h"
18 #include "include/core/SkFont.h"
19 #include "include/core/SkImage.h"
20 #include "include/core/SkImageFilter.h"
21 #include "include/core/SkImageInfo.h"
22 #include "include/core/SkMatrix.h"
23 #include "include/core/SkPaint.h"
24 #include "include/core/SkPicture.h"
25 #include "include/core/SkPictureRecorder.h"
26 #include "include/core/SkPoint.h"
27 #include "include/core/SkPoint3.h"
28 #include "include/core/SkRect.h"
29 #include "include/core/SkRefCnt.h"
30 #include "include/core/SkSamplingOptions.h"
31 #include "include/core/SkScalar.h"
32 #include "include/core/SkSerialProcs.h"
33 #include "include/core/SkShader.h"
34 #include "include/core/SkSize.h"
35 #include "include/core/SkSurface.h"
36 #include "include/core/SkSurfaceProps.h"
37 #include "include/core/SkTileMode.h"
38 #include "include/core/SkTypes.h"
39 #include "include/effects/SkGradientShader.h"
40 #include "include/effects/SkImageFilters.h"
41 #include "include/effects/SkPerlinNoiseShader.h"
42 #include "include/encode/SkPngEncoder.h"
43 #include "include/gpu/GpuTypes.h"
44 #include "include/gpu/ganesh/GrTypes.h"
45 #include "include/private/base/SkTArray.h"
46 #include "include/private/base/SkTo.h"
47 #include "src/core/SkBitmapDevice.h"
48 #include "src/core/SkDevice.h"
49 #include "src/core/SkImageFilterTypes.h"
50 #include "src/core/SkImageFilter_Base.h"
51 #include "src/core/SkRectPriv.h"
52 #include "src/core/SkSpecialImage.h"
53 #include "src/effects/colorfilters/SkColorFilterBase.h"
54 #include "src/image/SkImage_Base.h"
55 #include "tests/CtsEnforcement.h"
56 #include "tests/Test.h"
57 #include "tools/EncodeUtils.h"
58 #include "tools/Resources.h"
59 #include "tools/ToolUtils.h"
60 #include "tools/fonts/FontToolUtils.h"
61 
62 #if defined(SK_GANESH)
63 #include "include/gpu/ganesh/GrDirectContext.h"
64 #include "include/gpu/ganesh/GrRecordingContext.h"
65 #include "include/gpu/ganesh/SkImageGanesh.h"
66 #include "include/gpu/ganesh/SkSurfaceGanesh.h"
67 #include "src/gpu/ganesh/GrCaps.h"
68 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
69 #include "src/gpu/ganesh/image/GrImageUtils.h"
70 #include "src/gpu/ganesh/image/SkImage_GaneshBase.h"
71 #include "src/gpu/ganesh/image/SkSpecialImage_Ganesh.h"
72 #endif
73 
74 #if defined(SK_GRAPHITE)
75 #include "include/gpu/graphite/Context.h"
76 #include "include/gpu/graphite/Image.h"
77 #include "include/gpu/graphite/Surface.h"
78 #include "tools/graphite/GraphiteToolUtils.h"
79 #endif
80 
81 #include <algorithm>
82 #include <cstdint>
83 #include <cstring>
84 #include <utility>
85 #include <limits>
86 
87 using namespace skia_private;
88 
89 class SkReadBuffer;
90 class SkWriteBuffer;
91 struct GrContextOptions;
92 
93 static const int kBitmapSize = 4;
94 
95 namespace {
96 
97 static constexpr GrSurfaceOrigin kTestSurfaceOrigin = kTopLeft_GrSurfaceOrigin;
98 
99 class MatrixTestImageFilter : public SkImageFilter_Base {
100 public:
MatrixTestImageFilter(skiatest::Reporter * reporter,const SkMatrix & expectedMatrix)101     MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
102             : SkImageFilter_Base(nullptr, 0)
103             , fReporter(reporter)
104             , fExpectedMatrix(expectedMatrix) {
105         // Layers have an extra pixel of padding that adjusts the coordinate space
106         fExpectedMatrix.postTranslate(1.f, 1.f);
107     }
108 
109 private:
getFactory() const110     Factory getFactory() const override {
111         SK_ABORT("Does not participate in serialization");
112         return nullptr;
113     }
getTypeName() const114     const char* getTypeName() const override { return "MatrixTestImageFilter"; }
115 
onFilterImage(const skif::Context & ctx) const116     skif::FilterResult onFilterImage(const skif::Context& ctx) const override {
117         REPORTER_ASSERT(fReporter, ctx.mapping().layerMatrix() == fExpectedMatrix);
118         return ctx.source();
119     }
120 
onGetInputLayerBounds(const skif::Mapping & mapping,const skif::LayerSpace<SkIRect> & desiredOutput,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const121     skif::LayerSpace<SkIRect> onGetInputLayerBounds(
122             const skif::Mapping& mapping,
123             const skif::LayerSpace<SkIRect>& desiredOutput,
124             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override {
125         return desiredOutput;
126     }
127 
onGetOutputLayerBounds(const skif::Mapping & mapping,std::optional<skif::LayerSpace<SkIRect>> contentBounds) const128     std::optional<skif::LayerSpace<SkIRect>> onGetOutputLayerBounds(
129             const skif::Mapping& mapping,
130             std::optional<skif::LayerSpace<SkIRect>> contentBounds) const override {
131         return contentBounds;
132     }
133 
134     skiatest::Reporter* fReporter;
135     SkMatrix fExpectedMatrix;
136 };
137 
draw_gradient_circle(SkCanvas * canvas,int width,int height)138 void draw_gradient_circle(SkCanvas* canvas, int width, int height) {
139     SkScalar x = SkIntToScalar(width / 2);
140     SkScalar y = SkIntToScalar(height / 2);
141     SkScalar radius = std::min(x, y) * 0.8f;
142     canvas->clear(0x00000000);
143     SkColor colors[2];
144     colors[0] = SK_ColorWHITE;
145     colors[1] = SK_ColorBLACK;
146     sk_sp<SkShader> shader(
147         SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2,
148                                        SkTileMode::kClamp)
149     );
150     SkPaint paint;
151     paint.setShader(shader);
152     canvas->drawCircle(x, y, radius, paint);
153 }
154 
make_gradient_circle(int width,int height)155 SkBitmap make_gradient_circle(int width, int height) {
156     SkBitmap bitmap;
157     bitmap.allocN32Pixels(width, height);
158     SkCanvas canvas(bitmap);
159     draw_gradient_circle(&canvas, width, height);
160     return bitmap;
161 }
162 
163 class FilterList {
164 public:
FilterList(const sk_sp<SkImageFilter> & input,const SkIRect * cropRect=nullptr)165     FilterList(const sk_sp<SkImageFilter>& input, const SkIRect* cropRect = nullptr) {
166         static const SkScalar kBlurSigma = SkIntToScalar(5);
167 
168         SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
169         {
170             sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcIn));
171 
172             this->addFilter("color filter",
173                     SkImageFilters::ColorFilter(std::move(cf), input, cropRect));
174         }
175         {
176             sk_sp<SkImage> gradientImage(make_gradient_circle(64, 64).asImage());
177             sk_sp<SkImageFilter> gradientSource(SkImageFilters::Image(std::move(gradientImage),
178                                                                       SkFilterMode::kNearest));
179 
180             this->addFilter("displacement map",
181                     SkImageFilters::DisplacementMap(SkColorChannel::kR, SkColorChannel::kB, 20.0f,
182                                                     std::move(gradientSource), input, cropRect));
183         }
184         this->addFilter("blur", SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, input, cropRect));
185         this->addFilter("drop shadow", SkImageFilters::DropShadow(
186                 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input, cropRect));
187         this->addFilter("diffuse lighting",
188                 SkImageFilters::PointLitDiffuse(location, SK_ColorGREEN, 0, 0, input, cropRect));
189         this->addFilter("specular lighting",
190                 SkImageFilters::PointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input,
191                                                    cropRect));
192         {
193             SkScalar kernel[9] = {
194                 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
195                 SkIntToScalar(1), SkIntToScalar(-7), SkIntToScalar(1),
196                 SkIntToScalar(1), SkIntToScalar(1), SkIntToScalar(1),
197             };
198             const SkISize kernelSize = SkISize::Make(3, 3);
199             const SkScalar gain = SK_Scalar1, bias = 0;
200 
201             // This filter needs a saveLayer bc it is in repeat mode
202             this->addFilter("matrix convolution",
203                             SkImageFilters::MatrixConvolution(
204                                     kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
205                                     SkTileMode::kRepeat, false, input, cropRect),
206                             true);
207         }
208         this->addFilter("merge", SkImageFilters::Merge(input, input, cropRect));
209 
210         {
211             sk_sp<SkShader> greenColorShader = SkShaders::Color(SK_ColorGREEN);
212 
213             SkIRect leftSideCropRect = SkIRect::MakeXYWH(0, 0, 32, 64);
214             sk_sp<SkImageFilter> shaderFilterLeft(SkImageFilters::Shader(greenColorShader,
215                                                                          &leftSideCropRect));
216             SkIRect rightSideCropRect = SkIRect::MakeXYWH(32, 0, 32, 64);
217             sk_sp<SkImageFilter> shaderFilterRight(SkImageFilters::Shader(greenColorShader,
218                                                                           &rightSideCropRect));
219 
220 
221             this->addFilter("merge with disjoint inputs", SkImageFilters::Merge(
222                     std::move(shaderFilterLeft), std::move(shaderFilterRight), cropRect));
223         }
224 
225         this->addFilter("offset", SkImageFilters::Offset(SK_Scalar1, SK_Scalar1, input, cropRect));
226         this->addFilter("dilate", SkImageFilters::Dilate(3, 2, input, cropRect));
227         this->addFilter("erode", SkImageFilters::Erode(2, 3, input, cropRect));
228         this->addFilter("tile", SkImageFilters::Tile(SkRect::MakeXYWH(0, 0, 50, 50),
229                                                      cropRect ? SkRect::Make(*cropRect)
230                                                               : SkRect::MakeXYWH(0, 0, 100, 100),
231                                                      input));
232 
233         if (!cropRect) {
234             SkMatrix matrix;
235 
236             matrix.setTranslate(SK_Scalar1, SK_Scalar1);
237             matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
238 
239             this->addFilter("matrix",
240                     SkImageFilters::MatrixTransform(matrix,
241                                                     SkSamplingOptions(SkFilterMode::kLinear),
242                                                     input));
243         }
244         {
245             sk_sp<SkImageFilter> blur(SkImageFilters::Blur(kBlurSigma, kBlurSigma, input));
246 
247             this->addFilter("blur and offset", SkImageFilters::Offset(
248                     kBlurSigma, kBlurSigma, std::move(blur), cropRect));
249         }
250         {
251             SkPictureRecorder recorder;
252             SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
253 
254             SkPaint greenPaint;
255             greenPaint.setColor(SK_ColorGREEN);
256             recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
257             sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
258             sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(std::move(picture)));
259 
260             this->addFilter("picture and blur", SkImageFilters::Blur(
261                     kBlurSigma, kBlurSigma, std::move(pictureFilter), cropRect));
262         }
263         {
264             sk_sp<SkImageFilter> paintFilter(SkImageFilters::Shader(
265                     SkShaders::MakeTurbulence(SK_Scalar1, SK_Scalar1, 1, 0)));
266 
267             this->addFilter("paint and blur", SkImageFilters::Blur(
268                     kBlurSigma, kBlurSigma,  std::move(paintFilter), cropRect));
269         }
270         this->addFilter("blend", SkImageFilters::Blend(
271                 SkBlendMode::kSrc, input, input, cropRect));
272     }
count() const273     int count() const { return fFilters.size(); }
getFilter(int index) const274     SkImageFilter* getFilter(int index) const { return fFilters[index].fFilter.get(); }
getName(int index) const275     const char* getName(int index) const { return fFilters[index].fName; }
needsSaveLayer(int index) const276     bool needsSaveLayer(int index) const { return fFilters[index].fNeedsSaveLayer; }
277 private:
278     struct Filter {
Filter__anon16ba93fa0111::FilterList::Filter279         Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
Filter__anon16ba93fa0111::FilterList::Filter280         Filter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer)
281             : fName(name)
282             , fFilter(std::move(filter))
283             , fNeedsSaveLayer(needsSaveLayer) {
284         }
285         const char*                 fName;
286         sk_sp<SkImageFilter>        fFilter;
287         bool                        fNeedsSaveLayer;
288     };
addFilter(const char * name,sk_sp<SkImageFilter> filter,bool needsSaveLayer=false)289     void addFilter(const char* name, sk_sp<SkImageFilter> filter, bool needsSaveLayer = false) {
290         fFilters.push_back(Filter(name, std::move(filter), needsSaveLayer));
291     }
292 
293     TArray<Filter> fFilters;
294 };
295 
296 }  // namespace
297 
make_context(const SkIRect & out,const SkSpecialImage * src)298 static skif::Context make_context(const SkIRect& out, const SkSpecialImage* src) {
299     sk_sp<skif::Backend> backend;
300     if (src->isGaneshBacked()) {
301         backend = skif::MakeGaneshBackend(sk_ref_sp(src->getContext()), kTestSurfaceOrigin,
302                                           src->props(), src->colorType());
303     } else {
304         backend = skif::MakeRasterBackend(src->props(), src->colorType());
305     }
306 
307     return skif::Context{std::move(backend),
308                          skif::Mapping{SkMatrix::I()},
309                          skif::LayerSpace<SkIRect>{out},
310                          skif::FilterResult{sk_ref_sp(src)},
311                          src->getColorSpace(),
312                          /*stats=*/nullptr};
313 }
make_context(int outWidth,int outHeight,const SkSpecialImage * src)314 static skif::Context make_context(int outWidth, int outHeight, const SkSpecialImage* src) {
315     return make_context(SkIRect::MakeWH(outWidth, outHeight), src);
316 }
317 
make_small_image()318 static sk_sp<SkImage> make_small_image() {
319     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(kBitmapSize, kBitmapSize)));
320     SkCanvas* canvas = surface->getCanvas();
321     canvas->clear(0x00000000);
322     SkPaint darkPaint;
323     darkPaint.setColor(0xFF804020);
324     SkPaint lightPaint;
325     lightPaint.setColor(0xFF244484);
326     const int kRectSize = kBitmapSize / 4;
327     static_assert(kBitmapSize % 4 == 0, "bitmap size not multiple of 4");
328 
329     for (int y = 0; y < kBitmapSize; y += kRectSize) {
330         for (int x = 0; x < kBitmapSize; x += kRectSize) {
331             canvas->save();
332             canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
333             canvas->drawRect(
334                     SkRect::MakeXYWH(0,         0,         kRectSize, kRectSize), darkPaint);
335             canvas->drawRect(
336                     SkRect::MakeXYWH(kRectSize, 0,         kRectSize, kRectSize), lightPaint);
337             canvas->drawRect(
338                     SkRect::MakeXYWH(0,         kRectSize, kRectSize, kRectSize), lightPaint);
339             canvas->drawRect(
340                     SkRect::MakeXYWH(kRectSize, kRectSize, kRectSize, kRectSize), darkPaint);
341             canvas->restore();
342         }
343     }
344 
345     return surface->makeImageSnapshot();
346 }
347 
make_scale(float amount,sk_sp<SkImageFilter> input)348 static sk_sp<SkImageFilter> make_scale(float amount, sk_sp<SkImageFilter> input) {
349     float s = amount;
350     float matrix[20] = { s, 0, 0, 0, 0,
351                          0, s, 0, 0, 0,
352                          0, 0, s, 0, 0,
353                          0, 0, 0, s, 0 };
354     sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
355     return SkImageFilters::ColorFilter(std::move(filter), std::move(input));
356 }
357 
make_grayscale(sk_sp<SkImageFilter> input,const SkIRect * cropRect)358 static sk_sp<SkImageFilter> make_grayscale(sk_sp<SkImageFilter> input,
359                                            const SkIRect* cropRect) {
360     float matrix[20];
361     memset(matrix, 0, 20 * sizeof(float));
362     matrix[0] = matrix[5] = matrix[10] = 0.2126f;
363     matrix[1] = matrix[6] = matrix[11] = 0.7152f;
364     matrix[2] = matrix[7] = matrix[12] = 0.0722f;
365     matrix[18] = 1.0f;
366     sk_sp<SkColorFilter> filter(SkColorFilters::Matrix(matrix));
367     return SkImageFilters::ColorFilter(std::move(filter), std::move(input), cropRect);
368 }
369 
make_blue(sk_sp<SkImageFilter> input,const SkIRect * cropRect)370 static sk_sp<SkImageFilter> make_blue(sk_sp<SkImageFilter> input, const SkIRect* cropRect) {
371     sk_sp<SkColorFilter> filter(SkColorFilters::Blend(SK_ColorBLUE, SkBlendMode::kSrcIn));
372     return SkImageFilters::ColorFilter(std::move(filter), std::move(input), cropRect);
373 }
374 
375 
create_empty_device(GrRecordingContext * rContext,int widthHeight)376 static sk_sp<SkDevice> create_empty_device(GrRecordingContext* rContext, int widthHeight) {
377 
378     const SkImageInfo ii = SkImageInfo::Make({ widthHeight, widthHeight },
379                                              kRGBA_8888_SkColorType,
380                                              kPremul_SkAlphaType);
381 
382     if (rContext) {
383         return rContext->priv().createDevice(skgpu::Budgeted::kNo, ii, SkBackingFit::kApprox, 1,
384                                              skgpu::Mipmapped::kNo, skgpu::Protected::kNo,
385                                              kTestSurfaceOrigin, {},
386                                              skgpu::ganesh::Device::InitContents::kUninit);
387     } else {
388         SkBitmap bm;
389         SkAssertResult(bm.tryAllocPixels(ii));
390         return sk_make_sp<SkBitmapDevice>(bm, SkSurfaceProps());
391     }
392 }
393 
create_empty_special_image(GrRecordingContext * rContext,int widthHeight,SkColor4f color=SkColors::kTransparent)394 static sk_sp<SkSpecialImage> create_empty_special_image(GrRecordingContext* rContext,
395                                                         int widthHeight,
396                                                         SkColor4f color = SkColors::kTransparent) {
397     sk_sp<SkDevice> device = create_empty_device(rContext, widthHeight);
398 
399     SkASSERT(device);
400 
401     SkPaint p;
402     p.setColor4f(color, /*colorSpace=*/nullptr);
403     p.setBlendMode(SkBlendMode::kSrc);
404     device->drawPaint(p);
405     return device->snapSpecial(SkIRect::MakeWH(widthHeight, widthHeight));
406 }
407 
408 
DEF_TEST(ImageFilter,reporter)409 DEF_TEST(ImageFilter, reporter) {
410     {
411         // Check that a color matrix filter followed by a color matrix filter
412         // concatenates into a single filter.
413         sk_sp<SkImageFilter> doubleBrightness(make_scale(2.0f, nullptr));
414         sk_sp<SkImageFilter> halfBrightness(make_scale(0.5f, std::move(doubleBrightness)));
415         REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0));
416         SkColorFilter* cf;
417         REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf));
418         cf->unref();
419     }
420 
421     {
422         // Check that a color filter image filter without a crop rect can be
423         // expressed as a color filter.
424         sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
425         REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
426     }
427 
428     {
429         // Check that a colorfilterimage filter without a crop rect but with an input
430         // that is another colorfilterimage can be expressed as a colorfilter (composed).
431         sk_sp<SkImageFilter> mode(make_blue(nullptr, nullptr));
432         sk_sp<SkImageFilter> gray(make_grayscale(std::move(mode), nullptr));
433         REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr));
434     }
435 
436     {
437         // Test that if we exceed the limit of what ComposeColorFilter can combine, we still
438         // can build the DAG and won't assert if we call asColorFilter.
439         sk_sp<SkImageFilter> filter(make_blue(nullptr, nullptr));
440         const int kWayTooManyForComposeColorFilter = 100;
441         for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) {
442             filter = make_blue(filter, nullptr);
443             // the first few of these will succeed, but after we hit the internal limit,
444             // it will then return false.
445             (void)filter->asColorFilter(nullptr);
446         }
447     }
448 
449     {
450         // Check that a color filter image filter with a crop rect cannot
451         // be expressed as a color filter.
452         SkIRect cropRect = SkIRect::MakeWH(100, 100);
453         sk_sp<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect));
454         REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr));
455     }
456 
457     {
458         // Check that two non-commutative matrices are concatenated in
459         // the correct order.
460         float blueToRedMatrix[20] = { 0 };
461         blueToRedMatrix[2] = blueToRedMatrix[18] = 1;
462         float redToGreenMatrix[20] = { 0 };
463         redToGreenMatrix[5] = redToGreenMatrix[18] = 1;
464         sk_sp<SkColorFilter> blueToRed(SkColorFilters::Matrix(blueToRedMatrix));
465         sk_sp<SkImageFilter> filter1(SkImageFilters::ColorFilter(std::move(blueToRed), nullptr));
466         sk_sp<SkColorFilter> redToGreen(SkColorFilters::Matrix(redToGreenMatrix));
467         sk_sp<SkImageFilter> filter2(SkImageFilters::ColorFilter(std::move(redToGreen),
468                                                                  std::move(filter1)));
469 
470         SkBitmap result;
471         result.allocN32Pixels(kBitmapSize, kBitmapSize);
472 
473         SkPaint paint;
474         paint.setColor(SK_ColorBLUE);
475         paint.setImageFilter(std::move(filter2));
476         SkCanvas canvas(result);
477         canvas.clear(0x0);
478         SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
479         canvas.drawRect(rect, paint);
480         uint32_t pixel = *result.getAddr32(0, 0);
481         // The result here should be green, since we have effectively shifted blue to green.
482         REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
483     }
484 
485     {
486         // Tests pass by not asserting
487         sk_sp<SkImage> image(make_small_image());
488         SkBitmap result;
489         result.allocN32Pixels(kBitmapSize, kBitmapSize);
490 
491         {
492             // This tests for :
493             // 1 ) location at (0,0,1)
494             SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
495             // 2 ) location and target at same value
496             SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ);
497             // 3 ) large negative specular exponent value
498             SkScalar specularExponent = -1000;
499 
500             sk_sp<SkImageFilter> bmSrc(SkImageFilters::Image(std::move(image), {}));
501             SkPaint paint;
502             paint.setImageFilter(SkImageFilters::SpotLitSpecular(
503                     location, target, specularExponent, 180,
504                     0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
505                     std::move(bmSrc)));
506             SkCanvas canvas(result);
507             SkRect r = SkRect::MakeIWH(kBitmapSize, kBitmapSize);
508             canvas.drawRect(r, paint);
509         }
510     }
511 }
512 
test_cropRects(skiatest::Reporter * reporter,GrRecordingContext * rContext)513 static void test_cropRects(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
514     // Check that all filters offset to their absolute crop rect,
515     // unaffected by the input crop rect.
516     // Tests pass by not asserting.
517     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
518     SkASSERT(srcImg);
519 
520     SkIRect inputCropRect = SkIRect::MakeXYWH(8, 13, 80, 80);
521     SkIRect cropRect = SkIRect::MakeXYWH(20, 30, 60, 60);
522     sk_sp<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect));
523 
524     FilterList filters(input, &cropRect);
525 
526     for (int i = 0; i < filters.count(); ++i) {
527         SkImageFilter* filter = filters.getFilter(i);
528         SkIPoint offset;
529         skif::Context ctx = make_context(100, 100, srcImg.get());
530         sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx)
531                                                        .imageAndOffset(ctx, &offset));
532         REPORTER_ASSERT(reporter, resultImg, "%s", filters.getName(i));
533         REPORTER_ASSERT(reporter, offset.fX == 20 && offset.fY == 30, "%s", filters.getName(i));
534     }
535 }
536 
special_image_to_bitmap(GrDirectContext * dContext,const SkSpecialImage * src,SkBitmap * dst)537 static bool special_image_to_bitmap(GrDirectContext* dContext, const SkSpecialImage* src,
538                                     SkBitmap* dst) {
539     sk_sp<SkImage> img = src->asImage();
540     if (!img) {
541         return false;
542     }
543 
544     if (!dst->tryAllocN32Pixels(src->width(), src->height())) {
545         return false;
546     }
547 
548     return img->readPixels(dContext, dst->pixmap(), src->subset().fLeft, src->subset().fTop);
549 }
550 
test_negative_blur_sigma(skiatest::Reporter * reporter,GrDirectContext * dContext)551 static void test_negative_blur_sigma(skiatest::Reporter* reporter,
552                                      GrDirectContext* dContext) {
553     // Check that SkBlurImageFilter will reject a negative sigma on creation, but properly uses the
554     // absolute value of the mapped sigma after CTM application.
555     static const int kWidth = 32, kHeight = 32;
556     static const SkScalar kBlurSigma = SkIntToScalar(5);
557 
558     sk_sp<SkImageFilter> positiveFilter(SkImageFilters::Blur(kBlurSigma, kBlurSigma, nullptr));
559     sk_sp<SkImageFilter> negativeFilter(SkImageFilters::Blur(-kBlurSigma, kBlurSigma, nullptr));
560     REPORTER_ASSERT(reporter, !negativeFilter);
561 
562     sk_sp<SkImage> gradient = make_gradient_circle(kWidth, kHeight).asImage();
563     sk_sp<SkSpecialImage> imgSrc;
564     if (dContext) {
565         imgSrc = SkSpecialImages::MakeFromTextureImage(
566                 dContext, SkIRect::MakeWH(kWidth, kHeight), gradient, SkSurfaceProps());
567     } else {
568         imgSrc = SkSpecialImages::MakeFromRaster(SkIRect::MakeWH(kWidth, kHeight), gradient, {});
569     }
570 
571     SkIPoint offset;
572     skif::Context ctx = make_context(32, 32, imgSrc.get());
573 
574     sk_sp<SkSpecialImage> positiveResult(
575             as_IFB(positiveFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
576     REPORTER_ASSERT(reporter, positiveResult);
577 
578     SkMatrix negativeScale;
579     negativeScale.setScale(-SK_Scalar1, SK_Scalar1);
580     skif::Context negativeCTX = ctx.withNewMapping(skif::Mapping(negativeScale));
581 
582     sk_sp<SkSpecialImage> negativeResult(
583             as_IFB(positiveFilter)->filterImage(negativeCTX).imageAndOffset(ctx, &offset));
584     REPORTER_ASSERT(reporter, negativeResult);
585 
586 
587     SkBitmap positiveResultBM;
588     SkBitmap negativeResultBM;
589 
590     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, positiveResult.get(),
591                                                       &positiveResultBM));
592     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, negativeResult.get(),
593                                                       &negativeResultBM));
594 
595     for (int y = 0; y < kHeight; y++) {
596         int diffs = memcmp(positiveResultBM.getAddr32(0, y),
597                            negativeResultBM.getAddr32(0, y),
598                            positiveResultBM.rowBytes());
599         REPORTER_ASSERT(reporter, !diffs);
600         if (diffs) {
601             break;
602         }
603     }
604 }
605 
DEF_TEST(ImageFilterNegativeBlurSigma,reporter)606 DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
607     test_negative_blur_sigma(reporter, nullptr);
608 }
609 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)610 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu,
611                                        reporter,
612                                        ctxInfo,
613                                        CtsEnforcement::kNever) {
614     test_negative_blur_sigma(reporter, ctxInfo.directContext());
615 }
616 
test_morphology_radius_with_mirror_ctm(skiatest::Reporter * reporter,GrDirectContext * dContext)617 static void test_morphology_radius_with_mirror_ctm(skiatest::Reporter* reporter,
618                                                    GrDirectContext* dContext) {
619     // Check that SkMorphologyImageFilter maps the radius correctly when the
620     // CTM contains a mirroring transform.
621     static const int kWidth = 32, kHeight = 32;
622     static const int kRadius = 8;
623 
624     sk_sp<SkImageFilter> filter(SkImageFilters::Dilate(kRadius, kRadius, nullptr));
625 
626     SkBitmap bitmap;
627     bitmap.allocN32Pixels(kWidth, kHeight);
628     SkCanvas canvas(bitmap);
629     canvas.clear(SK_ColorTRANSPARENT);
630     SkPaint paint;
631     paint.setColor(SK_ColorWHITE);
632     canvas.drawRect(SkRect::MakeXYWH(kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2),
633                     paint);
634     sk_sp<SkImage> image = bitmap.asImage();
635     sk_sp<SkSpecialImage> imgSrc;
636     if (dContext) {
637         imgSrc = SkSpecialImages::MakeFromTextureImage(
638                 dContext, SkIRect::MakeWH(kWidth, kHeight), image, SkSurfaceProps());
639     } else {
640         imgSrc = SkSpecialImages::MakeFromRaster(SkIRect::MakeWH(kWidth, kHeight), image, {});
641     }
642 
643     SkIPoint offset;
644     skif::Context ctx = make_context(32, 32, imgSrc.get());
645 
646     sk_sp<SkSpecialImage> normalResult(
647             as_IFB(filter)->filterImage(ctx).imageAndOffset(ctx, &offset));
648     REPORTER_ASSERT(reporter, normalResult);
649 
650     SkMatrix mirrorX;
651     mirrorX.setTranslate(0, SkIntToScalar(32));
652     mirrorX.preScale(SK_Scalar1, -SK_Scalar1);
653     skif::Context mirrorXCTX = ctx.withNewMapping(skif::Mapping(mirrorX));
654 
655     sk_sp<SkSpecialImage> mirrorXResult(
656             as_IFB(filter)->filterImage(mirrorXCTX).imageAndOffset(ctx, &offset));
657     REPORTER_ASSERT(reporter, mirrorXResult);
658 
659     SkMatrix mirrorY;
660     mirrorY.setTranslate(SkIntToScalar(32), 0);
661     mirrorY.preScale(-SK_Scalar1, SK_Scalar1);
662     skif::Context mirrorYCTX = ctx.withNewMapping(skif::Mapping(mirrorY));
663 
664     sk_sp<SkSpecialImage> mirrorYResult(
665             as_IFB(filter)->filterImage(mirrorYCTX).imageAndOffset(ctx, &offset));
666     REPORTER_ASSERT(reporter, mirrorYResult);
667 
668     SkBitmap normalResultBM, mirrorXResultBM, mirrorYResultBM;
669 
670     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, normalResult.get(),
671                                                       &normalResultBM));
672     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, mirrorXResult.get(),
673                                                       &mirrorXResultBM));
674     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, mirrorYResult.get(),
675                                                       &mirrorYResultBM));
676 
677     for (int y = 0; y < kHeight; y++) {
678         int diffs = memcmp(normalResultBM.getAddr32(0, y),
679                            mirrorXResultBM.getAddr32(0, y),
680                            normalResultBM.rowBytes());
681         REPORTER_ASSERT(reporter, !diffs);
682         if (diffs) {
683             break;
684         }
685         diffs = memcmp(normalResultBM.getAddr32(0, y),
686                        mirrorYResultBM.getAddr32(0, y),
687                        normalResultBM.rowBytes());
688         REPORTER_ASSERT(reporter, !diffs);
689         if (diffs) {
690             break;
691         }
692     }
693 }
694 
DEF_TEST(MorphologyFilterRadiusWithMirrorCTM,reporter)695 DEF_TEST(MorphologyFilterRadiusWithMirrorCTM, reporter) {
696     test_morphology_radius_with_mirror_ctm(reporter, nullptr);
697 }
698 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)699 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu,
700                                        reporter,
701                                        ctxInfo,
702                                        CtsEnforcement::kNever) {
703     test_morphology_radius_with_mirror_ctm(reporter, ctxInfo.directContext());
704 }
705 
test_zero_blur_sigma(skiatest::Reporter * reporter,GrDirectContext * dContext)706 static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrDirectContext* dContext) {
707     // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
708     SkIRect cropRect = SkIRect::MakeXYWH(5, 0, 5, 10);
709     sk_sp<SkImageFilter> input(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
710     sk_sp<SkImageFilter> filter(SkImageFilters::Blur(0, 0, std::move(input), &cropRect));
711 
712     sk_sp<SkSpecialImage> image = create_empty_special_image(dContext, 10, SkColors::kGreen);
713 
714     SkIPoint offset;
715     skif::Context ctx = make_context(32, 32, image.get());
716 
717 
718     sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(ctx).imageAndOffset(ctx, &offset));
719     REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
720     REPORTER_ASSERT(reporter, result);
721     REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
722 
723     SkBitmap resultBM;
724 
725     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
726 
727     for (int y = 0; y < resultBM.height(); y++) {
728         for (int x = 0; x < resultBM.width(); x++) {
729             bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
730             REPORTER_ASSERT(reporter, !diff);
731             if (diff) {
732                 break;
733             }
734         }
735     }
736 }
737 
DEF_TEST(ImageFilterZeroBlurSigma,reporter)738 DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
739     test_zero_blur_sigma(reporter, nullptr);
740 }
741 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)742 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu,
743                                        reporter,
744                                        ctxInfo,
745                                        CtsEnforcement::kNever) {
746     test_zero_blur_sigma(reporter, ctxInfo.directContext());
747 }
748 
749 // Tests that, even when an upstream filter has returned null (due to failure or clipping), a
750 // downstream filter that affects transparent black still does so even with a nullptr input.
test_fail_affects_transparent_black(skiatest::Reporter * reporter,GrDirectContext * dContext)751 static void test_fail_affects_transparent_black(skiatest::Reporter* reporter,
752                                                 GrDirectContext* dContext) {
753     sk_sp<SkImageFilter> failFilter = SkImageFilters::Empty();
754     sk_sp<SkSpecialImage> source(create_empty_special_image(dContext, 5));
755     skif::Context ctx = make_context(1, 1, source.get());
756 
757     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
758     SkASSERT(as_CFB(green)->affectsTransparentBlack());
759     sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(std::move(green),
760                                                                  std::move(failFilter)));
761     SkIPoint offset;
762     sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(ctx)
763                                                      .imageAndOffset(ctx, &offset));
764     REPORTER_ASSERT(reporter, nullptr != result.get());
765     if (result) {
766         SkBitmap resultBM;
767         REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
768         REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
769     }
770 }
771 
DEF_TEST(ImageFilterFailAffectsTransparentBlack,reporter)772 DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
773     test_fail_affects_transparent_black(reporter, nullptr);
774 }
775 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)776 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu,
777                                        reporter,
778                                        ctxInfo,
779                                        CtsEnforcement::kNever) {
780     test_fail_affects_transparent_black(reporter, ctxInfo.directContext());
781 }
782 
DEF_TEST(ImageFilterDrawTiled,reporter)783 DEF_TEST(ImageFilterDrawTiled, reporter) {
784     // Check that all filters when drawn tiled (with subsequent clip rects) exactly
785     // match the same filters drawn with a single full-canvas bitmap draw.
786     // Tests pass by not asserting.
787 
788     FilterList filters(nullptr);
789 
790     SkBitmap untiledResult, tiledResult;
791     const int width = 64, height = 64;
792     untiledResult.allocN32Pixels(width, height);
793     tiledResult.allocN32Pixels(width, height);
794     SkCanvas tiledCanvas(tiledResult);
795     SkCanvas untiledCanvas(untiledResult);
796     const int tileSize = 8;
797 
798     SkPaint textPaint;
799     textPaint.setColor(SK_ColorWHITE);
800     SkFont font(ToolUtils::DefaultPortableTypeface(), height);
801 
802     const char* text = "ABC";
803     const SkScalar yPos = SkIntToScalar(height);
804 
805     for (int scale = 1; scale <= 2; ++scale) {
806         for (int i = 0; i < filters.count(); ++i) {
807             SkPaint combinedPaint;
808             combinedPaint.setColor(SK_ColorWHITE);
809             combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
810 
811             untiledCanvas.clear(SK_ColorTRANSPARENT);
812             untiledCanvas.save();
813             untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
814             untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
815             untiledCanvas.restore();
816 
817             tiledCanvas.clear(SK_ColorTRANSPARENT);
818             for (int y = 0; y < height; y += tileSize) {
819                 for (int x = 0; x < width; x += tileSize) {
820                     tiledCanvas.save();
821                     const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
822                     tiledCanvas.clipRect(clipRect);
823                     if (filters.needsSaveLayer(i)) {
824                         tiledCanvas.saveLayer(nullptr, &combinedPaint);
825                             tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
826                             tiledCanvas.drawString(text, 0, yPos, font, textPaint);
827                         tiledCanvas.restore();
828                     } else {
829                         tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
830                         tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
831                     }
832 
833                     tiledCanvas.restore();
834                 }
835             }
836 
837             if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
838                 SkString encoded;
839                 SkString errString("Tiled image filter doesn't match untiled reference");
840                 errString.append("\nExpected: ");
841                 if (ToolUtils::BitmapToBase64DataURI(untiledResult, &encoded)) {
842                     errString.append(encoded);
843                 } else {
844                     errString.append("failed to encode");
845                 }
846 
847                 errString.append("\nActual: ");
848                 if (ToolUtils::BitmapToBase64DataURI(tiledResult, &encoded)) {
849                     errString.append(encoded);
850                 } else {
851                     errString.append("failed to encode");
852                 }
853 
854                 ERRORF(reporter, "%s\n%s", filters.getName(i), errString.c_str());
855             }
856         }
857     }
858 }
859 
draw_saveLayer_picture(int width,int height,int tileSize,SkBBHFactory * factory,SkBitmap * result)860 static void draw_saveLayer_picture(int width, int height, int tileSize,
861                                    SkBBHFactory* factory, SkBitmap* result) {
862 
863     SkMatrix matrix;
864     matrix.setTranslate(SkIntToScalar(50), 0);
865 
866     sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
867     sk_sp<SkImageFilter> cfif(SkImageFilters::ColorFilter(std::move(cf), nullptr));
868     sk_sp<SkImageFilter> imageFilter(SkImageFilters::MatrixTransform(matrix,
869                                                                      SkSamplingOptions(),
870                                                                      std::move(cfif)));
871 
872     SkPaint paint;
873     paint.setImageFilter(std::move(imageFilter));
874     SkPictureRecorder recorder;
875     SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
876     SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
877                                                         SkIntToScalar(height),
878                                                         factory);
879     recordingCanvas->translate(-55, 0);
880     recordingCanvas->saveLayer(&bounds, &paint);
881     recordingCanvas->restore();
882     sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
883 
884     result->allocN32Pixels(width, height);
885     SkCanvas canvas(*result);
886     canvas.clear(0);
887     canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
888     canvas.drawPicture(picture1.get());
889 }
890 
DEF_TEST(ImageFilterDrawMatrixBBH,reporter)891 DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
892     // Check that matrix filter when drawn tiled with BBH exactly
893     // matches the same thing drawn without BBH.
894     // Tests pass by not asserting.
895 
896     const int width = 200, height = 200;
897     const int tileSize = 100;
898     SkBitmap result1, result2;
899     SkRTreeFactory factory;
900 
901     draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
902     draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
903 
904     for (int y = 0; y < height; y++) {
905         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
906         REPORTER_ASSERT(reporter, !diffs);
907         if (diffs) {
908             break;
909         }
910     }
911 }
912 
make_blur(sk_sp<SkImageFilter> input)913 static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
914     return SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, std::move(input));
915 }
916 
make_drop_shadow(sk_sp<SkImageFilter> input)917 static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
918     return SkImageFilters::DropShadow(100, 100, 10, 10, SK_ColorBLUE, std::move(input));
919 }
920 
DEF_TEST(ImageFilterBlurThenShadowBounds,reporter)921 DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
922     sk_sp<SkImageFilter> filter1(make_blur(nullptr));
923     sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
924 
925     static const SkIRect kContentBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
926 
927     // For output, the [0,0,100,100] source is expanded to [-3,-3,103,103] by the initial blur.
928     // The drop shadow is translated by [100,100] and further outset by 30px -> [67,67,233,233],
929     // The blend unions the inner blur result with the drop shadow to get [-3,-3,233,233].
930     static const SkIRect kExpectedOutputBounds = SkIRect::MakeLTRB(-3, -3, 233, 233);
931     SkIRect outputBounds = filter2->filterBounds(kContentBounds,
932                                                  SkMatrix::I(),
933                                                  SkImageFilter::kForward_MapDirection);
934     REPORTER_ASSERT(reporter, outputBounds == kExpectedOutputBounds);
935 
936     // For input, it should be able to restrict itself to the source content.
937     SkIRect inputBounds = filter2->filterBounds(kExpectedOutputBounds,
938                                                 SkMatrix::I(),
939                                                 SkImageFilter::kReverse_MapDirection,
940                                                 &kContentBounds);
941 
942     REPORTER_ASSERT(reporter, inputBounds == kContentBounds);
943 }
944 
DEF_TEST(ImageFilterShadowThenBlurBounds,reporter)945 DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
946     sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
947     sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
948 
949     static const SkIRect kContentBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
950     // For output, the [0,0,100,100] source is translated by 100px and outset by 30px for the drop
951     // shadow = [70,70,230,230], then blended back with its original to get [0,0,230,230]. This is
952     // then outset by 3px for the outer blur to get [-3,-3,233,233].
953     static const SkIRect kExpectedOutputBounds = SkIRect::MakeLTRB(-3, -3, 233, 233);
954     SkIRect outputBounds = filter2->filterBounds(kContentBounds,
955                                                  SkMatrix::I(),
956                                                  SkImageFilter::kForward_MapDirection);
957     REPORTER_ASSERT(reporter, outputBounds == kExpectedOutputBounds);
958 
959     // For input, it should be able to restrict itself to the source content.
960     SkIRect inputBounds = filter2->filterBounds(kExpectedOutputBounds,
961                                                 SkMatrix::I(),
962                                                 SkImageFilter::kReverse_MapDirection,
963                                                 &kContentBounds);
964     REPORTER_ASSERT(reporter, inputBounds == kContentBounds);
965 }
966 
DEF_TEST(ImageFilterDilateThenBlurBounds,reporter)967 DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
968     sk_sp<SkImageFilter> filter1(SkImageFilters::Dilate(2, 2, nullptr));
969     sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
970 
971     static const SkIRect kContentBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
972     // For output, the [0,0,100,100] source is outset by dilate radius (2px) to [-2,-2,102,102].
973     // This is then translated by 100px and outset by 30px for the drop shadow = [68,68,232,232].
974     // Finally this is joined with the original dilate result to get [-2,-2,232,232].
975     static const SkIRect kExpectedOutputBounds = SkIRect::MakeLTRB(-2, -2, 232, 232);
976     SkIRect outputBounds = filter2->filterBounds(kContentBounds,
977                                                  SkMatrix::I(),
978                                                  SkImageFilter::kForward_MapDirection);
979     REPORTER_ASSERT(reporter, outputBounds == kExpectedOutputBounds);
980 
981     // For input, it should be able to restrict itself to the source content.
982     SkIRect inputBounds = filter2->filterBounds(kExpectedOutputBounds,
983                                                 SkMatrix::I(),
984                                                 SkImageFilter::kReverse_MapDirection,
985                                                 &kContentBounds);
986     REPORTER_ASSERT(reporter, inputBounds == kContentBounds);
987 }
988 
DEF_TEST(ImageFilterScaledBlurRadius,reporter)989 DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
990     // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
991     // (before the CTM). Bounds should be computed correctly in the presence of
992     // a (possibly negative) scale.
993     sk_sp<SkImageFilter> blur(make_blur(nullptr));
994     sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
995     {
996         // Uniform scale by 2.
997         SkMatrix scaleMatrix;
998         scaleMatrix.setScale(2, 2);
999         static const SkIRect kBounds = SkIRect::MakeLTRB(0, 0, 200, 200);
1000 
1001         static const SkIRect kExpectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
1002         SkIRect blurBounds = blur->filterBounds(
1003                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1004         REPORTER_ASSERT(reporter, blurBounds == kExpectedBlurBounds);
1005         SkIRect reverseBlurBounds = blur->filterBounds(
1006                 kExpectedBlurBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1007         REPORTER_ASSERT(reporter, reverseBlurBounds == kBounds);
1008 
1009         static const SkIRect kExpectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
1010         SkIRect shadowBounds = dropShadow->filterBounds(
1011                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1012         REPORTER_ASSERT(reporter, shadowBounds == kExpectedShadowBounds);
1013 
1014         SkIRect reverseShadowBounds = dropShadow->filterBounds(
1015                 kExpectedShadowBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1016         REPORTER_ASSERT(reporter, reverseShadowBounds == kBounds);
1017     }
1018     {
1019         // Vertical flip.
1020         SkMatrix scaleMatrix;
1021         scaleMatrix.setScale(1, -1);
1022         static const SkIRect kBounds = SkIRect::MakeLTRB(0, -100, 100, 0);
1023 
1024         static const SkIRect kExpectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
1025         SkIRect blurBounds = blur->filterBounds(
1026                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1027         REPORTER_ASSERT(reporter, blurBounds == kExpectedBlurBounds);
1028         SkIRect reverseBlurBounds = blur->filterBounds(
1029                 kExpectedBlurBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1030         REPORTER_ASSERT(reporter, reverseBlurBounds == kBounds);
1031 
1032         SkIRect kExpectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
1033         SkIRect shadowBounds = dropShadow->filterBounds(
1034                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1035         REPORTER_ASSERT(reporter, shadowBounds == kExpectedShadowBounds);
1036         SkIRect reverseShadowBounds = dropShadow->filterBounds(
1037                 kExpectedShadowBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1038         REPORTER_ASSERT(reporter, reverseShadowBounds == kBounds);
1039     }
1040 }
1041 
DEF_TEST(ImageFilterComposedBlurFastBounds,reporter)1042 DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
1043     sk_sp<SkImageFilter> filter1(make_blur(nullptr));
1044     sk_sp<SkImageFilter> filter2(make_blur(nullptr));
1045     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(filter1),
1046                                                                 std::move(filter2)));
1047 
1048     static const SkRect kBoundsSrc = SkRect::MakeIWH(100, 100);
1049     static const SkRect kExpectedBounds = SkRect::MakeXYWH(-6, -6, 112, 112);
1050     SkRect boundsDst = composedFilter->computeFastBounds(kBoundsSrc);
1051 
1052     REPORTER_ASSERT(reporter, boundsDst == kExpectedBounds);
1053 }
1054 
DEF_TEST(ImageFilterUnionBounds,reporter)1055 DEF_TEST(ImageFilterUnionBounds, reporter) {
1056     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(50, 0, nullptr));
1057     // Regardless of which order they appear in, the image filter bounds should
1058     // be combined correctly.
1059     {
1060         sk_sp<SkImageFilter> composite(SkImageFilters::Blend(SkBlendMode::kSrcOver, offset));
1061         SkRect bounds = SkRect::MakeIWH(100, 100);
1062         // Intentionally aliasing here, as that's what the real callers do.
1063         bounds = composite->computeFastBounds(bounds);
1064         REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
1065     }
1066     {
1067         sk_sp<SkImageFilter> composite(SkImageFilters::Blend(SkBlendMode::kSrcOver, nullptr,
1068                                                              offset, nullptr));
1069         SkRect bounds = SkRect::MakeIWH(100, 100);
1070         // Intentionally aliasing here, as that's what the real callers do.
1071         bounds = composite->computeFastBounds(bounds);
1072         REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
1073     }
1074 }
1075 
test_imagefilter_merge_result_size(skiatest::Reporter * reporter,GrRecordingContext * rContext)1076 static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter,
1077                                                GrRecordingContext* rContext) {
1078     SkBitmap greenBM;
1079     greenBM.allocN32Pixels(20, 20);
1080     greenBM.eraseColor(SK_ColorGREEN);
1081     sk_sp<SkImage> greenImage(greenBM.asImage());
1082     sk_sp<SkImageFilter> source(SkImageFilters::Image(std::move(greenImage), {}));
1083     sk_sp<SkImageFilter> merge(SkImageFilters::Merge(source, source));
1084 
1085     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 1));
1086 
1087     skif::Context ctx = make_context(100, 100, srcImg.get());
1088     SkIPoint offset;
1089 
1090     sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(ctx).imageAndOffset(ctx, &offset));
1091     REPORTER_ASSERT(reporter, resultImg);
1092 
1093     REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
1094 }
1095 
DEF_TEST(ImageFilterMergeResultSize,reporter)1096 DEF_TEST(ImageFilterMergeResultSize, reporter) {
1097     test_imagefilter_merge_result_size(reporter, nullptr);
1098 }
1099 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1100 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu,
1101                                        reporter,
1102                                        ctxInfo,
1103                                        CtsEnforcement::kNever) {
1104     test_imagefilter_merge_result_size(reporter, ctxInfo.directContext());
1105 }
1106 
draw_blurred_rect(SkCanvas * canvas)1107 static void draw_blurred_rect(SkCanvas* canvas) {
1108     SkPaint filterPaint;
1109     filterPaint.setColor(SK_ColorWHITE);
1110     filterPaint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(8), 0, nullptr));
1111     canvas->saveLayer(nullptr, &filterPaint);
1112     SkPaint whitePaint;
1113     whitePaint.setColor(SK_ColorWHITE);
1114     canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1115     canvas->restore();
1116 }
1117 
draw_picture_clipped(SkCanvas * canvas,const SkRect & clipRect,const SkPicture * picture)1118 static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
1119     canvas->save();
1120     canvas->clipRect(clipRect);
1121     canvas->drawPicture(picture);
1122     canvas->restore();
1123 }
1124 
DEF_TEST(ImageFilterDrawTiledBlurRTree,reporter)1125 DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1126     // Check that the blur filter when recorded with RTree acceleration,
1127     // and drawn tiled (with subsequent clip rects) exactly
1128     // matches the same filter drawn with without RTree acceleration.
1129     // This tests that the "bleed" from the blur into the otherwise-blank
1130     // tiles is correctly rendered.
1131     // Tests pass by not asserting.
1132 
1133     int width = 16, height = 8;
1134     SkBitmap result1, result2;
1135     result1.allocN32Pixels(width, height);
1136     result2.allocN32Pixels(width, height);
1137     SkCanvas canvas1(result1);
1138     SkCanvas canvas2(result2);
1139     int tileSize = 8;
1140 
1141     canvas1.clear(0);
1142     canvas2.clear(0);
1143 
1144     SkRTreeFactory factory;
1145 
1146     SkPictureRecorder recorder1, recorder2;
1147     // The only difference between these two pictures is that one has RTree aceleration.
1148     SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height);
1149     SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory);
1150 
1151     draw_blurred_rect(recordingCanvas1);
1152     draw_blurred_rect(recordingCanvas2);
1153     sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1154     sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
1155     for (int y = 0; y < height; y += tileSize) {
1156         for (int x = 0; x < width; x += tileSize) {
1157             SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
1158             draw_picture_clipped(&canvas1, tileRect, picture1.get());
1159             draw_picture_clipped(&canvas2, tileRect, picture2.get());
1160         }
1161     }
1162     for (int y = 0; y < height; y++) {
1163         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1164         REPORTER_ASSERT(reporter, !diffs);
1165         if (diffs) {
1166             break;
1167         }
1168     }
1169 }
1170 
DEF_TEST(ImageFilterMatrixConvolution,reporter)1171 DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1172     // Check that a 1x3 filter does not cause a spurious assert.
1173     SkScalar kernel[3] = {
1174         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1175     };
1176     SkISize kernelSize = SkISize::Make(1, 3);
1177     SkScalar gain = SK_Scalar1, bias = 0;
1178     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1179 
1180     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1181             kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kRepeat, false, nullptr));
1182 
1183     SkBitmap result;
1184     int width = 16, height = 16;
1185     result.allocN32Pixels(width, height);
1186     SkCanvas canvas(result);
1187     canvas.clear(0);
1188 
1189     SkPaint paint;
1190     paint.setImageFilter(std::move(filter));
1191     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1192     canvas.drawRect(rect, paint);
1193 }
1194 
DEF_TEST(ImageFilterMatrixConvolutionBorder,reporter)1195 DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1196     // Check that a filter with borders outside the target bounds
1197     // does not crash.
1198     SkScalar kernel[3] = {
1199         0, 0, 0,
1200     };
1201     SkISize kernelSize = SkISize::Make(3, 1);
1202     SkScalar gain = SK_Scalar1, bias = 0;
1203     SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1204 
1205     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1206             kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kClamp, true, nullptr));
1207 
1208     SkBitmap result;
1209 
1210     int width = 10, height = 10;
1211     result.allocN32Pixels(width, height);
1212     SkCanvas canvas(result);
1213     canvas.clear(0);
1214 
1215     SkPaint filterPaint;
1216     filterPaint.setImageFilter(std::move(filter));
1217     SkRect bounds = SkRect::MakeIWH(1, 10);
1218     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1219     SkPaint rectPaint;
1220     canvas.saveLayer(&bounds, &filterPaint);
1221     canvas.drawRect(rect, rectPaint);
1222     canvas.restore();
1223 }
1224 
test_big_kernel(skiatest::Reporter * reporter,GrRecordingContext * rContext)1225 static void test_big_kernel(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
1226     // Check that a kernel that is too big for the GPU still works
1227     SkScalar identityKernel[49] = {
1228         0, 0, 0, 0, 0, 0, 0,
1229         0, 0, 0, 0, 0, 0, 0,
1230         0, 0, 0, 0, 0, 0, 0,
1231         0, 0, 0, 1, 0, 0, 0,
1232         0, 0, 0, 0, 0, 0, 0,
1233         0, 0, 0, 0, 0, 0, 0,
1234         0, 0, 0, 0, 0, 0, 0
1235     };
1236     SkISize kernelSize = SkISize::Make(7, 7);
1237     SkScalar gain = SK_Scalar1, bias = 0;
1238     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1239 
1240     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1241             kernelSize, identityKernel, gain, bias, kernelOffset,
1242             SkTileMode::kClamp, true, nullptr));
1243 
1244     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
1245     SkASSERT(srcImg);
1246 
1247     SkIPoint offset;
1248     skif::Context ctx = make_context(100, 100, srcImg.get());
1249     sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1250     REPORTER_ASSERT(reporter, resultImg);
1251     REPORTER_ASSERT(reporter, SkToBool(rContext) == resultImg->isGaneshBacked());
1252     REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1253     REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1254 }
1255 
DEF_TEST(ImageFilterMatrixConvolutionBigKernel,reporter)1256 DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
1257     test_big_kernel(reporter, nullptr);
1258 }
1259 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1260 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1261                                        reporter,
1262                                        ctxInfo,
1263                                        CtsEnforcement::kNever) {
1264     test_big_kernel(reporter, ctxInfo.directContext());
1265 }
1266 
DEF_TEST(ImageFilterCropRect,reporter)1267 DEF_TEST(ImageFilterCropRect, reporter) {
1268     test_cropRects(reporter, nullptr);
1269 }
1270 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1271 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu,
1272                                        reporter,
1273                                        ctxInfo,
1274                                        CtsEnforcement::kNever) {
1275     test_cropRects(reporter, ctxInfo.directContext());
1276 }
1277 
DEF_TEST(ImageFilterMatrix,reporter)1278 DEF_TEST(ImageFilterMatrix, reporter) {
1279     SkBitmap temp;
1280     temp.allocN32Pixels(100, 100);
1281     SkCanvas canvas(temp);
1282     canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1283 
1284     SkMatrix expectedMatrix = canvas.getTotalMatrix();
1285 
1286     SkRTreeFactory factory;
1287     SkPictureRecorder recorder;
1288     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory);
1289 
1290     SkPaint paint;
1291     paint.setImageFilter(sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix)));
1292     recordingCanvas->saveLayer(nullptr, &paint);
1293     SkPaint solidPaint;
1294     solidPaint.setColor(0xFFFFFFFF);
1295     recordingCanvas->save();
1296     recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1297     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1298     recordingCanvas->restore(); // scale
1299     recordingCanvas->restore(); // saveLayer
1300 
1301     canvas.drawPicture(recorder.finishRecordingAsPicture());
1302 }
1303 
test_clipped_picture_imagefilter(skiatest::Reporter * reporter,GrRecordingContext * rContext)1304 static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter,
1305                                              GrRecordingContext* rContext) {
1306     sk_sp<SkPicture> picture;
1307 
1308     {
1309         SkRTreeFactory factory;
1310         SkPictureRecorder recorder;
1311         SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory);
1312 
1313         // Create an SkPicture which simply draws a green 1x1 rectangle.
1314         SkPaint greenPaint;
1315         greenPaint.setColor(SK_ColorGREEN);
1316         recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
1317         picture = recorder.finishRecordingAsPicture();
1318     }
1319 
1320     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 2));
1321 
1322     sk_sp<SkImageFilter> imageFilter(SkImageFilters::Picture(picture));
1323 
1324     SkIPoint offset;
1325     skif::Context ctx = make_context(SkIRect::MakeXYWH(1,1,1,1), srcImg.get());
1326 
1327     sk_sp<SkSpecialImage> resultImage(
1328             as_IFB(imageFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1329     REPORTER_ASSERT(reporter, !resultImage);
1330 }
1331 
DEF_TEST(ImageFilterClippedPictureImageFilter,reporter)1332 DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
1333     test_clipped_picture_imagefilter(reporter, nullptr);
1334 }
1335 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1336 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu,
1337                                        reporter,
1338                                        ctxInfo,
1339                                        CtsEnforcement::kNever) {
1340     test_clipped_picture_imagefilter(reporter, ctxInfo.directContext());
1341 }
1342 
DEF_TEST(ImageFilterEmptySaveLayer,reporter)1343 DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
1344     // Even when there's an empty saveLayer()/restore(), ensure that an image
1345     // filter or color filter which affects transparent black still draws.
1346 
1347     SkBitmap bitmap;
1348     bitmap.allocN32Pixels(10, 10);
1349     SkCanvas canvas(bitmap);
1350 
1351     SkRTreeFactory factory;
1352     SkPictureRecorder recorder;
1353 
1354     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
1355     sk_sp<SkImageFilter> imageFilter(SkImageFilters::ColorFilter(green, nullptr));
1356     SkPaint imageFilterPaint;
1357     imageFilterPaint.setImageFilter(std::move(imageFilter));
1358     SkPaint colorFilterPaint;
1359     colorFilterPaint.setColorFilter(green);
1360 
1361     SkRect bounds = SkRect::MakeIWH(10, 10);
1362 
1363     SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory);
1364     recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1365     recordingCanvas->restore();
1366     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1367 
1368     canvas.clear(0);
1369     canvas.drawPicture(picture);
1370     uint32_t pixel = *bitmap.getAddr32(0, 0);
1371     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1372 
1373     recordingCanvas = recorder.beginRecording(10, 10, &factory);
1374     recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
1375     recordingCanvas->restore();
1376     sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
1377 
1378     canvas.clear(0);
1379     canvas.drawPicture(picture2);
1380     pixel = *bitmap.getAddr32(0, 0);
1381     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1382 
1383     recordingCanvas = recorder.beginRecording(10, 10, &factory);
1384     recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1385     recordingCanvas->restore();
1386     sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
1387 
1388     canvas.clear(0);
1389     canvas.drawPicture(picture3);
1390     pixel = *bitmap.getAddr32(0, 0);
1391     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1392 }
1393 
test_huge_blur(SkCanvas * canvas,skiatest::Reporter * reporter)1394 static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
1395     SkBitmap bitmap;
1396     bitmap.allocN32Pixels(100, 100);
1397     bitmap.eraseARGB(0, 0, 0, 0);
1398 
1399     // Check that a blur with a very large radius does not crash or assert.
1400     SkPaint paint;
1401     paint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(1<<30), SkIntToScalar(1<<30), nullptr));
1402     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
1403 }
1404 
DEF_TEST(HugeBlurImageFilter,reporter)1405 DEF_TEST(HugeBlurImageFilter, reporter) {
1406     SkBitmap temp;
1407     temp.allocN32Pixels(100, 100);
1408     SkCanvas canvas(temp);
1409     test_huge_blur(&canvas, reporter);
1410 }
1411 
DEF_TEST(ImageFilterMatrixConvolutionTest,reporter)1412 DEF_TEST(ImageFilterMatrixConvolutionTest, reporter) {
1413     SkScalar kernel[1] = { 0 };
1414     SkScalar gain = SK_Scalar1, bias = 0;
1415     SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1416 
1417     // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
1418     sk_sp<SkImageFilter> conv(SkImageFilters::MatrixConvolution(
1419             SkISize::Make(1<<30, 1<<30), kernel, gain, bias, kernelOffset,
1420             SkTileMode::kRepeat, false, nullptr));
1421 
1422     REPORTER_ASSERT(reporter, nullptr == conv.get());
1423 
1424     // Check that a nullptr kernel gives a nullptr filter.
1425     conv = SkImageFilters::MatrixConvolution(
1426             SkISize::Make(1, 1), nullptr, gain, bias, kernelOffset,
1427             SkTileMode::kRepeat, false, nullptr);
1428 
1429     REPORTER_ASSERT(reporter, nullptr == conv.get());
1430 
1431     // Check that a kernel width < 1 gives a nullptr filter.
1432     conv = SkImageFilters::MatrixConvolution(
1433             SkISize::Make(0, 1), kernel, gain, bias, kernelOffset,
1434             SkTileMode::kRepeat, false, nullptr);
1435 
1436     REPORTER_ASSERT(reporter, nullptr == conv.get());
1437 
1438     // Check that kernel height < 1 gives a nullptr filter.
1439     conv = SkImageFilters::MatrixConvolution(
1440             SkISize::Make(1, -1), kernel, gain, bias, kernelOffset,
1441             SkTileMode::kRepeat, false, nullptr);
1442 
1443     REPORTER_ASSERT(reporter, nullptr == conv.get());
1444 }
1445 
test_xfermode_cropped_input(SkSurface * surf,skiatest::Reporter * reporter)1446 static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1447     auto canvas = surf->getCanvas();
1448     canvas->clear(SK_ColorRED);
1449 
1450     SkBitmap bitmap;
1451     bitmap.allocN32Pixels(1, 1);
1452     bitmap.eraseARGB(255, 255, 255, 255);
1453 
1454     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
1455     sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(green, nullptr));
1456     SkIRect cropRect = SkIRect::MakeEmpty();
1457     sk_sp<SkImageFilter> croppedOut(SkImageFilters::ColorFilter(green, nullptr, &cropRect));
1458 
1459     // Check that an blend image filter whose input has been cropped out still draws the other
1460     // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1461     SkBlendMode mode = SkBlendMode::kSrcOver;
1462     sk_sp<SkImageFilter> xfermodeNoFg(SkImageFilters::Blend(
1463             mode, greenFilter, croppedOut, nullptr));
1464     sk_sp<SkImageFilter> xfermodeNoBg(SkImageFilters::Blend(
1465             mode, croppedOut, greenFilter, nullptr));
1466     sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkImageFilters::Blend(
1467             mode, croppedOut,  croppedOut, nullptr));
1468 
1469     SkPaint paint;
1470     paint.setImageFilter(std::move(xfermodeNoFg));
1471     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);   // drawSprite
1472 
1473     // xfermodeNoFg is a src-over blend between a green image and a transparent black image,
1474     // so should just be green.
1475     uint32_t pixel;
1476     SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1477     surf->readPixels(info, &pixel, 4, 0, 0);
1478     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1479 
1480     // xfermodeNoBg is the reverse of the above, but because it's src-over the final blend
1481     // between transparent black and green is still green.
1482     canvas->clear(SK_ColorRED); // should be overwritten
1483     paint.setImageFilter(std::move(xfermodeNoBg));
1484     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);   // drawSprite
1485     surf->readPixels(info, &pixel, 4, 0, 0);
1486     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1487 
1488     // xfermodeNoFgNoBg is a src-over blend of two empty images, so should produce no change
1489     // to the image.
1490     canvas->clear(SK_ColorRED); // should not be overwritten
1491     paint.setImageFilter(std::move(xfermodeNoFgNoBg));
1492     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);   // drawSprite
1493     surf->readPixels(info, &pixel, 4, 0, 0);
1494     REPORTER_ASSERT(reporter, pixel == SK_ColorRED);
1495 }
1496 
DEF_TEST(ImageFilterNestedSaveLayer,reporter)1497 DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1498     SkBitmap temp;
1499     temp.allocN32Pixels(50, 50);
1500     SkCanvas canvas(temp);
1501     canvas.clear(0x0);
1502 
1503     SkBitmap bitmap;
1504     bitmap.allocN32Pixels(10, 10);
1505     bitmap.eraseColor(SK_ColorGREEN);
1506 
1507     SkMatrix matrix;
1508     matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1509     matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1510     sk_sp<SkImageFilter> matrixFilter(
1511         SkImageFilters::MatrixTransform(matrix, SkSamplingOptions(SkFilterMode::kLinear), nullptr));
1512 
1513     // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1514     // correct offset to the filter matrix.
1515     SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1516     canvas.saveLayer(&bounds1, nullptr);
1517     SkPaint filterPaint;
1518     filterPaint.setImageFilter(std::move(matrixFilter));
1519     SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1520     canvas.saveLayer(&bounds2, &filterPaint);
1521     SkPaint greenPaint;
1522     greenPaint.setColor(SK_ColorGREEN);
1523     canvas.drawRect(bounds2, greenPaint);
1524     canvas.restore();
1525     canvas.restore();
1526     SkPaint strokePaint;
1527     strokePaint.setStyle(SkPaint::kStroke_Style);
1528     strokePaint.setColor(SK_ColorRED);
1529 
1530     SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1531     uint32_t pixel;
1532     temp.readPixels(info, &pixel, 4, 25, 25);
1533     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1534 
1535     // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1536     // correct offset to the filter matrix.
1537     canvas.clear(0x0);
1538     temp.readPixels(info, &pixel, 4, 25, 25);
1539     canvas.saveLayer(&bounds1, nullptr);
1540     canvas.drawImage(bitmap.asImage(), 20, 20, SkSamplingOptions(), &filterPaint); // drawSprite
1541     canvas.restore();
1542 
1543     temp.readPixels(info, &pixel, 4, 25, 25);
1544     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1545 }
1546 
DEF_TEST(XfermodeImageFilterCroppedInput,reporter)1547 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1548     test_xfermode_cropped_input(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)).get(),
1549                                 reporter);
1550 }
1551 
test_composed_imagefilter_offset(skiatest::Reporter * reporter,GrRecordingContext * rContext)1552 static void test_composed_imagefilter_offset(skiatest::Reporter* reporter,
1553                                              GrRecordingContext* rContext) {
1554     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
1555 
1556     SkIRect cropRect = SkIRect::MakeXYWH(1, 0, 20, 20);
1557     sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
1558     sk_sp<SkImageFilter> blurFilter(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1559                                                             nullptr, &cropRect));
1560     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(blurFilter),
1561                                                                 std::move(offsetFilter)));
1562     SkIPoint offset;
1563     skif::Context ctx = make_context(100, 100, srcImg.get());
1564 
1565     sk_sp<SkSpecialImage> resultImg(
1566             as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1567     REPORTER_ASSERT(reporter, resultImg);
1568     REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1569 }
1570 
DEF_TEST(ComposedImageFilterOffset,reporter)1571 DEF_TEST(ComposedImageFilterOffset, reporter) {
1572     test_composed_imagefilter_offset(reporter, nullptr);
1573 }
1574 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1575 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu,
1576                                        reporter,
1577                                        ctxInfo,
1578                                        CtsEnforcement::kNever) {
1579     test_composed_imagefilter_offset(reporter, ctxInfo.directContext());
1580 }
1581 
test_composed_imagefilter_bounds(skiatest::Reporter * reporter,GrDirectContext * dContext)1582 static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter,
1583                                              GrDirectContext* dContext) {
1584     // The bounds passed to the inner filter must be filtered by the outer
1585     // filter, so that the inner filter produces the pixels that the outer
1586     // filter requires as input. This matters if the outer filter moves pixels.
1587     // Here, accounting for the outer offset is necessary so that the green
1588     // pixels of the picture are not clipped.
1589 
1590     SkPictureRecorder recorder;
1591     SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeIWH(200, 100));
1592     recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1593     recordingCanvas->clear(SK_ColorGREEN);
1594     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1595     sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(picture));
1596     SkIRect cropRect = SkIRect::MakeWH(100, 100);
1597     sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(-100, 0, nullptr, &cropRect));
1598     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(offsetFilter),
1599                                                                 std::move(pictureFilter)));
1600 
1601     sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(dContext, 100));
1602     skif::Context ctx = make_context(100, 100, sourceImage.get());
1603 
1604     SkIPoint offset;
1605     sk_sp<SkSpecialImage> result(
1606             as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1607     REPORTER_ASSERT(reporter, offset.isZero());
1608     REPORTER_ASSERT(reporter, result);
1609     REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1610 
1611     SkBitmap resultBM;
1612     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
1613     REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1614 }
1615 
DEF_TEST(ComposedImageFilterBounds,reporter)1616 DEF_TEST(ComposedImageFilterBounds, reporter) {
1617     test_composed_imagefilter_bounds(reporter, nullptr);
1618 }
1619 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1620 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu,
1621                                        reporter,
1622                                        ctxInfo,
1623                                        CtsEnforcement::kNever) {
1624     test_composed_imagefilter_bounds(reporter, ctxInfo.directContext());
1625 }
1626 
DEF_TEST(ImageFilterCanComputeFastBounds,reporter)1627 DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1628 
1629     {
1630         SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1631         sk_sp<SkImageFilter> lighting(SkImageFilters::PointLitDiffuse(
1632                 location,  SK_ColorGREEN, 0, 0, nullptr));
1633         REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1634     }
1635 
1636     {
1637         sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1638         REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1639         {
1640             SkColorFilter* grayCF;
1641             REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1642             REPORTER_ASSERT(reporter, !as_CFB(grayCF)->affectsTransparentBlack());
1643             grayCF->unref();
1644         }
1645         REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1646 
1647         sk_sp<SkImageFilter> grayBlur(SkImageFilters::Blur(
1648                 SK_Scalar1, SK_Scalar1, std::move(gray)));
1649         REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1650     }
1651 
1652     {
1653         float greenMatrix[20] = { 0, 0, 0, 0, 0,
1654                                   0, 0, 0, 0, 1.0f/255,
1655                                   0, 0, 0, 0, 0,
1656                                   0, 0, 0, 0, 1.0f/255
1657         };
1658         sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
1659         sk_sp<SkImageFilter> green(SkImageFilters::ColorFilter(greenCF, nullptr));
1660 
1661         REPORTER_ASSERT(reporter, as_CFB(greenCF)->affectsTransparentBlack());
1662         REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1663 
1664         sk_sp<SkImageFilter> greenBlur(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1665                                                                std::move(green)));
1666         REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1667     }
1668 
1669     uint8_t allOne[256], identity[256];
1670     for (int i = 0; i < 256; ++i) {
1671         identity[i] = i;
1672         allOne[i] = 255;
1673     }
1674 
1675     sk_sp<SkColorFilter> identityCF(SkColorFilters::TableARGB(identity, identity,
1676                                                               identity, allOne));
1677     sk_sp<SkImageFilter> identityFilter(SkImageFilters::ColorFilter(identityCF, nullptr));
1678     REPORTER_ASSERT(reporter, !as_CFB(identityCF)->affectsTransparentBlack());
1679     REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1680 
1681     sk_sp<SkColorFilter> forceOpaqueCF(SkColorFilters::TableARGB(allOne, identity,
1682                                                                  identity, identity));
1683     sk_sp<SkImageFilter> forceOpaque(SkImageFilters::ColorFilter(forceOpaqueCF, nullptr));
1684     REPORTER_ASSERT(reporter, as_CFB(forceOpaqueCF)->affectsTransparentBlack());
1685     REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1686 }
1687 
1688 // Verify that SkImageSource survives serialization
DEF_TEST(ImageFilterImageSourceSerialization,reporter)1689 DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
1690     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10)));
1691     surface->getCanvas()->clear(SK_ColorGREEN);
1692     sk_sp<SkImage> image(surface->makeImageSnapshot());
1693     sk_sp<SkImageFilter> filter(SkImageFilters::Image(std::move(image), SkFilterMode::kNearest));
1694 
1695     SkSerialProcs sProcs;
1696     sProcs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
1697         return SkPngEncoder::Encode(as_IB(img)->directContext(), img, SkPngEncoder::Options{});
1698     };
1699     sk_sp<SkData> data(filter->serialize(&sProcs));
1700     sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1701     REPORTER_ASSERT(reporter, unflattenedFilter);
1702 
1703     SkBitmap bm;
1704     bm.allocN32Pixels(10, 10);
1705     bm.eraseColor(SK_ColorBLUE);
1706     SkPaint paint;
1707     paint.setColor(SK_ColorRED);
1708     paint.setImageFilter(unflattenedFilter);
1709 
1710     SkCanvas canvas(bm);
1711     canvas.drawRect(SkRect::MakeIWH(10, 10), paint);
1712     REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1713 }
1714 
DEF_TEST(ImageFilterImageSourceUninitialized,r)1715 DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1716     sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1717     if (!data) {
1718         return;
1719     }
1720     sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1721     // This will fail. More importantly, msan will verify that we did not
1722     // compare against uninitialized memory.
1723     REPORTER_ASSERT(r, !unflattenedFilter);
1724 }
1725 
test_large_blur_input(skiatest::Reporter * reporter,SkCanvas * canvas)1726 static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1727     SkBitmap largeBmp;
1728     int largeW = 5000;
1729     int largeH = 5000;
1730     // If we're GPU-backed make the bitmap too large to be converted into a texture.
1731     if (auto ctx = canvas->recordingContext()) {
1732         largeW = ctx->priv().caps()->maxTextureSize() + 1;
1733     }
1734 
1735     largeBmp.allocN32Pixels(largeW, largeH);
1736     largeBmp.eraseColor(0);
1737     if (!largeBmp.getPixels()) {
1738         ERRORF(reporter, "Failed to allocate large bmp.");
1739         return;
1740     }
1741 
1742     sk_sp<SkImage> largeImage(largeBmp.asImage());
1743     if (!largeImage) {
1744         ERRORF(reporter, "Failed to create large image.");
1745         return;
1746     }
1747 
1748     sk_sp<SkImageFilter> largeSource(SkImageFilters::Image(std::move(largeImage), {}));
1749     if (!largeSource) {
1750         ERRORF(reporter, "Failed to create large SkImageSource.");
1751         return;
1752     }
1753 
1754     sk_sp<SkImageFilter> blur(SkImageFilters::Blur(10.f, 10.f, std::move(largeSource)));
1755     if (!blur) {
1756         ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1757         return;
1758     }
1759 
1760     SkPaint paint;
1761     paint.setImageFilter(std::move(blur));
1762 
1763     // This should not crash (http://crbug.com/570479).
1764     canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1765 }
1766 
DEF_TEST(ImageFilterBlurLargeImage,reporter)1767 DEF_TEST(ImageFilterBlurLargeImage, reporter) {
1768     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
1769     test_large_blur_input(reporter, surface->getCanvas());
1770 }
1771 
test_make_with_filter(skiatest::Reporter * reporter,const std::function<sk_sp<SkSurface> (int width,int height)> & createSurface,const std::function<sk_sp<SkImage> (sk_sp<SkImage> src,const SkImageFilter * filter,const SkIRect & subset,const SkIRect & clipBounds,SkIRect * outSubset,SkIPoint * offset)> & makeWithFilter)1772 static void test_make_with_filter(
1773         skiatest::Reporter* reporter,
1774         const std::function<sk_sp<SkSurface>(int width, int height)>& createSurface,
1775         const std::function<sk_sp<SkImage>(sk_sp<SkImage> src,
1776                                            const SkImageFilter* filter,
1777                                            const SkIRect& subset,
1778                                            const SkIRect& clipBounds,
1779                                            SkIRect* outSubset,
1780                                            SkIPoint* offset)>& makeWithFilter) {
1781     sk_sp<SkSurface> surface(createSurface(192, 128));
1782     surface->getCanvas()->clear(SK_ColorRED);
1783     SkPaint bluePaint;
1784     bluePaint.setColor(SK_ColorBLUE);
1785     SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1786     surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1787     sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1788 
1789     sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1790     SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1791     SkIRect outSubset;
1792     SkIPoint offset;
1793     sk_sp<SkImage> result;
1794 
1795     result = makeWithFilter(sourceImage, nullptr, subset, clipBounds, &outSubset, &offset);
1796     REPORTER_ASSERT(reporter, !result);  // filter is required
1797 
1798     result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, nullptr, &offset);
1799     REPORTER_ASSERT(reporter, !result);  // outSubset is required
1800 
1801     result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, &outSubset, nullptr);
1802     REPORTER_ASSERT(reporter, !result);  // offset is required
1803 
1804     SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1805     result = makeWithFilter(sourceImage, filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1806     REPORTER_ASSERT(reporter, !result);  // subset needs to be w/in source's bounds
1807 
1808     const SkIRect kEmpty = SkIRect::MakeEmpty();
1809     result = makeWithFilter(sourceImage, filter.get(), kEmpty, clipBounds, &outSubset, &offset);
1810     REPORTER_ASSERT(reporter, !result);  // subset can't be empty
1811 
1812     result = makeWithFilter(sourceImage, filter.get(), subset, kEmpty, &outSubset, &offset);
1813     REPORTER_ASSERT(reporter, !result);  // clipBounds can't be empty
1814 
1815     const SkIRect kLeftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1816     result = makeWithFilter(sourceImage, filter.get(), subset, kLeftField, &outSubset, &offset);
1817     REPORTER_ASSERT(reporter, !result);
1818 
1819     result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, &outSubset, &offset);
1820 
1821     REPORTER_ASSERT(reporter, result);
1822     REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1823     SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1824                                          outSubset.width(), outSubset.height());
1825     REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1826 
1827     // In GPU-mode, this case creates a special image with a backing size that differs from
1828     // the content size
1829     {
1830         clipBounds.setXYWH(0, 0, 170, 100);
1831         subset.setXYWH(0, 0, 160, 90);
1832 
1833         filter = SkImageFilters::Blend(SkBlendMode::kSrcOver, nullptr);
1834         result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, &outSubset, &offset);
1835         REPORTER_ASSERT(reporter, result);
1836 
1837         // In Ganesh, we want the result image (and all intermediate steps) to have used the same
1838         // origin as the original surface.
1839         if (result && as_IB(result)->isGaneshBacked()) {
1840             SkImage_GaneshBase* base = static_cast<SkImage_GaneshBase*>(result.get());
1841             REPORTER_ASSERT(reporter, base->origin() == kTestSurfaceOrigin);
1842         }
1843     }
1844 }
1845 
DEF_TEST(ImageFilterMakeWithFilter,reporter)1846 DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1847     auto createRasterSurface = [](int width, int height) -> sk_sp<SkSurface> {
1848         const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
1849         return SkSurfaces::Raster(info);
1850     };
1851 
1852     auto raster = [](sk_sp<SkImage> src,
1853                      const SkImageFilter* filter,
1854                      const SkIRect& subset,
1855                      const SkIRect& clipBounds,
1856                      SkIRect* outSubset,
1857                      SkIPoint* offset) -> sk_sp<SkImage> {
1858                          return SkImages::MakeWithFilter(std::move(src),
1859                                                          filter,
1860                                                          subset,
1861                                                          clipBounds,
1862                                                          outSubset,
1863                                                          offset);
1864                      };
1865 
1866     test_make_with_filter(reporter, createRasterSurface, raster);
1867 }
1868 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Ganesh,reporter,ctxInfo,CtsEnforcement::kNever)1869 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Ganesh,
1870                                        reporter,
1871                                        ctxInfo,
1872                                        CtsEnforcement::kNever) {
1873     GrRecordingContext* rContext = ctxInfo.directContext();
1874 
1875     auto createGaneshSurface = [rContext](int width, int height) -> sk_sp<SkSurface> {
1876         const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
1877         return SkSurfaces::RenderTarget(
1878                 rContext, skgpu::Budgeted::kNo, info, 0, kTestSurfaceOrigin, nullptr);
1879     };
1880 
1881     auto ganesh = [rContext](sk_sp<SkImage> src,
1882                              const SkImageFilter* filter,
1883                              const SkIRect& subset,
1884                              const SkIRect& clipBounds,
1885                              SkIRect* outSubset,
1886                              SkIPoint* offset) -> sk_sp<SkImage> {
1887          return SkImages::MakeWithFilter(rContext,
1888                                          std::move(src),
1889                                          filter,
1890                                          subset,
1891                                          clipBounds,
1892                                          outSubset,
1893                                          offset);
1894     };
1895 
1896     test_make_with_filter(reporter, createGaneshSurface, ganesh);
1897 }
1898 
1899 #if defined(SK_GRAPHITE)
1900 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Graphite,reporter,context,CtsEnforcement::kApiLevel_V)1901 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Graphite,
1902                                          reporter,
1903                                          context,
1904                                          CtsEnforcement::kApiLevel_V) {
1905     std::unique_ptr<skgpu::graphite::Recorder> recorder =
1906             context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
1907 
1908     auto createGraphiteSurface = [r = recorder.get()](int width, int height) -> sk_sp<SkSurface> {
1909         const SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
1910         return SkSurfaces::RenderTarget(r, info);
1911     };
1912 
1913     auto graphite = [r = recorder.get()](sk_sp<SkImage> src,
1914                                          const SkImageFilter* filter,
1915                                          const SkIRect& subset,
1916                                          const SkIRect& clipBounds,
1917                                          SkIRect* outSubset,
1918                                          SkIPoint* offset) -> sk_sp<SkImage> {
1919         return SkImages::MakeWithFilter(r,
1920                                         std::move(src),
1921                                         filter,
1922                                         subset,
1923                                         clipBounds,
1924                                         outSubset,
1925                                         offset);
1926     };
1927 
1928     test_make_with_filter(reporter, createGraphiteSurface, graphite);
1929 }
1930 
1931 #endif
1932 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1933 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu,
1934                                        reporter,
1935                                        ctxInfo,
1936                                        CtsEnforcement::kNever) {
1937     sk_sp<SkSurface> surf(SkSurfaces::RenderTarget(
1938             ctxInfo.directContext(), skgpu::Budgeted::kNo, SkImageInfo::MakeN32Premul(100, 100)));
1939 
1940     SkCanvas* canvas = surf->getCanvas();
1941 
1942     test_huge_blur(canvas, reporter);
1943 }
1944 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1945 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu,
1946                                        reporter,
1947                                        ctxInfo,
1948                                        CtsEnforcement::kNever) {
1949     sk_sp<SkSurface> surf(SkSurfaces::RenderTarget(
1950             ctxInfo.directContext(),
1951             skgpu::Budgeted::kNo,
1952             SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1953 
1954     test_xfermode_cropped_input(surf.get(), reporter);
1955 }
1956 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1957 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu,
1958                                  reporter,
1959                                  ctxInfo,
1960                                  CtsEnforcement::kNever) {
1961     auto surface(SkSurfaces::RenderTarget(
1962             ctxInfo.directContext(),
1963             skgpu::Budgeted::kYes,
1964             SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1965     test_large_blur_input(reporter, surface->getCanvas());
1966 }
1967 
1968 /*
1969  *  Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1970  *  than just scale/translate, but that other filters do.
1971  */
DEF_TEST(ImageFilterComplexCTM,reporter)1972 DEF_TEST(ImageFilterComplexCTM, reporter) {
1973     // just need a colorfilter to exercise the corresponding imagefilter
1974     sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
1975     sk_sp<SkImageFilter> cfif = SkImageFilters::ColorFilter(cf, nullptr);    // can handle
1976     sk_sp<SkImageFilter> blif = SkImageFilters::Blur(3, 3, nullptr);         // cannot handle
1977     using MatrixCapability = SkImageFilter_Base::MatrixCapability;
1978 
1979     struct {
1980         sk_sp<SkImageFilter> fFilter;
1981         MatrixCapability     fExpectCapability;
1982     } recs[] = {
1983         { cfif,                                  MatrixCapability::kComplex },
1984         { SkImageFilters::ColorFilter(cf, cfif), MatrixCapability::kComplex },
1985         { SkImageFilters::Merge(cfif, cfif),     MatrixCapability::kComplex },
1986         { SkImageFilters::Compose(cfif, cfif),   MatrixCapability::kComplex },
1987 
1988         { blif,                                  MatrixCapability::kScaleTranslate },
1989         { SkImageFilters::Blur(3, 3, cfif),      MatrixCapability::kScaleTranslate },
1990         { SkImageFilters::ColorFilter(cf, blif), MatrixCapability::kScaleTranslate },
1991         { SkImageFilters::Merge(cfif, blif),     MatrixCapability::kScaleTranslate },
1992         { SkImageFilters::Compose(blif, cfif),   MatrixCapability::kScaleTranslate },
1993     };
1994 
1995     for (const auto& rec : recs) {
1996         const MatrixCapability capability = as_IFB(rec.fFilter)->getCTMCapability();
1997         REPORTER_ASSERT(reporter, capability == rec.fExpectCapability);
1998     }
1999 }
2000 
2001 // Test SkXfermodeImageFilter::filterBounds with different blending modes.
DEF_TEST(XfermodeImageFilterBounds,reporter)2002 DEF_TEST(XfermodeImageFilterBounds, reporter) {
2003     SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
2004     SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
2005     sk_sp<SkImageFilter> background = SkImageFilters::Crop(SkRect::Make(background_rect), nullptr);
2006     sk_sp<SkImageFilter> foreground = SkImageFilters::Crop(SkRect::Make(foreground_rect), nullptr);
2007 
2008     SkIRect expectedBounds[kSkBlendModeCount];
2009     // Expect union of input rects by default.
2010     for (int i = 0; i < kSkBlendModeCount; ++i) {
2011         expectedBounds[i] = background_rect;
2012         expectedBounds[i].join(foreground_rect);
2013     }
2014 
2015     SkIRect intersection = background_rect;
2016     intersection.intersect(foreground_rect);
2017     expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
2018     expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
2019     expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
2020     expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
2021     expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
2022     expectedBounds[static_cast<int>(SkBlendMode::kSrcOut)] = foreground_rect;
2023     expectedBounds[static_cast<int>(SkBlendMode::kDstOut)] = background_rect;
2024     expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
2025     expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
2026     expectedBounds[static_cast<int>(SkBlendMode::kModulate)] = intersection;
2027 
2028     // Use a very large input bounds so that the crop rects stored in 'background' and 'foreground'
2029     // aren't restricted.
2030     SkIRect src = SkRectPriv::MakeILarge();
2031     for (int i = 0; i < kSkBlendModeCount; ++i) {
2032         sk_sp<SkImageFilter> xfermode(SkImageFilters::Blend(static_cast<SkBlendMode>(i),
2033                                                             background, foreground, nullptr));
2034         auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
2035                                              SkImageFilter::kForward_MapDirection, nullptr);
2036         REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
2037     }
2038 
2039     // Test empty intersection.
2040     sk_sp<SkImageFilter> background2 =
2041             SkImageFilters::Crop(SkRect::MakeXYWH(0, 0, 20, 20), nullptr);
2042     sk_sp<SkImageFilter> foreground2 =
2043             SkImageFilters::Crop(SkRect::MakeXYWH(40, 40, 50, 50), nullptr);
2044     sk_sp<SkImageFilter> xfermode(SkImageFilters::Blend(
2045             SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
2046     auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
2047                                          SkImageFilter::kForward_MapDirection, nullptr);
2048     REPORTER_ASSERT(reporter, bounds.isEmpty());
2049 }
2050 
DEF_TEST(OffsetImageFilterBounds,reporter)2051 DEF_TEST(OffsetImageFilterBounds, reporter) {
2052     const SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
2053     const SkVector srcOffset = {-50.5f, -50.5f};
2054     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(srcOffset.fX, srcOffset.fY, nullptr));
2055 
2056     // Because the offset has a fractional component, the final output and required input bounds
2057     // will be rounded out to include an extra pixel.
2058     SkIRect expectedForward = SkRect::Make(src).makeOffset(srcOffset.fX, srcOffset.fY).roundOut();
2059     SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
2060                                                  SkImageFilter::kForward_MapDirection, nullptr);
2061     REPORTER_ASSERT(reporter, boundsForward == expectedForward);
2062 
2063     SkIRect expectedReverse = SkRect::Make(src).makeOffset(-srcOffset.fX, -srcOffset.fY).roundOut();
2064 
2065     // Intersect 'expectedReverse' with the source because we are passing &src in as the known
2066     // input bounds, which is the bounds of non-transparent pixels that can be moved by the offset.
2067     // While the ::Offset filter could show all pixels inside 'expectedReverse' given that 'src'
2068     // is also the target device output of the filter, the required input can be made tighter.
2069     SkAssertResult(expectedReverse.intersect(src));
2070 
2071     SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
2072                                                  SkImageFilter::kReverse_MapDirection, &src);
2073     REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
2074 }
2075 
DEF_TEST(OffsetImageFilterBoundsNoOverflow,reporter)2076 DEF_TEST(OffsetImageFilterBoundsNoOverflow, reporter) {
2077     const SkIRect src = SkIRect::MakeXYWH(-10.f, -10.f, 20.f, 20.f);
2078     const SkScalar bigOffset = SkIntToScalar(std::numeric_limits<int>::max()) * 2.f / 3.f;
2079 
2080     sk_sp<SkImageFilter> filter =
2081             SkImageFilters::Blend(SkBlendMode::kSrcOver,
2082                                   SkImageFilters::Offset(-bigOffset, -bigOffset, nullptr),
2083                                   SkImageFilters::Offset(bigOffset, bigOffset, nullptr));
2084     SkIRect boundsForward = filter->filterBounds(src, SkMatrix::I(),
2085                                                  SkImageFilter::kForward_MapDirection, nullptr);
2086     // NOTE: isEmpty() will return true even if the l/r or t/b didn't overflow but the dimensions
2087     // would overflow an int32. However, when isEmpty64() is false, it means the actual edge coords
2088     // are valid, which is good enough for our purposes (and gfx::Rect has its own strategies for
2089     // ensuring such a rectangle doesn't get accidentally treated as empty during chromium's
2090     // conversions).
2091     REPORTER_ASSERT(reporter, !boundsForward.isEmpty64());
2092 
2093     // When querying with unbounded input content, it should not overflow and should not be empty.
2094     SkIRect boundsReverse = filter->filterBounds(src, SkMatrix::I(),
2095                                                  SkImageFilter::kReverse_MapDirection, nullptr);
2096     REPORTER_ASSERT(reporter, !boundsReverse.isEmpty64());
2097 
2098     // However in this case, when 'src' is also passed as the content bounds, the ::Offset() filters
2099     // detect that they would be transparent black. This propagates up to the src-over blend and
2100     // the entire graph is identified as empty.
2101     boundsReverse = filter->filterBounds(src, SkMatrix::I(),
2102                                          SkImageFilter::kReverse_MapDirection, &src);
2103     REPORTER_ASSERT(reporter, boundsReverse.isEmpty64());
2104 }
2105 
test_arithmetic_bounds(skiatest::Reporter * reporter,float k1,float k2,float k3,float k4,sk_sp<SkImageFilter> background,sk_sp<SkImageFilter> foreground,const SkIRect * crop,const SkIRect & expected)2106 static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
2107                                    float k4, sk_sp<SkImageFilter> background,
2108                                    sk_sp<SkImageFilter> foreground,
2109                                    const SkIRect* crop, const SkIRect& expected) {
2110     sk_sp<SkImageFilter> arithmetic(SkImageFilters::Arithmetic(
2111             k1, k2, k3, k4, false, std::move(background), std::move(foreground), crop));
2112     // Use a very large input bounds so that the crop rects stored in 'background' and 'foreground'
2113     // aren't restricted.
2114     SkIRect src = SkRectPriv::MakeILarge();
2115     SkIRect bounds = arithmetic->filterBounds(src, SkMatrix::I(),
2116                                               SkImageFilter::kForward_MapDirection, nullptr);
2117     REPORTER_ASSERT(reporter, expected == bounds);
2118 }
2119 
test_arithmetic_combinations(skiatest::Reporter * reporter,float v)2120 static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
2121     SkIRect bgRect = SkIRect::MakeXYWH(0, 0, 100, 100);
2122     SkIRect fgRect = SkIRect::MakeXYWH(50, 50, 100, 100);
2123     sk_sp<SkImageFilter> background = SkImageFilters::Crop(SkRect::Make(bgRect), nullptr);
2124     sk_sp<SkImageFilter> foreground = SkImageFilters::Crop(SkRect::Make(fgRect), nullptr);
2125 
2126     SkIRect unionRect = bgRect;
2127     unionRect.join(fgRect);
2128     SkIRect intersection = bgRect;
2129     intersection.intersect(fgRect);
2130 
2131     // Test with crop. When k4 is non-zero, the result is expected to be cropRect
2132     // regardless of inputs because the filter affects the whole crop area. When there is no crop
2133     // rect, it should report an effectively infinite output.
2134     static const SkIRect kInf = SkRectPriv::MakeILarge();
2135     test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
2136                            SkIRect::MakeEmpty());
2137     test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, kInf);
2138     test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, bgRect);
2139     test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, kInf);
2140     test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, fgRect);
2141     test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, kInf);
2142     test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, unionRect);
2143     test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, kInf);
2144     test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
2145     test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, kInf);
2146     test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, bgRect);
2147     test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, kInf);
2148     test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, fgRect);
2149     test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, kInf);
2150     test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, unionRect);
2151     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, kInf);
2152 
2153     SkIRect cropRect = SkIRect::MakeXYWH(-111, -222, 333, 444);
2154     test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &cropRect,
2155                            SkIRect::MakeEmpty());
2156     test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &cropRect, cropRect);
2157     test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &cropRect, bgRect);
2158     test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &cropRect, cropRect);
2159     test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &cropRect, fgRect);
2160     test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &cropRect, cropRect);
2161     test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &cropRect, unionRect);
2162     test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &cropRect, cropRect);
2163     test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &cropRect, intersection);
2164     test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &cropRect, cropRect);
2165     test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &cropRect, bgRect);
2166     test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &cropRect, cropRect);
2167     test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &cropRect, fgRect);
2168     test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &cropRect, cropRect);
2169     test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &cropRect, unionRect);
2170     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &cropRect, cropRect);
2171 }
2172 
2173 // Test SkArithmeticImageFilter::filterBounds with different blending modes.
DEF_TEST(ArithmeticImageFilterBounds,reporter)2174 DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2175     test_arithmetic_combinations(reporter, 1);
2176     test_arithmetic_combinations(reporter, 0.5);
2177 }
2178 
2179 // Test SkDisplacementMapEffect::filterBounds.
DEF_TEST(DisplacementMapBounds,reporter)2180 DEF_TEST(DisplacementMapBounds, reporter) {
2181     SkIRect floodBounds(SkIRect::MakeXYWH(20, 30, 10, 10));
2182     sk_sp<SkImageFilter> flood(SkImageFilters::Shader(SkShaders::Color(SK_ColorGREEN),
2183                                                       &floodBounds));
2184     SkIRect tilingBounds(SkIRect::MakeXYWH(0, 0, 200, 100));
2185     sk_sp<SkImageFilter> tiling(SkImageFilters::Tile(SkRect::Make(floodBounds),
2186                                                      SkRect::Make(tilingBounds),
2187                                                      flood));
2188     sk_sp<SkImageFilter> displace(SkImageFilters::DisplacementMap(SkColorChannel::kR,
2189                                                                   SkColorChannel::kB,
2190                                                                   20.0f, nullptr, tiling));
2191 
2192     // The filter graph rooted at 'displace' uses the dynamic source image for the displacement
2193     // component of ::DisplacementMap, modifying the color component produced by the ::Tile. The
2194     // output of the tiling filter will be 'tilingBounds', regardless of its input, so 'floodBounds'
2195     // has no effect on the output. Since 'tiling' doesn't reference any dynamic source image, it
2196     // also will not affect the required input bounds. The displacement map is sampled 1-to-1
2197     // with the output pixels, and covers the output unless the color's output makes that impossible
2198     // and the output is a subset of the desired output. Thus, the displacement can impact the
2199     // reported output bounds.
2200     SkIRect input(SkIRect::MakeXYWH(20, 30, 40, 50));
2201 
2202     // 'input' is the desired output, which directly constrains the displacement component in this
2203     // specific filter graph.
2204     SkIRect actualInput = displace->filterBounds(input, SkMatrix::I(),
2205                                                  SkImageFilter::kReverse_MapDirection);
2206     REPORTER_ASSERT(reporter, input == actualInput);
2207 
2208     // 'input' is the content bounds, which don't affect output bounds because it's only referenced
2209     // by the displacement component and not the color component.
2210     SkIRect actualOutput = displace->filterBounds(input, SkMatrix::I(),
2211                                                   SkImageFilter::kForward_MapDirection);
2212     REPORTER_ASSERT(reporter, tilingBounds.makeOutset(10, 10) == actualOutput);
2213 }
2214 
2215 // Test SkImageSource::filterBounds.
DEF_TEST(ImageSourceBounds,reporter)2216 DEF_TEST(ImageSourceBounds, reporter) {
2217     sk_sp<SkImage> image(make_gradient_circle(64, 64).asImage());
2218     // Default src and dst rects.
2219     sk_sp<SkImageFilter> source1(SkImageFilters::Image(image, SkFilterMode::kNearest));
2220     SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2221     SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2222     REPORTER_ASSERT(reporter,
2223                     imageBounds == source1->filterBounds(input, SkMatrix::I(),
2224                                                          SkImageFilter::kForward_MapDirection,
2225                                                          nullptr));
2226     REPORTER_ASSERT(reporter,
2227                     source1->filterBounds(input, SkMatrix::I(),
2228                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2229     SkMatrix scale(SkMatrix::Scale(2, 2));
2230     SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2231     REPORTER_ASSERT(reporter,
2232                     scaledBounds == source1->filterBounds(input, scale,
2233                                                           SkImageFilter::kForward_MapDirection,
2234                                                           nullptr));
2235     REPORTER_ASSERT(reporter,
2236                     source1->filterBounds(input, scale,
2237                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2238 
2239     // Specified src and dst rects (which are outside available pixels).
2240     SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2241     SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2242     sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst,
2243                                                        SkSamplingOptions(SkFilterMode::kLinear,
2244                                                                          SkMipmapMode::kLinear)));
2245 
2246     SkRect clippedSrc = src;
2247     SkAssertResult(clippedSrc.intersect(SkRect::Make(image->dimensions())));
2248     SkRect clippedDst = SkMatrix::RectToRect(src, dst).mapRect(clippedSrc);
2249 
2250     REPORTER_ASSERT(reporter,
2251                     clippedDst.roundOut() ==
2252                     source2->filterBounds(input, SkMatrix::I(),
2253                                           SkImageFilter::kForward_MapDirection, nullptr));
2254     REPORTER_ASSERT(reporter,
2255                     source2->filterBounds(input, SkMatrix::I(),
2256                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2257     scale.mapRect(&clippedDst);
2258     scale.mapRect(&clippedSrc);
2259     REPORTER_ASSERT(reporter,
2260                     clippedDst.roundOut() ==
2261                     source2->filterBounds(input, scale,
2262                                           SkImageFilter::kForward_MapDirection, nullptr));
2263     REPORTER_ASSERT(reporter,
2264                     source2->filterBounds(input, scale,
2265                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2266 }
2267 
2268 // Test SkPictureImageFilter::filterBounds.
DEF_TEST(PictureImageSourceBounds,reporter)2269 DEF_TEST(PictureImageSourceBounds, reporter) {
2270     SkPictureRecorder recorder;
2271     SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
2272 
2273     SkPaint greenPaint;
2274     greenPaint.setColor(SK_ColorGREEN);
2275     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
2276     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
2277 
2278     // Default target rect.
2279     sk_sp<SkImageFilter> source1(SkImageFilters::Picture(picture));
2280     SkIRect pictureBounds = SkIRect::MakeWH(64, 64);
2281     SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2282     REPORTER_ASSERT(reporter,
2283                     pictureBounds == source1->filterBounds(input, SkMatrix::I(),
2284                                                            SkImageFilter::kForward_MapDirection,
2285                                                            nullptr));
2286     REPORTER_ASSERT(reporter,
2287                     source1->filterBounds(input, SkMatrix::I(),
2288                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2289     SkMatrix scale(SkMatrix::Scale(2, 2));
2290     SkIRect scaledPictureBounds = SkIRect::MakeWH(128, 128);
2291     REPORTER_ASSERT(reporter,
2292                     scaledPictureBounds == source1->filterBounds(input, scale,
2293                                                                  SkImageFilter::kForward_MapDirection,
2294                                                                  nullptr));
2295     REPORTER_ASSERT(reporter,
2296                     source1->filterBounds(input, scale,
2297                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2298 
2299     // Specified target rect.
2300     SkRect targetRect(SkRect::MakeXYWH(9.5, 9.5, 31, 21));
2301     sk_sp<SkImageFilter> source2(SkImageFilters::Picture(picture, targetRect));
2302     REPORTER_ASSERT(reporter,
2303                     targetRect.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2304                                                                    SkImageFilter::kForward_MapDirection,
2305                                                                    nullptr));
2306     REPORTER_ASSERT(reporter,
2307                     source2->filterBounds(input, SkMatrix::I(),
2308                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2309     scale.mapRect(&targetRect);
2310     REPORTER_ASSERT(reporter,
2311                     targetRect.roundOut() == source2->filterBounds(input, scale,
2312                                                                    SkImageFilter::kForward_MapDirection,
2313                                                                    nullptr));
2314     REPORTER_ASSERT(reporter,
2315                     source2->filterBounds(input, scale,
2316                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2317 }
2318 
DEF_TEST(DropShadowImageFilter_Huge,reporter)2319 DEF_TEST(DropShadowImageFilter_Huge, reporter) {
2320     // Successful if it doesn't crash or trigger ASAN. (crbug.com/1264705)
2321     auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(300, 150));
2322 
2323     SkPaint paint;
2324     paint.setImageFilter(SkImageFilters::DropShadowOnly(
2325             0.0f, 0.437009f, 14129.6f, 14129.6f, SK_ColorGRAY, nullptr));
2326 
2327     surf->getCanvas()->saveLayer(nullptr, &paint);
2328     surf->getCanvas()->restore();
2329 }
2330