diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/effects/SkBlurDrawLooper.cpp | 25 | ||||
-rw-r--r-- | src/effects/SkBlurMask.cpp | 48 | ||||
-rw-r--r-- | src/effects/SkBlurMask.h | 7 | ||||
-rw-r--r-- | src/effects/SkBlurMaskFilter.cpp | 4 | ||||
-rw-r--r-- | src/effects/SkEmbossMaskFilter.cpp | 2 | ||||
-rw-r--r-- | src/images/SkImageDecoder_libpng.cpp | 2 |
6 files changed, 75 insertions, 13 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; diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp index 112afbb80d..89f2db2a47 100644 --- a/src/images/SkImageDecoder_libpng.cpp +++ b/src/images/SkImageDecoder_libpng.cpp @@ -201,7 +201,7 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, } /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { - png_set_gray_1_2_4_to_8(png_ptr); + // png_set_gray_1_2_4_to_8(png_ptr); } /* Make a grayscale image into RGB. */ |