diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:09:42 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:09:42 +0000 |
commit | ae2c20f398933a9e86c387dcc465ec0f71065ffc (patch) | |
tree | de668b1411e2ee0b4e49b6d8f8b68183134ac990 /skia/effects/SkBlurMask.cpp | |
parent | 09911bf300f1a419907a9412154760efd0b7abc3 (diff) | |
download | chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.zip chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.tar.gz chromium_src-ae2c20f398933a9e86c387dcc465ec0f71065ffc.tar.bz2 |
Add skia to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia/effects/SkBlurMask.cpp')
-rw-r--r-- | skia/effects/SkBlurMask.cpp | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/skia/effects/SkBlurMask.cpp b/skia/effects/SkBlurMask.cpp new file mode 100644 index 0000000..f2c07a8 --- /dev/null +++ b/skia/effects/SkBlurMask.cpp @@ -0,0 +1,332 @@ +/* libs/graphics/effects/SkBlurMask.cpp +** +** Copyright 2006, Google Inc. +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "SkBlurMask.h" +#include "SkTemplates.h" + +static void build_sum_buffer(uint32_t dst[], int w, int h, const uint8_t src[], int srcRB) +{ + SkASSERT(srcRB >= w); + // mod srcRB so we can apply it after each row + srcRB -= w; + + int x, y; + + // special case first row + uint32_t X = 0; + for (x = w - 1; x >= 0; --x) + { + X = *src++ + X; + *dst++ = X; + } + src += srcRB; + + // now do the rest of the rows + for (y = h - 1; y > 0; --y) + { + uint32_t L = 0; + uint32_t C = 0; + for (x = w - 1; x >= 0; --x) + { + uint32_t T = dst[-w]; + X = *src++ + L + T - C; + *dst++ = X; + L = X; + C = T; + } + src += srcRB; + } +} + +static void apply_kernel(uint8_t dst[], int rx, int ry, const uint32_t src[], int sw, int sh) +{ + uint32_t scale = (1 << 24) / ((2*rx + 1)*(2*ry + 1)); + + int rowBytes = sw; + + int dw = sw + 2*rx; + int dh = sh + 2*ry; + + sw -= 1; // now it is max_x + sh -= 1; // now it is max_y + + int prev_y = -ry - 1 -ry; + int next_y = ry -ry; + + for (int y = 0; y < dh; y++) + { + int py = SkClampPos(prev_y) * rowBytes; + int ny = SkFastMin32(next_y, sh) * rowBytes; + + int prev_x = -rx - 1 -rx; + int next_x = rx -rx; + + for (int x = 0; x < dw; x++) + { + int px = SkClampPos(prev_x); + int nx = SkFastMin32(next_x, sw); + + uint32_t sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny]; + *dst++ = SkToU8(sum * scale >> 24); + + prev_x += 1; + next_x += 1; + } + prev_y += 1; + next_y += 1; + } +} + +static void apply_kernel_interp(uint8_t dst[], int rx, int ry, const uint32_t src[], int sw, int sh, U8CPU outer_weight) +{ + SkASSERT(rx > 0 && ry > 0); + SkASSERT(outer_weight <= 255); + + int inner_weight = 255 - outer_weight; + + // round these guys up if they're bigger than 127 + outer_weight += outer_weight >> 7; + inner_weight += inner_weight >> 7; + + uint32_t outer_scale = (outer_weight << 16) / ((2*rx + 1)*(2*ry + 1)); + uint32_t inner_scale = (inner_weight << 16) / ((2*rx - 1)*(2*ry - 1)); + + int rowBytes = sw; + + int dw = sw + 2*rx; + int dh = sh + 2*ry; + + sw -= 1; // now it is max_x + sh -= 1; // now it is max_y + + int prev_y = -ry - 1 -ry; + int next_y = ry -ry; + + for (int y = 0; y < dh; y++) + { + int py = SkClampPos(prev_y) * rowBytes; + int ny = SkFastMin32(next_y, sh) * rowBytes; + + int ipy = SkClampPos(prev_y + 1) * rowBytes; + int iny = SkClampMax(next_y - 1, sh) * rowBytes; + + int prev_x = -rx - 1 -rx; + int next_x = rx -rx; + + for (int x = 0; x < dw; x++) + { + int px = SkClampPos(prev_x); + int nx = SkFastMin32(next_x, sw); + + int ipx = SkClampPos(prev_x + 1); + int inx = SkClampMax(next_x - 1, sw); + + uint32_t outer_sum = src[px+py] + src[nx+ny] - src[nx+py] - src[px+ny]; + uint32_t inner_sum = src[ipx+ipy] + src[inx+iny] - src[inx+ipy] - src[ipx+iny]; + *dst++ = SkToU8((outer_sum * outer_scale + inner_sum * inner_scale) >> 24); + + prev_x += 1; + next_x += 1; + } + prev_y += 1; + next_y += 1; + } +} + +#include "SkColorPriv.h" + +static void merge_src_with_blur(uint8_t dst[], + const uint8_t src[], int sw, int sh, + const uint8_t blur[], int blurRowBytes) +{ + while (--sh >= 0) + { + for (int x = sw - 1; x >= 0; --x) + { + *dst = SkToU8(SkAlphaMul(*blur, SkAlpha255To256(*src))); + dst += 1; + src += 1; + blur += 1; + } + blur += blurRowBytes - sw; + } +} + +static void clamp_with_orig(uint8_t dst[], int dstRowBytes, + const uint8_t src[], int sw, int sh, + SkBlurMask::Style style) +{ + int x; + while (--sh >= 0) + { + switch (style) { + case SkBlurMask::kSolid_Style: + for (x = sw - 1; x >= 0; --x) + { + *dst = SkToU8(*src + SkAlphaMul(*dst, SkAlpha255To256(255 - *src))); + dst += 1; + src += 1; + } + break; + case SkBlurMask::kOuter_Style: + for (x = sw - 1; x >= 0; --x) + { + if (*src) + *dst = SkToU8(SkAlphaMul(*dst, SkAlpha255To256(255 - *src))); + dst += 1; + src += 1; + } + break; + default: + SkASSERT(!"Unexpected blur style here"); + break; + } + dst += dstRowBytes - sw; + } +} + +//////////////////////////////////////////////////////////////////////// + +// we use a local funciton to wrap the class static method to work around +// a bug in gcc98 +void SkMask_FreeImage(uint8_t* image); +void SkMask_FreeImage(uint8_t* image) +{ + SkMask::FreeImage(image); +} + +bool SkBlurMask::Blur(SkMask* dst, const SkMask& src, + SkScalar radius, Style style) +{ + if (src.fFormat != SkMask::kA8_Format) + return false; + + int rx = SkScalarCeil(radius); + int outer_weight = 255 - SkScalarRound((SkIntToScalar(rx) - radius) * 255); + + SkASSERT(rx >= 0); + SkASSERT((unsigned)outer_weight <= 255); + + if (rx == 0) + return false; + + 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); + dst->fRowBytes = SkToU16(dst->fBounds.width()); + dst->fFormat = SkMask::kA8_Format; + dst->fImage = NULL; + + if (src.fImage) + { + int sw = src.fBounds.width(); + int sh = src.fBounds.height(); + const uint8_t* sp = src.fImage; + uint8_t* dp = SkMask::AllocImage(dst->computeImageSize()); + + SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp); + + // build the blurry destination + { + SkAutoTMalloc<uint32_t> storage(sw * sh); + uint32_t* sumBuffer = storage.get(); + + build_sum_buffer(sumBuffer, sw, sh, sp, src.fRowBytes); + if (outer_weight == 255) + apply_kernel(dp, rx, ry, sumBuffer, sw, sh); + else + apply_kernel_interp(dp, rx, ry, sumBuffer, sw, sh, outer_weight); + } + + dst->fImage = dp; + // if need be, alloc the "real" dst (same size as src) and copy/merge + // the blur into it (applying the src) + if (style == kInner_Style) + { + dst->fImage = SkMask::AllocImage(src.computeImageSize()); + merge_src_with_blur(dst->fImage, sp, sw, sh, + dp + rx + ry*dst->fBounds.width(), + dst->fBounds.width()); + SkMask::FreeImage(dp); + } + else if (style != kNormal_Style) + { + clamp_with_orig(dp + rx + ry*dst->fBounds.width(), + dst->fBounds.width(), + sp, sw, sh, + style); + } + (void)autoCall.detach(); + } + + if (style == kInner_Style) + { + dst->fBounds = src.fBounds; // restore trimmed bounds + dst->fRowBytes = SkToU16(dst->fBounds.width()); + } + +#if 0 + if (gamma && dst->fImage) + { + uint8_t* image = dst->fImage; + uint8_t* stop = image + dst->computeImageSize(); + + for (; image < stop; image += 1) + *image = gamma[*image]; + } +#endif + return true; +} + +#if 0 +void SkBlurMask::BuildSqrtGamma(uint8_t gamma[256], SkScalar percent) +{ + SkASSERT(gamma); + SkASSERT(percent >= 0 && percent <= SK_Scalar1); + + int scale = SkScalarRound(percent * 256); + + for (int i = 0; i < 256; i++) + { + SkFixed n = i * 257; + n += n >> 15; + SkASSERT(n >= 0 && n <= SK_Fixed1); + n = SkFixedSqrt(n); + n = n * 255 >> 16; + n = SkAlphaBlend(n, i, scale); + gamma[i] = SkToU8(n); + } +} + +void SkBlurMask::BuildSqrGamma(uint8_t gamma[256], SkScalar percent) +{ + SkASSERT(gamma); + SkASSERT(percent >= 0 && percent <= SK_Scalar1); + + int scale = SkScalarRound(percent * 256); + SkFixed div255 = SK_Fixed1 / 255; + + for (int i = 0; i < 256; i++) + { + int square = i * i; + int linear = i * 255; + int n = SkAlphaBlend(square, linear, scale); + gamma[i] = SkToU8(n * div255 >> 16); + } +} +#endif |