1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com 2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/* 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 Google Inc. 4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */ 8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlurDrawLooper.h" 9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlurMaskFilter.h" 10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkCanvas.h" 1197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkColorFilter.h" 129ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com#include "SkFlattenableBuffers.h" 13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkMaskFilter.h" 1497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkPaint.h" 1597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkString.h" 1697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#include "SkStringUtils.h" 17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, 19740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org SkColor color, uint32_t flags) 20a8a02b7a570cbfb0966453a1e0fc4275975e734bvandebo@chromium.org : fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags), fState(kDone) { 21a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com 22740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org SkASSERT(flags <= kAll_BlurFlag); 23a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com if (radius > 0) { 24919114813d58933c9d9433b141e0222c34b700b1reed@google.com uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ? 25919114813d58933c9d9433b141e0222c34b700b1reed@google.com SkBlurMaskFilter::kIgnoreTransform_BlurFlag : 26740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org SkBlurMaskFilter::kNone_BlurFlag; 27740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org 286a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org blurFlags |= flags & kHighQuality_BlurFlag ? 29935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com SkBlurMaskFilter::kHighQuality_BlurFlag : 306a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org SkBlurMaskFilter::kNone_BlurFlag; 316a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org 32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fBlur = SkBlurMaskFilter::Create(radius, 33935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com SkBlurMaskFilter::kNormal_BlurStyle, 34740de996d9e77a695864fdd8b89b4bd55f8d304asenorblanco@chromium.org blurFlags); 35a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com } else { 36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fBlur = NULL; 376a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org } 386a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org 39a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com if (flags & kOverrideColor_BlurFlag) { 4088656e216fc42c21d45a66b566496d67d89bf513junov@google.com // Set alpha to 1 for the override since transparency will already 4188656e216fc42c21d45a66b566496d67d89bf513junov@google.com // be baked into the blurred mask. 4288656e216fc42c21d45a66b566496d67d89bf513junov@google.com SkColor opaqueColor = SkColorSetA(color, 255); 436a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org //The SrcIn xfer mode will multiply 'color' by the incoming alpha 44a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, 45a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com SkXfermode::kSrcIn_Mode); 46a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com } else { 476a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org fColorFilter = NULL; 486a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org } 49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 514079b3b1a4e9d99740a245692f530600879aa7c5reed@google.comSkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer) 524079b3b1a4e9d99740a245692f530600879aa7c5reed@google.com: INHERITED(buffer) { 534079b3b1a4e9d99740a245692f530600879aa7c5reed@google.com 54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fDx = buffer.readScalar(); 55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com fDy = buffer.readScalar(); 569ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com fBlurColor = buffer.readColor(); 579ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com fBlur = buffer.readFlattenableT<SkMaskFilter>(); 589ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com fColorFilter = buffer.readFlattenableT<SkColorFilter>(); 599ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com fBlurFlags = buffer.readUInt() & kAll_BlurFlag; 60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 62a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.comSkBlurDrawLooper::~SkBlurDrawLooper() { 63919114813d58933c9d9433b141e0222c34b700b1reed@google.com SkSafeUnref(fBlur); 646a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org SkSafeUnref(fColorFilter); 65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 67cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.comvoid SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer) const { 68cd2e444e946f5cfec4723f5bc46e9487d82e8e54djsollen@google.com this->INHERITED::flatten(buffer); 69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com buffer.writeScalar(fDx); 70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com buffer.writeScalar(fDy); 719ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com buffer.writeColor(fBlurColor); 72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com buffer.writeFlattenable(fBlur); 736a308c2d0484f049813f232190d5bda74e564da9senorblanco@chromium.org buffer.writeFlattenable(fColorFilter); 749ce78f26f529fd3e10a3eb4f044bc3f0037ead56djsollen@google.com buffer.writeUInt(fBlurFlags); 75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 7785f3b52a22c623fc8846d920660fc0b0a4b7afa7sugoi@google.comvoid SkBlurDrawLooper::init(SkCanvas*) { 78a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com fState = kBeforeEdge; 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 81a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.combool SkBlurDrawLooper::next(SkCanvas* canvas, SkPaint* paint) { 82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com switch (fState) { 83a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com case kBeforeEdge: 84a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com // we do nothing if a maskfilter is already installed 85a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com if (paint->getMaskFilter()) { 86a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com fState = kDone; 87a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com return false; 88a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com } 89f3a882d015181a30388e98b9a04e76d04d11b667djsollen@google.com#ifdef SK_BUILD_FOR_ANDROID 90d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com SkColor blurColor; 91d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com blurColor = fBlurColor; 92d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com if (SkColorGetA(blurColor) == 255) { 93d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com blurColor = SkColorSetA(blurColor, paint->getAlpha()); 94d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com } 95d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com paint->setColor(blurColor); 96d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com#else 97a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com paint->setColor(fBlurColor); 98d0562c06fbb517814989924bb84e6c6dfd7d962ddjsollen@google.com#endif 99a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com paint->setMaskFilter(fBlur); 100a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com paint->setColorFilter(fColorFilter); 101a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com canvas->save(SkCanvas::kMatrix_SaveFlag); 102a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com if (fBlurFlags & kIgnoreTransform_BlurFlag) { 103a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com SkMatrix transform(canvas->getTotalMatrix()); 104a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com transform.postTranslate(fDx, fDy); 105a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com canvas->setMatrix(transform); 106a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com } else { 107a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com canvas->translate(fDx, fDy); 108a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com } 109a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com fState = kAfterEdge; 110a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com return true; 111a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com case kAfterEdge: 112a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com canvas->restore(); 113a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com fState = kDone; 114a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com return true; 115a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com default: 116a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com SkASSERT(kDone == fState); 117a4b08d807093d60763cdd11ee1fe47832bafeea0reed@google.com return false; 118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 12097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com 12197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#ifdef SK_DEVELOPER 12297691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.comvoid SkBlurDrawLooper::toString(SkString* str) const { 12397691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append("SkBlurDrawLooper: "); 12497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com 12597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append("dx: "); 12697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->appendScalar(fDx); 12797691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com 12897691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append(" dy: "); 12997691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->appendScalar(fDy); 13097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com 13197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append(" color: "); 13297691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->appendHex(fBlurColor); 13397691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com 13497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append(" flags: ("); 13597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com if (kNone_BlurFlag == fBlurFlags) { 13697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append("None"); 13797691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com } else { 13897691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com bool needsSeparator = false; 139929e7ba58200cfee75f87275f137735bb5376e67skia.committer@gmail.com SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform", 14097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com &needsSeparator); 14197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor", 14297691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com &needsSeparator); 143929e7ba58200cfee75f87275f137735bb5376e67skia.committer@gmail.com SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality", 14497691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com &needsSeparator); 14597691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com } 14697691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com str->append(")"); 14797691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com 14897691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added 14997691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com // alternatively we could cache the radius in SkBlurDrawLooper and just add it here 15097691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com} 15197691397dde4a408e147903ceae35e00bd72e9a8robertphillips@google.com#endif 152