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