blob: 9f10ff5250f1bf39a23ae8b44c3ef519120ed704 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed@google.comdaaafa62014-04-29 15:20:16 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkBlurDrawLooper.h"
robertphillips@google.com7ce661d2013-08-27 16:14:03 +00009#include "SkBlurMask.h" // just for SkBlurMask::ConvertRadiusToSigma
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#include "SkBlurMaskFilter.h"
11#include "SkCanvas.h"
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +000012#include "SkColorFilter.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000013#include "SkReadBuffer.h"
14#include "SkWriteBuffer.h"
robertphillips@google.com4991b8f2013-01-28 20:21:59 +000015#include "SkMaskFilter.h"
16#include "SkPaint.h"
17#include "SkString.h"
18#include "SkStringUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000019
skia.committer@gmail.com7bd141d2013-08-28 07:01:18 +000020SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma,
robertphillips@google.com7ce661d2013-08-27 16:14:03 +000021 SkScalar dx, SkScalar dy, uint32_t flags) {
22 this->init(sigma, dx, dy, color, flags);
23}
24
reed@google.comdaaafa62014-04-29 15:20:16 +000025// only call from constructor
26void 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;
skia.committer@gmail.comeeaeafe2014-04-30 03:05:25 +000032
reed@google.comdaaafa62014-04-29 15:20:16 +000033 flags |= fBlurFlags & kHighQuality_BlurFlag ?
34 SkBlurMaskFilter::kHighQuality_BlurFlag :
35 SkBlurMaskFilter::kNone_BlurFlag;
skia.committer@gmail.comeeaeafe2014-04-30 03:05:25 +000036
reed@google.comdaaafa62014-04-29 15:20:16 +000037 fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, fSigma, flags);
reed@google.com4e2b3d32011-04-07 14:18:59 +000038 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070039 fBlur = nullptr;
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +000040 }
skia.committer@gmail.comeeaeafe2014-04-30 03:05:25 +000041
reed@google.comdaaafa62014-04-29 15:20:16 +000042 if (fBlurFlags & kOverrideColor_BlurFlag) {
junov@google.coma6398912011-03-11 16:45:00 +000043 // Set alpha to 1 for the override since transparency will already
44 // be baked into the blurred mask.
reed@google.comdaaafa62014-04-29 15:20:16 +000045 SkColor opaqueColor = SkColorSetA(fBlurColor, 255);
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +000046 //The SrcIn xfer mode will multiply 'color' by the incoming alpha
reed@google.com4e2b3d32011-04-07 14:18:59 +000047 fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor,
48 SkXfermode::kSrcIn_Mode);
49 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070050 fColorFilter = nullptr;
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +000051 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000052}
53
reed@google.comdaaafa62014-04-29 15:20:16 +000054void 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;
reed@google.com6bac9472011-06-21 19:24:00 +000061
reed@google.comdaaafa62014-04-29 15:20:16 +000062 this->initEffects();
63}
64
reed9fa60da2014-08-21 07:59:51 -070065SkFlattenable* 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}
reed@google.comdaaafa62014-04-29 15:20:16 +000073
74void SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const {
reed9fa60da2014-08-21 07:59:51 -070075 buffer.writeColor(fBlurColor);
reed@google.comdaaafa62014-04-29 15:20:16 +000076 buffer.writeScalar(fSigma);
77 buffer.writeScalar(fDx);
78 buffer.writeScalar(fDy);
reed@google.comdaaafa62014-04-29 15:20:16 +000079 buffer.write32(fBlurFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +000080}
81
reed@google.com4e2b3d32011-04-07 14:18:59 +000082SkBlurDrawLooper::~SkBlurDrawLooper() {
reed@google.com82065d62011-02-07 15:30:46 +000083 SkSafeUnref(fBlur);
senorblanco@chromium.org4868e6b2011-02-18 19:03:01 +000084 SkSafeUnref(fColorFilter);
reed@android.com8a1c16f2008-12-17 15:59:43 +000085}
86
reed@google.comdaaafa62014-04-29 15:20:16 +000087bool 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;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101}
102
reed@google.comdaaafa62014-04-29 15:20:16 +0000103////////////////////////////////////////////////////////////////////////////////////////
104
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000105SkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const {
halcanary385fe4d2015-08-26 13:07:48 -0700106 return new (storage) BlurDrawLooperContext(this);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107}
108
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000109SkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext(
110 const SkBlurDrawLooper* looper)
111 : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {}
112
113bool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas,
114 SkPaint* paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 switch (fState) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000116 case kBeforeEdge:
117 // we do nothing if a maskfilter is already installed
118 if (paint->getMaskFilter()) {
119 fState = kDone;
120 return false;
121 }
djsollen@google.com56c69772011-11-08 19:00:26 +0000122#ifdef SK_BUILD_FOR_ANDROID
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000123 SkColor blurColor;
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000124 blurColor = fLooper->fBlurColor;
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000125 if (SkColorGetA(blurColor) == 255) {
126 blurColor = SkColorSetA(blurColor, paint->getAlpha());
127 }
128 paint->setColor(blurColor);
129#else
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000130 paint->setColor(fLooper->fBlurColor);
djsollen@google.comf5dbe2f2011-04-15 13:41:26 +0000131#endif
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000132 paint->setMaskFilter(fLooper->fBlur);
133 paint->setColorFilter(fLooper->fColorFilter);
commit-bot@chromium.org74e608c2014-04-23 19:26:38 +0000134 canvas->save();
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000135 if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) {
reed@google.com4e2b3d32011-04-07 14:18:59 +0000136 SkMatrix transform(canvas->getTotalMatrix());
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000137 transform.postTranslate(fLooper->fDx, fLooper->fDy);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000138 canvas->setMatrix(transform);
139 } else {
commit-bot@chromium.org79fbb402014-03-12 09:42:01 +0000140 canvas->translate(fLooper->fDx, fLooper->fDy);
reed@google.com4e2b3d32011-04-07 14:18:59 +0000141 }
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;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 }
152}
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000153
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000154#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000155void 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;
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000172 SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform",
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000173 &needsSeparator);
174 SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor",
175 &needsSeparator);
skia.committer@gmail.comcdcb2ce2013-01-29 07:05:52 +0000176 SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality",
robertphillips@google.com4991b8f2013-01-28 20:21:59 +0000177 &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