1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "Test.h"
9#include "SkBlurMaskFilter.h"
10#include "SkCanvas.h"
11#include "SkMath.h"
12#include "SkPaint.h"
13#include "SkRandom.h"
14
15///////////////////////////////////////////////////////////////////////////////
16
17#define ILLEGAL_MODE    ((SkXfermode::Mode)-1)
18
19static const int outset = 100;
20static const SkColor bgColor = SK_ColorWHITE;
21static const int strokeWidth = 4;
22
23static void create(SkBitmap* bm, SkIRect bound, SkBitmap::Config config) {
24    bm->setConfig(config, bound.width(), bound.height());
25    bm->allocPixels();
26}
27
28static void drawBG(SkCanvas* canvas) {
29    canvas->drawColor(bgColor);
30}
31
32
33struct BlurTest {
34    void (*addPath)(SkPath*);
35    int viewLen;
36    SkIRect views[9];
37};
38
39//Path Draw Procs
40//Beware that paths themselves my draw differently depending on the clip.
41static void draw50x50Rect(SkPath* path) {
42    path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
43}
44
45//Tests
46static BlurTest tests[] = {
47    { draw50x50Rect, 3, {
48        //inner half of blur
49        { 0, 0, 50, 50 },
50        //blur, but no path.
51        { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
52        //just an edge
53        { 40, strokeWidth, 60, 50 - strokeWidth },
54    }},
55};
56
57/** Assumes that the ref draw was completely inside ref canvas --
58    implies that everything outside is "bgColor".
59    Checks that all overlap is the same and that all non-overlap on the
60    ref is "bgColor".
61 */
62static bool compare(const SkBitmap& ref, const SkIRect& iref,
63                    const SkBitmap& test, const SkIRect& itest)
64{
65    const int xOff = itest.fLeft - iref.fLeft;
66    const int yOff = itest.fTop - iref.fTop;
67
68    SkAutoLockPixels alpRef(ref);
69    SkAutoLockPixels alpTest(test);
70
71    for (int y = 0; y < test.height(); ++y) {
72        for (int x = 0; x < test.width(); ++x) {
73            SkColor testColor = test.getColor(x, y);
74            int refX = x + xOff;
75            int refY = y + yOff;
76            SkColor refColor;
77            if (refX >= 0 && refX < ref.width() &&
78                refY >= 0 && refY < ref.height())
79            {
80                refColor = ref.getColor(refX, refY);
81            } else {
82                refColor = bgColor;
83            }
84            if (refColor != testColor) {
85                return false;
86            }
87        }
88    }
89    return true;
90}
91
92static void test_blur(skiatest::Reporter* reporter) {
93
94    SkPaint paint;
95    paint.setColor(SK_ColorGRAY);
96    paint.setStyle(SkPaint::kStroke_Style);
97    paint.setStrokeWidth(SkIntToScalar(strokeWidth));
98
99    SkScalar radius = SkIntToScalar(5);
100    for (int style = 0; style < SkBlurMaskFilter::kBlurStyleCount; ++style) {
101        SkBlurMaskFilter::BlurStyle blurStyle =
102            static_cast<SkBlurMaskFilter::BlurStyle>(style);
103
104        const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
105        for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
106            SkMaskFilter* filter;
107            filter = SkBlurMaskFilter::Create(radius, blurStyle, flags);
108
109            SkMaskFilter::BlurInfo info;
110            sk_bzero(&info, sizeof(info));
111            SkMaskFilter::BlurType type = filter->asABlur(&info);
112
113            REPORTER_ASSERT(reporter, type ==
114                static_cast<SkMaskFilter::BlurType>(style + 1));
115            REPORTER_ASSERT(reporter, info.fRadius == radius);
116            REPORTER_ASSERT(reporter, info.fIgnoreTransform ==
117                SkToBool(flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag));
118            REPORTER_ASSERT(reporter, info.fHighQuality ==
119                SkToBool(flags & SkBlurMaskFilter::kHighQuality_BlurFlag));
120
121            paint.setMaskFilter(filter);
122            filter->unref();
123
124            for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
125                SkPath path;
126                tests[test].addPath(&path);
127                SkPath strokedPath;
128                paint.getFillPath(path, &strokedPath);
129                SkRect refBound = strokedPath.getBounds();
130                SkIRect iref;
131                refBound.roundOut(&iref);
132                iref.inset(-outset, -outset);
133                SkBitmap refBitmap;
134                create(&refBitmap, iref, SkBitmap::kARGB_8888_Config);
135
136                SkCanvas refCanvas(refBitmap);
137                refCanvas.translate(SkIntToScalar(-iref.fLeft),
138                                    SkIntToScalar(-iref.fTop));
139                drawBG(&refCanvas);
140                refCanvas.drawPath(path, paint);
141
142                for (int view = 0; view < tests[test].viewLen; ++view) {
143                    SkIRect itest = tests[test].views[view];
144                    SkBitmap testBitmap;
145                    create(&testBitmap, itest, SkBitmap::kARGB_8888_Config);
146
147                    SkCanvas testCanvas(testBitmap);
148                    testCanvas.translate(SkIntToScalar(-itest.fLeft),
149                                         SkIntToScalar(-itest.fTop));
150                    drawBG(&testCanvas);
151                    testCanvas.drawPath(path, paint);
152
153                    REPORTER_ASSERT(reporter,
154                        compare(refBitmap, iref, testBitmap, itest));
155                }
156            }
157        }
158    }
159}
160
161#include "TestClassDef.h"
162DEFINE_TESTCLASS("BlurMaskFilter", BlurTestClass, test_blur)
163