1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurDrawLooper.h" 97ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com#include "SkBlurMask.h" // just for SkBlurMask::ConvertRadiusToSigma 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlurMaskFilter.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkCanvas.h" 124991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkColorFilter.h" 138b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h" 148b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h" 164991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkPaint.h" 174991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkString.h" 184991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#include "SkStringUtils.h" 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 207bd141dce43ea3405bc60c9c84e6f910b851b079skia.committer@gmail.comSkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma, 217ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com SkScalar dx, SkScalar dy, uint32_t flags) { 227ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com this->init(sigma, dx, dy, color, flags); 237ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com} 247ce661d19c5cf4484305a1b20c44bd111f129847robertphillips@google.com 25daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com// only call from constructor 26daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comvoid SkBlurDrawLooper::initEffects() { 27daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkASSERT(fBlurFlags <= kAll_BlurFlag); 28daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com if (fSigma > 0) { 29daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com uint32_t flags = fBlurFlags & kIgnoreTransform_BlurFlag ? 30daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkBlurMaskFilter::kIgnoreTransform_BlurFlag : 31daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkBlurMaskFilter::kNone_BlurFlag; 32eeaeafebdeec2c546134b741ab8b3c6b7c5190abskia.committer@gmail.com 33daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com flags |= fBlurFlags & kHighQuality_BlurFlag ? 34daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkBlurMaskFilter::kHighQuality_BlurFlag : 35daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkBlurMaskFilter::kNone_BlurFlag; 36eeaeafebdeec2c546134b741ab8b3c6b7c5190abskia.committer@gmail.com 37daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fBlur = SkBlurMaskFilter::Create(kNormal_SkBlurStyle, fSigma, flags); 384e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com } else { 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fBlur = NULL; 404868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org } 41eeaeafebdeec2c546134b741ab8b3c6b7c5190abskia.committer@gmail.com 42daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com if (fBlurFlags & kOverrideColor_BlurFlag) { 43a6398911174d5445456ecb2f5f4f0565db2f100bjunov@google.com // Set alpha to 1 for the override since transparency will already 44a6398911174d5445456ecb2f5f4f0565db2f100bjunov@google.com // be baked into the blurred mask. 45daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkColor opaqueColor = SkColorSetA(fBlurColor, 255); 464868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org //The SrcIn xfer mode will multiply 'color' by the incoming alpha 474e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com fColorFilter = SkColorFilter::CreateModeFilter(opaqueColor, 484e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com SkXfermode::kSrcIn_Mode); 494e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com } else { 504868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org fColorFilter = NULL; 514868e6b221a4a98e40f977851af5fcf09631ea15senorblanco@chromium.org } 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 54daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comvoid SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy, 55daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkColor color, uint32_t flags) { 56daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fSigma = sigma; 57daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fDx = dx; 58daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fDy = dy; 59daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fBlurColor = color; 60daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fBlurFlags = flags; 61daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 62daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com this->initEffects(); 63daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com} 64daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 659fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING 66daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comSkBlurDrawLooper::SkBlurDrawLooper(SkReadBuffer& buffer) : INHERITED(buffer) { 676bac947cd5bc460dd9166ada6310d678fd2e39f8reed@google.com 68daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com fSigma = buffer.readScalar(); 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fDx = buffer.readScalar(); 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fDy = buffer.readScalar(); 71c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com fBlurColor = buffer.readColor(); 72c73dd5c6880739f26216f198c757028fd28df1a4djsollen@google.com fBlurFlags = buffer.readUInt() & kAll_BlurFlag; 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 74daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com this->initEffects(); 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 769fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed#endif 779fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed 789fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reedSkFlattenable* SkBlurDrawLooper::CreateProc(SkReadBuffer& buffer) { 799fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const SkColor color = buffer.readColor(); 809fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const SkScalar sigma = buffer.readScalar(); 819fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const SkScalar dx = buffer.readScalar(); 829fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const SkScalar dy = buffer.readScalar(); 839fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed const uint32_t flags = buffer.read32(); 849fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed return Create(color, sigma, dx, dy, flags); 859fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed} 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 878b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.orgvoid SkBlurDrawLooper::flatten(SkWriteBuffer& buffer) const { 889fa60daad4d5f54c0dbe3dbcc7608a8f6d721187reed buffer.writeColor(fBlurColor); 89daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com buffer.writeScalar(fSigma); 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com buffer.writeScalar(fDx); 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com buffer.writeScalar(fDy); 92daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com buffer.write32(fBlurFlags); 93daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com} 94daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 95daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.comSkBlurDrawLooper::~SkBlurDrawLooper() { 96daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkSafeUnref(fBlur); 97daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com SkSafeUnref(fColorFilter); 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 100daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.combool SkBlurDrawLooper::asABlurShadow(BlurShadowRec* rec) const { 101daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com if (fSigma <= 0 || (fBlurFlags & fBlurFlags & kIgnoreTransform_BlurFlag)) { 102daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com return false; 103daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com } 104daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 105daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com if (rec) { 106daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com rec->fSigma = fSigma; 107daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com rec->fColor = fBlurColor; 108daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com rec->fOffset.set(fDx, fDy); 109daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com rec->fStyle = kNormal_SkBlurStyle; 110daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com rec->fQuality = (fBlurFlags & kHighQuality_BlurFlag) ? 111daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com kHigh_SkBlurQuality : kLow_SkBlurQuality; 112daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com } 113daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com return true; 114daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com} 115daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 116daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com//////////////////////////////////////////////////////////////////////////////////////// 117daaafa6e81860e3dc52660ba019c336f0a43f1e7reed@google.com 11879fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.orgSkDrawLooper::Context* SkBlurDrawLooper::createContext(SkCanvas*, void* storage) const { 11979fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org return SkNEW_PLACEMENT_ARGS(storage, BlurDrawLooperContext, (this)); 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 12279fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.orgSkBlurDrawLooper::BlurDrawLooperContext::BlurDrawLooperContext( 12379fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org const SkBlurDrawLooper* looper) 12479fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org : fLooper(looper), fState(SkBlurDrawLooper::kBeforeEdge) {} 12579fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org 12679fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.orgbool SkBlurDrawLooper::BlurDrawLooperContext::next(SkCanvas* canvas, 12779fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org SkPaint* paint) { 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (fState) { 1294e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com case kBeforeEdge: 1304e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com // we do nothing if a maskfilter is already installed 1314e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com if (paint->getMaskFilter()) { 1324e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com fState = kDone; 1334e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com return false; 1344e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com } 13556c69773aea56c6c6bd47bc7e7970dd081205184djsollen@google.com#ifdef SK_BUILD_FOR_ANDROID 136f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com SkColor blurColor; 13779fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org blurColor = fLooper->fBlurColor; 138f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com if (SkColorGetA(blurColor) == 255) { 139f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com blurColor = SkColorSetA(blurColor, paint->getAlpha()); 140f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com } 141f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com paint->setColor(blurColor); 142f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com#else 14379fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org paint->setColor(fLooper->fBlurColor); 144f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com#endif 14579fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org paint->setMaskFilter(fLooper->fBlur); 14679fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org paint->setColorFilter(fLooper->fColorFilter); 14774e608cdc1e13593b54d54f11e65c1c309d19370commit-bot@chromium.org canvas->save(); 14879fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org if (fLooper->fBlurFlags & kIgnoreTransform_BlurFlag) { 1494e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com SkMatrix transform(canvas->getTotalMatrix()); 15079fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org transform.postTranslate(fLooper->fDx, fLooper->fDy); 1514e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com canvas->setMatrix(transform); 1524e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com } else { 15379fbb40bca9d815ef79b896b31ba6ee736817e0fcommit-bot@chromium.org canvas->translate(fLooper->fDx, fLooper->fDy); 1544e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com } 1554e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com fState = kAfterEdge; 1564e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com return true; 1574e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com case kAfterEdge: 1584e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com canvas->restore(); 1594e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com fState = kDone; 1604e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com return true; 1614e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com default: 1624e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com SkASSERT(kDone == fState); 1634e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com return false; 1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1664991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com 1670f10f7bf1fb43ca6346dc220a076773b1f19a367commit-bot@chromium.org#ifndef SK_IGNORE_TO_STRING 1684991b8f23482afc1494fd17647421ce68de53331robertphillips@google.comvoid SkBlurDrawLooper::toString(SkString* str) const { 1694991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append("SkBlurDrawLooper: "); 1704991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com 1714991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append("dx: "); 1724991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->appendScalar(fDx); 1734991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com 1744991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append(" dy: "); 1754991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->appendScalar(fDy); 1764991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com 1774991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append(" color: "); 1784991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->appendHex(fBlurColor); 1794991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com 1804991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append(" flags: ("); 1814991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com if (kNone_BlurFlag == fBlurFlags) { 1824991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append("None"); 1834991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com } else { 1844991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com bool needsSeparator = false; 185cdcb2ce2744c7e5c47453328dbf292edee79ab37skia.committer@gmail.com SkAddFlagToString(str, SkToBool(kIgnoreTransform_BlurFlag & fBlurFlags), "IgnoreTransform", 1864991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com &needsSeparator); 1874991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com SkAddFlagToString(str, SkToBool(kOverrideColor_BlurFlag & fBlurFlags), "OverrideColor", 1884991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com &needsSeparator); 189cdcb2ce2744c7e5c47453328dbf292edee79ab37skia.committer@gmail.com SkAddFlagToString(str, SkToBool(kHighQuality_BlurFlag & fBlurFlags), "HighQuality", 1904991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com &needsSeparator); 1914991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com } 1924991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com str->append(")"); 1934991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com 1944991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com // TODO: add optional "fBlurFilter->toString(str);" when SkMaskFilter::toString is added 1954991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com // alternatively we could cache the radius in SkBlurDrawLooper and just add it here 1964991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com} 1974991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com#endif 198