1 2 /* 3 * Copyright 2013 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 #include "SkBitmap.h" 10 #include "SkBitmapDevice.h" 11 #include "SkBlurImageFilter.h" 12 #include "SkCanvas.h" 13 #include "SkColorFilterImageFilter.h" 14 #include "SkColorMatrixFilter.h" 15 #include "SkComposeImageFilter.h" 16 #include "SkDisplacementMapEffect.h" 17 #include "SkDropShadowImageFilter.h" 18 #include "SkFlattenableSerialization.h" 19 #include "SkGradientShader.h" 20 #include "SkImage.h" 21 #include "SkImageSource.h" 22 #include "SkLightingImageFilter.h" 23 #include "SkMatrixConvolutionImageFilter.h" 24 #include "SkMergeImageFilter.h" 25 #include "SkMorphologyImageFilter.h" 26 #include "SkOffsetImageFilter.h" 27 #include "SkPaintImageFilter.h" 28 #include "SkPerlinNoiseShader.h" 29 #include "SkPicture.h" 30 #include "SkPictureImageFilter.h" 31 #include "SkPictureRecorder.h" 32 #include "SkPoint3.h" 33 #include "SkReadBuffer.h" 34 #include "SkRect.h" 35 #include "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 #include "SkGpuDevice.h" 44 #endif 45 46 static const int kBitmapSize = 4; 47 48 namespace { 49 50 class MatrixTestImageFilter : public SkImageFilter { 51 public: 52 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix) 53 : SkImageFilter(0, nullptr), fReporter(reporter), fExpectedMatrix(expectedMatrix) { 54 } 55 56 bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context& ctx, 57 SkBitmap* result, SkIPoint* offset) const override { 58 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix); 59 return true; 60 } 61 62 SK_TO_STRING_OVERRIDE() 63 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter) 64 65 protected: 66 void flatten(SkWriteBuffer& buffer) const override { 67 this->INHERITED::flatten(buffer); 68 buffer.writeFunctionPtr(fReporter); 69 buffer.writeMatrix(fExpectedMatrix); 70 } 71 72 private: 73 skiatest::Reporter* fReporter; 74 SkMatrix fExpectedMatrix; 75 76 typedef SkImageFilter INHERITED; 77 }; 78 79 } 80 81 SkFlattenable* MatrixTestImageFilter::CreateProc(SkReadBuffer& buffer) { 82 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1); 83 skiatest::Reporter* reporter = (skiatest::Reporter*)buffer.readFunctionPtr(); 84 SkMatrix matrix; 85 buffer.readMatrix(&matrix); 86 return new MatrixTestImageFilter(reporter, matrix); 87 } 88 89 #ifndef SK_IGNORE_TO_STRING 90 void MatrixTestImageFilter::toString(SkString* str) const { 91 str->appendf("MatrixTestImageFilter: ("); 92 str->append(")"); 93 } 94 #endif 95 96 static SkImage* make_small_image() { 97 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(kBitmapSize, kBitmapSize)); 98 SkCanvas* canvas = surface->getCanvas(); 99 canvas->clear(0x00000000); 100 SkPaint darkPaint; 101 darkPaint.setColor(0xFF804020); 102 SkPaint lightPaint; 103 lightPaint.setColor(0xFF244484); 104 const int i = kBitmapSize / 4; 105 for (int y = 0; y < kBitmapSize; y += i) { 106 for (int x = 0; x < kBitmapSize; x += i) { 107 canvas->save(); 108 canvas->translate(SkIntToScalar(x), SkIntToScalar(y)); 109 canvas->drawRect(SkRect::MakeXYWH(0, 0, 110 SkIntToScalar(i), 111 SkIntToScalar(i)), darkPaint); 112 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i), 113 0, 114 SkIntToScalar(i), 115 SkIntToScalar(i)), lightPaint); 116 canvas->drawRect(SkRect::MakeXYWH(0, 117 SkIntToScalar(i), 118 SkIntToScalar(i), 119 SkIntToScalar(i)), lightPaint); 120 canvas->drawRect(SkRect::MakeXYWH(SkIntToScalar(i), 121 SkIntToScalar(i), 122 SkIntToScalar(i), 123 SkIntToScalar(i)), darkPaint); 124 canvas->restore(); 125 } 126 } 127 128 return surface->newImageSnapshot(); 129 } 130 131 static SkImageFilter* make_scale(float amount, SkImageFilter* input = nullptr) { 132 SkScalar s = amount; 133 SkScalar matrix[20] = { s, 0, 0, 0, 0, 134 0, s, 0, 0, 0, 135 0, 0, s, 0, 0, 136 0, 0, 0, s, 0 }; 137 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix)); 138 return SkColorFilterImageFilter::Create(filter, input); 139 } 140 141 static SkImageFilter* make_grayscale(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) { 142 SkScalar matrix[20]; 143 memset(matrix, 0, 20 * sizeof(SkScalar)); 144 matrix[0] = matrix[5] = matrix[10] = 0.2126f; 145 matrix[1] = matrix[6] = matrix[11] = 0.7152f; 146 matrix[2] = matrix[7] = matrix[12] = 0.0722f; 147 matrix[18] = 1.0f; 148 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix)); 149 return SkColorFilterImageFilter::Create(filter, input, cropRect); 150 } 151 152 static SkImageFilter* make_blue(SkImageFilter* input, const SkImageFilter::CropRect* cropRect) { 153 SkAutoTUnref<SkColorFilter> filter(SkColorFilter::CreateModeFilter(SK_ColorBLUE, 154 SkXfermode::kSrcIn_Mode)); 155 return SkColorFilterImageFilter::Create(filter, input, cropRect); 156 } 157 158 DEF_TEST(ImageFilter, reporter) { 159 { 160 // Check that two non-clipping color-matrice-filters concatenate into a single filter. 161 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f)); 162 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness)); 163 REPORTER_ASSERT(reporter, nullptr == quarterBrightness->getInput(0)); 164 SkColorFilter* cf; 165 REPORTER_ASSERT(reporter, quarterBrightness->asColorFilter(&cf)); 166 REPORTER_ASSERT(reporter, cf->asColorMatrix(nullptr)); 167 cf->unref(); 168 } 169 170 { 171 // Check that a clipping color-matrice-filter followed by a color-matrice-filters 172 // concatenates into a single filter, but not a matrixfilter (due to clamping). 173 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f)); 174 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness)); 175 REPORTER_ASSERT(reporter, nullptr == halfBrightness->getInput(0)); 176 SkColorFilter* cf; 177 REPORTER_ASSERT(reporter, halfBrightness->asColorFilter(&cf)); 178 REPORTER_ASSERT(reporter, !cf->asColorMatrix(nullptr)); 179 cf->unref(); 180 } 181 182 { 183 // Check that a color filter image filter without a crop rect can be 184 // expressed as a color filter. 185 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr)); 186 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr)); 187 } 188 189 { 190 // Check that a colorfilterimage filter without a crop rect but with an input 191 // that is another colorfilterimage can be expressed as a colorfilter (composed). 192 SkAutoTUnref<SkImageFilter> mode(make_blue(nullptr, nullptr)); 193 SkAutoTUnref<SkImageFilter> gray(make_grayscale(mode, nullptr)); 194 REPORTER_ASSERT(reporter, true == gray->asColorFilter(nullptr)); 195 } 196 197 { 198 // Test that if we exceed the limit of what ComposeColorFilter can combine, we still 199 // can build the DAG and won't assert if we call asColorFilter. 200 SkAutoTUnref<SkImageFilter> filter(make_blue(nullptr, nullptr)); 201 const int kWayTooManyForComposeColorFilter = 100; 202 for (int i = 0; i < kWayTooManyForComposeColorFilter; ++i) { 203 filter.reset(make_blue(filter, nullptr)); 204 // the first few of these will succeed, but after we hit the internal limit, 205 // it will then return false. 206 (void)filter->asColorFilter(nullptr); 207 } 208 } 209 210 { 211 // Check that a color filter image filter with a crop rect cannot 212 // be expressed as a color filter. 213 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100)); 214 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(nullptr, &cropRect)); 215 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(nullptr)); 216 } 217 218 { 219 // Check that two non-commutative matrices are concatenated in 220 // the correct order. 221 SkScalar blueToRedMatrix[20] = { 0 }; 222 blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1; 223 SkScalar redToGreenMatrix[20] = { 0 }; 224 redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1; 225 SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix)); 226 SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get())); 227 SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix)); 228 SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get())); 229 230 SkBitmap result; 231 result.allocN32Pixels(kBitmapSize, kBitmapSize); 232 233 SkPaint paint; 234 paint.setColor(SK_ColorBLUE); 235 paint.setImageFilter(filter2.get()); 236 SkCanvas canvas(result); 237 canvas.clear(0x0); 238 SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize)); 239 canvas.drawRect(rect, paint); 240 uint32_t pixel = *result.getAddr32(0, 0); 241 // The result here should be green, since we have effectively shifted blue to green. 242 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 243 } 244 245 { 246 // Tests pass by not asserting 247 SkAutoTUnref<SkImage> image(make_small_image()); 248 SkBitmap result; 249 result.allocN32Pixels(kBitmapSize, kBitmapSize); 250 251 { 252 // This tests for : 253 // 1 ) location at (0,0,1) 254 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1); 255 // 2 ) location and target at same value 256 SkPoint3 target = SkPoint3::Make(location.fX, location.fY, location.fZ); 257 // 3 ) large negative specular exponent value 258 SkScalar specularExponent = -1000; 259 260 SkAutoTUnref<SkImageFilter> bmSrc(SkImageSource::Create(image)); 261 SkPaint paint; 262 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular( 263 location, target, specularExponent, 180, 264 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1, 265 bmSrc))->unref(); 266 SkCanvas canvas(result); 267 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize), 268 SkIntToScalar(kBitmapSize)); 269 canvas.drawRect(r, paint); 270 } 271 } 272 } 273 274 static void test_crop_rects(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) { 275 // Check that all filters offset to their absolute crop rect, 276 // unaffected by the input crop rect. 277 // Tests pass by not asserting. 278 SkBitmap bitmap; 279 bitmap.allocN32Pixels(100, 100); 280 bitmap.eraseARGB(0, 0, 0, 0); 281 282 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80)); 283 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60)); 284 SkAutoTUnref<SkImageFilter> input(make_grayscale(nullptr, &inputCropRect)); 285 286 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode)); 287 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1); 288 SkScalar kernel[9] = { 289 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 290 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1), 291 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 292 }; 293 SkISize kernelSize = SkISize::Make(3, 3); 294 SkScalar gain = SK_Scalar1, bias = 0; 295 296 SkImageFilter* filters[] = { 297 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect), 298 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType, 299 SkDisplacementMapEffect::kB_ChannelSelectorType, 300 40.0f, input.get(), input.get(), &cropRect), 301 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect), 302 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, 303 SK_ColorGREEN, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, 304 input.get(), &cropRect), 305 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect), 306 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect), 307 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect), 308 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect), 309 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect), 310 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect), 311 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect), 312 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect), 313 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()), 314 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect), 315 }; 316 317 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { 318 SkImageFilter* filter = filters[i]; 319 SkBitmap result; 320 SkIPoint offset; 321 SkString str; 322 str.printf("filter %d", static_cast<int>(i)); 323 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr); 324 REPORTER_ASSERT_MESSAGE(reporter, 325 filter->filterImageDeprecated(proxy, bitmap, ctx, 326 &result, &offset), 327 str.c_str()); 328 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str()); 329 } 330 331 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { 332 SkSafeUnref(filters[i]); 333 } 334 } 335 336 static SkBitmap make_gradient_circle(int width, int height) { 337 SkBitmap bitmap; 338 SkScalar x = SkIntToScalar(width / 2); 339 SkScalar y = SkIntToScalar(height / 2); 340 SkScalar radius = SkMinScalar(x, y) * 0.8f; 341 bitmap.allocN32Pixels(width, height); 342 SkCanvas canvas(bitmap); 343 canvas.clear(0x00000000); 344 SkColor colors[2]; 345 colors[0] = SK_ColorWHITE; 346 colors[1] = SK_ColorBLACK; 347 SkAutoTUnref<SkShader> shader( 348 SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2, 349 SkShader::kClamp_TileMode) 350 ); 351 SkPaint paint; 352 paint.setShader(shader); 353 canvas.drawCircle(x, y, radius, paint); 354 return bitmap; 355 } 356 357 static void test_negative_blur_sigma(SkImageFilter::Proxy* proxy, skiatest::Reporter* reporter) { 358 // Check that SkBlurImageFilter will accept a negative sigma, either in 359 // the given arguments or after CTM application. 360 const int width = 32, height = 32; 361 const SkScalar five = SkIntToScalar(5); 362 363 SkAutoTUnref<SkImageFilter> positiveFilter(SkBlurImageFilter::Create(five, five)); 364 SkAutoTUnref<SkImageFilter> negativeFilter(SkBlurImageFilter::Create(-five, five)); 365 366 SkBitmap gradient = make_gradient_circle(width, height); 367 SkBitmap positiveResult1, negativeResult1; 368 SkBitmap positiveResult2, negativeResult2; 369 SkIPoint offset; 370 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(32, 32), nullptr); 371 REPORTER_ASSERT(reporter, 372 positiveFilter->filterImageDeprecated(proxy, gradient, ctx, 373 &positiveResult1, &offset)); 374 REPORTER_ASSERT(reporter, 375 negativeFilter->filterImageDeprecated(proxy, gradient, ctx, 376 &negativeResult1, &offset)); 377 SkMatrix negativeScale; 378 negativeScale.setScale(-SK_Scalar1, SK_Scalar1); 379 SkImageFilter::Context negativeCTX(negativeScale, SkIRect::MakeWH(32, 32), nullptr); 380 REPORTER_ASSERT(reporter, 381 positiveFilter->filterImageDeprecated(proxy, gradient, negativeCTX, 382 &negativeResult2, &offset)); 383 REPORTER_ASSERT(reporter, 384 negativeFilter->filterImageDeprecated(proxy, gradient, negativeCTX, 385 &positiveResult2, &offset)); 386 SkAutoLockPixels lockP1(positiveResult1); 387 SkAutoLockPixels lockP2(positiveResult2); 388 SkAutoLockPixels lockN1(negativeResult1); 389 SkAutoLockPixels lockN2(negativeResult2); 390 for (int y = 0; y < height; y++) { 391 int diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult1.getAddr32(0, y), positiveResult1.rowBytes()); 392 REPORTER_ASSERT(reporter, !diffs); 393 if (diffs) { 394 break; 395 } 396 diffs = memcmp(positiveResult1.getAddr32(0, y), negativeResult2.getAddr32(0, y), positiveResult1.rowBytes()); 397 REPORTER_ASSERT(reporter, !diffs); 398 if (diffs) { 399 break; 400 } 401 diffs = memcmp(positiveResult1.getAddr32(0, y), positiveResult2.getAddr32(0, y), positiveResult1.rowBytes()); 402 REPORTER_ASSERT(reporter, !diffs); 403 if (diffs) { 404 break; 405 } 406 } 407 } 408 409 DEF_TEST(TestNegativeBlurSigma, reporter) { 410 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 411 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 412 413 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props)); 414 SkImageFilter::DeviceProxy proxy(device); 415 416 test_negative_blur_sigma(&proxy, reporter); 417 } 418 419 DEF_TEST(ImageFilterDrawTiled, reporter) { 420 // Check that all filters when drawn tiled (with subsequent clip rects) exactly 421 // match the same filters drawn with a single full-canvas bitmap draw. 422 // Tests pass by not asserting. 423 424 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode)); 425 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1); 426 SkScalar kernel[9] = { 427 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 428 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1), 429 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 430 }; 431 const SkISize kernelSize = SkISize::Make(3, 3); 432 const SkScalar gain = SK_Scalar1, bias = 0; 433 const SkScalar five = SkIntToScalar(5); 434 435 SkAutoTUnref<SkImage> gradientImage(SkImage::NewFromBitmap(make_gradient_circle(64, 64))); 436 SkAutoTUnref<SkImageFilter> gradientSource(SkImageSource::Create(gradientImage)); 437 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five)); 438 SkMatrix matrix; 439 440 matrix.setTranslate(SK_Scalar1, SK_Scalar1); 441 matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1); 442 443 SkRTreeFactory factory; 444 SkPictureRecorder recorder; 445 SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0); 446 447 SkPaint greenPaint; 448 greenPaint.setColor(SK_ColorGREEN); 449 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint); 450 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 451 SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get())); 452 SkAutoTUnref<SkShader> shader(SkPerlinNoiseShader::CreateTurbulence(SK_Scalar1, SK_Scalar1, 1, 0)); 453 SkPaint noisePaint; 454 noisePaint.setShader(shader); 455 456 SkAutoTUnref<SkImageFilter> paintFilter(SkPaintImageFilter::Create(noisePaint)); 457 458 SkImageFilter::CropRect leftSideCropRect(SkRect::MakeXYWH(0, 0, 32, 64)); 459 SkAutoTUnref<SkImageFilter> paintFilterLeft(SkPaintImageFilter::Create(greenPaint, &leftSideCropRect)); 460 SkImageFilter::CropRect rightSideCropRect(SkRect::MakeXYWH(32, 0, 32, 64)); 461 SkAutoTUnref<SkImageFilter> paintFilterRight(SkPaintImageFilter::Create(greenPaint, &rightSideCropRect)); 462 463 struct { 464 const char* fName; 465 SkImageFilter* fFilter; 466 } filters[] = { 467 { "color filter", SkColorFilterImageFilter::Create(cf.get()) }, 468 { "displacement map", SkDisplacementMapEffect::Create( 469 SkDisplacementMapEffect::kR_ChannelSelectorType, 470 SkDisplacementMapEffect::kB_ChannelSelectorType, 471 20.0f, gradientSource.get()) }, 472 { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) }, 473 { "drop shadow", SkDropShadowImageFilter::Create( 474 SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, 475 SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode) }, 476 { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse( 477 location, SK_ColorGREEN, 0, 0) }, 478 { "specular lighting", 479 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) }, 480 { "matrix convolution", 481 SkMatrixConvolutionImageFilter::Create( 482 kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), 483 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) }, 484 { "merge", SkMergeImageFilter::Create(nullptr, nullptr, SkXfermode::kSrcOver_Mode) }, 485 { "merge with disjoint inputs", SkMergeImageFilter::Create( 486 paintFilterLeft, paintFilterRight, SkXfermode::kSrcOver_Mode) }, 487 { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) }, 488 { "dilate", SkDilateImageFilter::Create(3, 2) }, 489 { "erode", SkErodeImageFilter::Create(2, 3) }, 490 { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50), 491 SkRect::MakeXYWH(0, 0, 100, 100), nullptr) }, 492 { "matrix", SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality) }, 493 { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) }, 494 { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) }, 495 { "paint and blur", SkBlurImageFilter::Create(five, five, paintFilter.get()) }, 496 }; 497 498 SkBitmap untiledResult, tiledResult; 499 const int width = 64, height = 64; 500 untiledResult.allocN32Pixels(width, height); 501 tiledResult.allocN32Pixels(width, height); 502 SkCanvas tiledCanvas(tiledResult); 503 SkCanvas untiledCanvas(untiledResult); 504 int tileSize = 8; 505 506 for (int scale = 1; scale <= 2; ++scale) { 507 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { 508 tiledCanvas.clear(0); 509 untiledCanvas.clear(0); 510 SkPaint paint; 511 paint.setImageFilter(filters[i].fFilter); 512 paint.setTextSize(SkIntToScalar(height)); 513 paint.setColor(SK_ColorWHITE); 514 SkString str; 515 const char* text = "ABC"; 516 SkScalar ypos = SkIntToScalar(height); 517 untiledCanvas.save(); 518 untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale)); 519 untiledCanvas.drawText(text, strlen(text), 0, ypos, paint); 520 untiledCanvas.restore(); 521 for (int y = 0; y < height; y += tileSize) { 522 for (int x = 0; x < width; x += tileSize) { 523 tiledCanvas.save(); 524 tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize))); 525 tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale)); 526 tiledCanvas.drawText(text, strlen(text), 0, ypos, paint); 527 tiledCanvas.restore(); 528 } 529 } 530 untiledCanvas.flush(); 531 tiledCanvas.flush(); 532 for (int y = 0; y < height; y++) { 533 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes()); 534 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName); 535 if (diffs) { 536 break; 537 } 538 } 539 } 540 } 541 542 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { 543 SkSafeUnref(filters[i].fFilter); 544 } 545 } 546 547 static void draw_saveLayer_picture(int width, int height, int tileSize, 548 SkBBHFactory* factory, SkBitmap* result) { 549 550 SkMatrix matrix; 551 matrix.setTranslate(SkIntToScalar(50), 0); 552 553 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode)); 554 SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get())); 555 SkAutoTUnref<SkImageFilter> imageFilter(SkImageFilter::CreateMatrixFilter(matrix, kNone_SkFilterQuality, cfif.get())); 556 557 SkPaint paint; 558 paint.setImageFilter(imageFilter.get()); 559 SkPictureRecorder recorder; 560 SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50)); 561 SkCanvas* recordingCanvas = recorder.beginRecording(SkIntToScalar(width), 562 SkIntToScalar(height), 563 factory, 0); 564 recordingCanvas->translate(-55, 0); 565 recordingCanvas->saveLayer(&bounds, &paint); 566 recordingCanvas->restore(); 567 SkAutoTUnref<SkPicture> picture1(recorder.endRecording()); 568 569 result->allocN32Pixels(width, height); 570 SkCanvas canvas(*result); 571 canvas.clear(0); 572 canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize))); 573 canvas.drawPicture(picture1.get()); 574 } 575 576 DEF_TEST(ImageFilterDrawMatrixBBH, reporter) { 577 // Check that matrix filter when drawn tiled with BBH exactly 578 // matches the same thing drawn without BBH. 579 // Tests pass by not asserting. 580 581 const int width = 200, height = 200; 582 const int tileSize = 100; 583 SkBitmap result1, result2; 584 SkRTreeFactory factory; 585 586 draw_saveLayer_picture(width, height, tileSize, &factory, &result1); 587 draw_saveLayer_picture(width, height, tileSize, nullptr, &result2); 588 589 for (int y = 0; y < height; y++) { 590 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes()); 591 REPORTER_ASSERT(reporter, !diffs); 592 if (diffs) { 593 break; 594 } 595 } 596 } 597 598 static SkImageFilter* makeBlur(SkImageFilter* input = nullptr) { 599 return SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input); 600 } 601 602 static SkImageFilter* makeDropShadow(SkImageFilter* input = nullptr) { 603 return SkDropShadowImageFilter::Create( 604 SkIntToScalar(100), SkIntToScalar(100), 605 SkIntToScalar(10), SkIntToScalar(10), 606 SK_ColorBLUE, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, 607 input, nullptr); 608 } 609 610 DEF_TEST(ImageFilterBlurThenShadowBounds, reporter) { 611 SkAutoTUnref<SkImageFilter> filter1(makeBlur()); 612 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get())); 613 614 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100); 615 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236); 616 filter2->filterBounds(bounds, SkMatrix::I(), &bounds); 617 618 REPORTER_ASSERT(reporter, bounds == expectedBounds); 619 } 620 621 DEF_TEST(ImageFilterShadowThenBlurBounds, reporter) { 622 SkAutoTUnref<SkImageFilter> filter1(makeDropShadow()); 623 SkAutoTUnref<SkImageFilter> filter2(makeBlur(filter1.get())); 624 625 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100); 626 SkIRect expectedBounds = SkIRect::MakeXYWH(-133, -133, 236, 236); 627 filter2->filterBounds(bounds, SkMatrix::I(), &bounds); 628 629 REPORTER_ASSERT(reporter, bounds == expectedBounds); 630 } 631 632 DEF_TEST(ImageFilterDilateThenBlurBounds, reporter) { 633 SkAutoTUnref<SkImageFilter> filter1(SkDilateImageFilter::Create(2, 2)); 634 SkAutoTUnref<SkImageFilter> filter2(makeDropShadow(filter1.get())); 635 636 SkIRect bounds = SkIRect::MakeXYWH(0, 0, 100, 100); 637 SkIRect expectedBounds = SkIRect::MakeXYWH(-132, -132, 234, 234); 638 filter2->filterBounds(bounds, SkMatrix::I(), &bounds); 639 640 REPORTER_ASSERT(reporter, bounds == expectedBounds); 641 } 642 643 DEF_TEST(ImageFilterComposedBlurFastBounds, reporter) { 644 SkAutoTUnref<SkImageFilter> filter1(makeBlur()); 645 SkAutoTUnref<SkImageFilter> filter2(makeBlur()); 646 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(filter1.get(), filter2.get())); 647 648 SkRect boundsSrc = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100)); 649 SkRect expectedBounds = SkRect::MakeXYWH( 650 SkIntToScalar(-6), SkIntToScalar(-6), SkIntToScalar(112), SkIntToScalar(112)); 651 SkRect boundsDst = SkRect::MakeEmpty(); 652 composedFilter->computeFastBounds(boundsSrc, &boundsDst); 653 654 REPORTER_ASSERT(reporter, boundsDst == expectedBounds); 655 } 656 657 DEF_TEST(ImageFilterMergeResultSize, reporter) { 658 SkBitmap greenBM; 659 greenBM.allocN32Pixels(20, 20); 660 greenBM.eraseColor(SK_ColorGREEN); 661 SkAutoTUnref<SkImage> greenImage(SkImage::NewFromBitmap(greenBM)); 662 SkAutoTUnref<SkImageFilter> source(SkImageSource::Create(greenImage.get())); 663 SkAutoTUnref<SkImageFilter> merge(SkMergeImageFilter::Create(source.get(), source.get())); 664 665 SkBitmap bitmap; 666 bitmap.allocN32Pixels(1, 1); 667 bitmap.eraseColor(0); 668 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 669 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 670 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props)); 671 SkImageFilter::DeviceProxy proxy(device); 672 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(0, 0, 100, 100), nullptr); 673 SkBitmap result; 674 SkIPoint offset; 675 REPORTER_ASSERT(reporter, merge->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset)); 676 REPORTER_ASSERT(reporter, result.width() == 20 && result.height() == 20); 677 } 678 679 static void draw_blurred_rect(SkCanvas* canvas) { 680 SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0)); 681 SkPaint filterPaint; 682 filterPaint.setColor(SK_ColorWHITE); 683 filterPaint.setImageFilter(filter); 684 canvas->saveLayer(nullptr, &filterPaint); 685 SkPaint whitePaint; 686 whitePaint.setColor(SK_ColorWHITE); 687 canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint); 688 canvas->restore(); 689 } 690 691 static void draw_picture_clipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) { 692 canvas->save(); 693 canvas->clipRect(clipRect); 694 canvas->drawPicture(picture); 695 canvas->restore(); 696 } 697 698 DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) { 699 // Check that the blur filter when recorded with RTree acceleration, 700 // and drawn tiled (with subsequent clip rects) exactly 701 // matches the same filter drawn with without RTree acceleration. 702 // This tests that the "bleed" from the blur into the otherwise-blank 703 // tiles is correctly rendered. 704 // Tests pass by not asserting. 705 706 int width = 16, height = 8; 707 SkBitmap result1, result2; 708 result1.allocN32Pixels(width, height); 709 result2.allocN32Pixels(width, height); 710 SkCanvas canvas1(result1); 711 SkCanvas canvas2(result2); 712 int tileSize = 8; 713 714 canvas1.clear(0); 715 canvas2.clear(0); 716 717 SkRTreeFactory factory; 718 719 SkPictureRecorder recorder1, recorder2; 720 // The only difference between these two pictures is that one has RTree aceleration. 721 SkCanvas* recordingCanvas1 = recorder1.beginRecording(SkIntToScalar(width), 722 SkIntToScalar(height), 723 nullptr, 0); 724 SkCanvas* recordingCanvas2 = recorder2.beginRecording(SkIntToScalar(width), 725 SkIntToScalar(height), 726 &factory, 0); 727 draw_blurred_rect(recordingCanvas1); 728 draw_blurred_rect(recordingCanvas2); 729 SkAutoTUnref<SkPicture> picture1(recorder1.endRecording()); 730 SkAutoTUnref<SkPicture> picture2(recorder2.endRecording()); 731 for (int y = 0; y < height; y += tileSize) { 732 for (int x = 0; x < width; x += tileSize) { 733 SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)); 734 draw_picture_clipped(&canvas1, tileRect, picture1); 735 draw_picture_clipped(&canvas2, tileRect, picture2); 736 } 737 } 738 for (int y = 0; y < height; y++) { 739 int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes()); 740 REPORTER_ASSERT(reporter, !diffs); 741 if (diffs) { 742 break; 743 } 744 } 745 } 746 747 DEF_TEST(ImageFilterMatrixConvolution, reporter) { 748 // Check that a 1x3 filter does not cause a spurious assert. 749 SkScalar kernel[3] = { 750 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 751 }; 752 SkISize kernelSize = SkISize::Make(1, 3); 753 SkScalar gain = SK_Scalar1, bias = 0; 754 SkIPoint kernelOffset = SkIPoint::Make(0, 0); 755 756 SkAutoTUnref<SkImageFilter> filter( 757 SkMatrixConvolutionImageFilter::Create( 758 kernelSize, kernel, gain, bias, kernelOffset, 759 SkMatrixConvolutionImageFilter::kRepeat_TileMode, false)); 760 761 SkBitmap result; 762 int width = 16, height = 16; 763 result.allocN32Pixels(width, height); 764 SkCanvas canvas(result); 765 canvas.clear(0); 766 767 SkPaint paint; 768 paint.setImageFilter(filter); 769 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height)); 770 canvas.drawRect(rect, paint); 771 } 772 773 DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) { 774 // Check that a filter with borders outside the target bounds 775 // does not crash. 776 SkScalar kernel[3] = { 777 0, 0, 0, 778 }; 779 SkISize kernelSize = SkISize::Make(3, 1); 780 SkScalar gain = SK_Scalar1, bias = 0; 781 SkIPoint kernelOffset = SkIPoint::Make(2, 0); 782 783 SkAutoTUnref<SkImageFilter> filter( 784 SkMatrixConvolutionImageFilter::Create( 785 kernelSize, kernel, gain, bias, kernelOffset, 786 SkMatrixConvolutionImageFilter::kClamp_TileMode, true)); 787 788 SkBitmap result; 789 790 int width = 10, height = 10; 791 result.allocN32Pixels(width, height); 792 SkCanvas canvas(result); 793 canvas.clear(0); 794 795 SkPaint filterPaint; 796 filterPaint.setImageFilter(filter); 797 SkRect bounds = SkRect::MakeWH(1, 10); 798 SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height)); 799 SkPaint rectPaint; 800 canvas.saveLayer(&bounds, &filterPaint); 801 canvas.drawRect(rect, rectPaint); 802 canvas.restore(); 803 } 804 805 DEF_TEST(ImageFilterCropRect, reporter) { 806 const SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); 807 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 808 809 SkAutoTUnref<SkBaseDevice> device(SkBitmapDevice::Create(info, props)); 810 SkImageFilter::DeviceProxy proxy(device); 811 812 test_crop_rects(&proxy, reporter); 813 } 814 815 DEF_TEST(ImageFilterMatrix, reporter) { 816 SkBitmap temp; 817 temp.allocN32Pixels(100, 100); 818 SkCanvas canvas(temp); 819 canvas.scale(SkIntToScalar(2), SkIntToScalar(2)); 820 821 SkMatrix expectedMatrix = canvas.getTotalMatrix(); 822 823 SkRTreeFactory factory; 824 SkPictureRecorder recorder; 825 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0); 826 827 SkPaint paint; 828 SkAutoTUnref<MatrixTestImageFilter> imageFilter( 829 new MatrixTestImageFilter(reporter, expectedMatrix)); 830 paint.setImageFilter(imageFilter.get()); 831 recordingCanvas->saveLayer(nullptr, &paint); 832 SkPaint solidPaint; 833 solidPaint.setColor(0xFFFFFFFF); 834 recordingCanvas->save(); 835 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10)); 836 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint); 837 recordingCanvas->restore(); // scale 838 recordingCanvas->restore(); // saveLayer 839 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 840 841 canvas.drawPicture(picture); 842 } 843 844 DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) { 845 SkRTreeFactory factory; 846 SkPictureRecorder recorder; 847 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0); 848 849 // Create an SkPicture which simply draws a green 1x1 rectangle. 850 SkPaint greenPaint; 851 greenPaint.setColor(SK_ColorGREEN); 852 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint); 853 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 854 855 // Wrap that SkPicture in an SkPictureImageFilter. 856 SkAutoTUnref<SkImageFilter> imageFilter( 857 SkPictureImageFilter::Create(picture.get())); 858 859 // Check that SkPictureImageFilter successfully serializes its contained 860 // SkPicture when not in cross-process mode. 861 SkPaint paint; 862 paint.setImageFilter(imageFilter.get()); 863 SkPictureRecorder outerRecorder; 864 SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0); 865 SkPaint redPaintWithFilter; 866 redPaintWithFilter.setColor(SK_ColorRED); 867 redPaintWithFilter.setImageFilter(imageFilter.get()); 868 outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter); 869 SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording()); 870 871 SkBitmap bitmap; 872 bitmap.allocN32Pixels(1, 1); 873 SkCanvas canvas(bitmap); 874 875 // The result here should be green, since the filter replaces the primitive's red interior. 876 canvas.clear(0x0); 877 canvas.drawPicture(outerPicture); 878 uint32_t pixel = *bitmap.getAddr32(0, 0); 879 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 880 881 // Check that, for now, SkPictureImageFilter does not serialize or 882 // deserialize its contained picture when the filter is serialized 883 // cross-process. Do this by "laundering" it through SkValidatingReadBuffer. 884 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get())); 885 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable( 886 data->data(), data->size(), SkImageFilter::GetFlattenableType())); 887 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get()); 888 889 redPaintWithFilter.setImageFilter(unflattenedFilter); 890 SkPictureRecorder crossProcessRecorder; 891 SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0); 892 crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter); 893 SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording()); 894 895 canvas.clear(0x0); 896 canvas.drawPicture(crossProcessPicture); 897 pixel = *bitmap.getAddr32(0, 0); 898 // If the security precautions are enabled, the result here should not be green, since the 899 // filter draws nothing. 900 REPORTER_ASSERT(reporter, SkPicture::PictureIOSecurityPrecautionsEnabled() 901 ? pixel != SK_ColorGREEN : pixel == SK_ColorGREEN); 902 } 903 904 DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) { 905 SkRTreeFactory factory; 906 SkPictureRecorder recorder; 907 SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0); 908 909 // Create an SkPicture which simply draws a green 1x1 rectangle. 910 SkPaint greenPaint; 911 greenPaint.setColor(SK_ColorGREEN); 912 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint); 913 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 914 915 SkAutoTUnref<SkImageFilter> imageFilter(SkPictureImageFilter::Create(picture.get())); 916 917 SkBitmap result; 918 SkIPoint offset; 919 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), nullptr); 920 SkBitmap bitmap; 921 bitmap.allocN32Pixels(2, 2); 922 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 923 SkBitmapDevice device(bitmap, props); 924 SkImageFilter::DeviceProxy proxy(&device); 925 REPORTER_ASSERT(reporter, 926 !imageFilter->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset)); 927 } 928 929 DEF_TEST(ImageFilterEmptySaveLayer, reporter) { 930 // Even when there's an empty saveLayer()/restore(), ensure that an image 931 // filter or color filter which affects transparent black still draws. 932 933 SkBitmap bitmap; 934 bitmap.allocN32Pixels(10, 10); 935 SkCanvas canvas(bitmap); 936 937 SkRTreeFactory factory; 938 SkPictureRecorder recorder; 939 940 SkAutoTUnref<SkColorFilter> green( 941 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode)); 942 SkAutoTUnref<SkImageFilter> imageFilter( 943 SkColorFilterImageFilter::Create(green.get())); 944 SkPaint imageFilterPaint; 945 imageFilterPaint.setImageFilter(imageFilter.get()); 946 SkPaint colorFilterPaint; 947 colorFilterPaint.setColorFilter(green.get()); 948 949 SkRect bounds = SkRect::MakeWH(10, 10); 950 951 SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0); 952 recordingCanvas->saveLayer(&bounds, &imageFilterPaint); 953 recordingCanvas->restore(); 954 SkAutoTUnref<SkPicture> picture(recorder.endRecording()); 955 956 canvas.clear(0); 957 canvas.drawPicture(picture); 958 uint32_t pixel = *bitmap.getAddr32(0, 0); 959 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 960 961 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0); 962 recordingCanvas->saveLayer(nullptr, &imageFilterPaint); 963 recordingCanvas->restore(); 964 SkAutoTUnref<SkPicture> picture2(recorder.endRecording()); 965 966 canvas.clear(0); 967 canvas.drawPicture(picture2); 968 pixel = *bitmap.getAddr32(0, 0); 969 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 970 971 recordingCanvas = recorder.beginRecording(10, 10, &factory, 0); 972 recordingCanvas->saveLayer(&bounds, &colorFilterPaint); 973 recordingCanvas->restore(); 974 SkAutoTUnref<SkPicture> picture3(recorder.endRecording()); 975 976 canvas.clear(0); 977 canvas.drawPicture(picture3); 978 pixel = *bitmap.getAddr32(0, 0); 979 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 980 } 981 982 static void test_huge_blur(SkCanvas* canvas, skiatest::Reporter* reporter) { 983 SkBitmap bitmap; 984 bitmap.allocN32Pixels(100, 100); 985 bitmap.eraseARGB(0, 0, 0, 0); 986 987 // Check that a blur with an insane radius does not crash or assert. 988 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30))); 989 990 SkPaint paint; 991 paint.setImageFilter(blur); 992 canvas->drawBitmap(bitmap, 0, 0, &paint); 993 } 994 995 DEF_TEST(HugeBlurImageFilter, reporter) { 996 SkBitmap temp; 997 temp.allocN32Pixels(100, 100); 998 SkCanvas canvas(temp); 999 test_huge_blur(&canvas, reporter); 1000 } 1001 1002 DEF_TEST(MatrixConvolutionSanityTest, reporter) { 1003 SkScalar kernel[1] = { 0 }; 1004 SkScalar gain = SK_Scalar1, bias = 0; 1005 SkIPoint kernelOffset = SkIPoint::Make(1, 1); 1006 1007 // Check that an enormous (non-allocatable) kernel gives a nullptr filter. 1008 SkAutoTUnref<SkImageFilter> conv(SkMatrixConvolutionImageFilter::Create( 1009 SkISize::Make(1<<30, 1<<30), 1010 kernel, 1011 gain, 1012 bias, 1013 kernelOffset, 1014 SkMatrixConvolutionImageFilter::kRepeat_TileMode, 1015 false)); 1016 1017 REPORTER_ASSERT(reporter, nullptr == conv.get()); 1018 1019 // Check that a nullptr kernel gives a nullptr filter. 1020 conv.reset(SkMatrixConvolutionImageFilter::Create( 1021 SkISize::Make(1, 1), 1022 nullptr, 1023 gain, 1024 bias, 1025 kernelOffset, 1026 SkMatrixConvolutionImageFilter::kRepeat_TileMode, 1027 false)); 1028 1029 REPORTER_ASSERT(reporter, nullptr == conv.get()); 1030 1031 // Check that a kernel width < 1 gives a nullptr filter. 1032 conv.reset(SkMatrixConvolutionImageFilter::Create( 1033 SkISize::Make(0, 1), 1034 kernel, 1035 gain, 1036 bias, 1037 kernelOffset, 1038 SkMatrixConvolutionImageFilter::kRepeat_TileMode, 1039 false)); 1040 1041 REPORTER_ASSERT(reporter, nullptr == conv.get()); 1042 1043 // Check that kernel height < 1 gives a nullptr filter. 1044 conv.reset(SkMatrixConvolutionImageFilter::Create( 1045 SkISize::Make(1, -1), 1046 kernel, 1047 gain, 1048 bias, 1049 kernelOffset, 1050 SkMatrixConvolutionImageFilter::kRepeat_TileMode, 1051 false)); 1052 1053 REPORTER_ASSERT(reporter, nullptr == conv.get()); 1054 } 1055 1056 static void test_xfermode_cropped_input(SkCanvas* canvas, skiatest::Reporter* reporter) { 1057 canvas->clear(0); 1058 1059 SkBitmap bitmap; 1060 bitmap.allocN32Pixels(1, 1); 1061 bitmap.eraseARGB(255, 255, 255, 255); 1062 1063 SkAutoTUnref<SkColorFilter> green( 1064 SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode)); 1065 SkAutoTUnref<SkImageFilter> greenFilter(SkColorFilterImageFilter::Create(green.get())); 1066 SkImageFilter::CropRect cropRect(SkRect::MakeEmpty()); 1067 SkAutoTUnref<SkImageFilter> croppedOut( 1068 SkColorFilterImageFilter::Create(green.get(), nullptr, &cropRect)); 1069 1070 // Check that an xfermode image filter whose input has been cropped out still draws the other 1071 // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning. 1072 SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode); 1073 SkAutoTUnref<SkImageFilter> xfermodeNoFg( 1074 SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut)); 1075 SkAutoTUnref<SkImageFilter> xfermodeNoBg( 1076 SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter)); 1077 SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg( 1078 SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut)); 1079 1080 SkPaint paint; 1081 paint.setImageFilter(xfermodeNoFg); 1082 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite 1083 1084 uint32_t pixel; 1085 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType); 1086 canvas->readPixels(info, &pixel, 4, 0, 0); 1087 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 1088 1089 paint.setImageFilter(xfermodeNoBg); 1090 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite 1091 canvas->readPixels(info, &pixel, 4, 0, 0); 1092 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 1093 1094 paint.setImageFilter(xfermodeNoFgNoBg); 1095 canvas->drawBitmap(bitmap, 0, 0, &paint); // drawSprite 1096 canvas->readPixels(info, &pixel, 4, 0, 0); 1097 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 1098 } 1099 1100 DEF_TEST(ImageFilterNestedSaveLayer, reporter) { 1101 SkBitmap temp; 1102 temp.allocN32Pixels(50, 50); 1103 SkCanvas canvas(temp); 1104 canvas.clear(0x0); 1105 1106 SkBitmap bitmap; 1107 bitmap.allocN32Pixels(10, 10); 1108 bitmap.eraseColor(SK_ColorGREEN); 1109 1110 SkMatrix matrix; 1111 matrix.setScale(SkIntToScalar(2), SkIntToScalar(2)); 1112 matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20)); 1113 SkAutoTUnref<SkImageFilter> matrixFilter( 1114 SkImageFilter::CreateMatrixFilter(matrix, kLow_SkFilterQuality)); 1115 1116 // Test that saveLayer() with a filter nested inside another saveLayer() applies the 1117 // correct offset to the filter matrix. 1118 SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30); 1119 canvas.saveLayer(&bounds1, nullptr); 1120 SkPaint filterPaint; 1121 filterPaint.setImageFilter(matrixFilter); 1122 SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10); 1123 canvas.saveLayer(&bounds2, &filterPaint); 1124 SkPaint greenPaint; 1125 greenPaint.setColor(SK_ColorGREEN); 1126 canvas.drawRect(bounds2, greenPaint); 1127 canvas.restore(); 1128 canvas.restore(); 1129 SkPaint strokePaint; 1130 strokePaint.setStyle(SkPaint::kStroke_Style); 1131 strokePaint.setColor(SK_ColorRED); 1132 1133 SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType, kUnpremul_SkAlphaType); 1134 uint32_t pixel; 1135 canvas.readPixels(info, &pixel, 4, 25, 25); 1136 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 1137 1138 // Test that drawSprite() with a filter nested inside a saveLayer() applies the 1139 // correct offset to the filter matrix. 1140 canvas.clear(0x0); 1141 canvas.readPixels(info, &pixel, 4, 25, 25); 1142 canvas.saveLayer(&bounds1, nullptr); 1143 canvas.drawBitmap(bitmap, 20, 20, &filterPaint); // drawSprite 1144 canvas.restore(); 1145 1146 canvas.readPixels(info, &pixel, 4, 25, 25); 1147 REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN); 1148 } 1149 1150 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) { 1151 SkBitmap temp; 1152 temp.allocN32Pixels(100, 100); 1153 SkCanvas canvas(temp); 1154 test_xfermode_cropped_input(&canvas, reporter); 1155 } 1156 1157 DEF_TEST(ComposedImageFilterOffset, reporter) { 1158 SkBitmap bitmap; 1159 bitmap.allocN32Pixels(100, 100); 1160 bitmap.eraseARGB(0, 0, 0, 0); 1161 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 1162 SkBitmapDevice device(bitmap, props); 1163 SkImageFilter::DeviceProxy proxy(&device); 1164 1165 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(1, 0, 20, 20)); 1166 SkAutoTUnref<SkImageFilter> offsetFilter(SkOffsetImageFilter::Create(0, 0, nullptr, &cropRect)); 1167 SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, 1168 nullptr, &cropRect)); 1169 SkAutoTUnref<SkImageFilter> composedFilter(SkComposeImageFilter::Create(blurFilter, 1170 offsetFilter.get())); 1171 SkBitmap result; 1172 SkIPoint offset; 1173 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr); 1174 REPORTER_ASSERT(reporter, 1175 composedFilter->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset)); 1176 REPORTER_ASSERT(reporter, offset.fX == 1 && offset.fY == 0); 1177 } 1178 1179 DEF_TEST(PartialCropRect, reporter) { 1180 SkBitmap bitmap; 1181 bitmap.allocN32Pixels(100, 100); 1182 bitmap.eraseARGB(0, 0, 0, 0); 1183 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 1184 SkBitmapDevice device(bitmap, props); 1185 SkImageFilter::DeviceProxy proxy(&device); 1186 1187 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(100, 0, 20, 30), 1188 SkImageFilter::CropRect::kHasWidth_CropEdge | SkImageFilter::CropRect::kHasHeight_CropEdge); 1189 SkAutoTUnref<SkImageFilter> filter(make_grayscale(nullptr, &cropRect)); 1190 SkBitmap result; 1191 SkIPoint offset; 1192 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeWH(100, 100), nullptr); 1193 REPORTER_ASSERT(reporter, 1194 filter->filterImageDeprecated(&proxy, bitmap, ctx, &result, &offset)); 1195 REPORTER_ASSERT(reporter, offset.fX == 0); 1196 REPORTER_ASSERT(reporter, offset.fY == 0); 1197 REPORTER_ASSERT(reporter, result.width() == 20); 1198 REPORTER_ASSERT(reporter, result.height() == 30); 1199 } 1200 1201 DEF_TEST(ImageFilterCanComputeFastBounds, reporter) { 1202 1203 SkPoint3 location = SkPoint3::Make(0, 0, SK_Scalar1); 1204 SkAutoTUnref<SkImageFilter> lighting(SkLightingImageFilter::CreatePointLitDiffuse( 1205 location, SK_ColorGREEN, 0, 0)); 1206 REPORTER_ASSERT(reporter, !lighting->canComputeFastBounds()); 1207 1208 SkAutoTUnref<SkImageFilter> gray(make_grayscale(nullptr, nullptr)); 1209 REPORTER_ASSERT(reporter, gray->canComputeFastBounds()); 1210 { 1211 SkColorFilter* grayCF; 1212 REPORTER_ASSERT(reporter, gray->asAColorFilter(&grayCF)); 1213 REPORTER_ASSERT(reporter, !grayCF->affectsTransparentBlack()); 1214 grayCF->unref(); 1215 } 1216 REPORTER_ASSERT(reporter, gray->canComputeFastBounds()); 1217 1218 SkAutoTUnref<SkImageFilter> grayBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, gray.get())); 1219 REPORTER_ASSERT(reporter, grayBlur->canComputeFastBounds()); 1220 1221 SkScalar greenMatrix[20] = { 0, 0, 0, 0, 0, 1222 0, 0, 0, 0, 1, 1223 0, 0, 0, 0, 0, 1224 0, 0, 0, 0, 1 }; 1225 SkAutoTUnref<SkColorFilter> greenCF(SkColorMatrixFilter::Create(greenMatrix)); 1226 SkAutoTUnref<SkImageFilter> green(SkColorFilterImageFilter::Create(greenCF)); 1227 1228 REPORTER_ASSERT(reporter, greenCF->affectsTransparentBlack()); 1229 REPORTER_ASSERT(reporter, !green->canComputeFastBounds()); 1230 1231 SkAutoTUnref<SkImageFilter> greenBlur(SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, green.get())); 1232 REPORTER_ASSERT(reporter, !greenBlur->canComputeFastBounds()); 1233 1234 uint8_t allOne[256], identity[256]; 1235 for (int i = 0; i < 256; ++i) { 1236 identity[i] = i; 1237 allOne[i] = 255; 1238 } 1239 1240 SkAutoTUnref<SkColorFilter> identityCF( 1241 SkTableColorFilter::CreateARGB(identity, identity, identity, allOne)); 1242 SkAutoTUnref<SkImageFilter> identityFilter(SkColorFilterImageFilter::Create(identityCF.get())); 1243 REPORTER_ASSERT(reporter, !identityCF->affectsTransparentBlack()); 1244 REPORTER_ASSERT(reporter, identityFilter->canComputeFastBounds()); 1245 1246 SkAutoTUnref<SkColorFilter> forceOpaqueCF( 1247 SkTableColorFilter::CreateARGB(allOne, identity, identity, identity)); 1248 SkAutoTUnref<SkImageFilter> forceOpaque(SkColorFilterImageFilter::Create(forceOpaqueCF.get())); 1249 REPORTER_ASSERT(reporter, forceOpaqueCF->affectsTransparentBlack()); 1250 REPORTER_ASSERT(reporter, !forceOpaque->canComputeFastBounds()); 1251 } 1252 1253 // Verify that SkImageSource survives serialization 1254 DEF_TEST(ImageFilterImageSourceSerialization, reporter) { 1255 SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(10, 10)); 1256 surface->getCanvas()->clear(SK_ColorGREEN); 1257 SkAutoTUnref<SkImage> image(surface->newImageSnapshot()); 1258 SkAutoTUnref<SkImageFilter> filter(SkImageSource::Create(image)); 1259 1260 SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(filter)); 1261 SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable( 1262 data->data(), data->size(), SkImageFilter::GetFlattenableType())); 1263 SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get()); 1264 REPORTER_ASSERT(reporter, unflattenedFilter); 1265 1266 SkBitmap bm; 1267 bm.allocN32Pixels(10, 10); 1268 bm.eraseColor(SK_ColorBLUE); 1269 SkPaint paint; 1270 paint.setColor(SK_ColorRED); 1271 paint.setImageFilter(unflattenedFilter); 1272 1273 SkCanvas canvas(bm); 1274 canvas.drawRect(SkRect::MakeWH(10, 10), paint); 1275 REPORTER_ASSERT(reporter, *bm.getAddr32(0, 0) == SkPreMultiplyColor(SK_ColorGREEN)); 1276 } 1277 1278 static void test_large_blur_input(skiatest::Reporter* reporter, SkCanvas* canvas) { 1279 SkBitmap largeBmp; 1280 int largeW = 5000; 1281 int largeH = 5000; 1282 #if SK_SUPPORT_GPU 1283 // If we're GPU-backed make the bitmap too large to be converted into a texture. 1284 if (GrContext* ctx = canvas->getGrContext()) { 1285 largeW = ctx->caps()->maxTextureSize() + 1; 1286 } 1287 #endif 1288 1289 largeBmp.allocN32Pixels(largeW, largeH); 1290 largeBmp.eraseColor(0); 1291 if (!largeBmp.getPixels()) { 1292 ERRORF(reporter, "Failed to allocate large bmp."); 1293 return; 1294 } 1295 1296 SkAutoTUnref<SkImage> largeImage(SkImage::NewFromBitmap(largeBmp)); 1297 if (!largeImage) { 1298 ERRORF(reporter, "Failed to create large image."); 1299 return; 1300 } 1301 1302 SkAutoTUnref<SkImageFilter> largeSource(SkImageSource::Create(largeImage)); 1303 if (!largeSource) { 1304 ERRORF(reporter, "Failed to create large SkImageSource."); 1305 return; 1306 } 1307 1308 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(10.f, 10.f, largeSource)); 1309 if (!blur) { 1310 ERRORF(reporter, "Failed to create SkBlurImageFilter."); 1311 return; 1312 } 1313 1314 SkPaint paint; 1315 paint.setImageFilter(blur); 1316 1317 // This should not crash (http://crbug.com/570479). 1318 canvas->drawRect(SkRect::MakeIWH(largeW, largeH), paint); 1319 } 1320 1321 DEF_TEST(BlurLargeImage, reporter) { 1322 SkAutoTUnref<SkSurface> surface(SkSurface::NewRaster(SkImageInfo::MakeN32Premul(100, 100))); 1323 test_large_blur_input(reporter, surface->getCanvas()); 1324 } 1325 1326 #if SK_SUPPORT_GPU 1327 1328 DEF_GPUTEST_FOR_NATIVE_CONTEXT(ImageFilterCropRect_Gpu, reporter, context) { 1329 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 1330 1331 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context, 1332 SkBudgeted::kNo, 1333 SkImageInfo::MakeN32Premul(100, 100), 1334 0, 1335 &props, 1336 SkGpuDevice::kUninit_InitContents)); 1337 SkImageFilter::DeviceProxy proxy(device); 1338 1339 test_crop_rects(&proxy, reporter); 1340 } 1341 1342 DEF_GPUTEST_FOR_NATIVE_CONTEXT(HugeBlurImageFilter_Gpu, reporter, context) { 1343 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 1344 1345 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context, 1346 SkBudgeted::kNo, 1347 SkImageInfo::MakeN32Premul(100, 100), 1348 0, 1349 &props, 1350 SkGpuDevice::kUninit_InitContents)); 1351 SkCanvas canvas(device); 1352 1353 test_huge_blur(&canvas, reporter); 1354 } 1355 1356 DEF_GPUTEST_FOR_NATIVE_CONTEXT(XfermodeImageFilterCroppedInput_Gpu, reporter, context) { 1357 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 1358 1359 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context, 1360 SkBudgeted::kNo, 1361 SkImageInfo::MakeN32Premul(1, 1), 1362 0, 1363 &props, 1364 SkGpuDevice::kUninit_InitContents)); 1365 SkCanvas canvas(device); 1366 1367 test_xfermode_cropped_input(&canvas, reporter); 1368 } 1369 1370 DEF_GPUTEST_FOR_NATIVE_CONTEXT(TestNegativeBlurSigma_Gpu, reporter, context) { 1371 const SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 1372 1373 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context, 1374 SkBudgeted::kNo, 1375 SkImageInfo::MakeN32Premul(1, 1), 1376 0, 1377 &props, 1378 SkGpuDevice::kUninit_InitContents)); 1379 SkImageFilter::DeviceProxy proxy(device); 1380 1381 test_negative_blur_sigma(&proxy, reporter); 1382 } 1383 1384 DEF_GPUTEST_FOR_ALL_CONTEXTS(BlurLargeImage_Gpu, reporter, context) { 1385 SkAutoTUnref<SkSurface> surface( 1386 SkSurface::NewRenderTarget(context, SkBudgeted::kYes, 1387 SkImageInfo::MakeN32Premul(100, 100))); 1388 test_large_blur_input(reporter, surface->getCanvas()); 1389 } 1390 #endif 1391