Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Unified Diff: src/effects/SkBlurMask.cpp

Issue 21835004: Blur refactoring (Closed) Base URL: http://skia.googlecode.com/svn/trunk/
Patch Set: Removed unneeded #includes Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/effects/SkBlurMask.h ('k') | src/effects/SkBlurMaskFilter.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/effects/SkBlurMask.cpp
===================================================================
--- src/effects/SkBlurMask.cpp (revision 10932)
+++ src/effects/SkBlurMask.cpp (working copy)
@@ -12,8 +12,20 @@
#include "SkTemplates.h"
#include "SkEndian.h"
-const SkScalar SkBlurMask::kBlurRadiusFudgeFactor = SkFloatToScalar(.57735f);
+SkScalar SkBlurMask::ConvertRadiusToSigma(SkScalar radius) {
+ // This constant approximates the scaling done in the software path's
+ // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
+ // IMHO, it actually should be 1: we blur "less" than we should do
+ // according to the CSS and canvas specs, simply because Safari does the same.
+ // Firefox used to do the same too, until 4.0 where they fixed it. So at some
+ // point we should probably get rid of these scaling constants and rebaseline
+ // all the blur tests.
+ static const SkScalar kBLUR_SIGMA_SCALE = SkFloatToScalar(0.57735f);
+
+ return radius ? kBLUR_SIGMA_SCALE * radius + 0.5f : 0.0f;
+}
+
#define UNROLL_SEPARABLE_LOOPS
/**
@@ -473,24 +485,40 @@
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
SkScalar radius, Style style, Quality quality,
- SkIPoint* margin)
-{
+ SkIPoint* margin) {
+ return SkBlurMask::BoxBlur(dst, src,
+ SkBlurMask::ConvertRadiusToSigma(radius),
+ style, quality, margin);
+}
+bool SkBlurMask::BoxBlur(SkMask* dst, const SkMask& src,
+ SkScalar sigma, Style style, Quality quality,
+ SkIPoint* margin) {
+
if (src.fFormat != SkMask::kA8_Format) {
return false;
}
// Force high quality off for small radii (performance)
- if (radius < SkIntToScalar(3)) {
+ if (sigma <= SkIntToScalar(2)) {
quality = kLow_Quality;
}
+ SkScalar passRadius;
+ if (kHigh_Quality == quality) {
+ // For the high quality path the 3 pass box blur kernel width is
+ // 6*rad+1 while the full Gaussian width is 6*sigma.
+ passRadius = sigma - (1/6.0f);
+ } else {
+ // For the low quality path we only attempt to cover 3*sigma of the
+ // Gaussian blur area (1.5*sigma on each side). The single pass box
+ // blur's kernel size is 2*rad+1.
+ passRadius = 1.5f*sigma - 0.5f;
+ }
+
// highQuality: use three box blur passes as a cheap way
// to approximate a Gaussian blur
int passCount = (kHigh_Quality == quality) ? 3 : 1;
- SkScalar passRadius = (kHigh_Quality == quality) ?
- SkScalarMul( radius, kBlurRadiusFudgeFactor):
- radius;
int rx = SkScalarCeil(passRadius);
int outerWeight = 255 - SkScalarRound((SkIntToScalar(rx) - passRadius) * 255);
@@ -510,7 +538,7 @@
margin->set(padx, pady);
}
dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
- src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
+ src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
dst->fRowBytes = dst->fBounds.width();
dst->fFormat = SkMask::kA8_Format;
@@ -651,13 +679,6 @@
return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
}
-// Compute the size of the array allocated for the profile.
-
-static int compute_profile_size(SkScalar radius) {
- return SkScalarRoundToInt(radius * 3);
-
-}
-
/* compute_profile allocates and fills in an array of floating
point values between 0 and 255 for the profile signature of
a blurred half-plane with the given blur radius. Since we're
@@ -669,13 +690,13 @@
memory returned in profile_out.
*/
-static void compute_profile(SkScalar radius, unsigned int **profile_out) {
- int size = compute_profile_size(radius);
+static void compute_profile(SkScalar sigma, unsigned int **profile_out) {
+ int size = SkScalarCeilToInt(6*sigma);
int center = size >> 1;
unsigned int *profile = SkNEW_ARRAY(unsigned int, size);
- float invr = 1.f/radius;
+ float invr = 1.f/(2*sigma);
profile[0] = 255;
for (int x = 1 ; x < size ; ++x) {
@@ -705,17 +726,18 @@
}
bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
- SkScalar provided_radius, Style style,
+ SkScalar radius, Style style,
SkIPoint *margin, SkMask::CreateMode createMode) {
- int profile_size;
+ return SkBlurMask::BlurRect(SkBlurMask::ConvertRadiusToSigma(radius),
+ dst, src,
+ style, margin, createMode);
+}
- float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
+bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst,
+ const SkRect &src, Style style,
+ SkIPoint *margin, SkMask::CreateMode createMode) {
+ int profile_size = SkScalarCeilToInt(6*sigma);
- // adjust blur radius to match interpretation from boxfilter code
- radius = (radius + .5f) * 2.f;
-
- profile_size = compute_profile_size(radius);
-
int pad = profile_size/2;
if (margin) {
margin->set( pad, pad );
@@ -745,7 +767,7 @@
}
unsigned int *profile = NULL;
- compute_profile(radius, &profile);
+ compute_profile(sigma, &profile);
SkAutoTDeleteArray<unsigned int> ada(profile);
size_t dstSize = dst->computeImageSize();
@@ -775,8 +797,8 @@
if (profile_size <= sw) {
horizontalScanline[x] = profile_lookup(profile, x, dstWidth, w);
} else {
- float span = float(sw)/radius;
- float giX = 1.5f - (x+.5f)/radius;
+ float span = float(sw)/(2*sigma);
+ float giX = 1.5f - (x+.5f)/(2*sigma);
horizontalScanline[x] = (uint8_t) (255 * (gaussianIntegral(giX) - gaussianIntegral(giX + span)));
}
}
@@ -786,8 +808,8 @@
if (profile_size <= sh) {
profile_y = profile_lookup(profile, y, dstHeight, h);
} else {
- float span = float(sh)/radius;
- float giY = 1.5f - (y+.5f)/radius;
+ float span = float(sh)/(2*sigma);
+ float giY = 1.5f - (y+.5f)/(2*sigma);
profile_y = (uint8_t) (255 * (gaussianIntegral(giY) - gaussianIntegral(giY + span)));
}
@@ -834,22 +856,24 @@
return true;
}
+bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar radius,
+ Style style, SkIPoint* margin) {
+ return BlurGroundTruth(ConvertRadiusToSigma(radius), dst, src, style, margin);
+}
// The "simple" blur is a direct implementation of separable convolution with a discrete
// gaussian kernel. It's "ground truth" in a sense; too slow to be used, but very
// useful for correctness comparisons.
-bool SkBlurMask::BlurGroundTruth(SkMask* dst, const SkMask& src, SkScalar provided_radius,
- Style style, SkIPoint* margin) {
+bool SkBlurMask::BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src,
+ Style style, SkIPoint* margin) {
if (src.fFormat != SkMask::kA8_Format) {
return false;
}
- float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
- float stddev = SkScalarToFloat(radius) /2.0f;
- float variance = stddev * stddev;
+ float variance = sigma * sigma;
- int windowSize = SkScalarCeil(stddev*4);
+ int windowSize = SkScalarCeil(sigma*4);
// round window size up to nearest odd number
windowSize |= 1;
« no previous file with comments | « src/effects/SkBlurMask.h ('k') | src/effects/SkBlurMaskFilter.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698