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