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