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