Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / tests / ImageFilterTest.cpp
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 "SkDeviceImageFilterProxy.h"
16 #include "SkDisplacementMapEffect.h"
17 #include "SkDropShadowImageFilter.h"
18 #include "SkFlattenableBuffers.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 "SkPicture.h"
28 #include "SkPictureImageFilter.h"
29 #include "SkPictureRecorder.h"
30 #include "SkRect.h"
31 #include "SkTileImageFilter.h"
32 #include "SkXfermodeImageFilter.h"
33 #include "Test.h"
34
35 #if SK_SUPPORT_GPU
36 #include "GrContextFactory.h"
37 #include "SkGpuDevice.h"
38 #endif
39
40 static const int kBitmapSize = 4;
41
42 namespace {
43
44 class MatrixTestImageFilter : public SkImageFilter {
45 public:
46     MatrixTestImageFilter(skiatest::Reporter* reporter, const SkMatrix& expectedMatrix)
47       : SkImageFilter(0, NULL), fReporter(reporter), fExpectedMatrix(expectedMatrix) {
48     }
49
50     virtual bool onFilterImage(Proxy*, const SkBitmap& src, const Context& ctx,
51                                SkBitmap* result, SkIPoint* offset) const SK_OVERRIDE {
52         REPORTER_ASSERT(fReporter, ctx.ctm() == fExpectedMatrix);
53         return true;
54     }
55
56     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(MatrixTestImageFilter)
57
58 protected:
59     explicit MatrixTestImageFilter(SkReadBuffer& buffer) : SkImageFilter(0, NULL) {
60         fReporter = static_cast<skiatest::Reporter*>(buffer.readFunctionPtr());
61         buffer.readMatrix(&fExpectedMatrix);
62     }
63
64     virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE {
65         buffer.writeFunctionPtr(fReporter);
66         buffer.writeMatrix(fExpectedMatrix);
67     }
68
69 private:
70     skiatest::Reporter* fReporter;
71     SkMatrix fExpectedMatrix;
72 };
73
74 }
75
76 static void make_small_bitmap(SkBitmap& bitmap) {
77     bitmap.allocN32Pixels(kBitmapSize, kBitmapSize);
78     SkCanvas canvas(bitmap);
79     canvas.clear(0x00000000);
80     SkPaint darkPaint;
81     darkPaint.setColor(0xFF804020);
82     SkPaint lightPaint;
83     lightPaint.setColor(0xFF244484);
84     const int i = kBitmapSize / 4;
85     for (int y = 0; y < kBitmapSize; y += i) {
86         for (int x = 0; x < kBitmapSize; x += i) {
87             canvas.save();
88             canvas.translate(SkIntToScalar(x), SkIntToScalar(y));
89             canvas.drawRect(SkRect::MakeXYWH(0, 0,
90                                              SkIntToScalar(i),
91                                              SkIntToScalar(i)), darkPaint);
92             canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
93                                              0,
94                                              SkIntToScalar(i),
95                                              SkIntToScalar(i)), lightPaint);
96             canvas.drawRect(SkRect::MakeXYWH(0,
97                                              SkIntToScalar(i),
98                                              SkIntToScalar(i),
99                                              SkIntToScalar(i)), lightPaint);
100             canvas.drawRect(SkRect::MakeXYWH(SkIntToScalar(i),
101                                              SkIntToScalar(i),
102                                              SkIntToScalar(i),
103                                              SkIntToScalar(i)), darkPaint);
104             canvas.restore();
105         }
106     }
107 }
108
109 static SkImageFilter* make_scale(float amount, SkImageFilter* input = NULL) {
110     SkScalar s = amount;
111     SkScalar matrix[20] = { s, 0, 0, 0, 0,
112                             0, s, 0, 0, 0,
113                             0, 0, s, 0, 0,
114                             0, 0, 0, s, 0 };
115     SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
116     return SkColorFilterImageFilter::Create(filter, input);
117 }
118
119 static SkImageFilter* make_grayscale(SkImageFilter* input = NULL, const SkImageFilter::CropRect* cropRect = NULL) {
120     SkScalar matrix[20];
121     memset(matrix, 0, 20 * sizeof(SkScalar));
122     matrix[0] = matrix[5] = matrix[10] = 0.2126f;
123     matrix[1] = matrix[6] = matrix[11] = 0.7152f;
124     matrix[2] = matrix[7] = matrix[12] = 0.0722f;
125     matrix[18] = 1.0f;
126     SkAutoTUnref<SkColorFilter> filter(SkColorMatrixFilter::Create(matrix));
127     return SkColorFilterImageFilter::Create(filter, input, cropRect);
128 }
129
130 DEF_TEST(ImageFilter, reporter) {
131     {
132         // Check that two non-clipping color matrices concatenate into a single filter.
133         SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f));
134         SkAutoTUnref<SkImageFilter> quarterBrightness(make_scale(0.5f, halfBrightness));
135         REPORTER_ASSERT(reporter, NULL == quarterBrightness->getInput(0));
136     }
137
138     {
139         // Check that a clipping color matrix followed by a grayscale does not concatenate into a single filter.
140         SkAutoTUnref<SkImageFilter> doubleBrightness(make_scale(2.0f));
141         SkAutoTUnref<SkImageFilter> halfBrightness(make_scale(0.5f, doubleBrightness));
142         REPORTER_ASSERT(reporter, NULL != halfBrightness->getInput(0));
143     }
144
145     {
146         // Check that a color filter image filter without a crop rect can be
147         // expressed as a color filter.
148         SkAutoTUnref<SkImageFilter> gray(make_grayscale());
149         REPORTER_ASSERT(reporter, true == gray->asColorFilter(NULL));
150     }
151
152     {
153         // Check that a color filter image filter with a crop rect cannot
154         // be expressed as a color filter.
155         SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(0, 0, 100, 100));
156         SkAutoTUnref<SkImageFilter> grayWithCrop(make_grayscale(NULL, &cropRect));
157         REPORTER_ASSERT(reporter, false == grayWithCrop->asColorFilter(NULL));
158     }
159
160     {
161         // Check that two non-commutative matrices are concatenated in
162         // the correct order.
163         SkScalar blueToRedMatrix[20] = { 0 };
164         blueToRedMatrix[2] = blueToRedMatrix[18] = SK_Scalar1;
165         SkScalar redToGreenMatrix[20] = { 0 };
166         redToGreenMatrix[5] = redToGreenMatrix[18] = SK_Scalar1;
167         SkAutoTUnref<SkColorFilter> blueToRed(SkColorMatrixFilter::Create(blueToRedMatrix));
168         SkAutoTUnref<SkImageFilter> filter1(SkColorFilterImageFilter::Create(blueToRed.get()));
169         SkAutoTUnref<SkColorFilter> redToGreen(SkColorMatrixFilter::Create(redToGreenMatrix));
170         SkAutoTUnref<SkImageFilter> filter2(SkColorFilterImageFilter::Create(redToGreen.get(), filter1.get()));
171
172         SkBitmap result;
173         result.allocN32Pixels(kBitmapSize, kBitmapSize);
174
175         SkPaint paint;
176         paint.setColor(SK_ColorBLUE);
177         paint.setImageFilter(filter2.get());
178         SkCanvas canvas(result);
179         canvas.clear(0x0);
180         SkRect rect = SkRect::Make(SkIRect::MakeWH(kBitmapSize, kBitmapSize));
181         canvas.drawRect(rect, paint);
182         uint32_t pixel = *result.getAddr32(0, 0);
183         // The result here should be green, since we have effectively shifted blue to green.
184         REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
185     }
186
187     {
188         // Tests pass by not asserting
189         SkBitmap bitmap, result;
190         make_small_bitmap(bitmap);
191         result.allocN32Pixels(kBitmapSize, kBitmapSize);
192
193         {
194             // This tests for :
195             // 1 ) location at (0,0,1)
196             SkPoint3 location(0, 0, SK_Scalar1);
197             // 2 ) location and target at same value
198             SkPoint3 target(location.fX, location.fY, location.fZ);
199             // 3 ) large negative specular exponent value
200             SkScalar specularExponent = -1000;
201
202             SkAutoTUnref<SkImageFilter> bmSrc(SkBitmapSource::Create(bitmap));
203             SkPaint paint;
204             paint.setImageFilter(SkLightingImageFilter::CreateSpotLitSpecular(
205                     location, target, specularExponent, 180,
206                     0xFFFFFFFF, SK_Scalar1, SK_Scalar1, SK_Scalar1,
207                     bmSrc))->unref();
208             SkCanvas canvas(result);
209             SkRect r = SkRect::MakeWH(SkIntToScalar(kBitmapSize),
210                                       SkIntToScalar(kBitmapSize));
211             canvas.drawRect(r, paint);
212         }
213     }
214 }
215
216 static void test_crop_rects(SkBaseDevice* device, skiatest::Reporter* reporter) {
217     // Check that all filters offset to their absolute crop rect,
218     // unaffected by the input crop rect.
219     // Tests pass by not asserting.
220     SkBitmap bitmap;
221     bitmap.allocN32Pixels(100, 100);
222     bitmap.eraseARGB(0, 0, 0, 0);
223     SkDeviceImageFilterProxy proxy(device);
224
225     SkImageFilter::CropRect inputCropRect(SkRect::MakeXYWH(8, 13, 80, 80));
226     SkImageFilter::CropRect cropRect(SkRect::MakeXYWH(20, 30, 60, 60));
227     SkAutoTUnref<SkImageFilter> input(make_grayscale(NULL, &inputCropRect));
228
229     SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
230     SkPoint3 location(0, 0, SK_Scalar1);
231     SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
232     SkScalar kernel[9] = {
233         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
234         SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
235         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
236     };
237     SkISize kernelSize = SkISize::Make(3, 3);
238     SkScalar gain = SK_Scalar1, bias = 0;
239
240     SkImageFilter* filters[] = {
241         SkColorFilterImageFilter::Create(cf.get(), input.get(), &cropRect),
242         SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType,
243                                         SkDisplacementMapEffect::kB_ChannelSelectorType,
244                                         40.0f, input.get(), input.get(), &cropRect),
245         SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
246         SkDropShadowImageFilter::Create(SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN, input.get(), &cropRect),
247         SkLightingImageFilter::CreatePointLitDiffuse(location, SK_ColorGREEN, 0, 0, input.get(), &cropRect),
248         SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0, input.get(), &cropRect),
249         SkMatrixConvolutionImageFilter::Create(kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1), SkMatrixConvolutionImageFilter::kRepeat_TileMode, false, input.get(), &cropRect),
250         SkMergeImageFilter::Create(input.get(), input.get(), SkXfermode::kSrcOver_Mode, &cropRect),
251         SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
252         SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1, input.get(), &cropRect),
253         SkDilateImageFilter::Create(3, 2, input.get(), &cropRect),
254         SkErodeImageFilter::Create(2, 3, input.get(), &cropRect),
255         SkTileImageFilter::Create(inputCropRect.rect(), cropRect.rect(), input.get()),
256         SkXfermodeImageFilter::Create(SkXfermode::Create(SkXfermode::kSrcOver_Mode), input.get(), input.get(), &cropRect),
257     };
258
259     for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
260         SkImageFilter* filter = filters[i];
261         SkBitmap result;
262         SkIPoint offset;
263         SkString str;
264         str.printf("filter %d", static_cast<int>(i));
265         SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeLargest(), NULL);
266         REPORTER_ASSERT_MESSAGE(reporter, filter->filterImage(&proxy, bitmap, ctx,
267                                 &result, &offset), str.c_str());
268         REPORTER_ASSERT_MESSAGE(reporter, offset.fX == 20 && offset.fY == 30, str.c_str());
269     }
270
271     for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
272         SkSafeUnref(filters[i]);
273     }
274 }
275
276 static SkBitmap make_gradient_circle(int width, int height) {
277     SkBitmap bitmap;
278     SkScalar x = SkIntToScalar(width / 2);
279     SkScalar y = SkIntToScalar(height / 2);
280     SkScalar radius = SkMinScalar(x, y) * 0.8f;
281     bitmap.allocN32Pixels(width, height);
282     SkCanvas canvas(bitmap);
283     canvas.clear(0x00000000);
284     SkColor colors[2];
285     colors[0] = SK_ColorWHITE;
286     colors[1] = SK_ColorBLACK;
287     SkAutoTUnref<SkShader> shader(
288         SkGradientShader::CreateRadial(SkPoint::Make(x, y), radius, colors, NULL, 2,
289                                        SkShader::kClamp_TileMode)
290     );
291     SkPaint paint;
292     paint.setShader(shader);
293     canvas.drawCircle(x, y, radius, paint);
294     return bitmap;
295 }
296
297 DEF_TEST(ImageFilterDrawTiled, reporter) {
298     // Check that all filters when drawn tiled (with subsequent clip rects) exactly
299     // match the same filters drawn with a single full-canvas bitmap draw.
300     // Tests pass by not asserting.
301
302     SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorRED, SkXfermode::kSrcIn_Mode));
303     SkPoint3 location(0, 0, SK_Scalar1);
304     SkPoint3 target(SK_Scalar1, SK_Scalar1, SK_Scalar1);
305     SkScalar kernel[9] = {
306         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
307         SkIntToScalar( 1), SkIntToScalar(-7), SkIntToScalar( 1),
308         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
309     };
310     SkISize kernelSize = SkISize::Make(3, 3);
311     SkScalar gain = SK_Scalar1, bias = 0;
312     SkScalar five = SkIntToScalar(5);
313
314     SkAutoTUnref<SkImageFilter> gradient_source(SkBitmapSource::Create(make_gradient_circle(64, 64)));
315     SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(five, five));
316     SkMatrix matrix;
317
318     matrix.setTranslate(SK_Scalar1, SK_Scalar1);
319     matrix.postRotate(SkIntToScalar(45), SK_Scalar1, SK_Scalar1);
320
321     SkRTreeFactory factory;
322     SkPictureRecorder recorder;
323     SkCanvas* recordingCanvas = recorder.beginRecording(64, 64, &factory, 0);
324
325     SkPaint greenPaint;
326     greenPaint.setColor(SK_ColorGREEN);
327     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeXYWH(10, 10, 30, 20)), greenPaint);
328     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
329     SkAutoTUnref<SkImageFilter> pictureFilter(SkPictureImageFilter::Create(picture.get()));
330
331     struct {
332         const char*    fName;
333         SkImageFilter* fFilter;
334     } filters[] = {
335         { "color filter", SkColorFilterImageFilter::Create(cf.get()) },
336         { "displacement map", SkDisplacementMapEffect::Create(
337               SkDisplacementMapEffect::kR_ChannelSelectorType,
338               SkDisplacementMapEffect::kB_ChannelSelectorType,
339               20.0f, gradient_source.get()) },
340         { "blur", SkBlurImageFilter::Create(SK_Scalar1, SK_Scalar1) },
341         { "drop shadow", SkDropShadowImageFilter::Create(
342               SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_Scalar1, SK_ColorGREEN) },
343         { "diffuse lighting", SkLightingImageFilter::CreatePointLitDiffuse(
344               location, SK_ColorGREEN, 0, 0) },
345         { "specular lighting",
346               SkLightingImageFilter::CreatePointLitSpecular(location, SK_ColorGREEN, 0, 0, 0) },
347         { "matrix convolution",
348               SkMatrixConvolutionImageFilter::Create(
349                   kernelSize, kernel, gain, bias, SkIPoint::Make(1, 1),
350                   SkMatrixConvolutionImageFilter::kRepeat_TileMode, false) },
351         { "merge", SkMergeImageFilter::Create(NULL, NULL, SkXfermode::kSrcOver_Mode) },
352         { "offset", SkOffsetImageFilter::Create(SK_Scalar1, SK_Scalar1) },
353         { "dilate", SkDilateImageFilter::Create(3, 2) },
354         { "erode", SkErodeImageFilter::Create(2, 3) },
355         { "tile", SkTileImageFilter::Create(SkRect::MakeXYWH(0, 0, 50, 50),
356                                             SkRect::MakeXYWH(0, 0, 100, 100), NULL) },
357         { "matrix", SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel) },
358         { "blur and offset", SkOffsetImageFilter::Create(five, five, blur.get()) },
359         { "picture and blur", SkBlurImageFilter::Create(five, five, pictureFilter.get()) },
360     };
361
362     SkBitmap untiledResult, tiledResult;
363     int width = 64, height = 64;
364     untiledResult.allocN32Pixels(width, height);
365     tiledResult.allocN32Pixels(width, height);
366     SkCanvas tiledCanvas(tiledResult);
367     SkCanvas untiledCanvas(untiledResult);
368     int tileSize = 8;
369
370     for (int scale = 1; scale <= 2; ++scale) {
371         for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
372             tiledCanvas.clear(0);
373             untiledCanvas.clear(0);
374             SkPaint paint;
375             paint.setImageFilter(filters[i].fFilter);
376             paint.setTextSize(SkIntToScalar(height));
377             paint.setColor(SK_ColorWHITE);
378             SkString str;
379             const char* text = "ABC";
380             SkScalar ypos = SkIntToScalar(height);
381             untiledCanvas.save();
382             untiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
383             untiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
384             untiledCanvas.restore();
385             for (int y = 0; y < height; y += tileSize) {
386                 for (int x = 0; x < width; x += tileSize) {
387                     tiledCanvas.save();
388                     tiledCanvas.clipRect(SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize)));
389                     tiledCanvas.scale(SkIntToScalar(scale), SkIntToScalar(scale));
390                     tiledCanvas.drawText(text, strlen(text), 0, ypos, paint);
391                     tiledCanvas.restore();
392                 }
393             }
394             untiledCanvas.flush();
395             tiledCanvas.flush();
396             for (int y = 0; y < height; y++) {
397                 int diffs = memcmp(untiledResult.getAddr32(0, y), tiledResult.getAddr32(0, y), untiledResult.rowBytes());
398                 REPORTER_ASSERT_MESSAGE(reporter, !diffs, filters[i].fName);
399                 if (diffs) {
400                     break;
401                 }
402             }
403         }
404     }
405
406     for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) {
407         SkSafeUnref(filters[i].fFilter);
408     }
409 }
410
411 static void drawSaveLayerPicture(int width, int height, int tileSize, SkBBHFactory* factory, SkBitmap* result) {
412
413     SkMatrix matrix;
414     matrix.setTranslate(SkIntToScalar(50), 0);
415
416     SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(SK_ColorWHITE, SkXfermode::kSrc_Mode));
417     SkAutoTUnref<SkImageFilter> cfif(SkColorFilterImageFilter::Create(cf.get()));
418     SkAutoTUnref<SkImageFilter> imageFilter(SkMatrixImageFilter::Create(matrix, SkPaint::kNone_FilterLevel, cfif.get()));
419
420     SkPaint paint;
421     paint.setImageFilter(imageFilter.get());
422     SkPictureRecorder recorder;
423     SkRect bounds = SkRect::Make(SkIRect::MakeXYWH(0, 0, 50, 50));
424     SkCanvas* recordingCanvas = recorder.beginRecording(width, height, factory, 0);
425     recordingCanvas->translate(-55, 0);
426     recordingCanvas->saveLayer(&bounds, &paint);
427     recordingCanvas->restore();
428     SkAutoTUnref<SkPicture> picture1(recorder.endRecording());
429
430     result->allocN32Pixels(width, height);
431     SkCanvas canvas(*result);
432     canvas.clear(0);
433     canvas.clipRect(SkRect::Make(SkIRect::MakeWH(tileSize, tileSize)));
434     canvas.drawPicture(picture1.get());
435 }
436
437 DEF_TEST(ImageFilterDrawMatrixBBH, reporter) {
438     // Check that matrix filter when drawn tiled with BBH exactly
439     // matches the same thing drawn without BBH.
440     // Tests pass by not asserting.
441
442     const int width = 200, height = 200;
443     const int tileSize = 100;
444     SkBitmap result1, result2;
445     SkRTreeFactory factory;
446
447     drawSaveLayerPicture(width, height, tileSize, &factory, &result1);
448     drawSaveLayerPicture(width, height, tileSize, NULL, &result2);
449
450     for (int y = 0; y < height; y++) {
451         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
452         REPORTER_ASSERT(reporter, !diffs);
453         if (diffs) {
454             break;
455         }
456     }
457 }
458
459 static void drawBlurredRect(SkCanvas* canvas) {
460     SkAutoTUnref<SkImageFilter> filter(SkBlurImageFilter::Create(SkIntToScalar(8), 0));
461     SkPaint filterPaint;
462     filterPaint.setColor(SK_ColorWHITE);
463     filterPaint.setImageFilter(filter);
464     canvas->saveLayer(NULL, &filterPaint);
465     SkPaint whitePaint;
466     whitePaint.setColor(SK_ColorWHITE);
467     canvas->drawRect(SkRect::Make(SkIRect::MakeWH(4, 4)), whitePaint);
468     canvas->restore();
469 }
470
471 static void drawPictureClipped(SkCanvas* canvas, const SkRect& clipRect, const SkPicture* picture) {
472     canvas->save();
473     canvas->clipRect(clipRect);
474     canvas->drawPicture(picture);
475     canvas->restore();
476 }
477
478 DEF_TEST(ImageFilterDrawTiledBlurRTree, reporter) {
479     // Check that the blur filter when recorded with RTree acceleration,
480     // and drawn tiled (with subsequent clip rects) exactly
481     // matches the same filter drawn with without RTree acceleration.
482     // This tests that the "bleed" from the blur into the otherwise-blank
483     // tiles is correctly rendered.
484     // Tests pass by not asserting.
485
486     int width = 16, height = 8;
487     SkBitmap result1, result2;
488     result1.allocN32Pixels(width, height);
489     result2.allocN32Pixels(width, height);
490     SkCanvas canvas1(result1);
491     SkCanvas canvas2(result2);
492     int tileSize = 8;
493
494     canvas1.clear(0);
495     canvas2.clear(0);
496
497     SkRTreeFactory factory;
498
499     SkPictureRecorder recorder1, recorder2;
500     // The only difference between these two pictures is that one has RTree aceleration.
501     SkCanvas* recordingCanvas1 = recorder1.beginRecording(width, height, NULL, 0);
502     SkCanvas* recordingCanvas2 = recorder2.beginRecording(width, height, &factory, 0);
503     drawBlurredRect(recordingCanvas1);
504     drawBlurredRect(recordingCanvas2);
505     SkAutoTUnref<SkPicture> picture1(recorder1.endRecording());
506     SkAutoTUnref<SkPicture> picture2(recorder2.endRecording());
507     for (int y = 0; y < height; y += tileSize) {
508         for (int x = 0; x < width; x += tileSize) {
509             SkRect tileRect = SkRect::Make(SkIRect::MakeXYWH(x, y, tileSize, tileSize));
510             drawPictureClipped(&canvas1, tileRect, picture1);
511             drawPictureClipped(&canvas2, tileRect, picture2);
512         }
513     }
514     for (int y = 0; y < height; y++) {
515         int diffs = memcmp(result1.getAddr32(0, y), result2.getAddr32(0, y), result1.rowBytes());
516         REPORTER_ASSERT(reporter, !diffs);
517         if (diffs) {
518             break;
519         }
520     }
521 }
522
523 DEF_TEST(ImageFilterMatrixConvolution, reporter) {
524     // Check that a 1x3 filter does not cause a spurious assert.
525     SkScalar kernel[3] = {
526         SkIntToScalar( 1), SkIntToScalar( 1), SkIntToScalar( 1),
527     };
528     SkISize kernelSize = SkISize::Make(1, 3);
529     SkScalar gain = SK_Scalar1, bias = 0;
530     SkIPoint kernelOffset = SkIPoint::Make(0, 0);
531
532     SkAutoTUnref<SkImageFilter> filter(
533         SkMatrixConvolutionImageFilter::Create(
534             kernelSize, kernel, gain, bias, kernelOffset,
535             SkMatrixConvolutionImageFilter::kRepeat_TileMode, false));
536
537     SkBitmap result;
538     int width = 16, height = 16;
539     result.allocN32Pixels(width, height);
540     SkCanvas canvas(result);
541     canvas.clear(0);
542
543     SkPaint paint;
544     paint.setImageFilter(filter);
545     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
546     canvas.drawRect(rect, paint);
547 }
548
549 DEF_TEST(ImageFilterMatrixConvolutionBorder, reporter) {
550     // Check that a filter with borders outside the target bounds
551     // does not crash.
552     SkScalar kernel[3] = {
553         0, 0, 0,
554     };
555     SkISize kernelSize = SkISize::Make(3, 1);
556     SkScalar gain = SK_Scalar1, bias = 0;
557     SkIPoint kernelOffset = SkIPoint::Make(2, 0);
558
559     SkAutoTUnref<SkImageFilter> filter(
560         SkMatrixConvolutionImageFilter::Create(
561             kernelSize, kernel, gain, bias, kernelOffset,
562             SkMatrixConvolutionImageFilter::kClamp_TileMode, true));
563
564     SkBitmap result;
565
566     int width = 10, height = 10;
567     result.allocN32Pixels(width, height);
568     SkCanvas canvas(result);
569     canvas.clear(0);
570
571     SkPaint filterPaint;
572     filterPaint.setImageFilter(filter);
573     SkRect bounds = SkRect::MakeWH(1, 10);
574     SkRect rect = SkRect::Make(SkIRect::MakeWH(width, height));
575     SkPaint rectPaint;
576     canvas.saveLayer(&bounds, &filterPaint);
577     canvas.drawRect(rect, rectPaint);
578     canvas.restore();
579 }
580
581 DEF_TEST(ImageFilterCropRect, reporter) {
582     SkBitmap temp;
583     temp.allocN32Pixels(100, 100);
584     SkBitmapDevice device(temp);
585     test_crop_rects(&device, reporter);
586 }
587
588 DEF_TEST(ImageFilterMatrix, reporter) {
589     SkBitmap temp;
590     temp.allocN32Pixels(100, 100);
591     SkBitmapDevice device(temp);
592     SkCanvas canvas(&device);
593     canvas.scale(SkIntToScalar(2), SkIntToScalar(2));
594
595     SkMatrix expectedMatrix = canvas.getTotalMatrix();
596
597     SkRTreeFactory factory;
598     SkPictureRecorder recorder;
599     SkCanvas* recordingCanvas = recorder.beginRecording(100, 100, &factory, 0);
600
601     SkPaint paint;
602     SkAutoTUnref<MatrixTestImageFilter> imageFilter(
603         new MatrixTestImageFilter(reporter, expectedMatrix));
604     paint.setImageFilter(imageFilter.get());
605     recordingCanvas->saveLayer(NULL, &paint);
606     SkPaint solidPaint;
607     solidPaint.setColor(0xFFFFFFFF);
608     recordingCanvas->save();
609     recordingCanvas->scale(SkIntToScalar(10), SkIntToScalar(10));
610     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(100, 100)), solidPaint);
611     recordingCanvas->restore(); // scale
612     recordingCanvas->restore(); // saveLayer
613     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
614
615     canvas.drawPicture(picture);
616 }
617
618 DEF_TEST(ImageFilterCrossProcessPictureImageFilter, reporter) {
619     SkRTreeFactory factory;
620     SkPictureRecorder recorder;
621     SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
622
623     // Create an SkPicture which simply draws a green 1x1 rectangle.
624     SkPaint greenPaint;
625     greenPaint.setColor(SK_ColorGREEN);
626     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
627     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
628
629     // Wrap that SkPicture in an SkPictureImageFilter.
630     SkAutoTUnref<SkImageFilter> imageFilter(
631         SkPictureImageFilter::Create(picture.get()));
632
633     // Check that SkPictureImageFilter successfully serializes its contained
634     // SkPicture when not in cross-process mode.
635     SkPaint paint;
636     paint.setImageFilter(imageFilter.get());
637     SkPictureRecorder outerRecorder;
638     SkCanvas* outerCanvas = outerRecorder.beginRecording(1, 1, &factory, 0);
639     SkPaint redPaintWithFilter;
640     redPaintWithFilter.setColor(SK_ColorRED);
641     redPaintWithFilter.setImageFilter(imageFilter.get());
642     outerCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
643     SkAutoTUnref<SkPicture> outerPicture(outerRecorder.endRecording());
644
645     SkBitmap bitmap;
646     bitmap.allocN32Pixels(1, 1);
647     SkBitmapDevice device(bitmap);
648     SkCanvas canvas(&device);
649
650     // The result here should be green, since the filter replaces the primitive's red interior.
651     canvas.clear(0x0);
652     canvas.drawPicture(outerPicture);
653     uint32_t pixel = *bitmap.getAddr32(0, 0);
654     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
655
656     // Check that, for now, SkPictureImageFilter does not serialize or
657     // deserialize its contained picture when the filter is serialized
658     // cross-process. Do this by "laundering" it through SkValidatingReadBuffer.
659     SkAutoTUnref<SkData> data(SkValidatingSerializeFlattenable(imageFilter.get()));
660     SkAutoTUnref<SkFlattenable> flattenable(SkValidatingDeserializeFlattenable(
661         data->data(), data->size(), SkImageFilter::GetFlattenableType()));
662     SkImageFilter* unflattenedFilter = static_cast<SkImageFilter*>(flattenable.get());
663
664     redPaintWithFilter.setImageFilter(unflattenedFilter);
665     SkPictureRecorder crossProcessRecorder;
666     SkCanvas* crossProcessCanvas = crossProcessRecorder.beginRecording(1, 1, &factory, 0);
667     crossProcessCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), redPaintWithFilter);
668     SkAutoTUnref<SkPicture> crossProcessPicture(crossProcessRecorder.endRecording());
669
670     canvas.clear(0x0);
671     canvas.drawPicture(crossProcessPicture);
672     pixel = *bitmap.getAddr32(0, 0);
673     // The result here should not be green, since the filter draws nothing.
674     REPORTER_ASSERT(reporter, pixel != SK_ColorGREEN);
675 }
676
677 DEF_TEST(ImageFilterClippedPictureImageFilter, reporter) {
678     SkRTreeFactory factory;
679     SkPictureRecorder recorder;
680     SkCanvas* recordingCanvas = recorder.beginRecording(1, 1, &factory, 0);
681
682     // Create an SkPicture which simply draws a green 1x1 rectangle.
683     SkPaint greenPaint;
684     greenPaint.setColor(SK_ColorGREEN);
685     recordingCanvas->drawRect(SkRect::Make(SkIRect::MakeWH(1, 1)), greenPaint);
686     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
687
688     SkAutoTUnref<SkImageFilter> imageFilter(
689         SkPictureImageFilter::Create(picture.get()));
690
691     SkBitmap result;
692     SkIPoint offset;
693     SkImageFilter::Context ctx(SkMatrix::I(), SkIRect::MakeXYWH(1, 1, 1, 1), NULL);
694     SkBitmap bitmap;
695     bitmap.allocN32Pixels(2, 2);
696     SkBitmapDevice device(bitmap);
697     SkDeviceImageFilterProxy proxy(&device);
698     REPORTER_ASSERT(reporter, !imageFilter->filterImage(&proxy, bitmap, ctx, &result, &offset));
699 }
700
701 DEF_TEST(ImageFilterEmptySaveLayer, reporter) {
702     // Even when there's an empty saveLayer()/restore(), ensure that an image
703     // filter or color filter which affects transparent black still draws.
704
705     SkBitmap bitmap;
706     bitmap.allocN32Pixels(10, 10);
707     SkBitmapDevice device(bitmap);
708     SkCanvas canvas(&device);
709
710     SkRTreeFactory factory;
711     SkPictureRecorder recorder;
712
713     SkAutoTUnref<SkColorFilter> green(
714         SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrc_Mode));
715     SkAutoTUnref<SkColorFilterImageFilter> imageFilter(
716         SkColorFilterImageFilter::Create(green.get()));
717     SkPaint imageFilterPaint;
718     imageFilterPaint.setImageFilter(imageFilter.get());
719     SkPaint colorFilterPaint;
720     colorFilterPaint.setColorFilter(green.get());
721
722     SkRect bounds = SkRect::MakeWH(10, 10);
723
724     SkCanvas* recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
725     recordingCanvas->saveLayer(&bounds, &imageFilterPaint);
726     recordingCanvas->restore();
727     SkAutoTUnref<SkPicture> picture(recorder.endRecording());
728
729     canvas.clear(0);
730     canvas.drawPicture(picture);
731     uint32_t pixel = *bitmap.getAddr32(0, 0);
732     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
733
734     recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
735     recordingCanvas->saveLayer(NULL, &imageFilterPaint);
736     recordingCanvas->restore();
737     SkAutoTUnref<SkPicture> picture2(recorder.endRecording());
738
739     canvas.clear(0);
740     canvas.drawPicture(picture2);
741     pixel = *bitmap.getAddr32(0, 0);
742     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
743
744     recordingCanvas = recorder.beginRecording(10, 10, &factory, 0);
745     recordingCanvas->saveLayer(&bounds, &colorFilterPaint);
746     recordingCanvas->restore();
747     SkAutoTUnref<SkPicture> picture3(recorder.endRecording());
748
749     canvas.clear(0);
750     canvas.drawPicture(picture3);
751     pixel = *bitmap.getAddr32(0, 0);
752     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
753 }
754
755 static void test_huge_blur(SkBaseDevice* device, skiatest::Reporter* reporter) {
756     SkCanvas canvas(device);
757
758     SkBitmap bitmap;
759     bitmap.allocN32Pixels(100, 100);
760     bitmap.eraseARGB(0, 0, 0, 0);
761
762     // Check that a blur with an insane radius does not crash or assert.
763     SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(SkIntToScalar(1<<30), SkIntToScalar(1<<30)));
764
765     SkPaint paint;
766     paint.setImageFilter(blur);
767     canvas.drawSprite(bitmap, 0, 0, &paint);
768 }
769
770 DEF_TEST(HugeBlurImageFilter, reporter) {
771     SkBitmap temp;
772     temp.allocN32Pixels(100, 100);
773     SkBitmapDevice device(temp);
774     test_huge_blur(&device, reporter);
775 }
776
777 static void test_xfermode_cropped_input(SkBaseDevice* device, skiatest::Reporter* reporter) {
778     SkCanvas canvas(device);
779     canvas.clear(0);
780
781     SkBitmap bitmap;
782     bitmap.allocN32Pixels(1, 1);
783     bitmap.eraseARGB(255, 255, 255, 255);
784
785     SkAutoTUnref<SkColorFilter> green(
786         SkColorFilter::CreateModeFilter(SK_ColorGREEN, SkXfermode::kSrcIn_Mode));
787     SkAutoTUnref<SkColorFilterImageFilter> greenFilter(
788         SkColorFilterImageFilter::Create(green.get()));
789     SkImageFilter::CropRect cropRect(SkRect::MakeEmpty());
790     SkAutoTUnref<SkColorFilterImageFilter> croppedOut(
791         SkColorFilterImageFilter::Create(green.get(), NULL, &cropRect));
792
793     // Check that an xfermode image filter whose input has been cropped out still draws the other
794     // input. Also check that drawing with both inputs cropped out doesn't cause a GPU warning.
795     SkXfermode* mode = SkXfermode::Create(SkXfermode::kSrcOver_Mode);
796     SkAutoTUnref<SkImageFilter> xfermodeNoFg(
797         SkXfermodeImageFilter::Create(mode, greenFilter, croppedOut));
798     SkAutoTUnref<SkImageFilter> xfermodeNoBg(
799         SkXfermodeImageFilter::Create(mode, croppedOut, greenFilter));
800     SkAutoTUnref<SkImageFilter> xfermodeNoFgNoBg(
801         SkXfermodeImageFilter::Create(mode, croppedOut, croppedOut));
802
803     SkPaint paint;
804     paint.setImageFilter(xfermodeNoFg);
805     canvas.drawSprite(bitmap, 0, 0, &paint);
806
807     uint32_t pixel;
808     SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
809     canvas.readPixels(info, &pixel, 4, 0, 0);
810     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
811
812     paint.setImageFilter(xfermodeNoBg);
813     canvas.drawSprite(bitmap, 0, 0, &paint);
814     canvas.readPixels(info, &pixel, 4, 0, 0);
815     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
816
817     paint.setImageFilter(xfermodeNoFgNoBg);
818     canvas.drawSprite(bitmap, 0, 0, &paint);
819     canvas.readPixels(info, &pixel, 4, 0, 0);
820     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
821 }
822
823 DEF_TEST(ImageFilterNestedSaveLayer, reporter) {
824     SkBitmap temp;
825     temp.allocN32Pixels(50, 50);
826     SkBitmapDevice device(temp);
827     SkCanvas canvas(&device);
828     canvas.clear(0x0);
829
830     SkBitmap bitmap;
831     bitmap.allocN32Pixels(10, 10);
832     bitmap.eraseColor(SK_ColorGREEN);
833
834     SkMatrix matrix;
835     matrix.setScale(SkIntToScalar(2), SkIntToScalar(2));
836     matrix.postTranslate(SkIntToScalar(-20), SkIntToScalar(-20));
837     SkAutoTUnref<SkImageFilter> matrixFilter(
838         SkMatrixImageFilter::Create(matrix, SkPaint::kLow_FilterLevel));
839
840     // Test that saveLayer() with a filter nested inside another saveLayer() applies the
841     // correct offset to the filter matrix.
842     SkRect bounds1 = SkRect::MakeXYWH(10, 10, 30, 30);
843     canvas.saveLayer(&bounds1, NULL);
844     SkPaint filterPaint;
845     filterPaint.setImageFilter(matrixFilter);
846     SkRect bounds2 = SkRect::MakeXYWH(20, 20, 10, 10);
847     canvas.saveLayer(&bounds2, &filterPaint);
848     SkPaint greenPaint;
849     greenPaint.setColor(SK_ColorGREEN);
850     canvas.drawRect(bounds2, greenPaint);
851     canvas.restore();
852     canvas.restore();
853     SkPaint strokePaint;
854     strokePaint.setStyle(SkPaint::kStroke_Style);
855     strokePaint.setColor(SK_ColorRED);
856
857     SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
858     uint32_t pixel;
859     canvas.readPixels(info, &pixel, 4, 25, 25);
860     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
861
862     // Test that drawSprite() with a filter nested inside a saveLayer() applies the
863     // correct offset to the filter matrix.
864     canvas.clear(0x0);
865     canvas.readPixels(info, &pixel, 4, 25, 25);
866     canvas.saveLayer(&bounds1, NULL);
867     canvas.drawSprite(bitmap, 20, 20, &filterPaint);
868     canvas.restore();
869
870     canvas.readPixels(info, &pixel, 4, 25, 25);
871     REPORTER_ASSERT(reporter, pixel == SK_ColorGREEN);
872 }
873
874 DEF_TEST(XfermodeImageFilterCroppedInput, reporter) {
875     SkBitmap temp;
876     temp.allocN32Pixels(100, 100);
877     SkBitmapDevice device(temp);
878     test_xfermode_cropped_input(&device, reporter);
879 }
880
881 #if SK_SUPPORT_GPU
882 DEF_GPUTEST(ImageFilterCropRectGPU, reporter, factory) {
883     GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
884     SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
885                                                          SkImageInfo::MakeN32Premul(100, 100),
886                                                          0));
887     test_crop_rects(device, reporter);
888 }
889
890 DEF_GPUTEST(HugeBlurImageFilterGPU, reporter, factory) {
891     GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
892     SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
893                                                          SkImageInfo::MakeN32Premul(100, 100),
894                                                          0));
895     test_huge_blur(device, reporter);
896 }
897
898 DEF_GPUTEST(XfermodeImageFilterCroppedInputGPU, reporter, factory) {
899     GrContext* context = factory->get(static_cast<GrContextFactory::GLContextType>(0));
900     SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(context,
901                                                          SkImageInfo::MakeN32Premul(1, 1),
902                                                          0));
903     test_xfermode_cropped_input(device, reporter);
904 }
905 #endif