1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2011 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBlurMask.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBlurMaskFilter.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkBlurDrawLooper.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCanvas.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkColorFilter.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkEmbossMaskFilter.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkLayerDrawLooper.h"
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMaskFilterBase.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkMath.h"
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPaint.h"
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h"
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPerlinNoiseShader.h"
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkSurface.h"
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Test.h"
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "GrContextFactory.h"
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkGpuDevice.h"
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define WRITE_CSV 0
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define ILLEGAL_MODE    ((SkXfermode::Mode)-1)
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const int outset = 100;
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const SkColor bgColor = SK_ColorWHITE;
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const int strokeWidth = 4;
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void create(SkBitmap* bm, const SkIRect& bound) {
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bm->allocN32Pixels(bound.width(), bound.height());
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void drawBG(SkCanvas* canvas) {
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas->drawColor(bgColor);
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct BlurTest {
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void (*addPath)(SkPath*);
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int viewLen;
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkIRect views[9];
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//Path Draw Procs
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//Beware that paths themselves my draw differently depending on the clip.
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void draw50x50Rect(SkPath* path) {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//Tests
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic BlurTest tests[] = {
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    { draw50x50Rect, 3, {
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        //inner half of blur
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 0, 0, 50, 50 },
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        //blur, but no path.
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        //just an edge
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 40, strokeWidth, 60, 50 - strokeWidth },
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }},
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/** Assumes that the ref draw was completely inside ref canvas --
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    implies that everything outside is "bgColor".
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    Checks that all overlap is the same and that all non-overlap on the
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    ref is "bgColor".
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool compare(const SkBitmap& ref, const SkIRect& iref,
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const SkBitmap& test, const SkIRect& itest)
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int xOff = itest.fLeft - iref.fLeft;
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const int yOff = itest.fTop - iref.fTop;
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int y = 0; y < test.height(); ++y) {
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int x = 0; x < test.width(); ++x) {
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkColor testColor = test.getColor(x, y);
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int refX = x + xOff;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int refY = y + yOff;
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            SkColor refColor;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (refX >= 0 && refX < ref.width() &&
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                refY >= 0 && refY < ref.height())
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            {
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                refColor = ref.getColor(refX, refY);
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            } else {
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                refColor = bgColor;
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (refColor != testColor) {
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                return false;
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(BlurDrawing, reporter) {
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint paint;
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    paint.setColor(SK_ColorGRAY);
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    paint.setStyle(SkPaint::kStroke_Style);
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    paint.setStrokeWidth(SkIntToScalar(strokeWidth));
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5));
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int style = 0; style <= kLastEnum_SkBlurStyle; ++style) {
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkBlurStyle blurStyle = static_cast<SkBlurStyle>(style);
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            paint.setMaskFilter(SkBlurMaskFilter::Make(blurStyle, sigma, flags));
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkPath path;
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                tests[test].addPath(&path);
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkPath strokedPath;
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                paint.getFillPath(path, &strokedPath);
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkRect refBound = strokedPath.getBounds();
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkIRect iref;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                refBound.roundOut(&iref);
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                iref.inset(-outset, -outset);
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkBitmap refBitmap;
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                create(&refBitmap, iref);
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkCanvas refCanvas(refBitmap);
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                refCanvas.translate(SkIntToScalar(-iref.fLeft),
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                    SkIntToScalar(-iref.fTop));
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                drawBG(&refCanvas);
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                refCanvas.drawPath(path, paint);
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int view = 0; view < tests[test].viewLen; ++view) {
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkIRect itest = tests[test].views[view];
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkBitmap testBitmap;
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    create(&testBitmap, itest);
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkCanvas testCanvas(testBitmap);
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    testCanvas.translate(SkIntToScalar(-itest.fLeft),
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         SkIntToScalar(-itest.fTop));
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    drawBG(&testCanvas);
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    testCanvas.drawPath(path, paint);
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    REPORTER_ASSERT(reporter,
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        compare(refBitmap, iref, testBitmap, itest));
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Use SkBlurMask::BlurGroundTruth to blur a 'width' x 'height' solid
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// white rect. Return the right half of the middle row in 'result'.
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void ground_truth_2d(int width, int height,
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            SkScalar sigma,
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            int* result, int resultCount) {
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMask src, dst;
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src.fBounds.set(0, 0, width, height);
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src.fFormat = SkMask::kA8_Format;
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src.fRowBytes = src.fBounds.width();
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    memset(src.fImage, 0xff, src.computeTotalImageSize());
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!SkBlurMask::BlurGroundTruth(sigma, &dst, src, kNormal_SkBlurStyle)) {
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return;
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int midX = dst.fBounds.centerX();
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int midY = dst.fBounds.centerY();
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint8_t* bytes = dst.getAddr8(midX, midY);
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int i;
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (i = 0; i < dst.fBounds.width()-(midX-dst.fBounds.fLeft); ++i) {
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (i < resultCount) {
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            result[i] = bytes[i];
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for ( ; i < resultCount; ++i) {
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result[i] = 0;
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMask::FreeImage(src.fImage);
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMask::FreeImage(dst.fImage);
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Implement a step function that is 255 between min and max; 0 elsewhere.
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int step(int x, SkScalar min, SkScalar max) {
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (min < x && x < max) {
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return 255;
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return 0;
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Implement a Gaussian function with 0 mean and std.dev. of 'sigma'.
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic float gaussian(int x, SkScalar sigma) {
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float k = SK_Scalar1/(sigma * sqrtf(2.0f*SK_ScalarPI));
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    float exponent = -(x * x) / (2 * sigma * sigma);
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return k * expf(exponent);
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Perform a brute force convolution of a step function with a Gaussian.
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Return the right half in 'result'
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void brute_force_1d(SkScalar stepMin, SkScalar stepMax,
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                           SkScalar gaussianSigma,
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                           int* result, int resultCount) {
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int gaussianRange = SkScalarCeilToInt(10 * gaussianSigma);
213fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
214fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < resultCount; ++i) {
215fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar sum = 0.0f;
216fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int j = -gaussianRange; j < gaussianRange; ++j) {
217fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            sum += gaussian(j, gaussianSigma) * step(i-j, stepMin, stepMax);
218fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
219fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
220fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result[i] = SkClampMax(SkClampPos(int(sum + 0.5f)), 255);
221fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
222fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
223fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
224fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void blur_path(SkCanvas* canvas, const SkPath& path,
225fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                      SkScalar gaussianSigma) {
226fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
227fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar midX = path.getBounds().centerX();
228fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar midY = path.getBounds().centerY();
229fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
230fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas->translate(-midX, -midY);
231fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
232fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint blurPaint;
233fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    blurPaint.setColor(SK_ColorWHITE);
234fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    blurPaint.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, gaussianSigma,
235fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                   SkBlurMaskFilter::kHighQuality_BlurFlag));
236fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
237fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas->drawColor(SK_ColorBLACK);
238fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas->drawPath(path, blurPaint);
239fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
240fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
241fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Readback the blurred draw results from the canvas
242fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void readback(const SkBitmap& src, int* result, int resultCount) {
243fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBitmap readback;
244fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    readback.allocN32Pixels(resultCount, 30);
245fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPixmap pm;
246fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    readback.peekPixels(&pm);
247fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    src.readPixels(pm, 0, 0);
248fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
249fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkPMColor* pixels = pm.addr32(0, 15);
250fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
251fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < resultCount; ++i) {
252fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result[i] = SkColorGetR(pixels[i]);
253fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
254fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
255fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
256fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Draw a blurred version of the provided path.
257fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Return the right half of the middle row in 'result'.
258fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void cpu_blur_path(const SkPath& path, SkScalar gaussianSigma,
259fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                          int* result, int resultCount) {
260fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
261fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkBitmap bitmap;
262fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bitmap.allocN32Pixels(resultCount, 30);
263fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkCanvas canvas(bitmap);
264fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
265fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    blur_path(&canvas, path, gaussianSigma);
266fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    readback(bitmap, result, resultCount);
267fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
268fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
269fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if WRITE_CSV
270fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void write_as_csv(const char* label, SkScalar scale, int* data, int count) {
271fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("%s_%.2f,", label, scale);
272fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count-1; ++i) {
273fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf("%d,", data[i]);
274fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
275fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("%d\n", data[count-1]);
276fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
277fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
278fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
279fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool match(int* first, int* second, int count, int tol) {
280fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int delta;
281fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count; ++i) {
282fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        delta = first[i] - second[i];
283fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (delta > tol || delta < -tol) {
284fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return false;
285fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
286fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
287fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
288fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return true;
289fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
290fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
291fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Test out the normal blur style with a wide range of sigmas
292fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(BlurSigmaRange, reporter) {
293fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const int kSize = 100;
294fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
295fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // The geometry is offset a smidge to trigger:
296fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // https://code.google.com/p/chromium/issues/detail?id=282418
297fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath rectPath;
298fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    rectPath.addRect(0.3f, 0.3f, 100.3f, 100.3f);
299fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
300fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPoint polyPts[] = {
301fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 0.3f, 0.3f },
302fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 100.3f, 0.3f },
303fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 100.3f, 100.3f },
304fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 0.3f, 100.3f },
305fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 2.3f, 50.3f }     // a little divet to throw off the rect special case
306fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
307fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath polyPath;
308fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    polyPath.addPoly(polyPts, SK_ARRAY_COUNT(polyPts), true);
309fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
310fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int rectSpecialCaseResult[kSize];
311fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int generalCaseResult[kSize];
312fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int groundTruthResult[kSize];
313fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int bruteForce1DResult[kSize];
314fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
315fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar sigma = 10.0f;
316fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
317fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < 4; ++i, sigma /= 10) {
318fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
319fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        cpu_blur_path(rectPath, sigma, rectSpecialCaseResult, kSize);
320fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        cpu_blur_path(polyPath, sigma, generalCaseResult, kSize);
321fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
322fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ground_truth_2d(100, 100, sigma, groundTruthResult, kSize);
323fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        brute_force_1d(-50.0f, 50.0f, sigma, bruteForce1DResult, kSize);
324fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
325fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, match(rectSpecialCaseResult, bruteForce1DResult, kSize, 5));
326fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, match(generalCaseResult, bruteForce1DResult, kSize, 15));
327fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, match(groundTruthResult, bruteForce1DResult, kSize, 1));
328fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
329fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if WRITE_CSV
330fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        write_as_csv("RectSpecialCase", sigma, rectSpecialCaseResult, kSize);
331fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        write_as_csv("GeneralCase", sigma, generalCaseResult, kSize);
332fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU
333fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        write_as_csv("GPU", sigma, gpuResult, kSize);
334fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
335fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        write_as_csv("GroundTruth2D", sigma, groundTruthResult, kSize);
336fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        write_as_csv("BruteForce1D", sigma, bruteForce1DResult, kSize);
337fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
338fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
339fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
340fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
341fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////
342fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
343fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic SkBlurQuality blurMaskFilterFlags_as_quality(uint32_t blurMaskFilterFlags) {
344fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return (blurMaskFilterFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
345fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            kHigh_SkBlurQuality : kLow_SkBlurQuality;
346fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
347fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
348fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_blurDrawLooper(skiatest::Reporter* reporter, SkScalar sigma,
349fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                SkBlurStyle style, uint32_t blurMaskFilterFlags) {
350fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (kNormal_SkBlurStyle != style) {
351fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return; // blurdrawlooper only supports normal
352fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
353fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
354fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkColor color = 0xFF335577;
355fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkScalar dx = 10;
356fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkScalar dy = -5;
357fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkDrawLooper> lp(SkBlurDrawLooper::Make(color, sigma, dx, dy));
358fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const bool expectSuccess = sigma > 0;
359fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
360fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (nullptr == lp) {
361fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, sigma <= 0);
362fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
363fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDrawLooper::BlurShadowRec rec;
364fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        bool success = lp->asABlurShadow(&rec);
365fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, success == expectSuccess);
366fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (success) {
367fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(reporter, rec.fSigma == sigma);
368fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(reporter, rec.fOffset.x() == dx);
369fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(reporter, rec.fOffset.y() == dy);
370fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(reporter, rec.fColor == color);
371fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(reporter, rec.fStyle == style);
372fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            REPORTER_ASSERT(reporter, rec.fQuality == kLow_SkBlurQuality);
373fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
374fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
375fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
376fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
377fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_looper(skiatest::Reporter* reporter, sk_sp<SkDrawLooper> lp, SkScalar sigma,
378fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
379fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDrawLooper::BlurShadowRec rec;
380fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool success = lp->asABlurShadow(&rec);
381fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    REPORTER_ASSERT(reporter, success == expectSuccess);
382fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (success != expectSuccess) {
383fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        lp->asABlurShadow(&rec);
384fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
385fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (success) {
386fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, rec.fSigma == sigma);
387fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, rec.fStyle == style);
388fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, rec.fQuality == quality);
389fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
390fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
391fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
392fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void make_noop_layer(SkLayerDrawLooper::Builder* builder) {
393fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkLayerDrawLooper::LayerInfo info;
394fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
395fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    info.fPaintBits = 0;
396fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    info.fColorMode = SkBlendMode::kDst;
397fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    builder->addLayer(info);
398fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
399fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
400fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void make_blur_layer(SkLayerDrawLooper::Builder* builder, sk_sp<SkMaskFilter> mf) {
401fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkLayerDrawLooper::LayerInfo info;
402fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
403fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
404fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    info.fColorMode = SkBlendMode::kSrc;
405fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint* paint = builder->addLayer(info);
406fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    paint->setMaskFilter(std::move(mf));
407fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
408fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
409fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void test_layerDrawLooper(skiatest::Reporter* reporter, sk_sp<SkMaskFilter> mf,
410fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 SkScalar sigma, SkBlurStyle style, SkBlurQuality quality,
411fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 bool expectSuccess) {
412fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
413fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkLayerDrawLooper::LayerInfo info;
414fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkLayerDrawLooper::Builder builder;
415fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
416fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 1 layer is too few
417fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_noop_layer(&builder);
418fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    test_looper(reporter, builder.detach(), sigma, style, quality, false);
419fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
420fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 2 layers is good, but need blur
421fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_noop_layer(&builder);
422fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_noop_layer(&builder);
423fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    test_looper(reporter, builder.detach(), sigma, style, quality, false);
424fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
425fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 2 layers is just right
426fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_noop_layer(&builder);
427fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_blur_layer(&builder, mf);
428fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    test_looper(reporter, builder.detach(), sigma, style, quality, expectSuccess);
429fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
430fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // 3 layers is too many
431fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_noop_layer(&builder);
432fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_blur_layer(&builder, mf);
433fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    make_noop_layer(&builder);
434fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    test_looper(reporter, builder.detach(), sigma, style, quality, false);
435fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
436fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
437fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(BlurAsABlur, reporter) {
438fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkBlurStyle styles[] = {
439fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        kNormal_SkBlurStyle, kSolid_SkBlurStyle, kOuter_SkBlurStyle, kInner_SkBlurStyle
440fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
441fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkScalar sigmas[] = {
442fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // values <= 0 should not success for a blur
443fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        -1, 0, 0.5f, 2
444fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
445fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
446fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Test asABlur for SkBlurMaskFilter
447fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //
448fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (size_t i = 0; i < SK_ARRAY_COUNT(styles); ++i) {
449fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkBlurStyle style = styles[i];
450fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
451fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkScalar sigma = sigmas[j];
452fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int flags = 0; flags <= SkBlurMaskFilter::kAll_BlurFlag; ++flags) {
453fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                const SkBlurQuality quality = blurMaskFilterFlags_as_quality(flags);
454fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
455fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                sk_sp<SkMaskFilter> mf(SkBlurMaskFilter::Make(style, sigma, flags));
456fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                if (nullptr == mf.get()) {
457fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    REPORTER_ASSERT(reporter, sigma <= 0);
458fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                } else {
459fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    REPORTER_ASSERT(reporter, sigma > 0);
460fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkMaskFilterBase::BlurRec rec;
461fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    bool success = as_MFB(mf)->asABlur(&rec);
462fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    if (flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
463fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter, !success);
464fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    } else {
465fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter, success);
466fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter, rec.fSigma == sigma);
467fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter, rec.fStyle == style);
468fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter, rec.fQuality == quality);
469fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
470fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    test_layerDrawLooper(reporter, std::move(mf), sigma, style, quality, success);
471fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
472fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                test_blurDrawLooper(reporter, sigma, style, flags);
473fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
474fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
475fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
476fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
477fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Test asABlur for SkEmbossMaskFilter -- should never succeed
478fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    //
479fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
480fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkEmbossMaskFilter::Light light = {
481fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            { 1, 1, 1 }, 0, 127, 127
482fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        };
483fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
484fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            const SkScalar sigma = sigmas[j];
485fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            auto mf(SkEmbossMaskFilter::Make(sigma, light));
486fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            if (mf) {
487fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                SkMaskFilterBase::BlurRec rec;
488fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                bool success = as_MFB(mf)->asABlur(&rec);
489fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                REPORTER_ASSERT(reporter, !success);
490fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
491fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
492fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
493fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
494fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
495fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#if SK_SUPPORT_GPU
496fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
497fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// This exercises the problem discovered in crbug.com/570232. The return value from
498fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// SkBlurMask::BoxBlur wasn't being checked in SkBlurMaskFilter.cpp::GrRRectBlurEffect::Create
499fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_GPUTEST_FOR_RENDERING_CONTEXTS(SmallBoxBlurBug, reporter, ctxInfo) {
500fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
501fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkImageInfo info = SkImageInfo::MakeN32Premul(128, 128);
502fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto surface(SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, info));
503fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkCanvas* canvas = surface->getCanvas();
504fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
505fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect r = SkRect::MakeXYWH(10, 10, 100, 100);
506fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRRect rr = SkRRect::MakeRectXY(r, 10, 10);
507fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
508fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint p;
509fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    p.setMaskFilter(SkBlurMaskFilter::Make(kNormal_SkBlurStyle, 0.01f));
510fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
511fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    canvas->drawRRect(rr, p);
512fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
513fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
514fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
515fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
516fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
517fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(BlurredRRectNinePatchComputation, reporter) {
518fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const SkRect r = SkRect::MakeXYWH(10, 10, 100, 100);
519fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static const SkScalar kBlurRad = 3.0f;
520fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
521fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    bool ninePatchable;
522fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRRect rrectToDraw;
523fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkISize size;
524fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar rectXs[SkBlurMaskFilter::kMaxDivisions], rectYs[SkBlurMaskFilter::kMaxDivisions];
525fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkScalar texXs[SkBlurMaskFilter::kMaxDivisions], texYs[SkBlurMaskFilter::kMaxDivisions];
526fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int numX, numY;
527fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    uint32_t skipMask;
528fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
529fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // not nine-patchable
530fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
531fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkVector radii[4] = { { 100, 100 }, { 0, 0 }, { 100, 100 }, { 0, 0 } };
532fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
533fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRRect rr;
534fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rr.setRectRadii(r, radii);
535fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
536fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(rr, rr, SkRect::MakeEmpty(),
537fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    kBlurRad, kBlurRad,
538fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &rrectToDraw, &size,
539fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    rectXs, rectYs, texXs, texYs,
540fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &numX, &numY, &skipMask);
541fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !ninePatchable);
542fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
543fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
544fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // simple circular
545fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
546fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kCornerRad = 10.0f;
547fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRRect rr;
548fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rr.setRectXY(r, kCornerRad, kCornerRad);
549fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
550fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(rr, rr, SkRect::MakeEmpty(),
551fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    kBlurRad, kBlurRad,
552fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &rrectToDraw, &size,
553fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    rectXs, rectYs, texXs, texYs,
554fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &numX, &numY, &skipMask);
555fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
556fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kAns = 12.0f * kBlurRad + 2.0f * kCornerRad + 1.0f;
557fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, ninePatchable);
558fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SkIntToScalar(size.fWidth), kAns));
559fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SkIntToScalar(size.fHeight), kAns));
560fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, 4 == numX && 4 == numY);
561fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !skipMask);
562fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
563fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
564fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // simple elliptical
565fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
566fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kXCornerRad = 2.0f;
567fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kYCornerRad = 10.0f;
568fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRRect rr;
569fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rr.setRectXY(r, kXCornerRad, kYCornerRad);
570fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
571fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(rr, rr, SkRect::MakeEmpty(),
572fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    kBlurRad, kBlurRad,
573fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &rrectToDraw, &size,
574fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    rectXs, rectYs, texXs, texYs,
575fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &numX, &numY, &skipMask);
576fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
577fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kXAns = 12.0f * kBlurRad + 2.0f * kXCornerRad + 1.0f;
578fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kYAns = 12.0f * kBlurRad + 2.0f * kYCornerRad + 1.0f;
579fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
580fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, ninePatchable);
581fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SkIntToScalar(size.fWidth), kXAns));
582fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, SkScalarNearlyEqual(SkIntToScalar(size.fHeight), kYAns));
583fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, 4 == numX && 4 == numY);
584fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        REPORTER_ASSERT(reporter, !skipMask);
585fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
586fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
587fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // test-out occlusion
588fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    {
589fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static const SkScalar kCornerRad = 10.0f;
590fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkRRect rr;
591fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        rr.setRectXY(r, kCornerRad, kCornerRad);
592fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
593fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // The rectXs & rectYs should be { 1, 29, 91, 119 }. Add two more points around each.
594fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkScalar testLocs[] = {
595fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             -18.0f, -9.0f,
596fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               1.0f,
597fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot               9.0f, 18.0f,
598fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              29.0f,
599fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              39.0f, 49.0f,
600fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot              91.0f,
601fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             109.0f, 118.0f,
602fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             119.0f,
603fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot             139.0f, 149.0f
604fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        };
605fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
606fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int minY = 0; minY < (int)SK_ARRAY_COUNT(testLocs); ++minY) {
607fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int maxY = minY+1; maxY < (int)SK_ARRAY_COUNT(testLocs); ++maxY) {
608fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (int minX = 0; minX < (int)SK_ARRAY_COUNT(testLocs); ++minX) {
609fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    for (int maxX = minX+1; maxX < (int)SK_ARRAY_COUNT(testLocs); ++maxX) {
610fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        SkRect occluder = SkRect::MakeLTRB(testLocs[minX], testLocs[minY],
611fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                           testLocs[maxX], testLocs[maxY]);
612fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        if (occluder.isEmpty()) {
613fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            continue;
614fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        }
615fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
616fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(
617fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    rr, rr, occluder,
618fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    kBlurRad, kBlurRad,
619fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &rrectToDraw, &size,
620fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    rectXs, rectYs, texXs, texYs,
621fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                                    &numX, &numY, &skipMask);
622fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
623fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        static const SkScalar kAns = 12.0f * kBlurRad + 2.0f * kCornerRad + 1.0f;
624fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter, ninePatchable);
625fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter,
626fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            SkScalarNearlyEqual(SkIntToScalar(size.fWidth), kAns));
627fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        REPORTER_ASSERT(reporter,
628fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            SkScalarNearlyEqual(SkIntToScalar(size.fHeight), kAns));
629fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
630fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        int checkBit = 0x1;
631fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        for (int y = 0; y < numY-1; ++y) {
632fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            for (int x = 0; x < numX-1; ++x) {
633fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                SkRect cell = SkRect::MakeLTRB(rectXs[x], rectYs[y],
634fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                               rectXs[x+1], rectYs[y+1]);
635fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                REPORTER_ASSERT(reporter,
636fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    SkToBool(skipMask & checkBit) ==
637fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                    (cell.isEmpty() || occluder.contains(cell)));
638fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
639fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                REPORTER_ASSERT(reporter, texXs[x] >= 0 &&
640fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                          texXs[x] <= size.fWidth);
641fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                REPORTER_ASSERT(reporter, texYs[y] >= 0 &&
642fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                          texXs[y] <= size.fHeight);
643fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
644fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                checkBit <<= 1;
645fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            }
646fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        }
647fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
648fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
649fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
650fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
651fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
652fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
653fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
654fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
655fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
656fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
657fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// https://crbugs.com/787712
658fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(EmbossPerlinCrash, reporter) {
659fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPaint p;
660fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
661fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    static constexpr SkEmbossMaskFilter::Light light = {
662fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        { 1, 1, 1 }, 0, 127, 127
663fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
664fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    p.setMaskFilter(SkEmbossMaskFilter::Make(1, light));
665fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    p.setShader(SkPerlinNoiseShader::MakeFractalNoise(1.0f, 1.0f, 2, 0.0f));
666fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
667fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(100, 100);
668fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    surface->getCanvas()->drawPaint(p);
669fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
670fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
671fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////////////////
672