aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/SkBlurDrawLooper.cpp25
-rw-r--r--src/effects/SkBlurMask.cpp48
-rw-r--r--src/effects/SkBlurMask.h7
-rw-r--r--src/effects/SkBlurMaskFilter.cpp4
-rw-r--r--src/effects/SkEmbossMaskFilter.cpp2
5 files changed, 74 insertions, 12 deletions
diff --git a/src/effects/SkBlurDrawLooper.cpp b/src/effects/SkBlurDrawLooper.cpp
index a3c4eacb6f..faaecb84fb 100644
--- a/src/effects/SkBlurDrawLooper.cpp
+++ b/src/effects/SkBlurDrawLooper.cpp
@@ -3,6 +3,7 @@
#include "SkCanvas.h"
#include "SkPaint.h"
#include "SkMaskFilter.h"
+#include "SkColorFilter.h"
SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
SkColor color, uint32_t flags)
@@ -15,12 +16,28 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
SkBlurMaskFilter::kNone_BlurFlag;
+ blurFlags |= flags & kHighQuality_BlurFlag ?
+ SkBlurMaskFilter::kHighQuality_BlurFlag :
+ SkBlurMaskFilter::kNone_BlurFlag;
+
fBlur = SkBlurMaskFilter::Create(radius,
- SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::kNormal_BlurStyle,
blurFlags);
}
else
+ {
fBlur = NULL;
+ }
+
+ if (flags & kOverrideColor_BlurFlag)
+ {
+ //The SrcIn xfer mode will multiply 'color' by the incoming alpha
+ fColorFilter = SkColorFilter::CreateModeFilter(color, SkXfermode::kSrcIn_Mode);
+ }
+ else
+ {
+ fColorFilter = NULL;
+ }
}
SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
@@ -29,12 +46,14 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkFlattenableReadBuffer& buffer)
fDy = buffer.readScalar();
fBlurColor = buffer.readU32();
fBlur = static_cast<SkMaskFilter*>(buffer.readFlattenable());
+ fColorFilter = static_cast<SkColorFilter*>(buffer.readFlattenable());
fBlurFlags = buffer.readU32() & kAll_BlurFlag;
}
SkBlurDrawLooper::~SkBlurDrawLooper()
{
SkSafeUnref(fBlur);
+ SkSafeUnref(fColorFilter);
}
void SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer)
@@ -43,6 +62,7 @@ void SkBlurDrawLooper::flatten(SkFlattenableWriteBuffer& buffer)
buffer.writeScalar(fDy);
buffer.write32(fBlurColor);
buffer.writeFlattenable(fBlur);
+ buffer.writeFlattenable(fColorFilter);
buffer.write32(fBlurFlags);
}
@@ -67,6 +87,7 @@ bool SkBlurDrawLooper::next()
fSavedColor = fPaint->getColor();
fPaint->setColor(fBlurColor);
fPaint->setMaskFilter(fBlur);
+ fPaint->setColorFilter(fColorFilter);
fCanvas->save(SkCanvas::kMatrix_SaveFlag);
if (fBlurFlags & kIgnoreTransform_BlurFlag)
{
@@ -83,6 +104,7 @@ bool SkBlurDrawLooper::next()
case kAfterEdge:
fPaint->setColor(fSavedColor);
fPaint->setMaskFilter(NULL);
+ fPaint->setColorFilter(NULL);
fCanvas->restore(); // to remove the translate we did earlier
fState = kDone;
return true;
@@ -98,6 +120,7 @@ void SkBlurDrawLooper::restore()
{
fPaint->setColor(fSavedColor);
fPaint->setMaskFilter(NULL);
+ fPaint->setColorFilter(NULL);
fCanvas->restore(); // to remove the translate we did earlier
fState = kDone;
}
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp
index a6492c3a02..f57a1776af 100644
--- a/src/effects/SkBlurMask.cpp
+++ b/src/effects/SkBlurMask.cpp
@@ -246,13 +246,20 @@ void SkMask_FreeImage(uint8_t* image)
}
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
- SkScalar radius, Style style)
+ SkScalar radius, Style style, Quality quality)
{
if (src.fFormat != SkMask::kA8_Format)
return false;
- int rx = SkScalarCeil(radius);
- int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - radius) * 255);
+ // Force high quality off for small radii (performance)
+ if (radius < SkIntToScalar(3)) quality = kLow_Quality;
+
+ // highQuality: use three box blur passes as a cheap way to approximate a Gaussian blur
+ int passCount = (quality == kHigh_Quality) ? 3 : 1;
+ SkScalar passRadius = SkScalarDiv(radius, SkScalarSqrt(SkIntToScalar(passCount)));
+
+ int rx = SkScalarCeil(passRadius);
+ int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
SkASSERT(rx >= 0);
SkASSERT((unsigned)outer_weight <= 255);
@@ -262,8 +269,10 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
int ry = rx; // only do square blur for now
- dst->fBounds.set(src.fBounds.fLeft - rx, src.fBounds.fTop - ry,
- src.fBounds.fRight + rx, src.fBounds.fBottom + ry);
+ int padx = passCount * rx;
+ int pady = passCount * ry;
+ dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
+ src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
dst->fRowBytes = dst->fBounds.width();
dst->fFormat = SkMask::kA8_Format;
dst->fImage = NULL;
@@ -283,15 +292,38 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
// build the blurry destination
{
- SkAutoTMalloc<uint32_t> storage((sw + 1) * (sh + 1));
+ SkAutoTMalloc<uint32_t> storage((sw + 2 * (passCount - 1) * rx + 1) * (sh + 2 * (passCount - 1) * ry + 1));
uint32_t* sumBuffer = storage.get();
+ //pass1: sp is source, dp is destination
build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes);
dump_sum_buffer(sumBuffer, sw, sh);
if (outer_weight == 255)
apply_kernel(dp, rx, ry, sumBuffer, sw, sh);
else
apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight);
+
+ if (quality == kHigh_Quality)
+ {
+ //pass2: dp is source, tmpBuffer is destination
+ int tmp_sw = sw + 2 * rx;
+ int tmp_sh = sh + 2 * ry;
+ SkAutoTMalloc<uint8_t> tmpBuffer(dstSize);
+ build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, dp, tmp_sw);
+ if (outer_weight == 255)
+ apply_kernel(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh);
+ else
+ apply_kernel_interp(tmpBuffer.get(), rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight);
+
+ //pass3: tmpBuffer is source, dp is destination
+ tmp_sw += 2 * rx;
+ tmp_sh += 2 * ry;
+ build_sum_buffer(sumBuffer, tmp_sw, tmp_sh, tmpBuffer.get(), tmp_sw);
+ if (outer_weight == 255)
+ apply_kernel(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh);
+ else
+ apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh, outer_weight);
+ }
}
dst->fImage = dp;
@@ -306,11 +338,11 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
dst->fImage = SkMask::AllocImage(srcSize);
merge_src_with_blur(dst->fImage, src.fRowBytes,
sp, src.fRowBytes,
- dp + rx + ry*dst->fRowBytes, dst->fRowBytes,
+ dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes,
sw, sh);
SkMask::FreeImage(dp);
} else if (style != kNormal_Style) {
- clamp_with_orig(dp + rx + ry*dst->fRowBytes, dst->fRowBytes,
+ clamp_with_orig(dp + passCount * (rx + ry * dst->fRowBytes), dst->fRowBytes,
sp, src.fRowBytes, sw, sh,
style);
}
diff --git a/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h
index 8f61d5436c..560ef48a47 100644
--- a/src/effects/SkBlurMask.h
+++ b/src/effects/SkBlurMask.h
@@ -31,7 +31,12 @@ public:
kStyleCount
};
- static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style);
+ enum Quality {
+ kLow_Quality, //!< box blur
+ kHigh_Quality //!< three pass box blur (similar to gaussian)
+ };
+
+ static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style, Quality quality);
};
#endif
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 8941cd1015..41e04b8a53 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -96,8 +96,10 @@ bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, const SkMa
// a request like 10,000)
static const SkScalar MAX_RADIUS = SkIntToScalar(128);
radius = SkMinScalar(radius, MAX_RADIUS);
+ SkBlurMask::Quality blurQuality = (fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
+ SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
- if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle))
+ if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle, blurQuality))
{
if (margin) {
// we need to integralize radius for our margin, so take the ceil
diff --git a/src/effects/SkEmbossMaskFilter.cpp b/src/effects/SkEmbossMaskFilter.cpp
index 67c8024c41..9d585ff3a7 100644
--- a/src/effects/SkEmbossMaskFilter.cpp
+++ b/src/effects/SkEmbossMaskFilter.cpp
@@ -73,7 +73,7 @@ bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src, const SkMatr
{
SkScalar radius = matrix.mapRadius(fBlurRadius);
- if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style))
+ if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style, SkBlurMask::kLow_Quality))
return false;
dst->fFormat = SkMask::k3D_Format;