1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
7daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
83dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#include "SkBlurMask.h"
92b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com#include "SkBlurMaskFilter.h"
10daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com#include "SkBlurDrawLooper.h"
11daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com#include "SkLayerDrawLooper.h"
12daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com#include "SkEmbossMaskFilter.h"
135af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com#include "SkCanvas.h"
14889bd8bd7f604acae0a6303365bc82c06da1e6f3tomhudson@google.com#include "SkMath.h"
155af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com#include "SkPaint.h"
164ee16bfaedb14aff8cf102f1f0722ff2529a9699tfarina@chromium.org#include "Test.h"
174ee16bfaedb14aff8cf102f1f0722ff2529a9699tfarina@chromium.org
183dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#if SK_SUPPORT_GPU
193dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#include "GrContextFactory.h"
203dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#include "SkGpuDevice.h"
213dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#endif
223dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
233dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#define WRITE_CSV 0
242b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
252b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com///////////////////////////////////////////////////////////////////////////////
262b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
272b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com#define ILLEGAL_MODE    ((SkXfermode::Mode)-1)
282b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
295af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic const int outset = 100;
305af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic const SkColor bgColor = SK_ColorWHITE;
315af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic const int strokeWidth = 4;
325af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
33fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.orgstatic void create(SkBitmap* bm, const SkIRect& bound) {
34fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org    bm->allocN32Pixels(bound.width(), bound.height());
355af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com}
365af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
375af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic void drawBG(SkCanvas* canvas) {
385af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    canvas->drawColor(bgColor);
395af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com}
405af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
415af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
425af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstruct BlurTest {
435af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    void (*addPath)(SkPath*);
445af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    int viewLen;
455af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    SkIRect views[9];
465af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com};
475af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
485af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com//Path Draw Procs
495af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com//Beware that paths themselves my draw differently depending on the clip.
505af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic void draw50x50Rect(SkPath* path) {
515af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
525af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com}
535af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
545af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com//Tests
555af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic BlurTest tests[] = {
565af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    { draw50x50Rect, 3, {
575af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        //inner half of blur
585af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        { 0, 0, 50, 50 },
595af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        //blur, but no path.
605af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        { 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
615af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        //just an edge
625af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        { 40, strokeWidth, 60, 50 - strokeWidth },
635af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    }},
645af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com};
655af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
665af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com/** Assumes that the ref draw was completely inside ref canvas --
675af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    implies that everything outside is "bgColor".
685af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    Checks that all overlap is the same and that all non-overlap on the
695af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    ref is "bgColor".
705af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com */
715af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.comstatic bool compare(const SkBitmap& ref, const SkIRect& iref,
725af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    const SkBitmap& test, const SkIRect& itest)
735af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com{
745af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    const int xOff = itest.fLeft - iref.fLeft;
755af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    const int yOff = itest.fTop - iref.fTop;
765af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
775af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    SkAutoLockPixels alpRef(ref);
785af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    SkAutoLockPixels alpTest(test);
795af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
805af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    for (int y = 0; y < test.height(); ++y) {
815af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        for (int x = 0; x < test.width(); ++x) {
825af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            SkColor testColor = test.getColor(x, y);
835af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            int refX = x + xOff;
845af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            int refY = y + yOff;
855af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            SkColor refColor;
865af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            if (refX >= 0 && refX < ref.width() &&
875af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                refY >= 0 && refY < ref.height())
885af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            {
895af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                refColor = ref.getColor(refX, refY);
905af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            } else {
915af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                refColor = bgColor;
925af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            }
935af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            if (refColor != testColor) {
945af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                return false;
955af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            }
965af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        }
975af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    }
985af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    return true;
995af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com}
1005af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
1013dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic void test_blur_drawing(skiatest::Reporter* reporter) {
1022b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1035af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    SkPaint paint;
1045af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    paint.setColor(SK_ColorGRAY);
1055af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    paint.setStyle(SkPaint::kStroke_Style);
1065af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com    paint.setStrokeWidth(SkIntToScalar(strokeWidth));
1075af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
108b7061176c7f414616fe2e79e832b3e0abe326af6robertphillips@google.com    SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5));
109e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    for (int style = 0; style <= kLastEnum_SkBlurStyle; ++style) {
110e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org        SkBlurStyle blurStyle = static_cast<SkBlurStyle>(style);
1115af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
1125af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
1135af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
1145af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            SkMaskFilter* filter;
115b7061176c7f414616fe2e79e832b3e0abe326af6robertphillips@google.com            filter = SkBlurMaskFilter::Create(blurStyle, sigma, flags);
1165af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
1175af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            paint.setMaskFilter(filter);
1185af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            filter->unref();
1195af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com
12083a444602ec580a0040713eed588c245b4ae0ee9tomhudson@google.com            for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
1215af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                SkPath path;
1225af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                tests[test].addPath(&path);
123d16872c21fba2898f3b608f9bb33287e9972a312bungeman@google.com                SkPath strokedPath;
124d16872c21fba2898f3b608f9bb33287e9972a312bungeman@google.com                paint.getFillPath(path, &strokedPath);
125d16872c21fba2898f3b608f9bb33287e9972a312bungeman@google.com                SkRect refBound = strokedPath.getBounds();
1265af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                SkIRect iref;
1275af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                refBound.roundOut(&iref);
128d16872c21fba2898f3b608f9bb33287e9972a312bungeman@google.com                iref.inset(-outset, -outset);
1295af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                SkBitmap refBitmap;
130fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org                create(&refBitmap, iref);
1312b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1325af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                SkCanvas refCanvas(refBitmap);
1335af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                refCanvas.translate(SkIntToScalar(-iref.fLeft),
1345af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                                    SkIntToScalar(-iref.fTop));
1355af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                drawBG(&refCanvas);
1365af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                refCanvas.drawPath(path, paint);
1372b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1385af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                for (int view = 0; view < tests[test].viewLen; ++view) {
1395af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    SkIRect itest = tests[test].views[view];
1405af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    SkBitmap testBitmap;
141fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org                    create(&testBitmap, itest);
1422b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1435af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    SkCanvas testCanvas(testBitmap);
1445af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    testCanvas.translate(SkIntToScalar(-itest.fLeft),
1455af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                                         SkIntToScalar(-itest.fTop));
1465af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    drawBG(&testCanvas);
1475af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    testCanvas.drawPath(path, paint);
1482b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1495af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                    REPORTER_ASSERT(reporter,
1505af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                        compare(refBitmap, iref, testBitmap, itest));
1515af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com                }
1525af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com            }
1535af16f8d670b3ce1c7644a4737e02e2e2257614ebungeman@google.com        }
1542b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com    }
1552b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com}
1562b75f4279a237ceea929ff8ac019f7fbd3ad08b5reed@google.com
1573dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com///////////////////////////////////////////////////////////////////////////////
1583dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
1593dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Use SkBlurMask::BlurGroundTruth to blur a 'width' x 'height' solid
1603dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// white rect. Return the right half of the middle row in 'result'.
1616fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.comstatic void ground_truth_2d(int width, int height,
1623dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                            SkScalar sigma,
1633dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                            int* result, int resultCount) {
1643dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkMask src, dst;
1653dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
1663dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    src.fBounds.set(0, 0, width, height);
1673dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    src.fFormat = SkMask::kA8_Format;
1683dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    src.fRowBytes = src.fBounds.width();
1693dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    src.fImage = SkMask::AllocImage(src.computeTotalImageSize());
1703dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
1713dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    memset(src.fImage, 0xff, src.computeTotalImageSize());
1723dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
1733dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    dst.fImage = NULL;
174e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkBlurMask::BlurGroundTruth(sigma, &dst, src, kNormal_SkBlurStyle);
1753dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
1763dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int midX = dst.fBounds.centerX();
1773dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int midY = dst.fBounds.centerY();
1783dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    uint8_t* bytes = dst.getAddr8(midX, midY);
1793dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int i;
1803dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for (i = 0; i < dst.fBounds.width()-(midX-dst.fBounds.fLeft); ++i) {
1813dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        if (i < resultCount) {
1823dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com            result[i] = bytes[i];
1833dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        }
1843dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
1853dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for ( ; i < resultCount; ++i) {
1863dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        result[i] = 0;
1873dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
1886d837aa1a12c1c03cce7cd37b1cae0ef4805f506robertphillips@google.com
1896d837aa1a12c1c03cce7cd37b1cae0ef4805f506robertphillips@google.com    SkMask::FreeImage(src.fImage);
1906d837aa1a12c1c03cce7cd37b1cae0ef4805f506robertphillips@google.com    SkMask::FreeImage(dst.fImage);
1913dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
1923dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
1933dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Implement a step function that is 255 between min and max; 0 elsewhere.
1943dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic int step(int x, SkScalar min, SkScalar max) {
1953dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    if (min < x && x < max) {
1963dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        return 255;
1973dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
1983dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    return 0;
1993dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
2003dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2013dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Implement a Gaussian function with 0 mean and std.dev. of 'sigma'.
2023dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic float gaussian(int x, SkScalar sigma) {
203b85564afffe630190fca81111a5f28cf9d4143berobertphillips@google.com    float k = SK_Scalar1/(sigma * sqrtf(2.0f*SK_ScalarPI));
2043dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    float exponent = -(x * x) / (2 * sigma * sigma);
205b85564afffe630190fca81111a5f28cf9d4143berobertphillips@google.com    return k * expf(exponent);
2063dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
2073dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2083dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Perform a brute force convolution of a step function with a Gaussian.
2093dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Return the right half in 'result'
2106fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.comstatic void brute_force_1d(SkScalar stepMin, SkScalar stepMax,
2113dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                           SkScalar gaussianSigma,
2123dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                           int* result, int resultCount) {
2133dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2143dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int gaussianRange = SkScalarCeilToInt(10 * gaussianSigma);
2153dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2163dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for (int i = 0; i < resultCount; ++i) {
2173dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        SkScalar sum = 0.0f;
2183dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        for (int j = -gaussianRange; j < gaussianRange; ++j) {
2193dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com            sum += gaussian(j, gaussianSigma) * step(i-j, stepMin, stepMax);
2203dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        }
2213dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2223dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        result[i] = SkClampMax(SkClampPos(int(sum + 0.5f)), 255);
2233dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
2243dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
2253dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2266fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.comstatic void blur_path(SkCanvas* canvas, const SkPath& path,
2273dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                      SkScalar gaussianSigma) {
2283dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2293dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkScalar midX = path.getBounds().centerX();
2303dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkScalar midY = path.getBounds().centerY();
2313dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2323dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    canvas->translate(-midX, -midY);
2333dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2343dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkPaint blurPaint;
2353dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    blurPaint.setColor(SK_ColorWHITE);
236e396455d2d60ddf8e625b5037254f3c09fbcdcf5commit-bot@chromium.org    SkMaskFilter* filter = SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
2373dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                                                    gaussianSigma,
2383dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                                                    SkBlurMaskFilter::kHighQuality_BlurFlag);
2393dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    blurPaint.setMaskFilter(filter)->unref();
2403dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2413dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    canvas->drawColor(SK_ColorBLACK);
2423dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    canvas->drawPath(path, blurPaint);
2433dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
2443dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2453dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Readback the blurred draw results from the canvas
2463dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic void readback(SkCanvas* canvas, int* result, int resultCount) {
2473dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkBitmap readback;
248fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org    readback.allocN32Pixels(resultCount, 30);
2493dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2503dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkIRect readBackRect = { 0, 0, resultCount, 30 };
2513dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2523dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    canvas->readPixels(readBackRect, &readback);
2533dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2543dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    readback.lockPixels();
2553dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkPMColor* pixels = (SkPMColor*) readback.getAddr32(0, 15);
2563dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2573dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for (int i = 0; i < resultCount; ++i) {
2583dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        result[i] = SkColorGetR(pixels[i]);
2593dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
2603dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
2613dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2626fc1b4998917791a73bf54428513940fe77dc058skia.committer@gmail.com// Draw a blurred version of the provided path.
2633dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Return the right half of the middle row in 'result'.
2643dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic void cpu_blur_path(const SkPath& path, SkScalar gaussianSigma,
2653dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                          int* result, int resultCount) {
2663dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2673dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkBitmap bitmap;
268fa9e5fa42a555712fb7a29d08d2ae2bdef0ed68ecommit-bot@chromium.org    bitmap.allocN32Pixels(resultCount, 30);
2693dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkCanvas canvas(bitmap);
2703dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2713dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    blur_path(&canvas, path, gaussianSigma);
2723dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    readback(&canvas, result, resultCount);
2733dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
2743dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2753dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#if SK_SUPPORT_GPU
2764a24cd8ff41a8b3d292d60e4351a631240a7ed75humper#if 0
2774a24cd8ff41a8b3d292d60e4351a631240a7ed75humper// temporary disable; see below for explanation
278cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.comstatic bool gpu_blur_path(GrContextFactory* factory, const SkPath& path,
2793dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                          SkScalar gaussianSigma,
2803dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com                          int* result, int resultCount) {
2813dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2823dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    GrContext* grContext = factory->get(GrContextFactory::kNative_GLContextType);
2833dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    if (NULL == grContext) {
284cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.com        return false;
2853dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
2863dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2873dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    GrTextureDesc desc;
2883dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    desc.fConfig = kSkia8888_GrPixelConfig;
2893dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    desc.fFlags = kRenderTarget_GrTextureFlagBit;
2903dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    desc.fWidth = resultCount;
2913dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    desc.fHeight = 30;
2923dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    desc.fSampleCnt = 0;
2933dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2943dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkAutoTUnref<GrTexture> texture(grContext->createUncachedTexture(desc, NULL, 0));
2953dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkAutoTUnref<SkGpuDevice> device(SkNEW_ARGS(SkGpuDevice, (grContext, texture.get())));
2963dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkCanvas canvas(device.get());
2973dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
2983dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    blur_path(&canvas, path, gaussianSigma);
2993dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    readback(&canvas, result, resultCount);
300cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.com    return true;
3013dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
3023dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#endif
3034a24cd8ff41a8b3d292d60e4351a631240a7ed75humper#endif
3043dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3053dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#if WRITE_CSV
3063dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic void write_as_csv(const char* label, SkScalar scale, int* data, int count) {
3073dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkDebugf("%s_%.2f,", label, scale);
3083dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for (int i = 0; i < count-1; ++i) {
3093dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        SkDebugf("%d,", data[i]);
3103dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
3113dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkDebugf("%d\n", data[count-1]);
3123dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
3133dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#endif
3143dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3153dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic bool match(int* first, int* second, int count, int tol) {
3163dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int delta;
3173dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for (int i = 0; i < count; ++i) {
3183dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        delta = first[i] - second[i];
3193dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        if (delta > tol || delta < -tol) {
3203dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com            return false;
3213dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        }
3223dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
3233dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3243dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    return true;
3253dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
3263dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3273dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com// Test out the normal blur style with a wide range of sigmas
3283dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.comstatic void test_sigma_range(skiatest::Reporter* reporter, GrContextFactory* factory) {
3293dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3303dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    static const int kSize = 100;
3313dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3323dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    // The geometry is offset a smidge to trigger:
3333dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    // https://code.google.com/p/chromium/issues/detail?id=282418
3343dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkPath rectPath;
3353dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    rectPath.addRect(0.3f, 0.3f, 100.3f, 100.3f);
3363dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3373dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkPoint polyPts[] = {
3383dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        { 0.3f, 0.3f },
3393dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        { 100.3f, 0.3f },
3403dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        { 100.3f, 100.3f },
3413dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        { 0.3f, 100.3f },
3423dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        { 2.3f, 50.3f }     // a little divet to throw off the rect special case
3433dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    };
3443dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    SkPath polyPath;
3453dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    polyPath.addPoly(polyPts, SK_ARRAY_COUNT(polyPts), true);
3463dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3473dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int rectSpecialCaseResult[kSize];
3483dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int generalCaseResult[kSize];
3493dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int groundTruthResult[kSize];
3503dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    int bruteForce1DResult[kSize];
3513dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3524b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org    SkScalar sigma = 10.0f;
3533dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3543dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    for (int i = 0; i < 4; ++i, sigma /= 10) {
3553dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3563dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        cpu_blur_path(rectPath, sigma, rectSpecialCaseResult, kSize);
3573dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        cpu_blur_path(polyPath, sigma, generalCaseResult, kSize);
3584a24cd8ff41a8b3d292d60e4351a631240a7ed75humper
3593dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        ground_truth_2d(100, 100, sigma, groundTruthResult, kSize);
3603dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        brute_force_1d(-50.0f, 50.0f, sigma, bruteForce1DResult, kSize);
3613dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3623dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        REPORTER_ASSERT(reporter, match(rectSpecialCaseResult, bruteForce1DResult, kSize, 5));
3633dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        REPORTER_ASSERT(reporter, match(generalCaseResult, bruteForce1DResult, kSize, 15));
3643dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#if SK_SUPPORT_GPU
3654a24cd8ff41a8b3d292d60e4351a631240a7ed75humper#if 0
3664a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        int gpuResult[kSize];
3674a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        bool haveGPUResult = gpu_blur_path(factory, rectPath, sigma, gpuResult, kSize);
3684a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        // Disabling this test for now -- I don't think it's a legit comparison.
3694a24cd8ff41a8b3d292d60e4351a631240a7ed75humper        // Will continue to investigate this.
370cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.com        if (haveGPUResult) {
371cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.com            // 1 works everywhere but: Ubuntu13 & Nexus4
372cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.com            REPORTER_ASSERT(reporter, match(gpuResult, bruteForce1DResult, kSize, 10));
373cb3b615af712fc71b19b86211c1d083430114d7erobertphillips@google.com        }
3743dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#endif
3754a24cd8ff41a8b3d292d60e4351a631240a7ed75humper#endif
3763dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        REPORTER_ASSERT(reporter, match(groundTruthResult, bruteForce1DResult, kSize, 1));
3773dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
3783dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#if WRITE_CSV
3793dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        write_as_csv("RectSpecialCase", sigma, rectSpecialCaseResult, kSize);
3803dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        write_as_csv("GeneralCase", sigma, generalCaseResult, kSize);
3813dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#if SK_SUPPORT_GPU
3823dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        write_as_csv("GPU", sigma, gpuResult, kSize);
3833dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#endif
3843dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        write_as_csv("GroundTruth2D", sigma, groundTruthResult, kSize);
3853dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com        write_as_csv("BruteForce1D", sigma, bruteForce1DResult, kSize);
3863dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com#endif
3873dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    }
3883dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
3893dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com
390daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com///////////////////////////////////////////////////////////////////////////////////////////
391daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
392daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic SkBlurQuality blurMaskFilterFlags_as_quality(uint32_t blurMaskFilterFlags) {
393daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    return (blurMaskFilterFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
394daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            kHigh_SkBlurQuality : kLow_SkBlurQuality;
395daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
396daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
397daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic uint32_t blurMaskFilterFlags_to_blurDrawLooperFlags(uint32_t bmf) {
398daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const struct {
399daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        uint32_t fBlurMaskFilterFlag;
400daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        uint32_t fBlurDrawLooperFlag;
401daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    } pairs[] = {
402daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        { SkBlurMaskFilter::kIgnoreTransform_BlurFlag, SkBlurDrawLooper::kIgnoreTransform_BlurFlag },
403daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        { SkBlurMaskFilter::kHighQuality_BlurFlag,     SkBlurDrawLooper::kHighQuality_BlurFlag },
404daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    };
405daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
406daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    uint32_t bdl = 0;
407daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    for (size_t i = 0; i < SK_ARRAY_COUNT(pairs); ++i) {
408daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        if (bmf & pairs[i].fBlurMaskFilterFlag) {
409daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            bdl |= pairs[i].fBlurDrawLooperFlag;
410daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        }
411daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
412daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    return bdl;
413daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
414daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
415daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic void test_blurDrawLooper(skiatest::Reporter* reporter, SkScalar sigma,
416daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                                SkBlurStyle style, uint32_t blurMaskFilterFlags) {
417daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    if (kNormal_SkBlurStyle != style) {
418daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        return; // blurdrawlooper only supports normal
419daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
420daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
421daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const SkColor color = 0xFF335577;
422daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const SkScalar dx = 10;
423daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const SkScalar dy = -5;
424daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const SkBlurQuality quality = blurMaskFilterFlags_as_quality(blurMaskFilterFlags);
425daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    uint32_t flags = blurMaskFilterFlags_to_blurDrawLooperFlags(blurMaskFilterFlags);
426daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
427daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkAutoTUnref<SkDrawLooper> lp(SkBlurDrawLooper::Create(color, sigma, dx, dy, flags));
428daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
429daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const bool expectSuccess = sigma > 0 &&
430daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                               0 == (flags & SkBlurDrawLooper::kIgnoreTransform_BlurFlag);
431daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
432daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    if (NULL == lp.get()) {
433daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        REPORTER_ASSERT(reporter, sigma <= 0);
434daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    } else {
435daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        SkDrawLooper::BlurShadowRec rec;
436daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        bool success = lp->asABlurShadow(&rec);
437daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        REPORTER_ASSERT(reporter, success == expectSuccess);
438daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        if (success) {
439daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            REPORTER_ASSERT(reporter, rec.fSigma == sigma);
440daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            REPORTER_ASSERT(reporter, rec.fOffset.x() == dx);
441daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            REPORTER_ASSERT(reporter, rec.fOffset.y() == dy);
442daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            REPORTER_ASSERT(reporter, rec.fColor == color);
443daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            REPORTER_ASSERT(reporter, rec.fStyle == style);
444daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            REPORTER_ASSERT(reporter, rec.fQuality == quality);
445daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        }
446daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
447daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
448daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
449daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic void test_delete_looper(skiatest::Reporter* reporter, SkDrawLooper* lp, SkScalar sigma,
450daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                               SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
451daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkDrawLooper::BlurShadowRec rec;
452daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    bool success = lp->asABlurShadow(&rec);
453daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    REPORTER_ASSERT(reporter, success == expectSuccess);
454daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    if (success != expectSuccess) {
455daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        lp->asABlurShadow(&rec);
456daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
457daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    if (success) {
458daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        REPORTER_ASSERT(reporter, rec.fSigma == sigma);
459daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        REPORTER_ASSERT(reporter, rec.fStyle == style);
460daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        REPORTER_ASSERT(reporter, rec.fQuality == quality);
461daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
462daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    lp->unref();
463daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
464daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
465daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic void make_noop_layer(SkLayerDrawLooper::Builder* builder) {
466daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkLayerDrawLooper::LayerInfo info;
467daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
468daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    info.fPaintBits = 0;
469daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    info.fColorMode = SkXfermode::kDst_Mode;
470daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    builder->addLayer(info);
471daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
472daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
473daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic void make_blur_layer(SkLayerDrawLooper::Builder* builder, SkMaskFilter* mf) {
474daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkLayerDrawLooper::LayerInfo info;
475daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
476daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    info.fPaintBits = SkLayerDrawLooper::kMaskFilter_Bit;
477daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    info.fColorMode = SkXfermode::kSrc_Mode;
478daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkPaint* paint = builder->addLayer(info);
479daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    paint->setMaskFilter(mf);
480daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
481daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
482daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic void test_layerDrawLooper(skiatest::Reporter* reporter, SkMaskFilter* mf, SkScalar sigma,
483daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                                 SkBlurStyle style, SkBlurQuality quality, bool expectSuccess) {
484daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
485daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkLayerDrawLooper::LayerInfo info;
486daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    SkLayerDrawLooper::Builder builder;
487daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
488daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    // 1 layer is too few
489daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_noop_layer(&builder);
490daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
491daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
492daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    // 2 layers is good, but need blur
493daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_noop_layer(&builder);
494daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_noop_layer(&builder);
495daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
496daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
497daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    // 2 layers is just right
498daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_noop_layer(&builder);
499daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_blur_layer(&builder, mf);
500daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, expectSuccess);
501daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
502daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    // 3 layers is too many
503daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_noop_layer(&builder);
504daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_blur_layer(&builder, mf);
505daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    make_noop_layer(&builder);
506daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    test_delete_looper(reporter, builder.detachLooper(), sigma, style, quality, false);
507daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
508daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
509daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comstatic void test_asABlur(skiatest::Reporter* reporter) {
510daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const SkBlurStyle styles[] = {
511daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        kNormal_SkBlurStyle, kSolid_SkBlurStyle, kOuter_SkBlurStyle, kInner_SkBlurStyle
512daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    };
513daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    const SkScalar sigmas[] = {
514daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        // values <= 0 should not success for a blur
515daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        -1, 0, 0.5f, 2
516daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    };
517daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
518daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    // Test asABlur for SkBlurMaskFilter
519daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    //
520daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    for (size_t i = 0; i < SK_ARRAY_COUNT(styles); ++i) {
521daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        const SkBlurStyle style = (SkBlurStyle)styles[i];
522daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
523daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            const SkScalar sigma = sigmas[j];
524daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            for (int flags = 0; flags <= SkBlurMaskFilter::kAll_BlurFlag; ++flags) {
525daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                const SkBlurQuality quality = blurMaskFilterFlags_as_quality(flags);
526daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
527daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                SkAutoTUnref<SkMaskFilter> mf(SkBlurMaskFilter::Create(style, sigma, flags));
528daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                if (NULL == mf.get()) {
529daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    REPORTER_ASSERT(reporter, sigma <= 0);
530daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                } else {
531daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    REPORTER_ASSERT(reporter, sigma > 0);
532daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    SkMaskFilter::BlurRec rec;
533daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    bool success = mf->asABlur(&rec);
534daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    if (flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
535daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                        REPORTER_ASSERT(reporter, !success);
536daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    } else {
537daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                        REPORTER_ASSERT(reporter, success);
538daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                        REPORTER_ASSERT(reporter, rec.fSigma == sigma);
539daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                        REPORTER_ASSERT(reporter, rec.fStyle == style);
540daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                        REPORTER_ASSERT(reporter, rec.fQuality == quality);
541daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    }
542daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                    test_layerDrawLooper(reporter, mf, sigma, style, quality, success);
543daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                }
544daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                test_blurDrawLooper(reporter, sigma, style, flags);
545daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            }
546daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        }
547daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
548daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
549daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    // Test asABlur for SkEmbossMaskFilter -- should never succeed
550daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    //
551daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    {
552daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        SkEmbossMaskFilter::Light light = {
553daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            { 1, 1, 1 }, 0, 127, 127
554daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        };
555daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        for (size_t j = 0; j < SK_ARRAY_COUNT(sigmas); ++j) {
556daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            const SkScalar sigma = sigmas[j];
557daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            SkAutoTUnref<SkMaskFilter> mf(SkEmbossMaskFilter::Create(sigma, light));
558daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            if (mf.get()) {
559daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                SkMaskFilter::BlurRec rec;
560daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                bool success = mf->asABlur(&rec);
561daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com                REPORTER_ASSERT(reporter, !success);
562daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com            }
563daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com        }
564daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    }
565daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com}
566daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
567daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com///////////////////////////////////////////////////////////////////////////////////////////
568daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com
5694ee16bfaedb14aff8cf102f1f0722ff2529a9699tfarina@chromium.orgDEF_GPUTEST(Blur, reporter, factory) {
5703dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    test_blur_drawing(reporter);
5713dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com    test_sigma_range(reporter, factory);
572daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com    test_asABlur(reporter);
5733dfa4cc07cb1b5c8dc90e022b7e5001a77a82066robertphillips@google.com}
574