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