1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 Google Inc.
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlurDrawLooper.h"
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlurMaskFilter.h"
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkCanvas.h"
1197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkColorFilter.h"
129ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkFlattenableBuffers.h"
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkMaskFilter.h"
1497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkPaint.h"
1597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkString.h"
1697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkStringUtils.h"
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
19740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org                                   SkColor color, uint32_t flags)
20a8a02b7a570cbfb0966453a1e0fc4275975e734bvandebo@chromium.org    : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags), fState(kDone) {
21a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com
22740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org    SkASSERT(flags <= kAll_BlurFlag);
23a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com    if (radius > 0) {
24919114813d58933c9d9433b141e0222c34b700b1reed@google.com        uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
25919114813d58933c9d9433b141e0222c34b700b1reed@google.com            SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
26740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org            SkBlurMaskFilter::kNone_BlurFlag;
27740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org
286a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org        blurFlags |= flags & kHighQuality_BlurFlag ?
29935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com            SkBlurMaskFilter::kHighQuality_BlurFlag :
306a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org            SkBlurMaskFilter::kNone_BlurFlag;
316a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fBlur = SkBlurMaskFilter::Create(radius,
33935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com                                         SkBlurMaskFilter::kNormal_BlurStyle,
34740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org                                         blurFlags);
35a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com    } else {
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fBlur = NULL;
376a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org    }
386a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org
39a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com    if (flags & kOverrideColor_BlurFlag) {
4088656e216fc42c21d45a66b566496d67d89bf513junov@google.com        // Set alpha to 1 for the override since transparency will already
4188656e216fc42c21d45a66b566496d67d89bf513junov@google.com        // be baked into the blurred mask.
4288656e216fc42c21d45a66b566496d67d89bf513junov@google.com        SkColor opaqueColor = SkColorSetA(color, 255);
436a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org        //The SrcIn xfer mode will multiply 'color' by the incoming alpha
44a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com        fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
45a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                                                       SkXfermode::kSrcIn_Mode);
46a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com    } else {
476a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org        fColorFilter = NULL;
486a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org    }
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
514079b3b1a4e9d99740a245692f530600879aa7c5reed@google.comSkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
524079b3b1a4e9d99740a245692f530600879aa7c5reed@google.com: INHERITED(buffer) {
534079b3b1a4e9d99740a245692f530600879aa7c5reed@google.com
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fDx = buffer.readScalar();
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fDy = buffer.readScalar();
569ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fBlurColor = buffer.readColor();
579ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fBlur = buffer.readFlattenableT<SkMaskFilter>();
589ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fColorFilter = buffer.readFlattenableT<SkColorFilter>();
599ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    fBlurFlags = buffer.readUInt() & kAll_BlurFlag;
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
62a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.comSkBlurDrawLooper::~SkBlurDrawLooper() {
63919114813d58933c9d9433b141e0222c34b700b1reed@google.com    SkSafeUnref(fBlur);
646a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org    SkSafeUnref(fColorFilter);
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
67cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.comvoid SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) const {
68cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.com    this->INHERITED::flatten(buffer);
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    buffer.writeScalar(fDx);
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    buffer.writeScalar(fDy);
719ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeColor(fBlurColor);
72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    buffer.writeFlattenable(fBlur);
736a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org    buffer.writeFlattenable(fColorFilter);
749ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com    buffer.writeUInt(fBlurFlags);
75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
7785f3b52a22c623fc8846d920660fc0b0a4b7afa7sugoi@google.comvoid SkBlurDrawLooper::init(SkCanvas*) {
78a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com    fState = kBeforeEdge;
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
81a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.combool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) {
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    switch (fState) {
83a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com        case kBeforeEdge:
84a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            // we do nothing if a maskfilter is already installed
85a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            if (paint->getMaskFilter()) {
86a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                fState = kDone;
87a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                return false;
88a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            }
89f3a882d015181a30388e98b9a04e76d04d11b667djsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
90d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com            SkColor blurColor;
91d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com            blurColor = fBlurColor;
92d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com            if (SkColorGetA(blurColor) == 255) {
93d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com                blurColor = SkColorSetA(blurColor, paint->getAlpha());
94d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com            }
95d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com            paint->setColor(blurColor);
96d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com#else
97a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            paint->setColor(fBlurColor);
98d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com#endif
99a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            paint->setMaskFilter(fBlur);
100a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            paint->setColorFilter(fColorFilter);
101a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            canvas->save(SkCanvas::kMatrix_SaveFlag);
102a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            if (fBlurFlags & kIgnoreTransform_BlurFlag) {
103a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                SkMatrix transform(canvas->getTotalMatrix());
104a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                transform.postTranslate(fDx, fDy);
105a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                canvas->setMatrix(transform);
106a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            } else {
107a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com                canvas->translate(fDx, fDy);
108a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            }
109a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            fState = kAfterEdge;
110a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            return true;
111a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com        case kAfterEdge:
112a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            canvas->restore();
113a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            fState = kDone;
114a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            return true;
115a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com        default:
116a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            SkASSERT(kDone == fState);
117a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com            return false;
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
12097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com
12197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#ifdef SK_DEVELOPER
12297691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.comvoid SkBlurDrawLooper::toString(SkString* str) const {
12397691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->append("SkBlurDrawLooper: ");
12497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com
12597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->append("dx: ");
12697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->appendScalar(fDx);
12797691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com
12897691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->append(" dy: ");
12997691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->appendScalar(fDy);
13097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com
13197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->append(" color: ");
13297691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->appendHex(fBlurColor);
13397691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com
13497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->append(" flags: (");
13597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    if (kNone_BlurFlag == fBlurFlags) {
13697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com        str->append("None");
13797691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    } else {
13897691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com        bool needsSeparator = false;
139929e7ba58200cfee75f87275f137735bb5376e67skia.committer@gmail.com        SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform",
14097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com                          &needsSeparator);
14197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com        SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor",
14297691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com                          &needsSeparator);
143929e7ba58200cfee75f87275f137735bb5376e67skia.committer@gmail.com        SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality",
14497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com                          &needsSeparator);
14597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    }
14697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    str->append(")");
14797691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com
14897691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added
14997691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com    // alternatively we could cache the radius in SkBlurDrawLooper and just add it here
15097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com}
15197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#endif
152