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