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