SkBlurDrawLooper.cpp revision 2880df2609eba09b555ca37be04b6ad89290c765
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 = nullptr;
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 = nullptr;
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
65SkFlattenable* SkBlurDrawLooper::CreateProc(SkReadBuffer& buffer) {
66    const SkColor color = buffer.readColor();
67    const SkScalar sigma = buffer.readScalar();
68    const SkScalar dx = buffer.readScalar();
69    const SkScalar dy = buffer.readScalar();
70    const uint32_t flags = buffer.read32();
71    return Create(color, sigma, dx, dy, flags);
72}
73
74void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const {
75    buffer.writeColor(fBlurColor);
76    buffer.writeScalar(fSigma);
77    buffer.writeScalar(fDx);
78    buffer.writeScalar(fDy);
79    buffer.write32(fBlurFlags);
80}
81
82SkBlurDrawLooper::~SkBlurDrawLooper() {
83    SkSafeUnref(fBlur);
84    SkSafeUnref(fColorFilter);
85}
86
87bool SkBlurDrawLooper::asABlurShadow(BlurShadowRec* rec) const {
88    if (fSigma <= 0 || (fBlurFlags & fBlurFlags & kIgnoreTransform_BlurFlag)) {
89        return false;
90    }
91
92    if (rec) {
93        rec->fSigma = fSigma;
94        rec->fColor = fBlurColor;
95        rec->fOffset.set(fDx, fDy);
96        rec->fStyle = kNormal_SkBlurStyle;
97        rec->fQuality = (fBlurFlags & kHighQuality_BlurFlag) ?
98                        kHigh_SkBlurQuality : kLow_SkBlurQuality;
99    }
100    return true;
101}
102
103////////////////////////////////////////////////////////////////////////////////////////
104
105SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const {
106    return new (storage) BlurDrawLooperContext(this);
107}
108
109SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext(
110        const SkBlurDrawLooper* looper)
111    : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {}
112
113bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas,
114                                                   SkPaint* paint) {
115    switch (fState) {
116        case kBeforeEdge:
117            // we do nothing if a maskfilter is already installed
118            if (paint->getMaskFilter()) {
119                fState = kDone;
120                return false;
121            }
122#ifdef SK_BUILD_FOR_ANDROID
123            SkColor blurColor;
124            blurColor = fLooper->fBlurColor;
125            if (SkColorGetA(blurColor) == 255) {
126                blurColor = SkColorSetA(blurColor, paint->getAlpha());
127            }
128            paint->setColor(blurColor);
129#else
130            paint->setColor(fLooper->fBlurColor);
131#endif
132            paint->setMaskFilter(fLooper->fBlur);
133            paint->setColorFilter(fLooper->fColorFilter);
134            canvas->save();
135            if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) {
136                SkMatrix transform(canvas->getTotalMatrix());
137                transform.postTranslate(fLooper->fDx, fLooper->fDy);
138                canvas->setMatrix(transform);
139            } else {
140                canvas->translate(fLooper->fDx, fLooper->fDy);
141            }
142            fState = kAfterEdge;
143            return true;
144        case kAfterEdge:
145            canvas->restore();
146            fState = kDone;
147            return true;
148        default:
149            SkASSERT(kDone == fState);
150            return false;
151    }
152}
153
154#ifndef SK_IGNORE_TO_STRING
155void SkBlurDrawLooper::toString(SkString* str) const {
156    str->append("SkBlurDrawLooper: ");
157
158    str->append("dx: ");
159    str->appendScalar(fDx);
160
161    str->append(" dy: ");
162    str->appendScalar(fDy);
163
164    str->append(" color: ");
165    str->appendHex(fBlurColor);
166
167    str->append(" flags: (");
168    if (kNone_BlurFlag == fBlurFlags) {
169        str->append("None");
170    } else {
171        bool needsSeparator = false;
172        SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform",
173                          &needsSeparator);
174        SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor",
175                          &needsSeparator);
176        SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality",
177                          &needsSeparator);
178    }
179    str->append(")");
180
181    // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added
182    // alternatively we could cache the radius in SkBlurDrawLooper and just add it here
183}
184#endif
185