SkBlurDrawLooper.cpp revision 0f10f7bf1fb43ca6346dc220a076773b1f19a367
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
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(SkScalar radius, SkScalar dx, SkScalar dy,
21                                   SkColor color, uint32_t flags) {
22    this->init(SkBlurMask::ConvertRadiusToSigma(radius), dx, dy, color, flags);
23}
24
25SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma,
26                                   SkScalar dx, SkScalar dy, uint32_t flags) {
27    this->init(sigma, dx, dy, color, flags);
28}
29
30void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy,
31                            SkColor color, uint32_t flags) {
32    fDx = dx;
33    fDy = dy;
34    fBlurColor = color;
35    fBlurFlags = flags;
36
37    SkASSERT(flags <= kAll_BlurFlag);
38    if (sigma > 0) {
39        uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
40            SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
41            SkBlurMaskFilter::kNone_BlurFlag;
42
43        blurFlags |= flags & kHighQuality_BlurFlag ?
44            SkBlurMaskFilter::kHighQuality_BlurFlag :
45            SkBlurMaskFilter::kNone_BlurFlag;
46
47        fBlur = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle,
48                                         sigma,
49                                         blurFlags);
50    } else {
51        fBlur = NULL;
52    }
53
54    if (flags & kOverrideColor_BlurFlag) {
55        // Set alpha to 1 for the override since transparency will already
56        // be baked into the blurred mask.
57        SkColor opaqueColor = SkColorSetA(color, 255);
58        //The SrcIn xfer mode will multiply 'color' by the incoming alpha
59        fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
60                                                       SkXfermode::kSrcIn_Mode);
61    } else {
62        fColorFilter = NULL;
63    }
64}
65
66SkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer)
67: INHERITED(buffer) {
68
69    fDx = buffer.readScalar();
70    fDy = buffer.readScalar();
71    fBlurColor = buffer.readColor();
72    fBlur = buffer.readMaskFilter();
73    fColorFilter = buffer.readColorFilter();
74    fBlurFlags = buffer.readUInt() & kAll_BlurFlag;
75}
76
77SkBlurDrawLooper::~SkBlurDrawLooper() {
78    SkSafeUnref(fBlur);
79    SkSafeUnref(fColorFilter);
80}
81
82void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const {
83    this->INHERITED::flatten(buffer);
84    buffer.writeScalar(fDx);
85    buffer.writeScalar(fDy);
86    buffer.writeColor(fBlurColor);
87    buffer.writeFlattenable(fBlur);
88    buffer.writeFlattenable(fColorFilter);
89    buffer.writeUInt(fBlurFlags);
90}
91
92SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const {
93    return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this));
94}
95
96SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext(
97        const SkBlurDrawLooper* looper)
98    : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {}
99
100bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas,
101                                                   SkPaint* paint) {
102    switch (fState) {
103        case kBeforeEdge:
104            // we do nothing if a maskfilter is already installed
105            if (paint->getMaskFilter()) {
106                fState = kDone;
107                return false;
108            }
109#ifdef SK_BUILD_FOR_ANDROID
110            SkColor blurColor;
111            blurColor = fLooper->fBlurColor;
112            if (SkColorGetA(blurColor) == 255) {
113                blurColor = SkColorSetA(blurColor, paint->getAlpha());
114            }
115            paint->setColor(blurColor);
116#else
117            paint->setColor(fLooper->fBlurColor);
118#endif
119            paint->setMaskFilter(fLooper->fBlur);
120            paint->setColorFilter(fLooper->fColorFilter);
121            canvas->save(SkCanvas::kMatrix_SaveFlag);
122            if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) {
123                SkMatrix transform(canvas->getTotalMatrix());
124                transform.postTranslate(fLooper->fDx, fLooper->fDy);
125                canvas->setMatrix(transform);
126            } else {
127                canvas->translate(fLooper->fDx, fLooper->fDy);
128            }
129            fState = kAfterEdge;
130            return true;
131        case kAfterEdge:
132            canvas->restore();
133            fState = kDone;
134            return true;
135        default:
136            SkASSERT(kDone == fState);
137            return false;
138    }
139}
140
141#ifndef SK_IGNORE_TO_STRING
142void SkBlurDrawLooper::toString(SkString* str) const {
143    str->append("SkBlurDrawLooper: ");
144
145    str->append("dx: ");
146    str->appendScalar(fDx);
147
148    str->append(" dy: ");
149    str->appendScalar(fDy);
150
151    str->append(" color: ");
152    str->appendHex(fBlurColor);
153
154    str->append(" flags: (");
155    if (kNone_BlurFlag == fBlurFlags) {
156        str->append("None");
157    } else {
158        bool needsSeparator = false;
159        SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform",
160                          &needsSeparator);
161        SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor",
162                          &needsSeparator);
163        SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality",
164                          &needsSeparator);
165    }
166    str->append(")");
167
168    // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added
169    // alternatively we could cache the radius in SkBlurDrawLooper and just add it here
170}
171#endif
172