https://codereview.chromium.org/21835004/



git-svn-id: http://skia.googlecode.com/svn/trunk@10936 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2013-08-27 16:14:03 +00:00
Родитель 45891b8e37
Коммит 7ce661d19c
20 изменённых файлов: 286 добавлений и 203 удалений

Просмотреть файл

@ -141,8 +141,8 @@ protected:
SkMask mask;
mask.fImage = NULL;
SkBlurMask::Blur(&mask, fSrcMask, this->radius(),
SkBlurMask::kNormal_Style,
SkBlurMask::kHigh_Quality);
SkBlurMask::kNormal_Style,
SkBlurMask::kHigh_Quality);
SkMask::FreeImage(mask.fImage);
}
private:

Просмотреть файл

@ -71,12 +71,12 @@ class BlurRectGM : public skiagm::GM {
SkAlpha fAlpha;
public:
BlurRectGM(const char name[], PaintProc pproc, U8CPU alpha,
SkBlurMaskFilter::BlurStyle bs) :
fMaskFilter(SkBlurMaskFilter::Create(STROKE_WIDTH/2, bs,
SkBlurMaskFilter::kHighQuality_BlurFlag))
, fName(name)
, fPProc(pproc)
, fAlpha(SkToU8(alpha)) {
SkBlurMaskFilter::BlurStyle bs)
: fMaskFilter(SkBlurMaskFilter::Create(STROKE_WIDTH/2, bs,
SkBlurMaskFilter::kHighQuality_BlurFlag))
, fName(name)
, fPProc(pproc)
, fAlpha(SkToU8(alpha)) {
fName.appendf("_%s", gBlurStyle2Name[bs]);
}
@ -208,13 +208,12 @@ private:
class BlurRectFastGM: public BlurRectCompareGM {
public:
BlurRectFastGM(const char name[], unsigned int rect_width,
unsigned int rect_height, float blur_radius,
BlurRectFastGM(const char name[], unsigned int rectWidth,
unsigned int rectHeight, float blurRadius,
SkBlurMask::Style style) :
INHERITED(name, rect_width, rect_height, blur_radius, style)
{
INHERITED(name, rectWidth, rectHeight, blurRadius, style) {
}
protected:
virtual bool makeMask(SkMask *m, const SkRect& r) SK_OVERRIDE {
return SkBlurMask::BlurRect(m, r, this->radius(), this->style());

Просмотреть файл

@ -60,31 +60,29 @@ protected:
for (size_t i = 0; i < SK_ARRAY_COUNT(gRecs); i++) {
if (gRecs[i].fStyle != NONE) {
SkMaskFilter* mf = SkBlurMaskFilter::Create(
SkIntToScalar(20), gRecs[i].fStyle, flags
);
SkIntToScalar(20), gRecs[i].fStyle, flags);
paint.setMaskFilter(mf)->unref();
} else {
paint.setMaskFilter(NULL);
}
canvas->drawCircle(SkIntToScalar(200 + gRecs[i].fCx*100)
, SkIntToScalar(200 + gRecs[i].fCy*100)
, SkIntToScalar(50)
, paint);
canvas->drawCircle(SkIntToScalar(200 + gRecs[i].fCx*100),
SkIntToScalar(200 + gRecs[i].fCy*100),
SkIntToScalar(50),
paint);
}
// draw text
{
SkMaskFilter* mf = SkBlurMaskFilter::Create(
SkIntToScalar(4)
, SkBlurMaskFilter::kNormal_BlurStyle
, flags
);
SkIntToScalar(4),
SkBlurMaskFilter::kNormal_BlurStyle,
flags);
paint.setMaskFilter(mf)->unref();
SkScalar x = SkIntToScalar(70);
SkScalar y = SkIntToScalar(400);
paint.setColor(SK_ColorBLACK);
canvas->drawText("Hamburgefons Style", 18, x, y, paint);
canvas->drawText("Hamburgefons Style", 18
, x, y + SkIntToScalar(50), paint);
canvas->drawText("Hamburgefons Style", 18,
x, y + SkIntToScalar(50), paint);
paint.setMaskFilter(NULL);
paint.setColor(SK_ColorWHITE);
x -= SkIntToScalar(2);

Просмотреть файл

@ -83,7 +83,7 @@ protected:
SkIntToScalar(10), 0xFF0000FF,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkBlurDrawLooper::kHighQuality_BlurFlag);
SkAutoUnref aurL0(shadowLooper);
p.setLooper(shadowLooper);
fPaints.push_back(p);

Просмотреть файл

@ -88,7 +88,7 @@ protected:
SkIntToScalar(10), SK_ColorWHITE,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkBlurDrawLooper::kHighQuality_BlurFlag);
SkAutoUnref aurL0(shadowLooper);
p.setLooper(shadowLooper);
fPaints.push_back(p);

Просмотреть файл

@ -50,33 +50,33 @@ protected:
SkIntToScalar(10), 0xFF0000FF,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkBlurDrawLooper::kHighQuality_BlurFlag);
SkAutoUnref aurL0(shadowLoopers[0]);
shadowLoopers[1] =
new SkBlurDrawLooper (SkIntToScalar(10), SkIntToScalar(5),
SkIntToScalar(10), 0xFF0000FF,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag );
SkBlurDrawLooper::kOverrideColor_BlurFlag);
SkAutoUnref aurL1(shadowLoopers[1]);
shadowLoopers[2] =
new SkBlurDrawLooper (SkIntToScalar(5), SkIntToScalar(5),
SkIntToScalar(10), 0xFF000000,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkBlurDrawLooper::kHighQuality_BlurFlag);
SkAutoUnref aurL2(shadowLoopers[2]);
shadowLoopers[3] =
new SkBlurDrawLooper (SkIntToScalar(5), SkIntToScalar(-5),
SkIntToScalar(-10), 0x7FFF0000,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkBlurDrawLooper::kHighQuality_BlurFlag);
SkAutoUnref aurL3(shadowLoopers[3]);
shadowLoopers[4] =
new SkBlurDrawLooper (SkIntToScalar(0), SkIntToScalar(5),
SkIntToScalar(5), 0xFF000000,
SkBlurDrawLooper::kIgnoreTransform_BlurFlag |
SkBlurDrawLooper::kOverrideColor_BlurFlag |
SkBlurDrawLooper::kHighQuality_BlurFlag );
SkBlurDrawLooper::kHighQuality_BlurFlag);
SkAutoUnref aurL4(shadowLoopers[4]);
static const struct {

Просмотреть файл

@ -209,6 +209,7 @@ protected:
// V11: modify how readBitmap and writeBitmap store their info.
// V12: add conics to SkPath, use new SkPathRef flattening
// V13: add flag to drawBitmapRectToRect
// parameterize blurs by sigma rather than radius
#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
static const uint32_t PRIOR_PICTURE_VERSION = 12; // TODO: remove when .skps regenerated
#endif

Просмотреть файл

@ -35,6 +35,10 @@ public:
kAll_BlurFlag = 0x07
};
SkBlurDrawLooper(SkColor color, SkScalar sigma, SkScalar dx, SkScalar dy,
uint32_t flags = kNone_BlurFlag);
// DEPRECATED - radius-based
SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy, SkColor color,
uint32_t flags = kNone_BlurFlag);
virtual ~SkBlurDrawLooper();
@ -64,6 +68,8 @@ private:
};
State fState;
void init(SkScalar sigma, SkScalar dx, SkScalar dy, SkColor color, uint32_t flags);
typedef SkDrawLooper INHERITED;
};

Просмотреть файл

@ -33,27 +33,39 @@ public:
kAll_BlurFlag = 0x03
};
/** Create a blur maskfilter.
@param radius The radius to extend the blur from the original mask. Must be > 0.
@param style The BlurStyle to use
@param flags Flags to use - defaults to none
@return The new blur maskfilter
*/
/**
* DEPRECATED - radius-based
*/
static SkMaskFilter* Create(SkScalar radius, BlurStyle style,
uint32_t flags = kNone_BlurFlag);
/** Create a blur maskfilter.
@param style The BlurStyle to use
@param sigma Standard deviation of the Gaussian blur to apply. Must be > 0.
@param flags Flags to use - defaults to none
@return The new blur maskfilter
*/
static SkMaskFilter* Create(BlurStyle style, SkScalar sigma,
uint32_t flags = kNone_BlurFlag);
/** Create an emboss maskfilter
@param blurSigma standard deviation of the Gaussian blur to apply
before applying lighting (e.g. 3)
@param direction array of 3 scalars [x, y, z] specifying the direction of the light source
@param ambient 0...1 amount of ambient light
@param specular coefficient for specular highlights (e.g. 8)
@param blurRadius amount to blur before applying lighting (e.g. 3)
@return the emboss maskfilter
*/
static SkMaskFilter* CreateEmboss( const SkScalar direction[3],
SkScalar ambient, SkScalar specular,
SkScalar blurRadius);
static SkMaskFilter* CreateEmboss(SkScalar blurSigma, const SkScalar direction[3],
SkScalar ambient, SkScalar specular);
// DEPRECATED - radius-based
static SkMaskFilter* CreateEmboss(const SkScalar direction[3],
SkScalar ambient, SkScalar specular,
SkScalar blurRadius);
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()
private:
SkBlurMaskFilter(); // can't be instantiated
};

Просмотреть файл

@ -23,6 +23,9 @@ public:
uint8_t fSpecular; // exponent, 4.4 right now
};
SkEmbossMaskFilter(SkScalar blurSigma, const Light& light);
// DEPRECATED - radius-based
SkEmbossMaskFilter(const Light& light, SkScalar blurRadius);
// overrides from SkMaskFilter
@ -41,7 +44,7 @@ protected:
private:
Light fLight;
SkScalar fBlurRadius;
SkScalar fBlurSigma;
typedef SkMaskFilter INHERITED;
};

Просмотреть файл

@ -80,7 +80,8 @@ private:
static void r0(SkLayerRasterizer* rast, SkPaint& p) {
p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(3),
SkBlurMaskFilter::kNormal_BlurStyle))->unref();
SkBlurMaskFilter::kNormal_BlurStyle,
SkBlurMaskFilter::kNone_BlurFlag))->unref();
rast->addLayer(p, SkIntToScalar(3), SkIntToScalar(3));
p.setMaskFilter(NULL);
@ -254,7 +255,10 @@ static void apply_shader(SkPaint* paint, int index) {
#if 1
SkScalar dir[] = { SK_Scalar1, SK_Scalar1, SK_Scalar1 };
paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir, SK_Scalar1/4, SkIntToScalar(4), SkIntToScalar(3)))->unref();
paint->setMaskFilter(SkBlurMaskFilter::CreateEmboss(dir,
SK_Scalar1/4,
SkIntToScalar(4),
SkIntToScalar(3)))->unref();
paint->setColor(SK_ColorBLUE);
#endif
}
@ -383,8 +387,7 @@ protected:
light.fAmbient = 0x48;
light.fSpecular = 0x80;
SkScalar radius = SkIntToScalar(12)/5;
SkEmbossMaskFilter* embossFilter = new SkEmbossMaskFilter(light,
radius);
SkEmbossMaskFilter* embossFilter = new SkEmbossMaskFilter(light, radius);
SkXfermode* xfermode = SkXfermode::Create(SkXfermode::kXor_Mode);
SkColorFilter* lightingFilter = SkColorFilter::CreateLightingFilter(

Просмотреть файл

@ -46,7 +46,8 @@ class XfermodesBlurView : public SampleView {
void draw_mode(SkCanvas* canvas, SkXfermode* mode, int alpha,
SkScalar x, SkScalar y) {
SkPaint p;
SkMaskFilter* mf = SkBlurMaskFilter::Create(5, SkBlurMaskFilter::kNormal_BlurStyle, 0);
SkMaskFilter* mf = SkBlurMaskFilter::Create(5, SkBlurMaskFilter::kNormal_BlurStyle,
SkBlurMaskFilter::kNone_BlurFlag);
p.setMaskFilter(mf)->unref();
SkScalar ww = SkIntToScalar(W);

Просмотреть файл

@ -12,22 +12,23 @@
#if SK_USE_CONDENSED_INFO == 0
const SkMemberInfo SkDrawEmboss::fInfo[] = {
SK_MEMBER(ambient, Float),
SK_MEMBER_ARRAY(direction, Float),
SK_MEMBER(radius, Float),
SK_MEMBER(specular, Float)
SK_MEMBER(fAmbient, Float),
SK_MEMBER_ARRAY(fDirection, Float),
SK_MEMBER(fSigma, Float),
SK_MEMBER(fSpecular, Float)
};
#endif
DEFINE_GET_MEMBER(SkDrawEmboss);
SkDrawEmboss::SkDrawEmboss() : radius(-1) {
direction.setCount(3);
SkDrawEmboss::SkDrawEmboss() : fSigma(-1) {
fDirection.setCount(3);
}
SkMaskFilter* SkDrawEmboss::getMaskFilter() {
if (radius < 0 || direction.count() !=3)
if (fSigma < 0 || fDirection.count() !=3)
return NULL;
return SkBlurMaskFilter::CreateEmboss(direction.begin(), ambient, specular, radius);
return SkBlurMaskFilter::CreateEmboss(fSigma, fDirection.begin(),
fAmbient, fSpecular);
}

Просмотреть файл

@ -15,10 +15,14 @@
class SkDrawEmboss : public SkDrawMaskFilter {
DECLARE_DRAW_MEMBER_INFO(Emboss);
SkDrawEmboss();
virtual SkMaskFilter* getMaskFilter();
virtual SkMaskFilter* getMaskFilter() SK_OVERRIDE;
protected:
SkTDScalarArray direction;
SkScalar radius, ambient, specular;
SkTDScalarArray fDirection;
SkScalar fSigma;
SkScalar fAmbient;
SkScalar fSpecular;
typedef SkDrawMaskFilter INHERITED;
};
#endif // SkDrawEmboss_DEFINED

Просмотреть файл

@ -275,6 +275,7 @@ bool SkPicture::StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
}
if (PICTURE_VERSION != info.fVersion
#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
// V13 is backwards compatible with V12
&& PRIOR_PICTURE_VERSION != info.fVersion // TODO: remove when .skps regenerated
#endif
) {

Просмотреть файл

@ -6,6 +6,7 @@
* found in the LICENSE file.
*/
#include "SkBlurDrawLooper.h"
#include "SkBlurMask.h" // just for SkBlurMask::ConvertRadiusToSigma
#include "SkBlurMaskFilter.h"
#include "SkCanvas.h"
#include "SkColorFilter.h"
@ -16,11 +17,25 @@
#include "SkStringUtils.h"
SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
SkColor color, uint32_t flags)
: fDx(dx), fDy(dy), fBlurColor(color), fBlurFlags(flags), fState(kDone) {
SkColor color, uint32_t flags) {
this->init(SkBlurMask::ConvertRadiusToSigma(radius), dx, dy, color, flags);
}
SkBlurDrawLooper::SkBlurDrawLooper(SkColor color, SkScalar sigma,
SkScalar dx, SkScalar dy, uint32_t flags) {
this->init(sigma, dx, dy, color, flags);
}
void SkBlurDrawLooper::init(SkScalar sigma, SkScalar dx, SkScalar dy,
SkColor color, uint32_t flags) {
fDx = dx;
fDy = dy;
fBlurColor = color;
fBlurFlags = flags;
fState = kDone;
SkASSERT(flags <= kAll_BlurFlag);
if (radius > 0) {
if (sigma > 0) {
uint32_t blurFlags = flags & kIgnoreTransform_BlurFlag ?
SkBlurMaskFilter::kIgnoreTransform_BlurFlag :
SkBlurMaskFilter::kNone_BlurFlag;
@ -29,8 +44,8 @@ SkBlurDrawLooper::SkBlurDrawLooper(SkScalar radius, SkScalar dx, SkScalar dy,
SkBlurMaskFilter::kHighQuality_BlurFlag :
SkBlurMaskFilter::kNone_BlurFlag;
fBlur = SkBlurMaskFilter::Create(radius,
SkBlurMaskFilter::kNormal_BlurStyle,
fBlur = SkBlurMaskFilter::Create(SkBlurMaskFilter::kNormal_BlurStyle,
sigma,
blurFlags);
} else {
fBlur = NULL;

Просмотреть файл

@ -12,7 +12,19 @@
#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 @@ void SkMask_FreeImage(uint8_t* image) {
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 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
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 @@ static float gaussianIntegral(float x) {
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 @@ static int compute_profile_size(SkScalar radius) {
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,16 +726,17 @@ static inline unsigned int profile_lookup( unsigned int *profile, int loc, int b
}
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));
// adjust blur radius to match interpretation from boxfilter code
radius = (radius + .5f) * 2.f;
profile_size = compute_profile_size(radius);
bool SkBlurMask::BlurRect(SkScalar sigma, SkMask *dst,
const SkRect &src, Style style,
SkIPoint *margin, SkMask::CreateMode createMode) {
int profile_size = SkScalarCeilToInt(6*sigma);
int pad = profile_size/2;
if (margin) {
@ -745,7 +767,7 @@ bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
}
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 @@ bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
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 @@ bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
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 @@ bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
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;

Просмотреть файл

@ -29,27 +29,37 @@ public:
kHigh_Quality //!< three pass box blur (similar to gaussian)
};
static bool BlurRect(SkMask *dst, const SkRect &src,
SkScalar radius, Style style,
static bool BlurRect(SkScalar sigma, SkMask *dst, const SkRect &src,
Style style,
SkIPoint *margin = NULL,
SkMask::CreateMode createMode=SkMask::kComputeBoundsAndRenderImage_CreateMode);
static bool Blur(SkMask* dst, const SkMask& src,
SkScalar radius, Style style, Quality quality,
SkIPoint* margin = NULL);
SkMask::CreateMode createMode =
SkMask::kComputeBoundsAndRenderImage_CreateMode);
static bool BoxBlur(SkMask* dst, const SkMask& src,
SkScalar sigma, Style style, Quality quality,
SkIPoint* margin = NULL);
// the "ground truth" blur does a gaussian convolution; it's slow
// but useful for comparison purposes.
static bool BlurGroundTruth(SkScalar sigma, SkMask* dst, const SkMask& src,
Style style,
SkIPoint* margin = NULL);
// DEPRECATED - radius-based
static bool BlurRect(SkMask *dst, const SkRect &src,
SkScalar radius, Style style,
SkIPoint *margin = NULL,
SkMask::CreateMode createMode =
SkMask::kComputeBoundsAndRenderImage_CreateMode);
// DEPRECATED - radius-based
static bool Blur(SkMask* dst, const SkMask& src,
SkScalar radius, Style style, Quality quality,
SkIPoint* margin = NULL);
// DEPRECATED - radius-based
static bool BlurGroundTruth(SkMask* dst, const SkMask& src,
SkScalar provided_radius, Style style,
SkIPoint* margin = NULL);
// scale factor for the blur radius to match the behavior of the all existing blur
// code (both on the CPU and the GPU). This magic constant is 1/sqrt(3).
// TODO: get rid of this fudge factor and move any required fudging up into
// the calling library
static const SkScalar kBlurRadiusFudgeFactor;
SkScalar radius, Style style,
SkIPoint* margin = NULL);
static SkScalar ConvertRadiusToSigma(SkScalar radius);
};
#endif

Просмотреть файл

@ -24,8 +24,7 @@
class SkBlurMaskFilterImpl : public SkMaskFilter {
public:
SkBlurMaskFilterImpl(SkScalar radius, SkBlurMaskFilter::BlurStyle,
uint32_t flags);
SkBlurMaskFilterImpl(SkScalar sigma, SkBlurMaskFilter::BlurStyle, uint32_t flags);
// overrides from SkMaskFilter
virtual SkMask::Format getFormat() const SK_OVERRIDE;
@ -60,37 +59,26 @@ private:
// To avoid unseemly allocation requests (esp. for finite platforms like
// handset) we limit the radius so something manageable. (as opposed to
// a request like 10,000)
static const SkScalar kMAX_BLUR_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;
static const SkScalar kMAX_BLUR_SIGMA;
SkScalar fRadius;
SkScalar fSigma;
SkBlurMaskFilter::BlurStyle fBlurStyle;
uint32_t fBlurFlags;
SkBlurMaskFilterImpl(SkFlattenableReadBuffer&);
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
#if SK_SUPPORT_GPU
SkScalar computeXformedRadius(const SkMatrix& ctm) const {
SkScalar computeXformedSigma(const SkMatrix& ctm) const {
bool ignoreTransform = SkToBool(fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag);
SkScalar xformedRadius = ignoreTransform ? fRadius
: ctm.mapRadius(fRadius);
return SkMinScalar(xformedRadius, kMAX_BLUR_RADIUS);
SkScalar xformedSigma = ignoreTransform ? fSigma : ctm.mapRadius(fSigma);
return SkMinScalar(xformedSigma, kMAX_BLUR_SIGMA);
}
#endif
typedef SkMaskFilter INHERITED;
};
const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_RADIUS = SkIntToScalar(128);
const SkScalar SkBlurMaskFilterImpl::kBLUR_SIGMA_SCALE = SkFloatToScalar(0.6f);
const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_SIGMA = SkIntToScalar(128);
SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
SkBlurMaskFilter::BlurStyle style,
@ -101,15 +89,29 @@ SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
return NULL;
}
return SkNEW_ARGS(SkBlurMaskFilterImpl, (radius, style, flags));
SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius);
return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
}
SkMaskFilter* SkBlurMaskFilter::Create(SkBlurMaskFilter::BlurStyle style,
SkScalar sigma,
uint32_t flags) {
// use !(sigma > 0) instead of sigma <= 0 to reject NaN values
if (!(sigma > 0) || (unsigned)style >= SkBlurMaskFilter::kBlurStyleCount
|| flags > SkBlurMaskFilter::kAll_BlurFlag) {
return NULL;
}
return SkNEW_ARGS(SkBlurMaskFilterImpl, (sigma, style, flags));
}
///////////////////////////////////////////////////////////////////////////////
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma,
SkBlurMaskFilter::BlurStyle style,
uint32_t flags)
: fRadius(radius), fBlurStyle(style), fBlurFlags(flags) {
: fSigma(sigma), fBlurStyle(style), fBlurFlags(flags) {
#if 0
fGamma = NULL;
if (gammaScale) {
@ -120,7 +122,7 @@ SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar radius,
SkBlurMask::BuildSqrtGamma(fGamma, -gammaScale);
}
#endif
SkASSERT(radius >= 0);
SkASSERT(fSigma >= 0);
SkASSERT((unsigned)style < SkBlurMaskFilter::kBlurStyleCount);
SkASSERT(flags <= SkBlurMaskFilter::kAll_BlurFlag);
}
@ -132,35 +134,22 @@ SkMask::Format SkBlurMaskFilterImpl::getFormat() const {
bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
const SkMatrix& matrix,
SkIPoint* margin) const{
SkScalar radius;
if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
radius = fRadius;
} else {
radius = matrix.mapRadius(fRadius);
}
SkScalar sigma = this->computeXformedSigma(matrix);
radius = SkMinScalar(radius, kMAX_BLUR_RADIUS);
SkBlurMask::Quality blurQuality =
(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
blurQuality, margin);
return SkBlurMask::BoxBlur(dst, src, sigma, (SkBlurMask::Style)fBlurStyle,
blurQuality, margin);
}
bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
const SkMatrix& matrix,
SkIPoint* margin, SkMask::CreateMode createMode) const{
SkScalar radius;
if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
radius = fRadius;
} else {
radius = matrix.mapRadius(fRadius);
}
SkScalar sigma = computeXformedSigma(matrix);
radius = SkMinScalar(radius, kMAX_BLUR_RADIUS);
return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle,
return SkBlurMask::BlurRect(sigma, dst, r, (SkBlurMask::Style)fBlurStyle,
margin, createMode);
}
@ -334,24 +323,7 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
SkRect* dst) const {
SkScalar gpuPad, rasterPad;
{
// GPU path
SkScalar sigma = SkScalarMul(fRadius, kBLUR_SIGMA_SCALE);
gpuPad = sigma * 3.0f;
}
{
// raster path
SkScalar radius = SkScalarMul(fRadius, SkBlurMask::kBlurRadiusFudgeFactor);
radius = (radius + .5f) * 2.f;
rasterPad = SkIntToScalar(SkScalarRoundToInt(radius * 3)/2);
}
SkScalar pad = SkMaxScalar(gpuPad, rasterPad);
SkScalar pad = 3.0f * fSigma;
dst->set(src.fLeft - pad, src.fTop - pad,
src.fRight + pad, src.fBottom + pad);
@ -359,16 +331,27 @@ void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)
: SkMaskFilter(buffer) {
fRadius = buffer.readScalar();
fSigma = buffer.readScalar();
#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
// Fixing this must be done in two stages. When the skps are recaptured in V13,
// remove the ConvertRadiusToSigma but retain the absolute value.
// At the same time, switch the code in flatten to write a positive value.
// When the skps are captured in V14 the absolute value can be removed.
if (fSigma > 0) {
fSigma = SkBlurMask::ConvertRadiusToSigma(fSigma);
} else {
fSigma = -fSigma;
}
#endif
fBlurStyle = (SkBlurMaskFilter::BlurStyle)buffer.readInt();
fBlurFlags = buffer.readUInt() & SkBlurMaskFilter::kAll_BlurFlag;
SkASSERT(fRadius >= 0);
SkASSERT(fSigma >= 0);
SkASSERT((unsigned)fBlurStyle < SkBlurMaskFilter::kBlurStyleCount);
}
void SkBlurMaskFilterImpl::flatten(SkFlattenableWriteBuffer& buffer) const {
this->INHERITED::flatten(buffer);
buffer.writeScalar(fRadius);
buffer.writeScalar(-fSigma);
buffer.writeInt(fBlurStyle);
buffer.writeUInt(fBlurFlags);
}
@ -379,17 +362,17 @@ bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
const SkIRect& clipBounds,
const SkMatrix& ctm,
SkRect* maskRect) const {
SkScalar xformedRadius = this->computeXformedRadius(ctm);
if (xformedRadius <= 0) {
SkScalar xformedSigma = this->computeXformedSigma(ctm);
if (xformedSigma <= 0) {
return false;
}
static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64);
static const SkScalar kMIN_GPU_BLUR_RADIUS = SkIntToScalar(32);
static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64);
static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32);
if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE &&
srcBounds.height() <= kMIN_GPU_BLUR_SIZE &&
xformedRadius <= kMIN_GPU_BLUR_RADIUS) {
xformedSigma <= kMIN_GPU_BLUR_SIGMA) {
// We prefer to blur small rect with small radius via CPU.
return false;
}
@ -399,7 +382,7 @@ bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds,
return true;
}
float sigma3 = 3 * SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE;
float sigma3 = 3 * SkScalarToFloat(xformedSigma);
SkRect clipRect = SkRect::MakeFromIRect(clipBounds);
SkRect srcRect(srcBounds);
@ -422,16 +405,14 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
GrContext::AutoWideOpenIdentityDraw awo(context, NULL);
SkScalar xformedRadius = this->computeXformedRadius(context->getMatrix());
SkASSERT(xformedRadius > 0);
float sigma = SkScalarToFloat(xformedRadius) * kBLUR_SIGMA_SCALE;
SkScalar xformedSigma = this->computeXformedSigma(context->getMatrix());
SkASSERT(xformedSigma > 0);
// If we're doing a normal blur, we can clobber the pathTexture in the
// gaussianBlur. Otherwise, we need to save it for later compositing.
bool isNormalBlur = (SkBlurMaskFilter::kNormal_BlurStyle == fBlurStyle);
*result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
clipRect, false, sigma, sigma);
clipRect, false, xformedSigma, xformedSigma);
if (NULL == *result) {
return false;
}
@ -469,8 +450,8 @@ bool SkBlurMaskFilterImpl::filterMaskGPU(GrTexture* src,
void SkBlurMaskFilterImpl::toString(SkString* str) const {
str->append("SkBlurMaskFilterImpl: (");
str->append("radius: ");
str->appendScalar(fRadius);
str->append("sigma: ");
str->appendScalar(fSigma);
str->append(" ");
static const char* gStyleName[SkBlurMaskFilter::kBlurStyleCount] = {

Просмотреть файл

@ -26,6 +26,12 @@ static inline int pin2byte(int n) {
SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
SkScalar ambient, SkScalar specular,
SkScalar blurRadius) {
return SkBlurMaskFilter::CreateEmboss(SkBlurMask::ConvertRadiusToSigma(blurRadius),
direction, ambient, specular);
}
SkMaskFilter* SkBlurMaskFilter::CreateEmboss(SkScalar blurSigma, const SkScalar direction[3],
SkScalar ambient, SkScalar specular) {
if (direction == NULL) {
return NULL;
}
@ -42,7 +48,7 @@ SkMaskFilter* SkBlurMaskFilter::CreateEmboss(const SkScalar direction[3],
light.fAmbient = SkToU8(am);
light.fSpecular = SkToU8(sp);
return SkNEW_ARGS(SkEmbossMaskFilter, (light, blurRadius));
return SkNEW_ARGS(SkEmbossMaskFilter, (blurSigma, light));
}
///////////////////////////////////////////////////////////////////////////////
@ -56,27 +62,34 @@ static void normalize(SkScalar v[3]) {
}
}
SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
: fLight(light), fBlurRadius(blurRadius) {
SkEmbossMaskFilter::SkEmbossMaskFilter(SkScalar blurSigma, const Light& light)
: fBlurSigma(blurSigma), fLight(light) {
normalize(fLight.fDirection);
}
SkEmbossMaskFilter::SkEmbossMaskFilter(const Light& light, SkScalar blurRadius)
: fLight(light) {
normalize(fLight.fDirection);
fBlurSigma = SkBlurMask::ConvertRadiusToSigma(blurRadius);
}
SkMask::Format SkEmbossMaskFilter::getFormat() const {
return SkMask::k3D_Format;
}
bool SkEmbossMaskFilter::filterMask(SkMask* dst, const SkMask& src,
const SkMatrix& matrix, SkIPoint* margin) const {
SkScalar radius = matrix.mapRadius(fBlurRadius);
const SkMatrix& matrix, SkIPoint* margin) const {
SkScalar sigma = matrix.mapRadius(fBlurSigma);
if (!SkBlurMask::Blur(dst, src, radius, SkBlurMask::kInner_Style,
SkBlurMask::kLow_Quality)) {
if (!SkBlurMask::BoxBlur(dst, src, sigma, SkBlurMask::kInner_Style,
SkBlurMask::kLow_Quality)) {
return false;
}
dst->fFormat = SkMask::k3D_Format;
if (margin) {
margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
margin->set(SkScalarCeil(3*sigma), SkScalarCeil(3*sigma));
}
if (src.fImage == NULL) {
@ -121,7 +134,18 @@ SkEmbossMaskFilter::SkEmbossMaskFilter(SkFlattenableReadBuffer& buffer)
SkASSERT(buffer.getArrayCount() == sizeof(Light));
buffer.readByteArray(&fLight);
SkASSERT(fLight.fPad == 0); // for the font-cache lookup to be clean
fBlurRadius = buffer.readScalar();
fBlurSigma = buffer.readScalar();
#ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V13_AND_ALL_OTHER_INSTANCES_TOO
// Fixing this must be done in two stages. When the skps are recaptured in V13,
// remove the ConvertRadiusToSigma but retain the absolute value.
// At the same time, switch the code in flatten to write a positive value.
// When the skps are captured in V14 the absolute value can be removed.
if (fBlurSigma > 0) {
fBlurSigma = SkBlurMask::ConvertRadiusToSigma(fBlurSigma);
} else {
fBlurSigma = -fBlurSigma;
}
#endif
}
void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
@ -130,7 +154,7 @@ void SkEmbossMaskFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
Light tmpLight = fLight;
tmpLight.fPad = 0; // for the font-cache lookup to be clean
buffer.writeByteArray(&tmpLight, sizeof(tmpLight));
buffer.writeScalar(fBlurRadius);
buffer.writeScalar(-fBlurSigma);
}
#ifdef SK_DEVELOPER
@ -148,8 +172,8 @@ void SkEmbossMaskFilter::toString(SkString* str) const {
str->appendf("ambient: %d specular: %d ",
fLight.fAmbient, fLight.fSpecular);
str->append("blurRadius: ");
str->appendScalar(fBlurRadius);
str->append("blurSigma: ");
str->appendScalar(fBlurSigma);
str->append(")");
}
#endif