summaryrefslogtreecommitdiffstats
path: root/skia/effects/SkBlurMask.cpp
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:09:42 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-27 00:09:42 +0000
commitae2c20f398933a9e86c387dcc465ec0f71065ffc (patch)
treede668b1411e2ee0b4e49b6d8f8b68183134ac990 /skia/effects/SkBlurMask.cpp
parent09911bf300f1a419907a9412154760efd0b7abc3 (diff)
downloadchromium_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.cpp332
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