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 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 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 = 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 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 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 74 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 82 SkBlurDrawLooper::~SkBlurDrawLooper() { 83 SkSafeUnref(fBlur); 84 SkSafeUnref(fColorFilter); 85 } 86 87 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 105 SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const { 106 return new (storage) BlurDrawLooperContext(this); 107 } 108 109 SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext( 110 const SkBlurDrawLooper* looper) 111 : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {} 112 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 155 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