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