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