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