SkBlurDrawLooper.cpp revision 941ff78d79a3239d8a4c18be868423e52563bca5
1/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkBlurDrawLooper.h"
9#include "SkBlurMask.h"     // just for SkBlurMask::ConvertRadiusToSigma
10#include "SkBlurMaskFilter.h"
11#include "SkCanvas.h"
12#include "SkColorFilter.h"
13#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
15#include "SkMaskFilter.h"
16#include "SkPaint.h"
17#include "SkString.h"
18#include "SkStringUtils.h"
19
20SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma,
21                                   SkScalar dx, SkScalar dy, uint32_t flags) {
22    this->init(sigma, dx, dy, color, flags);
23}
24
25// only call from constructor
26void SkBlurDrawLooper::initEffects() {
27    SkASSERT(fBlurFlags <= kAll_BlurFlag);
28    if (fSigma > 0) {
29        uint32_t flags = fBlurFlags & kIgnoreTransform_BlurFlag ?
30                            SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
31                            SkBlurMaskFilter::kNone_BlurFlag;
32
33        flags |= fBlurFlags & kHighQuality_BlurFlag ?
34                    SkBlurMaskFilter::kHighQuality_BlurFlag :
35                    SkBlurMaskFilter::kNone_BlurFlag;
36
37        fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, fSigma, flags);
38    } else {
39        fBlur = NULL;
40    }
41
42    if (fBlurFlags & kOverrideColor_BlurFlag) {
43        // Set alpha to 1 for the override since transparency will already
44        // be baked into the blurred mask.
45        SkColor opaqueColor = SkColorSetA(fBlurColor, 255);
46        //The SrcIn xfer mode will multiply 'color' by the incoming alpha
47        fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
48                                                       SkXfermode::kSrcIn_Mode);
49    } else {
50        fColorFilter = NULL;
51    }
52}
53
54void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy,
55                            SkColor color, uint32_t flags) {
56    fSigma = sigma;
57    fDx = dx;
58    fDy = dy;
59    fBlurColor = color;
60    fBlurFlags = flags;
61
62    this->initEffects();
63}
64
65SkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer) : INHERITED(buffer) {
66
67    fSigma = buffer.readScalar();
68    fDx = buffer.readScalar();
69    fDy = buffer.readScalar();
70    fBlurColor = buffer.readColor();
71    fBlurFlags = buffer.readUInt() & kAll_BlurFlag;
72
73    this->initEffects();
74}
75
76void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const {
77    this->INHERITED::flatten(buffer);
78    buffer.writeScalar(fSigma);
79    buffer.writeScalar(fDx);
80    buffer.writeScalar(fDy);
81    buffer.writeColor(fBlurColor);
82    buffer.write32(fBlurFlags);
83}
84
85SkBlurDrawLooper::~SkBlurDrawLooper() {
86    SkSafeUnref(fBlur);
87    SkSafeUnref(fColorFilter);
88}
89
90bool SkBlurDrawLooper::asABlurShadow(BlurShadowRec* rec) const {
91    if (fSigma <= 0 || (fBlurFlags & fBlurFlags & kIgnoreTransform_BlurFlag)) {
92        return false;
93    }
94
95    if (rec) {
96        rec->fSigma = fSigma;
97        rec->fColor = fBlurColor;
98        rec->fOffset.set(fDx, fDy);
99        rec->fStyle = kNormal_SkBlurStyle;
100        rec->fQuality = (fBlurFlags & kHighQuality_BlurFlag) ?
101                        kHigh_SkBlurQuality : kLow_SkBlurQuality;
102    }
103    return true;
104}
105
106////////////////////////////////////////////////////////////////////////////////////////
107
108SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const {
109    return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this));
110}
111
112SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext(
113        const SkBlurDrawLooper* looper)
114    : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {}
115
116bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas,
117                                                   SkPaint* paint) {
118    switch (fState) {
119        case kBeforeEdge:
120            // we do nothing if a maskfilter is already installed
121            if (paint->getMaskFilter()) {
122                fState = kDone;
123                return false;
124            }
125#ifdef SK_BUILD_FOR_ANDROID
126            SkColor blurColor;
127            blurColor = fLooper->fBlurColor;
128            if (SkColorGetA(blurColor) == 255) {
129                blurColor = SkColorSetA(blurColor, paint->getAlpha());
130            }
131            paint->setColor(blurColor);
132#else
133            paint->setColor(fLooper->fBlurColor);
134#endif
135            paint->setMaskFilter(fLooper->fBlur);
136            paint->setColorFilter(fLooper->fColorFilter);
137            canvas->save();
138            if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) {
139                SkMatrix transform(canvas->getTotalMatrix());
140                transform.postTranslate(fLooper->fDx, fLooper->fDy);
141                canvas->setMatrix(transform);
142            } else {
143                canvas->translate(fLooper->fDx, fLooper->fDy);
144            }
145            fState = kAfterEdge;
146            return true;
147        case kAfterEdge:
148            canvas->restore();
149            fState = kDone;
150            return true;
151        default:
152            SkASSERT(kDone == fState);
153            return false;
154    }
155}
156
157#ifndef SK_IGNORE_TO_STRING
158void SkBlurDrawLooper::toString(SkString* str) const {
159    str->append("SkBlurDrawLooper: ");
160
161    str->append("dx: ");
162    str->appendScalar(fDx);
163
164    str->append(" dy: ");
165    str->appendScalar(fDy);
166
167    str->append(" color: ");
168    str->appendHex(fBlurColor);
169
170    str->append(" flags: (");
171    if (kNone_BlurFlag == fBlurFlags) {
172        str->append("None");
173    } else {
174        bool needsSeparator = false;
175        SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform",
176                          &needsSeparator);
177        SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor",
178                          &needsSeparator);
179        SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality",
180                          &needsSeparator);
181    }
182    str->append(")");
183
184    // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added
185    // alternatively we could cache the radius in SkBlurDrawLooper and just add it here
186}
187#endif
188