ImageFilterTest.cpp revision 09843fd5c15e84e9b14ab511a04d9d639149fa75
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 "SkBicubicImageFilter.h" 9#include "SkBitmap.h" 10#include "SkBitmapDevice.h" 11#include "SkBitmapSource.h" 12#include "SkBlurImageFilter.h" 13#include "SkCanvas.h" 14#include "SkColorFilterImageFilter.h" 15#include "SkColorMatrixFilter.h" 16#include "SkDeviceImageFilterProxy.h" 17#include "SkDisplacementMapEffect.h" 18#include "SkDropShadowImageFilter.h" 19#include "SkFlattenableBuffers.h" 20#include "SkLightingImageFilter.h" 21#include "SkMatrixConvolutionImageFilter.h" 22#include "SkMergeImageFilter.h" 23#include "SkMorphologyImageFilter.h" 24#include "SkOffsetImageFilter.h" 25#include "SkPicture.h" 26#include "SkRect.h" 27#include "SkTileImageFilter.h" 28#include "SkXfermodeImageFilter.h" 29#include "Test.h" 30 31#if SK_SUPPORT_GPU 32#include "GrContextFactory.h" 33#include "SkGpuDevice.h" 34#endif 35 36static const int kBitmapSize = 4; 37 38namespace { 39 40class MatrixTestImageFilter : public SkImageFilter { 41public: 42 MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix) 43 : SkImageFilter(0), fReporter(reporter), fExpectedMatrix(expectedMatrix) { 44 } 45 46 virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx, 47 SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE { 48 REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix); 49 return true; 50 } 51 52 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter) 53 54protected: 55 explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0) { 56 fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr()); 57 buffer.readMatrix(&fExpectedMatrix); 58 } 59 60 virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE { 61 buffer.writeFunctionPtr(fReporter); 62 buffer.writeMatrix(fExpectedMatrix); 63 } 64 65private: 66 skiatest::Reporter* fReporter; 67 SkMatrix fExpectedMatrix; 68}; 69 70} 71 72static void make_small_bitmap(SkBitmap& bitmap) { 73 bitmap.allocN32Pixels(kBitmapSize, kBitmapSize); 74 SkCanvas canvas(bitmap); 75 canvas.clear(0x00000000); 76 SkPaint darkPaint; 77 darkPaint.setColor(0xFF804020); 78 SkPaint lightPaint; 79 lightPaint.setColor(0xFF244484); 80 const int i = kBitmapSize / 4; 81 for (int y = 0; y < kBitmapSize; y += i) { 82 for (int x = 0; x < kBitmapSize; x += i) { 83 canvas.save(); 84 canvas.translate(SkIntToScalar(x), SkIntToScalar(y)); 85 canvas.drawRect(SkRect::MakeXYWH(0, 0, 86 SkIntToScalar(i), 87 SkIntToScalar(i)), darkPaint); 88 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i), 89 0, 90 SkIntToScalar(i), 91 SkIntToScalar(i)), lightPaint); 92 canvas.drawRect(SkRect::MakeXYWH(0, 93 SkIntToScalar(i), 94 SkIntToScalar(i), 95 SkIntToScalar(i)), lightPaint); 96 canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i), 97 SkIntToScalar(i), 98 SkIntToScalar(i), 99 SkIntToScalar(i)), darkPaint); 100 canvas.restore(); 101 } 102 } 103} 104 105static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) { 106 SkScalar s = amount; 107 SkScalar matrix[20] = { s, 0, 0, 0, 0, 108 0, s, 0, 0, 0, 109 0, 0, s, 0, 0, 110 0, 0, 0, s, 0 }; 111 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix)); 112 return SkColorFilterImageFilter::Create(filter, input); 113} 114 115static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) { 116 SkScalar matrix[20]; 117 memset(matrix, 0, 20 * sizeof(SkScalar)); 118 matrix[0] = matrix[5] = matrix[10] = 0.2126f; 119 matrix[1] = matrix[6] = matrix[11] = 0.7152f; 120 matrix[2] = matrix[7] = matrix[12] = 0.0722f; 121 matrix[18] = 1.0f; 122 SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix)); 123 return SkColorFilterImageFilter::Create(filter, input, cropRect); 124} 125 126DEF_TEST(ImageFilter, reporter) { 127 { 128 // Check that two non-clipping color matrices concatenate into a single filter. 129 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f)); 130 SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness)); 131 REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0)); 132 } 133 134 { 135 // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter. 136 SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f)); 137 SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness)); 138 REPORTER_ASSERT(reporter, NULL != halfBrightness->getInput(0)); 139 } 140 141 { 142 // Check that a color filter image filter without a crop rect can be 143 // expressed as a color filter. 144 SkAutoTUnref<SkImageFilter> gray(make_grayscale()); 145 REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL)); 146 } 147 148 { 149 // Check that a color filter image filter with a crop rect cannot 150 // be expressed as a color filter. 151 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100)); 152 SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect)); 153 REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL)); 154 } 155 156 { 157 // Tests pass by not asserting 158 SkBitmap bitmap, result; 159 make_small_bitmap(bitmap); 160 result.allocN32Pixels(kBitmapSize, kBitmapSize); 161 162 { 163 // This tests for : 164 // 1 ) location at (0,0,1) 165 SkPoint3 location(0, 0, SK_Scalar1); 166 // 2 ) location and target at same value 167 SkPoint3 target(location.fX, location.fY, location.fZ); 168 // 3 ) large negative specular exponent value 169 SkScalar specularExponent = -1000; 170 171 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap)); 172 SkPaint paint; 173 paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular( 174 location, target, specularExponent, 180, 175 0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1, 176 bmSrc))->unref(); 177 SkCanvas canvas(result); 178 SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize), 179 SkIntToScalar(kBitmapSize)); 180 canvas.drawRect(r, paint); 181 } 182 183 { 184 // This tests for scale bringing width to 0 185 SkSize scale = SkSize::Make(-0.001f, SK_Scalar1); 186 SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap)); 187 SkAutoTUnref<SkBicubicImageFilter> bicubic( 188 SkBicubicImageFilter::CreateMitchell(scale, bmSrc)); 189 SkBitmapDevice device(bitmap); 190 SkDeviceImageFilterProxy proxy(&device); 191 SkIPoint loc = SkIPoint::Make(0, 0); 192 // An empty input should early return and return false 193 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeEmpty()); 194 REPORTER_ASSERT(reporter, 195 !bicubic->filterImage(&proxy, bitmap, ctx, &result, &loc)); 196 } 197 } 198} 199 200static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) { 201 // Check that all filters offset to their absolute crop rect, 202 // unaffected by the input crop rect. 203 // Tests pass by not asserting. 204 SkBitmap bitmap; 205 bitmap.allocN32Pixels(100, 100); 206 bitmap.eraseARGB(0, 0, 0, 0); 207 SkDeviceImageFilterProxy proxy(device); 208 209 SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80)); 210 SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60)); 211 SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect)); 212 213 SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode)); 214 SkPoint3 location(0, 0, SK_Scalar1); 215 SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1); 216 SkScalar kernel[9] = { 217 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 218 SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1), 219 SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1), 220 }; 221 SkISize kernelSize = SkISize::Make(3, 3); 222 SkScalar gain = SK_Scalar1, bias = 0; 223 224 SkImageFilter* filters[] = { 225 SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect), 226 SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType, 227 SkDisplacementMapEffect::kB_ChannelSelectorType, 228 40.0f, input.get(), input.get(), &cropRect), 229 SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect), 230 SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input.get(), &cropRect), 231 SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect), 232 SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect), 233 SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect), 234 SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect), 235 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect), 236 SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect), 237 SkDilateImageFilter::Create(3, 2, input.get(), &cropRect), 238 SkErodeImageFilter::Create(2, 3, input.get(), &cropRect), 239 SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()), 240 SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect), 241 }; 242 243 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { 244 SkImageFilter* filter = filters[i]; 245 SkBitmap result; 246 SkIPoint offset; 247 SkString str; 248 str.printf("filter %d", static_cast<int>(i)); 249 SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest()); 250 REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx, &result, &offset), str.c_str()); 251 REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str()); 252 } 253 254 for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { 255 SkSafeUnref(filters[i]); 256 } 257} 258 259DEF_TEST(ImageFilterCropRect, reporter) { 260 SkBitmap temp; 261 temp.allocN32Pixels(100, 100); 262 SkBitmapDevice device(temp); 263 test_crop_rects(&device, reporter); 264} 265 266DEF_TEST(ImageFilterMatrixTest, reporter) { 267 SkBitmap temp; 268 temp.allocN32Pixels(100, 100); 269 SkBitmapDevice device(temp); 270 SkCanvas canvas(&device); 271 canvas.scale(SkIntToScalar(2), SkIntToScalar(2)); 272 273 SkMatrix expectedMatrix = canvas.getTotalMatrix(); 274 275 SkPicture picture; 276 SkCanvas* recordingCanvas = picture.beginRecording(100, 100, 277 SkPicture::kOptimizeForClippedPlayback_RecordingFlag); 278 279 SkPaint paint; 280 SkAutoTUnref<MatrixTestImageFilter> imageFilter( 281 new MatrixTestImageFilter(reporter, expectedMatrix)); 282 paint.setImageFilter(imageFilter.get()); 283 SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>( 284 SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag); 285 recordingCanvas->saveLayer(NULL, &paint, saveFlags); 286 SkPaint solidPaint; 287 solidPaint.setColor(0xFFFFFFFF); 288 recordingCanvas->save(); 289 recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10)); 290 recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint); 291 recordingCanvas->restore(); // scale 292 recordingCanvas->restore(); // saveLayer 293 picture.endRecording(); 294 295 canvas.drawPicture(picture); 296} 297 298void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) { 299 SkCanvas canvas(device); 300 301 SkBitmap bitmap; 302 bitmap.allocN32Pixels(100, 100); 303 bitmap.eraseARGB(0, 0, 0, 0); 304 305 // Check that a blur with an insane radius does not crash or assert. 306 SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30))); 307 308 SkPaint paint; 309 paint.setImageFilter(blur); 310 canvas.drawSprite(bitmap, 0, 0, &paint); 311} 312 313DEF_TEST(HugeBlurImageFilter, reporter) { 314 SkBitmap temp; 315 temp.allocN32Pixels(100, 100); 316 SkBitmapDevice device(temp); 317 test_huge_blur(&device, reporter); 318} 319 320 321#if SK_SUPPORT_GPU 322DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) { 323 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0)); 324 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context, 325 SkImageInfo::MakeN32Premul(100, 100), 326 0)); 327 test_crop_rects(device, reporter); 328} 329 330DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) { 331 GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0)); 332 SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context, 333 SkImageInfo::MakeN32Premul(100, 100), 334 0)); 335 test_huge_blur(device, reporter); 336} 337#endif 338