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