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 
SkBlurDrawLooper(SkColor color,SkScalar sigma,SkScalar dx,SkScalar dy,uint32_t flags)20 SkBlurDrawLooper::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
initEffects()26 void 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 
init(SkScalar sigma,SkScalar dx,SkScalar dy,SkColor color,uint32_t flags)54 void 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 
CreateProc(SkReadBuffer & buffer)65 SkFlattenable* 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 
flatten(SkWriteBuffer & buffer) const74 void 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 
~SkBlurDrawLooper()82 SkBlurDrawLooper::~SkBlurDrawLooper() {
83     SkSafeUnref(fBlur);
84     SkSafeUnref(fColorFilter);
85 }
86 
asABlurShadow(BlurShadowRec * rec) const87 bool 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 
createContext(SkCanvas *,void * storage) const105 SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const {
106     return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this));
107 }
108 
BlurDrawLooperContext(const SkBlurDrawLooper * looper)109 SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext(
110         const SkBlurDrawLooper* looper)
111     : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {}
112 
next(SkCanvas * canvas,SkPaint * paint)113 bool 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
toString(SkString * str) const155 void 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