• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/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 SkM44 & expectedMatrix)101     MatrixTestImageFilter(skiatest::Reporter* reporter, const SkM44& 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     SkM44 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__anon7cf8de7a0111::FilterList::Filter279         Filter() : fName(nullptr), fNeedsSaveLayer(false) {}
Filter__anon7cf8de7a0111::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{SkM44()},
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     const SkM44 negativeScale = SkM44::Scale(-SK_Scalar1, SK_Scalar1);
579     skif::Context negativeCTX = ctx.withNewMapping(skif::Mapping(negativeScale));
580 
581     sk_sp<SkSpecialImage> negativeResult(
582             as_IFB(positiveFilter)->filterImage(negativeCTX).imageAndOffset(ctx, &offset));
583     REPORTER_ASSERT(reporter, negativeResult);
584 
585 
586     SkBitmap positiveResultBM;
587     SkBitmap negativeResultBM;
588 
589     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, positiveResult.get(),
590                                                       &positiveResultBM));
591     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, negativeResult.get(),
592                                                       &negativeResultBM));
593 
594     for (int y = 0; y < kHeight; y++) {
595         int diffs = memcmp(positiveResultBM.getAddr32(0, y),
596                            negativeResultBM.getAddr32(0, y),
597                            positiveResultBM.rowBytes());
598         REPORTER_ASSERT(reporter, !diffs);
599         if (diffs) {
600             break;
601         }
602     }
603 }
604 
DEF_TEST(ImageFilterNegativeBlurSigma,reporter)605 DEF_TEST(ImageFilterNegativeBlurSigma, reporter) {
606     test_negative_blur_sigma(reporter, nullptr);
607 }
608 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)609 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterNegativeBlurSigma_Gpu,
610                                        reporter,
611                                        ctxInfo,
612                                        CtsEnforcement::kNever) {
613     test_negative_blur_sigma(reporter, ctxInfo.directContext());
614 }
615 
test_morphology_radius_with_mirror_ctm(skiatest::Reporter * reporter,GrDirectContext * dContext)616 static void test_morphology_radius_with_mirror_ctm(skiatest::Reporter* reporter,
617                                                    GrDirectContext* dContext) {
618     // Check that SkMorphologyImageFilter maps the radius correctly when the
619     // CTM contains a mirroring transform.
620     static const int kWidth = 32, kHeight = 32;
621     static const int kRadius = 8;
622 
623     sk_sp<SkImageFilter> filter(SkImageFilters::Dilate(kRadius, kRadius, nullptr));
624 
625     SkBitmap bitmap;
626     bitmap.allocN32Pixels(kWidth, kHeight);
627     SkCanvas canvas(bitmap);
628     canvas.clear(SK_ColorTRANSPARENT);
629     SkPaint paint;
630     paint.setColor(SK_ColorWHITE);
631     canvas.drawRect(SkRect::MakeXYWH(kWidth / 4, kHeight / 4, kWidth / 2, kHeight / 2),
632                     paint);
633     sk_sp<SkImage> image = bitmap.asImage();
634     sk_sp<SkSpecialImage> imgSrc;
635     if (dContext) {
636         imgSrc = SkSpecialImages::MakeFromTextureImage(
637                 dContext, SkIRect::MakeWH(kWidth, kHeight), image, SkSurfaceProps());
638     } else {
639         imgSrc = SkSpecialImages::MakeFromRaster(SkIRect::MakeWH(kWidth, kHeight), image, {});
640     }
641 
642     SkIPoint offset;
643     skif::Context ctx = make_context(32, 32, imgSrc.get());
644 
645     sk_sp<SkSpecialImage> normalResult(
646             as_IFB(filter)->filterImage(ctx).imageAndOffset(ctx, &offset));
647     REPORTER_ASSERT(reporter, normalResult);
648 
649     SkM44 mirrorX = SkM44::Translate(0, 32);
650     mirrorX.preScale(SK_Scalar1, -SK_Scalar1);
651     skif::Context mirrorXCTX = ctx.withNewMapping(skif::Mapping(mirrorX));
652 
653     sk_sp<SkSpecialImage> mirrorXResult(
654             as_IFB(filter)->filterImage(mirrorXCTX).imageAndOffset(ctx, &offset));
655     REPORTER_ASSERT(reporter, mirrorXResult);
656 
657     SkM44 mirrorY = SkM44::Translate(32, 0);
658     mirrorY.preScale(-SK_Scalar1, SK_Scalar1);
659     skif::Context mirrorYCTX = ctx.withNewMapping(skif::Mapping(mirrorY));
660 
661     sk_sp<SkSpecialImage> mirrorYResult(
662             as_IFB(filter)->filterImage(mirrorYCTX).imageAndOffset(ctx, &offset));
663     REPORTER_ASSERT(reporter, mirrorYResult);
664 
665     SkBitmap normalResultBM, mirrorXResultBM, mirrorYResultBM;
666 
667     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, normalResult.get(),
668                                                       &normalResultBM));
669     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, mirrorXResult.get(),
670                                                       &mirrorXResultBM));
671     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, mirrorYResult.get(),
672                                                       &mirrorYResultBM));
673 
674     for (int y = 0; y < kHeight; y++) {
675         int diffs = memcmp(normalResultBM.getAddr32(0, y),
676                            mirrorXResultBM.getAddr32(0, y),
677                            normalResultBM.rowBytes());
678         REPORTER_ASSERT(reporter, !diffs);
679         if (diffs) {
680             break;
681         }
682         diffs = memcmp(normalResultBM.getAddr32(0, y),
683                        mirrorYResultBM.getAddr32(0, y),
684                        normalResultBM.rowBytes());
685         REPORTER_ASSERT(reporter, !diffs);
686         if (diffs) {
687             break;
688         }
689     }
690 }
691 
DEF_TEST(MorphologyFilterRadiusWithMirrorCTM,reporter)692 DEF_TEST(MorphologyFilterRadiusWithMirrorCTM, reporter) {
693     test_morphology_radius_with_mirror_ctm(reporter, nullptr);
694 }
695 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)696 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(MorphologyFilterRadiusWithMirrorCTM_Gpu,
697                                        reporter,
698                                        ctxInfo,
699                                        CtsEnforcement::kNever) {
700     test_morphology_radius_with_mirror_ctm(reporter, ctxInfo.directContext());
701 }
702 
test_zero_blur_sigma(skiatest::Reporter * reporter,GrDirectContext * dContext)703 static void test_zero_blur_sigma(skiatest::Reporter* reporter, GrDirectContext* dContext) {
704     // Check that SkBlurImageFilter with a zero sigma and a non-zero srcOffset works correctly.
705     SkIRect cropRect = SkIRect::MakeXYWH(5, 0, 5, 10);
706     sk_sp<SkImageFilter> input(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
707     sk_sp<SkImageFilter> filter(SkImageFilters::Blur(0, 0, std::move(input), &cropRect));
708 
709     sk_sp<SkSpecialImage> image = create_empty_special_image(dContext, 10, SkColors::kGreen);
710 
711     SkIPoint offset;
712     skif::Context ctx = make_context(32, 32, image.get());
713 
714 
715     sk_sp<SkSpecialImage> result(as_IFB(filter)->filterImage(ctx).imageAndOffset(ctx, &offset));
716     REPORTER_ASSERT(reporter, offset.fX == 5 && offset.fY == 0);
717     REPORTER_ASSERT(reporter, result);
718     REPORTER_ASSERT(reporter, result->width() == 5 && result->height() == 10);
719 
720     SkBitmap resultBM;
721 
722     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
723 
724     for (int y = 0; y < resultBM.height(); y++) {
725         for (int x = 0; x < resultBM.width(); x++) {
726             bool diff = *resultBM.getAddr32(x, y) != SK_ColorGREEN;
727             REPORTER_ASSERT(reporter, !diff);
728             if (diff) {
729                 break;
730             }
731         }
732     }
733 }
734 
DEF_TEST(ImageFilterZeroBlurSigma,reporter)735 DEF_TEST(ImageFilterZeroBlurSigma, reporter) {
736     test_zero_blur_sigma(reporter, nullptr);
737 }
738 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)739 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterZeroBlurSigma_Gpu,
740                                        reporter,
741                                        ctxInfo,
742                                        CtsEnforcement::kNever) {
743     test_zero_blur_sigma(reporter, ctxInfo.directContext());
744 }
745 
746 // Tests that, even when an upstream filter has returned null (due to failure or clipping), a
747 // downstream filter that affects transparent black still does so even with a nullptr input.
test_fail_affects_transparent_black(skiatest::Reporter * reporter,GrDirectContext * dContext)748 static void test_fail_affects_transparent_black(skiatest::Reporter* reporter,
749                                                 GrDirectContext* dContext) {
750     sk_sp<SkImageFilter> failFilter = SkImageFilters::Empty();
751     sk_sp<SkSpecialImage> source(create_empty_special_image(dContext, 5));
752     skif::Context ctx = make_context(1, 1, source.get());
753 
754     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
755     SkASSERT(as_CFB(green)->affectsTransparentBlack());
756     sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(std::move(green),
757                                                                  std::move(failFilter)));
758     SkIPoint offset;
759     sk_sp<SkSpecialImage> result(as_IFB(greenFilter)->filterImage(ctx)
760                                                      .imageAndOffset(ctx, &offset));
761     REPORTER_ASSERT(reporter, nullptr != result.get());
762     if (result) {
763         SkBitmap resultBM;
764         REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
765         REPORTER_ASSERT(reporter, *resultBM.getAddr32(0, 0) == SK_ColorGREEN);
766     }
767 }
768 
DEF_TEST(ImageFilterFailAffectsTransparentBlack,reporter)769 DEF_TEST(ImageFilterFailAffectsTransparentBlack, reporter) {
770     test_fail_affects_transparent_black(reporter, nullptr);
771 }
772 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)773 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterFailAffectsTransparentBlack_Gpu,
774                                        reporter,
775                                        ctxInfo,
776                                        CtsEnforcement::kNever) {
777     test_fail_affects_transparent_black(reporter, ctxInfo.directContext());
778 }
779 
DEF_TEST(ImageFilterDrawTiled,reporter)780 DEF_TEST(ImageFilterDrawTiled, reporter) {
781     // Check that all filters when drawn tiled (with subsequent clip rects) exactly
782     // match the same filters drawn with a single full-canvas bitmap draw.
783     // Tests pass by not asserting.
784 
785     FilterList filters(nullptr);
786 
787     SkBitmap untiledResult, tiledResult;
788     const int width = 64, height = 64;
789     untiledResult.allocN32Pixels(width, height);
790     tiledResult.allocN32Pixels(width, height);
791     SkCanvas tiledCanvas(tiledResult);
792     SkCanvas untiledCanvas(untiledResult);
793     const int tileSize = 8;
794 
795     SkPaint textPaint;
796     textPaint.setColor(SK_ColorWHITE);
797     SkFont font(ToolUtils::DefaultPortableTypeface(), height);
798 
799     const char* text = "ABC";
800     const SkScalar yPos = SkIntToScalar(height);
801 
802     for (int scale = 1; scale <= 2; ++scale) {
803         for (int i = 0; i < filters.count(); ++i) {
804             SkPaint combinedPaint;
805             combinedPaint.setColor(SK_ColorWHITE);
806             combinedPaint.setImageFilter(sk_ref_sp(filters.getFilter(i)));
807 
808             untiledCanvas.clear(SK_ColorTRANSPARENT);
809             untiledCanvas.save();
810             untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
811             untiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
812             untiledCanvas.restore();
813 
814             tiledCanvas.clear(SK_ColorTRANSPARENT);
815             for (int y = 0; y < height; y += tileSize) {
816                 for (int x = 0; x < width; x += tileSize) {
817                     tiledCanvas.save();
818                     const SkRect clipRect = SkRect::MakeXYWH(x, y, tileSize, tileSize);
819                     tiledCanvas.clipRect(clipRect);
820                     if (filters.needsSaveLayer(i)) {
821                         tiledCanvas.saveLayer(nullptr, &combinedPaint);
822                             tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
823                             tiledCanvas.drawString(text, 0, yPos, font, textPaint);
824                         tiledCanvas.restore();
825                     } else {
826                         tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
827                         tiledCanvas.drawString(text, 0, yPos, font, combinedPaint);
828                     }
829 
830                     tiledCanvas.restore();
831                 }
832             }
833 
834             if (!ToolUtils::equal_pixels(untiledResult, tiledResult)) {
835                 SkString encoded;
836                 SkString errString("Tiled image filter doesn't match untiled reference");
837                 errString.append("\nExpected: ");
838                 if (ToolUtils::BitmapToBase64DataURI(untiledResult, &encoded)) {
839                     errString.append(encoded);
840                 } else {
841                     errString.append("failed to encode");
842                 }
843 
844                 errString.append("\nActual: ");
845                 if (ToolUtils::BitmapToBase64DataURI(tiledResult, &encoded)) {
846                     errString.append(encoded);
847                 } else {
848                     errString.append("failed to encode");
849                 }
850 
851                 ERRORF(reporter, "%s\n%s", filters.getName(i), errString.c_str());
852             }
853         }
854     }
855 }
856 
draw_saveLayer_picture(int width,int height,int tileSize,SkBBHFactory * factory,SkBitmap * result)857 static void draw_saveLayer_picture(int width, int height, int tileSize,
858                                    SkBBHFactory* factory, SkBitmap* result) {
859 
860     SkMatrix matrix;
861     matrix.setTranslate(SkIntToScalar(50), 0);
862 
863     sk_sp<SkColorFilter> cf(SkColorFilters::Blend(SK_ColorWHITE, SkBlendMode::kSrc));
864     sk_sp<SkImageFilter> cfif(SkImageFilters::ColorFilter(std::move(cf), nullptr));
865     sk_sp<SkImageFilter> imageFilter(SkImageFilters::MatrixTransform(matrix,
866                                                                      SkSamplingOptions(),
867                                                                      std::move(cfif)));
868 
869     SkPaint paint;
870     paint.setImageFilter(std::move(imageFilter));
871     SkPictureRecorder recorder;
872     SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
873     SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width),
874                                                         SkIntToScalar(height),
875                                                         factory);
876     recordingCanvas->translate(-55, 0);
877     recordingCanvas->saveLayer(&bounds, &paint);
878     recordingCanvas->restore();
879     sk_sp<SkPicture> picture1(recorder.finishRecordingAsPicture());
880 
881     result->allocN32Pixels(width, height);
882     SkCanvas canvas(*result);
883     canvas.clear(0);
884     canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
885     canvas.drawPicture(picture1.get());
886 }
887 
DEF_TEST(ImageFilterDrawMatrixBBH,reporter)888 DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
889     // Check that matrix filter when drawn tiled with BBH exactly
890     // matches the same thing drawn without BBH.
891     // Tests pass by not asserting.
892 
893     const int width = 200, height = 200;
894     const int tileSize = 100;
895     SkBitmap result1, result2;
896     SkRTreeFactory factory;
897 
898     draw_saveLayer_picture(width, height, tileSize, &factory, &result1);
899     draw_saveLayer_picture(width, height, tileSize, nullptr, &result2);
900 
901     for (int y = 0; y < height; y++) {
902         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
903         REPORTER_ASSERT(reporter, !diffs);
904         if (diffs) {
905             break;
906         }
907     }
908 }
909 
make_blur(sk_sp<SkImageFilter> input)910 static sk_sp<SkImageFilter> make_blur(sk_sp<SkImageFilter> input) {
911     return SkImageFilters::Blur(SK_Scalar1, SK_Scalar1, std::move(input));
912 }
913 
make_drop_shadow(sk_sp<SkImageFilter> input)914 static sk_sp<SkImageFilter> make_drop_shadow(sk_sp<SkImageFilter> input) {
915     return SkImageFilters::DropShadow(100, 100, 10, 10, SK_ColorBLUE, std::move(input));
916 }
917 
DEF_TEST(ImageFilterBlurThenShadowBounds,reporter)918 DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) {
919     sk_sp<SkImageFilter> filter1(make_blur(nullptr));
920     sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
921 
922     static const SkIRect kContentBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
923 
924     // For output, the [0,0,100,100] source is expanded to [-3,-3,103,103] by the initial blur.
925     // The drop shadow is translated by [100,100] and further outset by 30px -> [67,67,233,233],
926     // The blend unions the inner blur result with the drop shadow to get [-3,-3,233,233].
927     static const SkIRect kExpectedOutputBounds = SkIRect::MakeLTRB(-3, -3, 233, 233);
928     SkIRect outputBounds = filter2->filterBounds(kContentBounds,
929                                                  SkMatrix::I(),
930                                                  SkImageFilter::kForward_MapDirection);
931     REPORTER_ASSERT(reporter, outputBounds == kExpectedOutputBounds);
932 
933     // For input, it should be able to restrict itself to the source content.
934     SkIRect inputBounds = filter2->filterBounds(kExpectedOutputBounds,
935                                                 SkMatrix::I(),
936                                                 SkImageFilter::kReverse_MapDirection,
937                                                 &kContentBounds);
938 
939     REPORTER_ASSERT(reporter, inputBounds == kContentBounds);
940 }
941 
DEF_TEST(ImageFilterShadowThenBlurBounds,reporter)942 DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) {
943     sk_sp<SkImageFilter> filter1(make_drop_shadow(nullptr));
944     sk_sp<SkImageFilter> filter2(make_blur(std::move(filter1)));
945 
946     static const SkIRect kContentBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
947     // For output, the [0,0,100,100] source is translated by 100px and outset by 30px for the drop
948     // shadow = [70,70,230,230], then blended back with its original to get [0,0,230,230]. This is
949     // then outset by 3px for the outer blur to get [-3,-3,233,233].
950     static const SkIRect kExpectedOutputBounds = SkIRect::MakeLTRB(-3, -3, 233, 233);
951     SkIRect outputBounds = filter2->filterBounds(kContentBounds,
952                                                  SkMatrix::I(),
953                                                  SkImageFilter::kForward_MapDirection);
954     REPORTER_ASSERT(reporter, outputBounds == kExpectedOutputBounds);
955 
956     // For input, it should be able to restrict itself to the source content.
957     SkIRect inputBounds = filter2->filterBounds(kExpectedOutputBounds,
958                                                 SkMatrix::I(),
959                                                 SkImageFilter::kReverse_MapDirection,
960                                                 &kContentBounds);
961     REPORTER_ASSERT(reporter, inputBounds == kContentBounds);
962 }
963 
DEF_TEST(ImageFilterDilateThenBlurBounds,reporter)964 DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) {
965     sk_sp<SkImageFilter> filter1(SkImageFilters::Dilate(2, 2, nullptr));
966     sk_sp<SkImageFilter> filter2(make_drop_shadow(std::move(filter1)));
967 
968     static const SkIRect kContentBounds = SkIRect::MakeXYWH(0, 0, 100, 100);
969     // For output, the [0,0,100,100] source is outset by dilate radius (2px) to [-2,-2,102,102].
970     // This is then translated by 100px and outset by 30px for the drop shadow = [68,68,232,232].
971     // Finally this is joined with the original dilate result to get [-2,-2,232,232].
972     static const SkIRect kExpectedOutputBounds = SkIRect::MakeLTRB(-2, -2, 232, 232);
973     SkIRect outputBounds = filter2->filterBounds(kContentBounds,
974                                                  SkMatrix::I(),
975                                                  SkImageFilter::kForward_MapDirection);
976     REPORTER_ASSERT(reporter, outputBounds == kExpectedOutputBounds);
977 
978     // For input, it should be able to restrict itself to the source content.
979     SkIRect inputBounds = filter2->filterBounds(kExpectedOutputBounds,
980                                                 SkMatrix::I(),
981                                                 SkImageFilter::kReverse_MapDirection,
982                                                 &kContentBounds);
983     REPORTER_ASSERT(reporter, inputBounds == kContentBounds);
984 }
985 
DEF_TEST(ImageFilterScaledBlurRadius,reporter)986 DEF_TEST(ImageFilterScaledBlurRadius, reporter) {
987     // Each blur should spread 3*sigma, so 3 for the blur and 30 for the shadow
988     // (before the CTM). Bounds should be computed correctly in the presence of
989     // a (possibly negative) scale.
990     sk_sp<SkImageFilter> blur(make_blur(nullptr));
991     sk_sp<SkImageFilter> dropShadow(make_drop_shadow(nullptr));
992     {
993         // Uniform scale by 2.
994         SkMatrix scaleMatrix;
995         scaleMatrix.setScale(2, 2);
996         static const SkIRect kBounds = SkIRect::MakeLTRB(0, 0, 200, 200);
997 
998         static const SkIRect kExpectedBlurBounds = SkIRect::MakeLTRB(-6, -6, 206, 206);
999         SkIRect blurBounds = blur->filterBounds(
1000                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1001         REPORTER_ASSERT(reporter, blurBounds == kExpectedBlurBounds);
1002         SkIRect reverseBlurBounds = blur->filterBounds(
1003                 kExpectedBlurBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1004         REPORTER_ASSERT(reporter, reverseBlurBounds == kBounds);
1005 
1006         static const SkIRect kExpectedShadowBounds = SkIRect::MakeLTRB(0, 0, 460, 460);
1007         SkIRect shadowBounds = dropShadow->filterBounds(
1008                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1009         REPORTER_ASSERT(reporter, shadowBounds == kExpectedShadowBounds);
1010 
1011         SkIRect reverseShadowBounds = dropShadow->filterBounds(
1012                 kExpectedShadowBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1013         REPORTER_ASSERT(reporter, reverseShadowBounds == kBounds);
1014     }
1015     {
1016         // Vertical flip.
1017         SkMatrix scaleMatrix;
1018         scaleMatrix.setScale(1, -1);
1019         static const SkIRect kBounds = SkIRect::MakeLTRB(0, -100, 100, 0);
1020 
1021         static const SkIRect kExpectedBlurBounds = SkIRect::MakeLTRB(-3, -103, 103, 3);
1022         SkIRect blurBounds = blur->filterBounds(
1023                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1024         REPORTER_ASSERT(reporter, blurBounds == kExpectedBlurBounds);
1025         SkIRect reverseBlurBounds = blur->filterBounds(
1026                 kExpectedBlurBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1027         REPORTER_ASSERT(reporter, reverseBlurBounds == kBounds);
1028 
1029         SkIRect kExpectedShadowBounds = SkIRect::MakeLTRB(0, -230, 230, 0);
1030         SkIRect shadowBounds = dropShadow->filterBounds(
1031                 kBounds, scaleMatrix, SkImageFilter::kForward_MapDirection, nullptr);
1032         REPORTER_ASSERT(reporter, shadowBounds == kExpectedShadowBounds);
1033         SkIRect reverseShadowBounds = dropShadow->filterBounds(
1034                 kExpectedShadowBounds, scaleMatrix, SkImageFilter::kReverse_MapDirection, &kBounds);
1035         REPORTER_ASSERT(reporter, reverseShadowBounds == kBounds);
1036     }
1037 }
1038 
DEF_TEST(ImageFilterComposedBlurFastBounds,reporter)1039 DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) {
1040     sk_sp<SkImageFilter> filter1(make_blur(nullptr));
1041     sk_sp<SkImageFilter> filter2(make_blur(nullptr));
1042     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(filter1),
1043                                                                 std::move(filter2)));
1044 
1045     static const SkRect kBoundsSrc = SkRect::MakeIWH(100, 100);
1046     static const SkRect kExpectedBounds = SkRect::MakeXYWH(-6, -6, 112, 112);
1047     SkRect boundsDst = composedFilter->computeFastBounds(kBoundsSrc);
1048 
1049     REPORTER_ASSERT(reporter, boundsDst == kExpectedBounds);
1050 }
1051 
DEF_TEST(ImageFilterUnionBounds,reporter)1052 DEF_TEST(ImageFilterUnionBounds, reporter) {
1053     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(50, 0, nullptr));
1054     // Regardless of which order they appear in, the image filter bounds should
1055     // be combined correctly.
1056     {
1057         sk_sp<SkImageFilter> composite(SkImageFilters::Blend(SkBlendMode::kSrcOver, offset));
1058         SkRect bounds = SkRect::MakeIWH(100, 100);
1059         // Intentionally aliasing here, as that's what the real callers do.
1060         bounds = composite->computeFastBounds(bounds);
1061         REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
1062     }
1063     {
1064         sk_sp<SkImageFilter> composite(SkImageFilters::Blend(SkBlendMode::kSrcOver, nullptr,
1065                                                              offset, nullptr));
1066         SkRect bounds = SkRect::MakeIWH(100, 100);
1067         // Intentionally aliasing here, as that's what the real callers do.
1068         bounds = composite->computeFastBounds(bounds);
1069         REPORTER_ASSERT(reporter, bounds == SkRect::MakeIWH(150, 100));
1070     }
1071 }
1072 
test_imagefilter_merge_result_size(skiatest::Reporter * reporter,GrRecordingContext * rContext)1073 static void test_imagefilter_merge_result_size(skiatest::Reporter* reporter,
1074                                                GrRecordingContext* rContext) {
1075     SkBitmap greenBM;
1076     greenBM.allocN32Pixels(20, 20);
1077     greenBM.eraseColor(SK_ColorGREEN);
1078     sk_sp<SkImage> greenImage(greenBM.asImage());
1079     sk_sp<SkImageFilter> source(SkImageFilters::Image(std::move(greenImage), {}));
1080     sk_sp<SkImageFilter> merge(SkImageFilters::Merge(source, source));
1081 
1082     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 1));
1083 
1084     skif::Context ctx = make_context(100, 100, srcImg.get());
1085     SkIPoint offset;
1086 
1087     sk_sp<SkSpecialImage> resultImg(as_IFB(merge)->filterImage(ctx).imageAndOffset(ctx, &offset));
1088     REPORTER_ASSERT(reporter, resultImg);
1089 
1090     REPORTER_ASSERT(reporter, resultImg->width() == 20 && resultImg->height() == 20);
1091 }
1092 
DEF_TEST(ImageFilterMergeResultSize,reporter)1093 DEF_TEST(ImageFilterMergeResultSize, reporter) {
1094     test_imagefilter_merge_result_size(reporter, nullptr);
1095 }
1096 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1097 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMergeResultSize_Gpu,
1098                                        reporter,
1099                                        ctxInfo,
1100                                        CtsEnforcement::kNever) {
1101     test_imagefilter_merge_result_size(reporter, ctxInfo.directContext());
1102 }
1103 
draw_blurred_rect(SkCanvas * canvas)1104 static void draw_blurred_rect(SkCanvas* canvas) {
1105     SkPaint filterPaint;
1106     filterPaint.setColor(SK_ColorWHITE);
1107     filterPaint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(8), 0, nullptr));
1108     canvas->saveLayer(nullptr, &filterPaint);
1109     SkPaint whitePaint;
1110     whitePaint.setColor(SK_ColorWHITE);
1111     canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
1112     canvas->restore();
1113 }
1114 
draw_picture_clipped(SkCanvas * canvas,const SkRect & clipRect,const SkPicture * picture)1115 static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
1116     canvas->save();
1117     canvas->clipRect(clipRect);
1118     canvas->drawPicture(picture);
1119     canvas->restore();
1120 }
1121 
DEF_TEST(ImageFilterDrawTiledBlurRTree,reporter)1122 DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
1123     // Check that the blur filter when recorded with RTree acceleration,
1124     // and drawn tiled (with subsequent clip rects) exactly
1125     // matches the same filter drawn with without RTree acceleration.
1126     // This tests that the "bleed" from the blur into the otherwise-blank
1127     // tiles is correctly rendered.
1128     // Tests pass by not asserting.
1129 
1130     int width = 16, height = 8;
1131     SkBitmap result1, result2;
1132     result1.allocN32Pixels(width, height);
1133     result2.allocN32Pixels(width, height);
1134     SkCanvas canvas1(result1);
1135     SkCanvas canvas2(result2);
1136     int tileSize = 8;
1137 
1138     canvas1.clear(0);
1139     canvas2.clear(0);
1140 
1141     SkRTreeFactory factory;
1142 
1143     SkPictureRecorder recorder1, recorder2;
1144     // The only difference between these two pictures is that one has RTree aceleration.
1145     SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height);
1146     SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory);
1147 
1148     draw_blurred_rect(recordingCanvas1);
1149     draw_blurred_rect(recordingCanvas2);
1150     sk_sp<SkPicture> picture1(recorder1.finishRecordingAsPicture());
1151     sk_sp<SkPicture> picture2(recorder2.finishRecordingAsPicture());
1152     for (int y = 0; y < height; y += tileSize) {
1153         for (int x = 0; x < width; x += tileSize) {
1154             SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
1155             draw_picture_clipped(&canvas1, tileRect, picture1.get());
1156             draw_picture_clipped(&canvas2, tileRect, picture2.get());
1157         }
1158     }
1159     for (int y = 0; y < height; y++) {
1160         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
1161         REPORTER_ASSERT(reporter, !diffs);
1162         if (diffs) {
1163             break;
1164         }
1165     }
1166 }
1167 
DEF_TEST(ImageFilterMatrixConvolution,reporter)1168 DEF_TEST(ImageFilterMatrixConvolution, reporter) {
1169     // Check that a 1x3 filter does not cause a spurious assert.
1170     SkScalar kernel[3] = {
1171         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
1172     };
1173     SkISize kernelSize = SkISize::Make(1, 3);
1174     SkScalar gain = SK_Scalar1, bias = 0;
1175     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1176 
1177     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1178             kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kRepeat, false, nullptr));
1179 
1180     SkBitmap result;
1181     int width = 16, height = 16;
1182     result.allocN32Pixels(width, height);
1183     SkCanvas canvas(result);
1184     canvas.clear(0);
1185 
1186     SkPaint paint;
1187     paint.setImageFilter(std::move(filter));
1188     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1189     canvas.drawRect(rect, paint);
1190 }
1191 
DEF_TEST(ImageFilterMatrixConvolutionBorder,reporter)1192 DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
1193     // Check that a filter with borders outside the target bounds
1194     // does not crash.
1195     SkScalar kernel[3] = {
1196         0, 0, 0,
1197     };
1198     SkISize kernelSize = SkISize::Make(3, 1);
1199     SkScalar gain = SK_Scalar1, bias = 0;
1200     SkIPoint kernelOffset = SkIPoint::Make(2, 0);
1201 
1202     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1203             kernelSize, kernel, gain, bias, kernelOffset, SkTileMode::kClamp, true, nullptr));
1204 
1205     SkBitmap result;
1206 
1207     int width = 10, height = 10;
1208     result.allocN32Pixels(width, height);
1209     SkCanvas canvas(result);
1210     canvas.clear(0);
1211 
1212     SkPaint filterPaint;
1213     filterPaint.setImageFilter(std::move(filter));
1214     SkRect bounds = SkRect::MakeIWH(1, 10);
1215     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
1216     SkPaint rectPaint;
1217     canvas.saveLayer(&bounds, &filterPaint);
1218     canvas.drawRect(rect, rectPaint);
1219     canvas.restore();
1220 }
1221 
test_big_kernel(skiatest::Reporter * reporter,GrRecordingContext * rContext)1222 static void test_big_kernel(skiatest::Reporter* reporter, GrRecordingContext* rContext) {
1223     // Check that a kernel that is too big for the GPU still works
1224     SkScalar identityKernel[49] = {
1225         0, 0, 0, 0, 0, 0, 0,
1226         0, 0, 0, 0, 0, 0, 0,
1227         0, 0, 0, 0, 0, 0, 0,
1228         0, 0, 0, 1, 0, 0, 0,
1229         0, 0, 0, 0, 0, 0, 0,
1230         0, 0, 0, 0, 0, 0, 0,
1231         0, 0, 0, 0, 0, 0, 0
1232     };
1233     SkISize kernelSize = SkISize::Make(7, 7);
1234     SkScalar gain = SK_Scalar1, bias = 0;
1235     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
1236 
1237     sk_sp<SkImageFilter> filter(SkImageFilters::MatrixConvolution(
1238             kernelSize, identityKernel, gain, bias, kernelOffset,
1239             SkTileMode::kClamp, true, nullptr));
1240 
1241     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
1242     SkASSERT(srcImg);
1243 
1244     SkIPoint offset;
1245     skif::Context ctx = make_context(100, 100, srcImg.get());
1246     sk_sp<SkSpecialImage> resultImg(as_IFB(filter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1247     REPORTER_ASSERT(reporter, resultImg);
1248     REPORTER_ASSERT(reporter, SkToBool(rContext) == resultImg->isGaneshBacked());
1249     REPORTER_ASSERT(reporter, resultImg->width() == 100 && resultImg->height() == 100);
1250     REPORTER_ASSERT(reporter, offset.fX == 0 && offset.fY == 0);
1251 }
1252 
DEF_TEST(ImageFilterMatrixConvolutionBigKernel,reporter)1253 DEF_TEST(ImageFilterMatrixConvolutionBigKernel, reporter) {
1254     test_big_kernel(reporter, nullptr);
1255 }
1256 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1257 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMatrixConvolutionBigKernel_Gpu,
1258                                        reporter,
1259                                        ctxInfo,
1260                                        CtsEnforcement::kNever) {
1261     test_big_kernel(reporter, ctxInfo.directContext());
1262 }
1263 
DEF_TEST(ImageFilterCropRect,reporter)1264 DEF_TEST(ImageFilterCropRect, reporter) {
1265     test_cropRects(reporter, nullptr);
1266 }
1267 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1268 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterCropRect_Gpu,
1269                                        reporter,
1270                                        ctxInfo,
1271                                        CtsEnforcement::kNever) {
1272     test_cropRects(reporter, ctxInfo.directContext());
1273 }
1274 
DEF_TEST(ImageFilterMatrix,reporter)1275 DEF_TEST(ImageFilterMatrix, reporter) {
1276     SkBitmap temp;
1277     temp.allocN32Pixels(100, 100);
1278     SkCanvas canvas(temp);
1279     canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
1280 
1281     const SkM44 expectedMatrix = canvas.getLocalToDevice();
1282 
1283     SkRTreeFactory factory;
1284     SkPictureRecorder recorder;
1285     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory);
1286 
1287     SkPaint paint;
1288     paint.setImageFilter(sk_sp<SkImageFilter>(new MatrixTestImageFilter(reporter, expectedMatrix)));
1289     recordingCanvas->saveLayer(nullptr, &paint);
1290     SkPaint solidPaint;
1291     solidPaint.setColor(0xFFFFFFFF);
1292     recordingCanvas->save();
1293     recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
1294     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
1295     recordingCanvas->restore(); // scale
1296     recordingCanvas->restore(); // saveLayer
1297 
1298     canvas.drawPicture(recorder.finishRecordingAsPicture());
1299 }
1300 
test_clipped_picture_imagefilter(skiatest::Reporter * reporter,GrRecordingContext * rContext)1301 static void test_clipped_picture_imagefilter(skiatest::Reporter* reporter,
1302                                              GrRecordingContext* rContext) {
1303     sk_sp<SkPicture> picture;
1304 
1305     {
1306         SkRTreeFactory factory;
1307         SkPictureRecorder recorder;
1308         SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory);
1309 
1310         // Create an SkPicture which simply draws a green 1x1 rectangle.
1311         SkPaint greenPaint;
1312         greenPaint.setColor(SK_ColorGREEN);
1313         recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
1314         picture = recorder.finishRecordingAsPicture();
1315     }
1316 
1317     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 2));
1318 
1319     sk_sp<SkImageFilter> imageFilter(SkImageFilters::Picture(picture));
1320 
1321     SkIPoint offset;
1322     skif::Context ctx = make_context(SkIRect::MakeXYWH(1,1,1,1), srcImg.get());
1323 
1324     sk_sp<SkSpecialImage> resultImage(
1325             as_IFB(imageFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1326     REPORTER_ASSERT(reporter, !resultImage);
1327 }
1328 
DEF_TEST(ImageFilterClippedPictureImageFilter,reporter)1329 DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
1330     test_clipped_picture_imagefilter(reporter, nullptr);
1331 }
1332 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1333 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterClippedPictureImageFilter_Gpu,
1334                                        reporter,
1335                                        ctxInfo,
1336                                        CtsEnforcement::kNever) {
1337     test_clipped_picture_imagefilter(reporter, ctxInfo.directContext());
1338 }
1339 
DEF_TEST(ImageFilterEmptySaveLayer,reporter)1340 DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
1341     // Even when there's an empty saveLayer()/restore(), ensure that an image
1342     // filter or color filter which affects transparent black still draws.
1343 
1344     SkBitmap bitmap;
1345     bitmap.allocN32Pixels(10, 10);
1346     SkCanvas canvas(bitmap);
1347 
1348     SkRTreeFactory factory;
1349     SkPictureRecorder recorder;
1350 
1351     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrc));
1352     sk_sp<SkImageFilter> imageFilter(SkImageFilters::ColorFilter(green, nullptr));
1353     SkPaint imageFilterPaint;
1354     imageFilterPaint.setImageFilter(std::move(imageFilter));
1355     SkPaint colorFilterPaint;
1356     colorFilterPaint.setColorFilter(green);
1357 
1358     SkRect bounds = SkRect::MakeIWH(10, 10);
1359 
1360     SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory);
1361     recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
1362     recordingCanvas->restore();
1363     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1364 
1365     canvas.clear(0);
1366     canvas.drawPicture(picture);
1367     uint32_t pixel = *bitmap.getAddr32(0, 0);
1368     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1369 
1370     recordingCanvas = recorder.beginRecording(10, 10, &factory);
1371     recordingCanvas->saveLayer(nullptr, &imageFilterPaint);
1372     recordingCanvas->restore();
1373     sk_sp<SkPicture> picture2(recorder.finishRecordingAsPicture());
1374 
1375     canvas.clear(0);
1376     canvas.drawPicture(picture2);
1377     pixel = *bitmap.getAddr32(0, 0);
1378     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1379 
1380     recordingCanvas = recorder.beginRecording(10, 10, &factory);
1381     recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
1382     recordingCanvas->restore();
1383     sk_sp<SkPicture> picture3(recorder.finishRecordingAsPicture());
1384 
1385     canvas.clear(0);
1386     canvas.drawPicture(picture3);
1387     pixel = *bitmap.getAddr32(0, 0);
1388     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1389 }
1390 
test_huge_blur(SkCanvas * canvas,skiatest::Reporter * reporter)1391 static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) {
1392     SkBitmap bitmap;
1393     bitmap.allocN32Pixels(100, 100);
1394     bitmap.eraseARGB(0, 0, 0, 0);
1395 
1396     // Check that a blur with a very large radius does not crash or assert.
1397     SkPaint paint;
1398     paint.setImageFilter(SkImageFilters::Blur(SkIntToScalar(1<<30), SkIntToScalar(1<<30), nullptr));
1399     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);
1400 }
1401 
DEF_TEST(HugeBlurImageFilter,reporter)1402 DEF_TEST(HugeBlurImageFilter, reporter) {
1403     SkBitmap temp;
1404     temp.allocN32Pixels(100, 100);
1405     SkCanvas canvas(temp);
1406     test_huge_blur(&canvas, reporter);
1407 }
1408 
DEF_TEST(ImageFilterMatrixConvolutionTest,reporter)1409 DEF_TEST(ImageFilterMatrixConvolutionTest, reporter) {
1410     SkScalar kernel[1] = { 0 };
1411     SkScalar gain = SK_Scalar1, bias = 0;
1412     SkIPoint kernelOffset = SkIPoint::Make(1, 1);
1413 
1414     // Check that an enormous (non-allocatable) kernel gives a nullptr filter.
1415     sk_sp<SkImageFilter> conv(SkImageFilters::MatrixConvolution(
1416             SkISize::Make(1<<30, 1<<30), kernel, gain, bias, kernelOffset,
1417             SkTileMode::kRepeat, false, nullptr));
1418 
1419     REPORTER_ASSERT(reporter, nullptr == conv.get());
1420 
1421     // Check that a nullptr kernel gives a nullptr filter.
1422     conv = SkImageFilters::MatrixConvolution(
1423             SkISize::Make(1, 1), nullptr, gain, bias, kernelOffset,
1424             SkTileMode::kRepeat, false, nullptr);
1425 
1426     REPORTER_ASSERT(reporter, nullptr == conv.get());
1427 
1428     // Check that a kernel width < 1 gives a nullptr filter.
1429     conv = SkImageFilters::MatrixConvolution(
1430             SkISize::Make(0, 1), kernel, gain, bias, kernelOffset,
1431             SkTileMode::kRepeat, false, nullptr);
1432 
1433     REPORTER_ASSERT(reporter, nullptr == conv.get());
1434 
1435     // Check that kernel height < 1 gives a nullptr filter.
1436     conv = SkImageFilters::MatrixConvolution(
1437             SkISize::Make(1, -1), kernel, gain, bias, kernelOffset,
1438             SkTileMode::kRepeat, false, nullptr);
1439 
1440     REPORTER_ASSERT(reporter, nullptr == conv.get());
1441 }
1442 
test_xfermode_cropped_input(SkSurface * surf,skiatest::Reporter * reporter)1443 static void test_xfermode_cropped_input(SkSurface* surf, skiatest::Reporter* reporter) {
1444     auto canvas = surf->getCanvas();
1445     canvas->clear(SK_ColorRED);
1446 
1447     SkBitmap bitmap;
1448     bitmap.allocN32Pixels(1, 1);
1449     bitmap.eraseARGB(255, 255, 255, 255);
1450 
1451     sk_sp<SkColorFilter> green(SkColorFilters::Blend(SK_ColorGREEN, SkBlendMode::kSrcIn));
1452     sk_sp<SkImageFilter> greenFilter(SkImageFilters::ColorFilter(green, nullptr));
1453     SkIRect cropRect = SkIRect::MakeEmpty();
1454     sk_sp<SkImageFilter> croppedOut(SkImageFilters::ColorFilter(green, nullptr, &cropRect));
1455 
1456     // Check that an blend image filter whose input has been cropped out still draws the other
1457     // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
1458     SkBlendMode mode = SkBlendMode::kSrcOver;
1459     sk_sp<SkImageFilter> xfermodeNoFg(SkImageFilters::Blend(
1460             mode, greenFilter, croppedOut, nullptr));
1461     sk_sp<SkImageFilter> xfermodeNoBg(SkImageFilters::Blend(
1462             mode, croppedOut, greenFilter, nullptr));
1463     sk_sp<SkImageFilter> xfermodeNoFgNoBg(SkImageFilters::Blend(
1464             mode, croppedOut,  croppedOut, nullptr));
1465 
1466     SkPaint paint;
1467     paint.setImageFilter(std::move(xfermodeNoFg));
1468     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);   // drawSprite
1469 
1470     // xfermodeNoFg is a src-over blend between a green image and a transparent black image,
1471     // so should just be green.
1472     uint32_t pixel;
1473     SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1474     surf->readPixels(info, &pixel, 4, 0, 0);
1475     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1476 
1477     // xfermodeNoBg is the reverse of the above, but because it's src-over the final blend
1478     // between transparent black and green is still green.
1479     canvas->clear(SK_ColorRED); // should be overwritten
1480     paint.setImageFilter(std::move(xfermodeNoBg));
1481     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);   // drawSprite
1482     surf->readPixels(info, &pixel, 4, 0, 0);
1483     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1484 
1485     // xfermodeNoFgNoBg is a src-over blend of two empty images, so should produce no change
1486     // to the image.
1487     canvas->clear(SK_ColorRED); // should not be overwritten
1488     paint.setImageFilter(std::move(xfermodeNoFgNoBg));
1489     canvas->drawImage(bitmap.asImage(), 0, 0, SkSamplingOptions(), &paint);   // drawSprite
1490     surf->readPixels(info, &pixel, 4, 0, 0);
1491     REPORTER_ASSERT(reporter, pixel == SK_ColorRED);
1492 }
1493 
DEF_TEST(ImageFilterNestedSaveLayer,reporter)1494 DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
1495     SkBitmap temp;
1496     temp.allocN32Pixels(50, 50);
1497     SkCanvas canvas(temp);
1498     canvas.clear(0x0);
1499 
1500     SkBitmap bitmap;
1501     bitmap.allocN32Pixels(10, 10);
1502     bitmap.eraseColor(SK_ColorGREEN);
1503 
1504     SkMatrix matrix;
1505     matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
1506     matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
1507     sk_sp<SkImageFilter> matrixFilter(
1508         SkImageFilters::MatrixTransform(matrix, SkSamplingOptions(SkFilterMode::kLinear), nullptr));
1509 
1510     // Test that saveLayer() with a filter nested inside another saveLayer() applies the
1511     // correct offset to the filter matrix.
1512     SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
1513     canvas.saveLayer(&bounds1, nullptr);
1514     SkPaint filterPaint;
1515     filterPaint.setImageFilter(std::move(matrixFilter));
1516     SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
1517     canvas.saveLayer(&bounds2, &filterPaint);
1518     SkPaint greenPaint;
1519     greenPaint.setColor(SK_ColorGREEN);
1520     canvas.drawRect(bounds2, greenPaint);
1521     canvas.restore();
1522     canvas.restore();
1523     SkPaint strokePaint;
1524     strokePaint.setStyle(SkPaint::kStroke_Style);
1525     strokePaint.setColor(SK_ColorRED);
1526 
1527     SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType);
1528     uint32_t pixel;
1529     temp.readPixels(info, &pixel, 4, 25, 25);
1530     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1531 
1532     // Test that drawSprite() with a filter nested inside a saveLayer() applies the
1533     // correct offset to the filter matrix.
1534     canvas.clear(0x0);
1535     temp.readPixels(info, &pixel, 4, 25, 25);
1536     canvas.saveLayer(&bounds1, nullptr);
1537     canvas.drawImage(bitmap.asImage(), 20, 20, SkSamplingOptions(), &filterPaint); // drawSprite
1538     canvas.restore();
1539 
1540     temp.readPixels(info, &pixel, 4, 25, 25);
1541     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
1542 }
1543 
DEF_TEST(XfermodeImageFilterCroppedInput,reporter)1544 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
1545     test_xfermode_cropped_input(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)).get(),
1546                                 reporter);
1547 }
1548 
test_composed_imagefilter_offset(skiatest::Reporter * reporter,GrRecordingContext * rContext)1549 static void test_composed_imagefilter_offset(skiatest::Reporter* reporter,
1550                                              GrRecordingContext* rContext) {
1551     sk_sp<SkSpecialImage> srcImg(create_empty_special_image(rContext, 100));
1552 
1553     SkIRect cropRect = SkIRect::MakeXYWH(1, 0, 20, 20);
1554     sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(0, 0, nullptr, &cropRect));
1555     sk_sp<SkImageFilter> blurFilter(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1556                                                             nullptr, &cropRect));
1557     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(blurFilter),
1558                                                                 std::move(offsetFilter)));
1559     SkIPoint offset;
1560     skif::Context ctx = make_context(100, 100, srcImg.get());
1561 
1562     sk_sp<SkSpecialImage> resultImg(
1563             as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1564     REPORTER_ASSERT(reporter, resultImg);
1565     REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0);
1566 }
1567 
DEF_TEST(ComposedImageFilterOffset,reporter)1568 DEF_TEST(ComposedImageFilterOffset, reporter) {
1569     test_composed_imagefilter_offset(reporter, nullptr);
1570 }
1571 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1572 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterOffset_Gpu,
1573                                        reporter,
1574                                        ctxInfo,
1575                                        CtsEnforcement::kNever) {
1576     test_composed_imagefilter_offset(reporter, ctxInfo.directContext());
1577 }
1578 
test_composed_imagefilter_bounds(skiatest::Reporter * reporter,GrDirectContext * dContext)1579 static void test_composed_imagefilter_bounds(skiatest::Reporter* reporter,
1580                                              GrDirectContext* dContext) {
1581     // The bounds passed to the inner filter must be filtered by the outer
1582     // filter, so that the inner filter produces the pixels that the outer
1583     // filter requires as input. This matters if the outer filter moves pixels.
1584     // Here, accounting for the outer offset is necessary so that the green
1585     // pixels of the picture are not clipped.
1586 
1587     SkPictureRecorder recorder;
1588     SkCanvas* recordingCanvas = recorder.beginRecording(SkRect::MakeIWH(200, 100));
1589     recordingCanvas->clipRect(SkRect::MakeXYWH(100, 0, 100, 100));
1590     recordingCanvas->clear(SK_ColorGREEN);
1591     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
1592     sk_sp<SkImageFilter> pictureFilter(SkImageFilters::Picture(picture));
1593     SkIRect cropRect = SkIRect::MakeWH(100, 100);
1594     sk_sp<SkImageFilter> offsetFilter(SkImageFilters::Offset(-100, 0, nullptr, &cropRect));
1595     sk_sp<SkImageFilter> composedFilter(SkImageFilters::Compose(std::move(offsetFilter),
1596                                                                 std::move(pictureFilter)));
1597 
1598     sk_sp<SkSpecialImage> sourceImage(create_empty_special_image(dContext, 100));
1599     skif::Context ctx = make_context(100, 100, sourceImage.get());
1600 
1601     SkIPoint offset;
1602     sk_sp<SkSpecialImage> result(
1603             as_IFB(composedFilter)->filterImage(ctx).imageAndOffset(ctx, &offset));
1604     REPORTER_ASSERT(reporter, offset.isZero());
1605     REPORTER_ASSERT(reporter, result);
1606     REPORTER_ASSERT(reporter, result->subset().size() == SkISize::Make(100, 100));
1607 
1608     SkBitmap resultBM;
1609     REPORTER_ASSERT(reporter, special_image_to_bitmap(dContext, result.get(), &resultBM));
1610     REPORTER_ASSERT(reporter, resultBM.getColor(50, 50) == SK_ColorGREEN);
1611 }
1612 
DEF_TEST(ComposedImageFilterBounds,reporter)1613 DEF_TEST(ComposedImageFilterBounds, reporter) {
1614     test_composed_imagefilter_bounds(reporter, nullptr);
1615 }
1616 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1617 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ComposedImageFilterBounds_Gpu,
1618                                        reporter,
1619                                        ctxInfo,
1620                                        CtsEnforcement::kNever) {
1621     test_composed_imagefilter_bounds(reporter, ctxInfo.directContext());
1622 }
1623 
DEF_TEST(ImageFilterCanComputeFastBounds,reporter)1624 DEF_TEST(ImageFilterCanComputeFastBounds, reporter) {
1625 
1626     {
1627         SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1);
1628         sk_sp<SkImageFilter> lighting(SkImageFilters::PointLitDiffuse(
1629                 location,  SK_ColorGREEN, 0, 0, nullptr));
1630         REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds());
1631     }
1632 
1633     {
1634         sk_sp<SkImageFilter> gray(make_grayscale(nullptr, nullptr));
1635         REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1636         {
1637             SkColorFilter* grayCF;
1638             REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF));
1639             REPORTER_ASSERT(reporter, !as_CFB(grayCF)->affectsTransparentBlack());
1640             grayCF->unref();
1641         }
1642         REPORTER_ASSERT(reporter, gray->canComputeFastBounds());
1643 
1644         sk_sp<SkImageFilter> grayBlur(SkImageFilters::Blur(
1645                 SK_Scalar1, SK_Scalar1, std::move(gray)));
1646         REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds());
1647     }
1648 
1649     {
1650         float greenMatrix[20] = { 0, 0, 0, 0, 0,
1651                                   0, 0, 0, 0, 1.0f/255,
1652                                   0, 0, 0, 0, 0,
1653                                   0, 0, 0, 0, 1.0f/255
1654         };
1655         sk_sp<SkColorFilter> greenCF(SkColorFilters::Matrix(greenMatrix));
1656         sk_sp<SkImageFilter> green(SkImageFilters::ColorFilter(greenCF, nullptr));
1657 
1658         REPORTER_ASSERT(reporter, as_CFB(greenCF)->affectsTransparentBlack());
1659         REPORTER_ASSERT(reporter, !green->canComputeFastBounds());
1660 
1661         sk_sp<SkImageFilter> greenBlur(SkImageFilters::Blur(SK_Scalar1, SK_Scalar1,
1662                                                                std::move(green)));
1663         REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds());
1664     }
1665 
1666     uint8_t allOne[256], identity[256];
1667     for (int i = 0; i < 256; ++i) {
1668         identity[i] = i;
1669         allOne[i] = 255;
1670     }
1671 
1672     sk_sp<SkColorFilter> identityCF(SkColorFilters::TableARGB(identity, identity,
1673                                                               identity, allOne));
1674     sk_sp<SkImageFilter> identityFilter(SkImageFilters::ColorFilter(identityCF, nullptr));
1675     REPORTER_ASSERT(reporter, !as_CFB(identityCF)->affectsTransparentBlack());
1676     REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds());
1677 
1678     sk_sp<SkColorFilter> forceOpaqueCF(SkColorFilters::TableARGB(allOne, identity,
1679                                                                  identity, identity));
1680     sk_sp<SkImageFilter> forceOpaque(SkImageFilters::ColorFilter(forceOpaqueCF, nullptr));
1681     REPORTER_ASSERT(reporter, as_CFB(forceOpaqueCF)->affectsTransparentBlack());
1682     REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds());
1683 }
1684 
1685 // Verify that SkImageSource survives serialization
DEF_TEST(ImageFilterImageSourceSerialization,reporter)1686 DEF_TEST(ImageFilterImageSourceSerialization, reporter) {
1687     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(10, 10)));
1688     surface->getCanvas()->clear(SK_ColorGREEN);
1689     sk_sp<SkImage> image(surface->makeImageSnapshot());
1690     sk_sp<SkImageFilter> filter(SkImageFilters::Image(std::move(image), SkFilterMode::kNearest));
1691 
1692     SkSerialProcs sProcs;
1693     sProcs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
1694         return SkPngEncoder::Encode(as_IB(img)->directContext(), img, SkPngEncoder::Options{});
1695     };
1696     sk_sp<SkData> data(filter->serialize(&sProcs));
1697     sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1698     REPORTER_ASSERT(reporter, unflattenedFilter);
1699 
1700     SkBitmap bm;
1701     bm.allocN32Pixels(10, 10);
1702     bm.eraseColor(SK_ColorBLUE);
1703     SkPaint paint;
1704     paint.setColor(SK_ColorRED);
1705     paint.setImageFilter(unflattenedFilter);
1706 
1707     SkCanvas canvas(bm);
1708     canvas.drawRect(SkRect::MakeIWH(10, 10), paint);
1709     REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN));
1710 }
1711 
DEF_TEST(ImageFilterImageSourceUninitialized,r)1712 DEF_TEST(ImageFilterImageSourceUninitialized, r) {
1713     sk_sp<SkData> data(GetResourceAsData("crbug769134.fil"));
1714     if (!data) {
1715         return;
1716     }
1717     sk_sp<SkImageFilter> unflattenedFilter = SkImageFilter::Deserialize(data->data(), data->size());
1718     // This will fail. More importantly, msan will verify that we did not
1719     // compare against uninitialized memory.
1720     REPORTER_ASSERT(r, !unflattenedFilter);
1721 }
1722 
test_large_blur_input(skiatest::Reporter * reporter,SkCanvas * canvas)1723 static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) {
1724     SkBitmap largeBmp;
1725     int largeW = 5000;
1726     int largeH = 5000;
1727     // If we're GPU-backed make the bitmap too large to be converted into a texture.
1728     if (auto ctx = canvas->recordingContext()) {
1729         largeW = ctx->priv().caps()->maxTextureSize() + 1;
1730     }
1731 
1732     largeBmp.allocN32Pixels(largeW, largeH);
1733     largeBmp.eraseColor(0);
1734     if (!largeBmp.getPixels()) {
1735         ERRORF(reporter, "Failed to allocate large bmp.");
1736         return;
1737     }
1738 
1739     sk_sp<SkImage> largeImage(largeBmp.asImage());
1740     if (!largeImage) {
1741         ERRORF(reporter, "Failed to create large image.");
1742         return;
1743     }
1744 
1745     sk_sp<SkImageFilter> largeSource(SkImageFilters::Image(std::move(largeImage), {}));
1746     if (!largeSource) {
1747         ERRORF(reporter, "Failed to create large SkImageSource.");
1748         return;
1749     }
1750 
1751     sk_sp<SkImageFilter> blur(SkImageFilters::Blur(10.f, 10.f, std::move(largeSource)));
1752     if (!blur) {
1753         ERRORF(reporter, "Failed to create SkBlurImageFilter.");
1754         return;
1755     }
1756 
1757     SkPaint paint;
1758     paint.setImageFilter(std::move(blur));
1759 
1760     // This should not crash (http://crbug.com/570479).
1761     canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint);
1762 }
1763 
DEF_TEST(ImageFilterBlurLargeImage,reporter)1764 DEF_TEST(ImageFilterBlurLargeImage, reporter) {
1765     auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)));
1766     test_large_blur_input(reporter, surface->getCanvas());
1767 }
1768 
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)1769 static void test_make_with_filter(
1770         skiatest::Reporter* reporter,
1771         const std::function<sk_sp<SkSurface>(int width, int height)>& createSurface,
1772         const std::function<sk_sp<SkImage>(sk_sp<SkImage> src,
1773                                            const SkImageFilter* filter,
1774                                            const SkIRect& subset,
1775                                            const SkIRect& clipBounds,
1776                                            SkIRect* outSubset,
1777                                            SkIPoint* offset)>& makeWithFilter) {
1778     sk_sp<SkSurface> surface(createSurface(192, 128));
1779     surface->getCanvas()->clear(SK_ColorRED);
1780     SkPaint bluePaint;
1781     bluePaint.setColor(SK_ColorBLUE);
1782     SkIRect subset = SkIRect::MakeXYWH(25, 20, 50, 50);
1783     surface->getCanvas()->drawRect(SkRect::Make(subset), bluePaint);
1784     sk_sp<SkImage> sourceImage = surface->makeImageSnapshot();
1785 
1786     sk_sp<SkImageFilter> filter = make_grayscale(nullptr, nullptr);
1787     SkIRect clipBounds = SkIRect::MakeXYWH(30, 35, 100, 100);
1788     SkIRect outSubset;
1789     SkIPoint offset;
1790     sk_sp<SkImage> result;
1791 
1792     result = makeWithFilter(sourceImage, nullptr, subset, clipBounds, &outSubset, &offset);
1793     REPORTER_ASSERT(reporter, !result);  // filter is required
1794 
1795     result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, nullptr, &offset);
1796     REPORTER_ASSERT(reporter, !result);  // outSubset is required
1797 
1798     result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, &outSubset, nullptr);
1799     REPORTER_ASSERT(reporter, !result);  // offset is required
1800 
1801     SkIRect bigSubset = SkIRect::MakeXYWH(-10000, -10000, 20000, 20000);
1802     result = makeWithFilter(sourceImage, filter.get(), bigSubset, clipBounds, &outSubset, &offset);
1803     REPORTER_ASSERT(reporter, !result);  // subset needs to be w/in source's bounds
1804 
1805     const SkIRect kEmpty = SkIRect::MakeEmpty();
1806     result = makeWithFilter(sourceImage, filter.get(), kEmpty, clipBounds, &outSubset, &offset);
1807     REPORTER_ASSERT(reporter, !result);  // subset can't be empty
1808 
1809     result = makeWithFilter(sourceImage, filter.get(), subset, kEmpty, &outSubset, &offset);
1810     REPORTER_ASSERT(reporter, !result);  // clipBounds can't be empty
1811 
1812     const SkIRect kLeftField = SkIRect::MakeXYWH(-1000, 0, 100, 100);
1813     result = makeWithFilter(sourceImage, filter.get(), subset, kLeftField, &outSubset, &offset);
1814     REPORTER_ASSERT(reporter, !result);
1815 
1816     result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, &outSubset, &offset);
1817 
1818     REPORTER_ASSERT(reporter, result);
1819     REPORTER_ASSERT(reporter, result->bounds().contains(outSubset));
1820     SkIRect destRect = SkIRect::MakeXYWH(offset.x(), offset.y(),
1821                                          outSubset.width(), outSubset.height());
1822     REPORTER_ASSERT(reporter, clipBounds.contains(destRect));
1823 
1824     // In GPU-mode, this case creates a special image with a backing size that differs from
1825     // the content size
1826     {
1827         clipBounds.setXYWH(0, 0, 170, 100);
1828         subset.setXYWH(0, 0, 160, 90);
1829 
1830         filter = SkImageFilters::Blend(SkBlendMode::kSrcOver, nullptr);
1831         result = makeWithFilter(sourceImage, filter.get(), subset, clipBounds, &outSubset, &offset);
1832         REPORTER_ASSERT(reporter, result);
1833 
1834         // In Ganesh, we want the result image (and all intermediate steps) to have used the same
1835         // origin as the original surface.
1836         if (result && as_IB(result)->isGaneshBacked()) {
1837             SkImage_GaneshBase* base = static_cast<SkImage_GaneshBase*>(result.get());
1838             REPORTER_ASSERT(reporter, base->origin() == kTestSurfaceOrigin);
1839         }
1840     }
1841 }
1842 
DEF_TEST(ImageFilterMakeWithFilter,reporter)1843 DEF_TEST(ImageFilterMakeWithFilter, reporter) {
1844     auto createRasterSurface = [](int width, int height) -> sk_sp<SkSurface> {
1845         const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
1846         return SkSurfaces::Raster(info);
1847     };
1848 
1849     auto raster = [](sk_sp<SkImage> src,
1850                      const SkImageFilter* filter,
1851                      const SkIRect& subset,
1852                      const SkIRect& clipBounds,
1853                      SkIRect* outSubset,
1854                      SkIPoint* offset) -> sk_sp<SkImage> {
1855                          return SkImages::MakeWithFilter(std::move(src),
1856                                                          filter,
1857                                                          subset,
1858                                                          clipBounds,
1859                                                          outSubset,
1860                                                          offset);
1861                      };
1862 
1863     test_make_with_filter(reporter, createRasterSurface, raster);
1864 }
1865 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Ganesh,reporter,ctxInfo,CtsEnforcement::kNever)1866 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Ganesh,
1867                                        reporter,
1868                                        ctxInfo,
1869                                        CtsEnforcement::kNever) {
1870     GrRecordingContext* rContext = ctxInfo.directContext();
1871 
1872     auto createGaneshSurface = [rContext](int width, int height) -> sk_sp<SkSurface> {
1873         const SkImageInfo info = SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType);
1874         return SkSurfaces::RenderTarget(
1875                 rContext, skgpu::Budgeted::kNo, info, 0, kTestSurfaceOrigin, nullptr);
1876     };
1877 
1878     auto ganesh = [rContext](sk_sp<SkImage> src,
1879                              const SkImageFilter* filter,
1880                              const SkIRect& subset,
1881                              const SkIRect& clipBounds,
1882                              SkIRect* outSubset,
1883                              SkIPoint* offset) -> sk_sp<SkImage> {
1884          return SkImages::MakeWithFilter(rContext,
1885                                          std::move(src),
1886                                          filter,
1887                                          subset,
1888                                          clipBounds,
1889                                          outSubset,
1890                                          offset);
1891     };
1892 
1893     test_make_with_filter(reporter, createGaneshSurface, ganesh);
1894 }
1895 
1896 #if defined(SK_GRAPHITE)
1897 
DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Graphite,reporter,context,CtsEnforcement::kApiLevel_202404)1898 DEF_GRAPHITE_TEST_FOR_RENDERING_CONTEXTS(ImageFilterMakeWithFilter_Graphite,
1899                                          reporter,
1900                                          context,
1901                                          CtsEnforcement::kApiLevel_202404) {
1902     std::unique_ptr<skgpu::graphite::Recorder> recorder =
1903             context->makeRecorder(ToolUtils::CreateTestingRecorderOptions());
1904 
1905     auto createGraphiteSurface = [r = recorder.get()](int width, int height) -> sk_sp<SkSurface> {
1906         const SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType);
1907         return SkSurfaces::RenderTarget(r, info);
1908     };
1909 
1910     auto graphite = [r = recorder.get()](sk_sp<SkImage> src,
1911                                          const SkImageFilter* filter,
1912                                          const SkIRect& subset,
1913                                          const SkIRect& clipBounds,
1914                                          SkIRect* outSubset,
1915                                          SkIPoint* offset) -> sk_sp<SkImage> {
1916         return SkImages::MakeWithFilter(r,
1917                                         std::move(src),
1918                                         filter,
1919                                         subset,
1920                                         clipBounds,
1921                                         outSubset,
1922                                         offset);
1923     };
1924 
1925     test_make_with_filter(reporter, createGraphiteSurface, graphite);
1926 }
1927 
1928 #endif
1929 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1930 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterHugeBlur_Gpu,
1931                                        reporter,
1932                                        ctxInfo,
1933                                        CtsEnforcement::kNever) {
1934     sk_sp<SkSurface> surf(SkSurfaces::RenderTarget(
1935             ctxInfo.directContext(), skgpu::Budgeted::kNo, SkImageInfo::MakeN32Premul(100, 100)));
1936 
1937     SkCanvas* canvas = surf->getCanvas();
1938 
1939     test_huge_blur(canvas, reporter);
1940 }
1941 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1942 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(XfermodeImageFilterCroppedInput_Gpu,
1943                                        reporter,
1944                                        ctxInfo,
1945                                        CtsEnforcement::kNever) {
1946     sk_sp<SkSurface> surf(SkSurfaces::RenderTarget(
1947             ctxInfo.directContext(),
1948             skgpu::Budgeted::kNo,
1949             SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1950 
1951     test_xfermode_cropped_input(surf.get(), reporter);
1952 }
1953 
DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu,reporter,ctxInfo,CtsEnforcement::kNever)1954 DEF_GANESH_TEST_FOR_ALL_CONTEXTS(ImageFilterBlurLargeImage_Gpu,
1955                                  reporter,
1956                                  ctxInfo,
1957                                  CtsEnforcement::kNever) {
1958     auto surface(SkSurfaces::RenderTarget(
1959             ctxInfo.directContext(),
1960             skgpu::Budgeted::kYes,
1961             SkImageInfo::Make(100, 100, kRGBA_8888_SkColorType, kPremul_SkAlphaType)));
1962     test_large_blur_input(reporter, surface->getCanvas());
1963 }
1964 
1965 /*
1966  *  Test that colorfilterimagefilter does not require its CTM to be decomposed when it has more
1967  *  than just scale/translate, but that other filters do.
1968  */
DEF_TEST(ImageFilterComplexCTM,reporter)1969 DEF_TEST(ImageFilterComplexCTM, reporter) {
1970     // just need a colorfilter to exercise the corresponding imagefilter
1971     sk_sp<SkColorFilter> cf = SkColorFilters::Blend(SK_ColorRED, SkBlendMode::kSrcATop);
1972     sk_sp<SkImageFilter> cfif = SkImageFilters::ColorFilter(cf, nullptr);    // can handle
1973     sk_sp<SkImageFilter> blif = SkImageFilters::Blur(3, 3, nullptr);         // cannot handle
1974     using MatrixCapability = SkImageFilter_Base::MatrixCapability;
1975 
1976     struct {
1977         sk_sp<SkImageFilter> fFilter;
1978         MatrixCapability     fExpectCapability;
1979     } recs[] = {
1980         { cfif,                                  MatrixCapability::kComplex },
1981         { SkImageFilters::ColorFilter(cf, cfif), MatrixCapability::kComplex },
1982         { SkImageFilters::Merge(cfif, cfif),     MatrixCapability::kComplex },
1983         { SkImageFilters::Compose(cfif, cfif),   MatrixCapability::kComplex },
1984 
1985         { blif,                                  MatrixCapability::kScaleTranslate },
1986         { SkImageFilters::Blur(3, 3, cfif),      MatrixCapability::kScaleTranslate },
1987         { SkImageFilters::ColorFilter(cf, blif), MatrixCapability::kScaleTranslate },
1988         { SkImageFilters::Merge(cfif, blif),     MatrixCapability::kScaleTranslate },
1989         { SkImageFilters::Compose(blif, cfif),   MatrixCapability::kScaleTranslate },
1990     };
1991 
1992     for (const auto& rec : recs) {
1993         const MatrixCapability capability = as_IFB(rec.fFilter)->getCTMCapability();
1994         REPORTER_ASSERT(reporter, capability == rec.fExpectCapability);
1995     }
1996 }
1997 
1998 // Test SkXfermodeImageFilter::filterBounds with different blending modes.
DEF_TEST(XfermodeImageFilterBounds,reporter)1999 DEF_TEST(XfermodeImageFilterBounds, reporter) {
2000     SkIRect background_rect = SkIRect::MakeXYWH(0, 0, 100, 100);
2001     SkIRect foreground_rect = SkIRect::MakeXYWH(50, 50, 100, 100);
2002     sk_sp<SkImageFilter> background = SkImageFilters::Crop(SkRect::Make(background_rect), nullptr);
2003     sk_sp<SkImageFilter> foreground = SkImageFilters::Crop(SkRect::Make(foreground_rect), nullptr);
2004 
2005     SkIRect expectedBounds[kSkBlendModeCount];
2006     // Expect union of input rects by default.
2007     for (int i = 0; i < kSkBlendModeCount; ++i) {
2008         expectedBounds[i] = background_rect;
2009         expectedBounds[i].join(foreground_rect);
2010     }
2011 
2012     SkIRect intersection = background_rect;
2013     intersection.intersect(foreground_rect);
2014     expectedBounds[static_cast<int>(SkBlendMode::kClear)] = SkIRect::MakeEmpty();
2015     expectedBounds[static_cast<int>(SkBlendMode::kSrc)] = foreground_rect;
2016     expectedBounds[static_cast<int>(SkBlendMode::kDst)] = background_rect;
2017     expectedBounds[static_cast<int>(SkBlendMode::kSrcIn)] = intersection;
2018     expectedBounds[static_cast<int>(SkBlendMode::kDstIn)] = intersection;
2019     expectedBounds[static_cast<int>(SkBlendMode::kSrcOut)] = foreground_rect;
2020     expectedBounds[static_cast<int>(SkBlendMode::kDstOut)] = background_rect;
2021     expectedBounds[static_cast<int>(SkBlendMode::kSrcATop)] = background_rect;
2022     expectedBounds[static_cast<int>(SkBlendMode::kDstATop)] = foreground_rect;
2023     expectedBounds[static_cast<int>(SkBlendMode::kModulate)] = intersection;
2024 
2025     // Use a very large input bounds so that the crop rects stored in 'background' and 'foreground'
2026     // aren't restricted.
2027     SkIRect src = SkRectPriv::MakeILarge();
2028     for (int i = 0; i < kSkBlendModeCount; ++i) {
2029         sk_sp<SkImageFilter> xfermode(SkImageFilters::Blend(static_cast<SkBlendMode>(i),
2030                                                             background, foreground, nullptr));
2031         auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
2032                                              SkImageFilter::kForward_MapDirection, nullptr);
2033         REPORTER_ASSERT(reporter, bounds == expectedBounds[i]);
2034     }
2035 
2036     // Test empty intersection.
2037     sk_sp<SkImageFilter> background2 =
2038             SkImageFilters::Crop(SkRect::MakeXYWH(0, 0, 20, 20), nullptr);
2039     sk_sp<SkImageFilter> foreground2 =
2040             SkImageFilters::Crop(SkRect::MakeXYWH(40, 40, 50, 50), nullptr);
2041     sk_sp<SkImageFilter> xfermode(SkImageFilters::Blend(
2042             SkBlendMode::kSrcIn, std::move(background2), std::move(foreground2), nullptr));
2043     auto bounds = xfermode->filterBounds(src, SkMatrix::I(),
2044                                          SkImageFilter::kForward_MapDirection, nullptr);
2045     REPORTER_ASSERT(reporter, bounds.isEmpty());
2046 }
2047 
DEF_TEST(OffsetImageFilterBounds,reporter)2048 DEF_TEST(OffsetImageFilterBounds, reporter) {
2049     const SkIRect src = SkIRect::MakeXYWH(0, 0, 100, 100);
2050     const SkVector srcOffset = {-50.5f, -50.5f};
2051     sk_sp<SkImageFilter> offset(SkImageFilters::Offset(srcOffset.fX, srcOffset.fY, nullptr));
2052 
2053     // Because the offset has a fractional component, the final output and required input bounds
2054     // will be rounded out to include an extra pixel.
2055     SkIRect expectedForward = SkRect::Make(src).makeOffset(srcOffset.fX, srcOffset.fY).roundOut();
2056     SkIRect boundsForward = offset->filterBounds(src, SkMatrix::I(),
2057                                                  SkImageFilter::kForward_MapDirection, nullptr);
2058     REPORTER_ASSERT(reporter, boundsForward == expectedForward);
2059 
2060     SkIRect expectedReverse = SkRect::Make(src).makeOffset(-srcOffset.fX, -srcOffset.fY).roundOut();
2061 
2062     // Intersect 'expectedReverse' with the source because we are passing &src in as the known
2063     // input bounds, which is the bounds of non-transparent pixels that can be moved by the offset.
2064     // While the ::Offset filter could show all pixels inside 'expectedReverse' given that 'src'
2065     // is also the target device output of the filter, the required input can be made tighter.
2066     SkAssertResult(expectedReverse.intersect(src));
2067 
2068     SkIRect boundsReverse = offset->filterBounds(src, SkMatrix::I(),
2069                                                  SkImageFilter::kReverse_MapDirection, &src);
2070     REPORTER_ASSERT(reporter, boundsReverse == expectedReverse);
2071 }
2072 
DEF_TEST(OffsetImageFilterBoundsNoOverflow,reporter)2073 DEF_TEST(OffsetImageFilterBoundsNoOverflow, reporter) {
2074     const SkIRect src = SkIRect::MakeXYWH(-10.f, -10.f, 20.f, 20.f);
2075     const SkScalar bigOffset = SkIntToScalar(std::numeric_limits<int>::max()) * 2.f / 3.f;
2076 
2077     sk_sp<SkImageFilter> filter =
2078             SkImageFilters::Blend(SkBlendMode::kSrcOver,
2079                                   SkImageFilters::Offset(-bigOffset, -bigOffset, nullptr),
2080                                   SkImageFilters::Offset(bigOffset, bigOffset, nullptr));
2081     SkIRect boundsForward = filter->filterBounds(src, SkMatrix::I(),
2082                                                  SkImageFilter::kForward_MapDirection, nullptr);
2083     // NOTE: isEmpty() will return true even if the l/r or t/b didn't overflow but the dimensions
2084     // would overflow an int32. However, when isEmpty64() is false, it means the actual edge coords
2085     // are valid, which is good enough for our purposes (and gfx::Rect has its own strategies for
2086     // ensuring such a rectangle doesn't get accidentally treated as empty during chromium's
2087     // conversions).
2088     REPORTER_ASSERT(reporter, !boundsForward.isEmpty64());
2089 
2090     // When querying with unbounded input content, it should not overflow and should not be empty.
2091     SkIRect boundsReverse = filter->filterBounds(src, SkMatrix::I(),
2092                                                  SkImageFilter::kReverse_MapDirection, nullptr);
2093     REPORTER_ASSERT(reporter, !boundsReverse.isEmpty64());
2094 
2095     // However in this case, when 'src' is also passed as the content bounds, the ::Offset() filters
2096     // detect that they would be transparent black. This propagates up to the src-over blend and
2097     // the entire graph is identified as empty.
2098     boundsReverse = filter->filterBounds(src, SkMatrix::I(),
2099                                          SkImageFilter::kReverse_MapDirection, &src);
2100     REPORTER_ASSERT(reporter, boundsReverse.isEmpty64());
2101 }
2102 
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)2103 static void test_arithmetic_bounds(skiatest::Reporter* reporter, float k1, float k2, float k3,
2104                                    float k4, sk_sp<SkImageFilter> background,
2105                                    sk_sp<SkImageFilter> foreground,
2106                                    const SkIRect* crop, const SkIRect& expected) {
2107     sk_sp<SkImageFilter> arithmetic(SkImageFilters::Arithmetic(
2108             k1, k2, k3, k4, false, std::move(background), std::move(foreground), crop));
2109     // Use a very large input bounds so that the crop rects stored in 'background' and 'foreground'
2110     // aren't restricted.
2111     SkIRect src = SkRectPriv::MakeILarge();
2112     SkIRect bounds = arithmetic->filterBounds(src, SkMatrix::I(),
2113                                               SkImageFilter::kForward_MapDirection, nullptr);
2114     REPORTER_ASSERT(reporter, expected == bounds);
2115 }
2116 
test_arithmetic_combinations(skiatest::Reporter * reporter,float v)2117 static void test_arithmetic_combinations(skiatest::Reporter* reporter, float v) {
2118     SkIRect bgRect = SkIRect::MakeXYWH(0, 0, 100, 100);
2119     SkIRect fgRect = SkIRect::MakeXYWH(50, 50, 100, 100);
2120     sk_sp<SkImageFilter> background = SkImageFilters::Crop(SkRect::Make(bgRect), nullptr);
2121     sk_sp<SkImageFilter> foreground = SkImageFilters::Crop(SkRect::Make(fgRect), nullptr);
2122 
2123     SkIRect unionRect = bgRect;
2124     unionRect.join(fgRect);
2125     SkIRect intersection = bgRect;
2126     intersection.intersect(fgRect);
2127 
2128     // Test with crop. When k4 is non-zero, the result is expected to be cropRect
2129     // regardless of inputs because the filter affects the whole crop area. When there is no crop
2130     // rect, it should report an effectively infinite output.
2131     static const SkIRect kInf = SkRectPriv::MakeILarge();
2132     test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, nullptr,
2133                            SkIRect::MakeEmpty());
2134     test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, nullptr, kInf);
2135     test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, nullptr, bgRect);
2136     test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, nullptr, kInf);
2137     test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, nullptr, fgRect);
2138     test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, nullptr, kInf);
2139     test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, nullptr, unionRect);
2140     test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, nullptr, kInf);
2141     test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, nullptr, intersection);
2142     test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, nullptr, kInf);
2143     test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, nullptr, bgRect);
2144     test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, nullptr, kInf);
2145     test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, nullptr, fgRect);
2146     test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, nullptr, kInf);
2147     test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, nullptr, unionRect);
2148     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, nullptr, kInf);
2149 
2150     SkIRect cropRect = SkIRect::MakeXYWH(-111, -222, 333, 444);
2151     test_arithmetic_bounds(reporter, 0, 0, 0, 0, background, foreground, &cropRect,
2152                            SkIRect::MakeEmpty());
2153     test_arithmetic_bounds(reporter, 0, 0, 0, v, background, foreground, &cropRect, cropRect);
2154     test_arithmetic_bounds(reporter, 0, 0, v, 0, background, foreground, &cropRect, bgRect);
2155     test_arithmetic_bounds(reporter, 0, 0, v, v, background, foreground, &cropRect, cropRect);
2156     test_arithmetic_bounds(reporter, 0, v, 0, 0, background, foreground, &cropRect, fgRect);
2157     test_arithmetic_bounds(reporter, 0, v, 0, v, background, foreground, &cropRect, cropRect);
2158     test_arithmetic_bounds(reporter, 0, v, v, 0, background, foreground, &cropRect, unionRect);
2159     test_arithmetic_bounds(reporter, 0, v, v, v, background, foreground, &cropRect, cropRect);
2160     test_arithmetic_bounds(reporter, v, 0, 0, 0, background, foreground, &cropRect, intersection);
2161     test_arithmetic_bounds(reporter, v, 0, 0, v, background, foreground, &cropRect, cropRect);
2162     test_arithmetic_bounds(reporter, v, 0, v, 0, background, foreground, &cropRect, bgRect);
2163     test_arithmetic_bounds(reporter, v, 0, v, v, background, foreground, &cropRect, cropRect);
2164     test_arithmetic_bounds(reporter, v, v, 0, 0, background, foreground, &cropRect, fgRect);
2165     test_arithmetic_bounds(reporter, v, v, 0, v, background, foreground, &cropRect, cropRect);
2166     test_arithmetic_bounds(reporter, v, v, v, 0, background, foreground, &cropRect, unionRect);
2167     test_arithmetic_bounds(reporter, v, v, v, v, background, foreground, &cropRect, cropRect);
2168 }
2169 
2170 // Test SkArithmeticImageFilter::filterBounds with different blending modes.
DEF_TEST(ArithmeticImageFilterBounds,reporter)2171 DEF_TEST(ArithmeticImageFilterBounds, reporter) {
2172     test_arithmetic_combinations(reporter, 1);
2173     test_arithmetic_combinations(reporter, 0.5);
2174 }
2175 
2176 // Test SkDisplacementMapEffect::filterBounds.
DEF_TEST(DisplacementMapBounds,reporter)2177 DEF_TEST(DisplacementMapBounds, reporter) {
2178     SkIRect floodBounds(SkIRect::MakeXYWH(20, 30, 10, 10));
2179     sk_sp<SkImageFilter> flood(SkImageFilters::Shader(SkShaders::Color(SK_ColorGREEN),
2180                                                       &floodBounds));
2181     SkIRect tilingBounds(SkIRect::MakeXYWH(0, 0, 200, 100));
2182     sk_sp<SkImageFilter> tiling(SkImageFilters::Tile(SkRect::Make(floodBounds),
2183                                                      SkRect::Make(tilingBounds),
2184                                                      flood));
2185     sk_sp<SkImageFilter> displace(SkImageFilters::DisplacementMap(SkColorChannel::kR,
2186                                                                   SkColorChannel::kB,
2187                                                                   20.0f, nullptr, tiling));
2188 
2189     // The filter graph rooted at 'displace' uses the dynamic source image for the displacement
2190     // component of ::DisplacementMap, modifying the color component produced by the ::Tile. The
2191     // output of the tiling filter will be 'tilingBounds', regardless of its input, so 'floodBounds'
2192     // has no effect on the output. Since 'tiling' doesn't reference any dynamic source image, it
2193     // also will not affect the required input bounds. The displacement map is sampled 1-to-1
2194     // with the output pixels, and covers the output unless the color's output makes that impossible
2195     // and the output is a subset of the desired output. Thus, the displacement can impact the
2196     // reported output bounds.
2197     SkIRect input(SkIRect::MakeXYWH(20, 30, 40, 50));
2198 
2199     // 'input' is the desired output, which directly constrains the displacement component in this
2200     // specific filter graph.
2201     SkIRect actualInput = displace->filterBounds(input, SkMatrix::I(),
2202                                                  SkImageFilter::kReverse_MapDirection);
2203     REPORTER_ASSERT(reporter, input == actualInput);
2204 
2205     // 'input' is the content bounds, which don't affect output bounds because it's only referenced
2206     // by the displacement component and not the color component.
2207     SkIRect actualOutput = displace->filterBounds(input, SkMatrix::I(),
2208                                                   SkImageFilter::kForward_MapDirection);
2209     REPORTER_ASSERT(reporter, tilingBounds.makeOutset(10, 10) == actualOutput);
2210 }
2211 
2212 // Test SkImageSource::filterBounds.
DEF_TEST(ImageSourceBounds,reporter)2213 DEF_TEST(ImageSourceBounds, reporter) {
2214     sk_sp<SkImage> image(make_gradient_circle(64, 64).asImage());
2215     // Default src and dst rects.
2216     sk_sp<SkImageFilter> source1(SkImageFilters::Image(image, SkFilterMode::kNearest));
2217     SkIRect imageBounds = SkIRect::MakeWH(64, 64);
2218     SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2219     REPORTER_ASSERT(reporter,
2220                     imageBounds == source1->filterBounds(input, SkMatrix::I(),
2221                                                          SkImageFilter::kForward_MapDirection,
2222                                                          nullptr));
2223     REPORTER_ASSERT(reporter,
2224                     source1->filterBounds(input, SkMatrix::I(),
2225                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2226     SkMatrix scale(SkMatrix::Scale(2, 2));
2227     SkIRect scaledBounds = SkIRect::MakeWH(128, 128);
2228     REPORTER_ASSERT(reporter,
2229                     scaledBounds == source1->filterBounds(input, scale,
2230                                                           SkImageFilter::kForward_MapDirection,
2231                                                           nullptr));
2232     REPORTER_ASSERT(reporter,
2233                     source1->filterBounds(input, scale,
2234                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2235 
2236     // Specified src and dst rects (which are outside available pixels).
2237     SkRect src(SkRect::MakeXYWH(0.5, 0.5, 100.5, 100.5));
2238     SkRect dst(SkRect::MakeXYWH(-10.5, -10.5, 120.5, 120.5));
2239     sk_sp<SkImageFilter> source2(SkImageFilters::Image(image, src, dst,
2240                                                        SkSamplingOptions(SkFilterMode::kLinear,
2241                                                                          SkMipmapMode::kLinear)));
2242 
2243     SkRect clippedSrc = src;
2244     SkAssertResult(clippedSrc.intersect(SkRect::Make(image->dimensions())));
2245     SkRect clippedDst = SkMatrix::RectToRect(src, dst).mapRect(clippedSrc);
2246 
2247     REPORTER_ASSERT(reporter,
2248                     clippedDst.roundOut() ==
2249                     source2->filterBounds(input, SkMatrix::I(),
2250                                           SkImageFilter::kForward_MapDirection, nullptr));
2251     REPORTER_ASSERT(reporter,
2252                     source2->filterBounds(input, SkMatrix::I(),
2253                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2254     scale.mapRect(&clippedDst);
2255     scale.mapRect(&clippedSrc);
2256     REPORTER_ASSERT(reporter,
2257                     clippedDst.roundOut() ==
2258                     source2->filterBounds(input, scale,
2259                                           SkImageFilter::kForward_MapDirection, nullptr));
2260     REPORTER_ASSERT(reporter,
2261                     source2->filterBounds(input, scale,
2262                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2263 }
2264 
2265 // Test SkPictureImageFilter::filterBounds.
DEF_TEST(PictureImageSourceBounds,reporter)2266 DEF_TEST(PictureImageSourceBounds, reporter) {
2267     SkPictureRecorder recorder;
2268     SkCanvas* recordingCanvas = recorder.beginRecording(64, 64);
2269 
2270     SkPaint greenPaint;
2271     greenPaint.setColor(SK_ColorGREEN);
2272     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
2273     sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
2274 
2275     // Default target rect.
2276     sk_sp<SkImageFilter> source1(SkImageFilters::Picture(picture));
2277     SkIRect pictureBounds = SkIRect::MakeWH(64, 64);
2278     SkIRect input(SkIRect::MakeXYWH(10, 20, 30, 40));
2279     REPORTER_ASSERT(reporter,
2280                     pictureBounds == source1->filterBounds(input, SkMatrix::I(),
2281                                                            SkImageFilter::kForward_MapDirection,
2282                                                            nullptr));
2283     REPORTER_ASSERT(reporter,
2284                     source1->filterBounds(input, SkMatrix::I(),
2285                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2286     SkMatrix scale(SkMatrix::Scale(2, 2));
2287     SkIRect scaledPictureBounds = SkIRect::MakeWH(128, 128);
2288     REPORTER_ASSERT(reporter,
2289                     scaledPictureBounds == source1->filterBounds(input, scale,
2290                                                                  SkImageFilter::kForward_MapDirection,
2291                                                                  nullptr));
2292     REPORTER_ASSERT(reporter,
2293                     source1->filterBounds(input, scale,
2294                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2295 
2296     // Specified target rect.
2297     SkRect targetRect(SkRect::MakeXYWH(9.5, 9.5, 31, 21));
2298     sk_sp<SkImageFilter> source2(SkImageFilters::Picture(picture, targetRect));
2299     REPORTER_ASSERT(reporter,
2300                     targetRect.roundOut() == source2->filterBounds(input, SkMatrix::I(),
2301                                                                    SkImageFilter::kForward_MapDirection,
2302                                                                    nullptr));
2303     REPORTER_ASSERT(reporter,
2304                     source2->filterBounds(input, SkMatrix::I(),
2305                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2306     scale.mapRect(&targetRect);
2307     REPORTER_ASSERT(reporter,
2308                     targetRect.roundOut() == source2->filterBounds(input, scale,
2309                                                                    SkImageFilter::kForward_MapDirection,
2310                                                                    nullptr));
2311     REPORTER_ASSERT(reporter,
2312                     source2->filterBounds(input, scale,
2313                                           SkImageFilter::kReverse_MapDirection, &input).isEmpty());
2314 }
2315 
DEF_TEST(DropShadowImageFilter_Huge,reporter)2316 DEF_TEST(DropShadowImageFilter_Huge, reporter) {
2317     // Successful if it doesn't crash or trigger ASAN. (crbug.com/1264705)
2318     auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(300, 150));
2319 
2320     SkPaint paint;
2321     paint.setImageFilter(SkImageFilters::DropShadowOnly(
2322             0.0f, 0.437009f, 14129.6f, 14129.6f, SK_ColorGRAY, nullptr));
2323 
2324     surf->getCanvas()->saveLayer(nullptr, &paint);
2325     surf->getCanvas()->restore();
2326 }
2327 
DEF_TEST(DisplacementImageFilter_InvalidInputs_ReturnsNullptr,reporter)2328 DEF_TEST(DisplacementImageFilter_InvalidInputs_ReturnsNullptr, reporter) {
2329     sk_sp<SkImageFilter> valid(SkImageFilters::Shader(SkShaders::Color(SK_ColorGREEN)));
2330     REPORTER_ASSERT(reporter, valid != nullptr);
2331 
2332     REPORTER_ASSERT(
2333             reporter,
2334             nullptr == SkImageFilters::DisplacementMap(SkColorChannel::kR,
2335                                                        SkColorChannel::kB,
2336                                                        std::numeric_limits<float>::infinity(),
2337                                                        valid,
2338                                                        valid));
2339 
2340     REPORTER_ASSERT(reporter,
2341                     nullptr == SkImageFilters::DisplacementMap(static_cast<SkColorChannel>(22),
2342                                                                SkColorChannel::kB,
2343                                                                5.f,
2344                                                                valid,
2345                                                                valid));
2346 }
2347 
DEF_TEST(ImageFilter_DrawExtremeMatrixTransform_DoesNotAssert,reporter)2348 DEF_TEST(ImageFilter_DrawExtremeMatrixTransform_DoesNotAssert, reporter) {
2349     // Found by fuzzing
2350     SkPaint p;
2351     p.setDither(true);
2352     p.setColor(SkColorSetARGB(255, 1, 255, 255));
2353     p.setStyle(SkPaint::Style::kFill_Style);
2354 
2355     SkRRect rr = SkRRect::MakeRectXY({5, 10, 15, 20}, 2, 2);
2356 
2357     sk_sp<SkImageFilter> ifs[4];
2358     ifs[0] = nullptr;
2359     ifs[1] = SkImageFilters::Blur(SkBits2Float(0xe0e0e0e), SkBits2Float(0x10108000), nullptr);
2360     SkSamplingOptions sampling(SkFilterMode::kLinear, SkMipmapMode::kLinear);
2361     SkMatrix matrix = SkMatrix::MakeAll(SkBits2Float(0xfdfe0200),
2362                                         SkBits2Float(0xfdfdfdfd),
2363                                         SkBits2Float(0x2a0202fe),
2364                                         SkBits2Float(0x2020202),
2365                                         SkBits2Float(0x2020202),
2366                                         SkBits2Float(0x20200202),
2367                                         SkBits2Float(0x2fab0024),
2368                                         SkBits2Float(0x8),
2369                                         SkBits2Float(0x0));
2370     ifs[2] = SkImageFilters::MatrixTransform(matrix, sampling, nullptr);
2371     ifs[3] = SkImageFilters::Shader(nullptr);
2372     auto merged = SkImageFilters::Merge(ifs, 4, nullptr);
2373     p.setImageFilter(merged);
2374 
2375     auto surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(128, 160));
2376     surface->getCanvas()->clear(SK_ColorWHITE);
2377     surface->getCanvas()->drawRRect(rr, p);
2378 }
2379