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