SkBlurDrawLooper.cpp revision 4991b8f23482afc1494fd17647421ce68de53331
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurDrawLooper.h"
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMaskFilter.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCanvas.h"
114991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkColorFilter.h"
12c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com#include "SkFlattenableBuffers.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h"
144991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkPaint.h"
154991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkString.h"
164991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkStringUtils.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
19038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org                                   SkColor color, uint32_t flags)
20a728e35edcffd99216e3965a4b908ad0df7f69c2vandebo@chromium.org    : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags), fState(kDone) {
214e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com
22038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org    SkASSERT(flags <= kAll_BlurFlag);
234e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    if (radius > 0) {
2482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com        uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
2582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com            SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
26038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org            SkBlurMaskFilter::kNone_BlurFlag;
27038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org
284868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org        blurFlags |= flags & kHighQuality_BlurFlag ?
29fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com            SkBlurMaskFilter::kHighQuality_BlurFlag :
304868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org            SkBlurMaskFilter::kNone_BlurFlag;
314868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlur = SkBlurMaskFilter::Create(radius,
33fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com                                         SkBlurMaskFilter::kNormal_BlurStyle,
34038aff623d9fd47946cd31685f74cf473f7c84f0senorblanco@chromium.org                                         blurFlags);
354e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    } else {
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBlur = NULL;
374868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    }
384868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org
394e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    if (flags & kOverrideColor_BlurFlag) {
40a6398911174d5445456ecb2f5f4f0565db2f100bjunov@google.com        // Set alpha to 1 for the override since transparency will already
41a6398911174d5445456ecb2f5f4f0565db2f100bjunov@google.com        // be baked into the blurred mask.
42a6398911174d5445456ecb2f5f4f0565db2f100bjunov@google.com        SkColor opaqueColor = SkColorSetA(color, 255);
434868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org        //The SrcIn xfer mode will multiply 'color' by the incoming alpha
444e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
454e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                                                       SkXfermode::kSrcIn_Mode);
464e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    } else {
474868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org        fColorFilter = NULL;
484868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    }
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
516bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.comSkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
526bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com: INHERITED(buffer) {
536bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDx = buffer.readScalar();
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDy = buffer.readScalar();
56c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fBlurColor = buffer.readColor();
57c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fBlur = buffer.readFlattenableT<SkMaskFilter>();
58c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fColorFilter = buffer.readFlattenableT<SkColorFilter>();
59c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    fBlurFlags = buffer.readUInt() & kAll_BlurFlag;
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
624e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.comSkBlurDrawLooper::~SkBlurDrawLooper() {
6382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    SkSafeUnref(fBlur);
644868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    SkSafeUnref(fColorFilter);
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6754924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.comvoid SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) const {
6854924243c1b65b3ee6d8fa064b50a9b1bb2a19a5djsollen@google.com    this->INHERITED::flatten(buffer);
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeScalar(fDx);
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeScalar(fDy);
71c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeColor(fBlurColor);
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    buffer.writeFlattenable(fBlur);
734868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org    buffer.writeFlattenable(fColorFilter);
74c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com    buffer.writeUInt(fBlurFlags);
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
774e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.comvoid SkBlurDrawLooper::init(SkCanvas* canvas) {
784e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com    fState = kBeforeEdge;
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
814e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.combool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (fState) {
834e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        case kBeforeEdge:
844e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            // we do nothing if a maskfilter is already installed
854e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            if (paint->getMaskFilter()) {
864e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                fState = kDone;
874e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                return false;
884e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            }
8956c69773aea56c6c6bd47bc7e7970dd081205184djsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
90f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com            SkColor blurColor;
91f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com            blurColor = fBlurColor;
92f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com            if (SkColorGetA(blurColor) == 255) {
93f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com                blurColor = SkColorSetA(blurColor, paint->getAlpha());
94f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com            }
95f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com            paint->setColor(blurColor);
96f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com#else
974e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            paint->setColor(fBlurColor);
98f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com#endif
994e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            paint->setMaskFilter(fBlur);
1004e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            paint->setColorFilter(fColorFilter);
1014e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            canvas->save(SkCanvas::kMatrix_SaveFlag);
1024e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            if (fBlurFlags & kIgnoreTransform_BlurFlag) {
1034e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                SkMatrix transform(canvas->getTotalMatrix());
1044e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                transform.postTranslate(fDx, fDy);
1054e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                canvas->setMatrix(transform);
1064e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            } else {
1074e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com                canvas->translate(fDx, fDy);
1084e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            }
1094e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            fState = kAfterEdge;
1104e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            return true;
1114e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        case kAfterEdge:
1124e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            canvas->restore();
1134e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            fState = kDone;
1144e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            return true;
1154e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com        default:
1164e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            SkASSERT(kDone == fState);
1174e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com            return false;
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1204991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
1214991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#ifdef SK_DEVELOPER
1224991b8f23482afc1494fd17647421ce68de53331robertphillips@google.comvoid SkBlurDrawLooper::toString(SkString* str) const {
1234991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->append("SkBlurDrawLooper: ");
1244991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
1254991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->append("dx: ");
1264991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->appendScalar(fDx);
1274991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
1284991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->append(" dy: ");
1294991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->appendScalar(fDy);
1304991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
1314991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->append(" color: ");
1324991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->appendHex(fBlurColor);
1334991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
1344991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->append(" flags: (");
1354991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    if (kNone_BlurFlag == fBlurFlags) {
1364991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com        str->append("None");
1374991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    } else {
1384991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com        bool needsSeparator = false;
1394991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com        SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform",
1404991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com                          &needsSeparator);
1414991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com        SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor",
1424991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com                          &needsSeparator);
1434991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com        SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality",
1444991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com                          &needsSeparator);
1454991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    }
1464991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    str->append(")");
1474991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com
1484991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added
1494991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com    // alternatively we could cache the radius in SkBlurDrawLooper and just add it here
1504991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com}
1514991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#endif
152