Reduce size of filter mask.
http://codereview.appspot.com/4965057/ Reduce the size of filter masks, fix HQ blur when clipped, and add tests. git-svn-id: http://skia.googlecode.com/svn/trunk@2211 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
abb061acfe
commit
5af16f8d67
@ -2441,9 +2441,6 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
|
||||
return false;
|
||||
}
|
||||
|
||||
SkIPoint margin;
|
||||
margin.set(0, 0);
|
||||
|
||||
// init our bounds from the path
|
||||
{
|
||||
SkRect pathBounds = devPath.getBounds();
|
||||
@ -2451,10 +2448,11 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
|
||||
pathBounds.roundOut(bounds);
|
||||
}
|
||||
|
||||
SkIPoint margin;
|
||||
if (filter) {
|
||||
SkASSERT(filterMatrix);
|
||||
|
||||
SkMask srcM, dstM;
|
||||
SkMask srcM, dstM;
|
||||
|
||||
srcM.fBounds = *bounds;
|
||||
srcM.fFormat = SkMask::kA8_Format;
|
||||
@ -2462,18 +2460,12 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
|
||||
if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
|
||||
return false;
|
||||
}
|
||||
*bounds = dstM.fBounds;
|
||||
}
|
||||
|
||||
if (clipBounds && !SkIRect::Intersects(*clipBounds, *bounds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// (possibly) trim the srcM bounds to reflect the clip
|
||||
// (possibly) trim the bounds to reflect the clip
|
||||
// (plus whatever slop the filter needs)
|
||||
if (clipBounds && !clipBounds->contains(*bounds)) {
|
||||
SkIRect tmp = *bounds;
|
||||
(void)tmp.intersect(*clipBounds);
|
||||
if (clipBounds) {
|
||||
SkIRect tmp = *clipBounds;
|
||||
// Ugh. Guard against gigantic margins from wacky filters. Without this
|
||||
// check we can request arbitrary amounts of slop beyond our visible
|
||||
// clip, and bring down the renderer (at least on finite RAM machines
|
||||
@ -2483,7 +2475,9 @@ static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
|
||||
static const int MAX_MARGIN = 128;
|
||||
tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
|
||||
-SkMin32(margin.fY, MAX_MARGIN));
|
||||
(void)bounds->intersect(tmp);
|
||||
if (!bounds->intersect(tmp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -222,7 +222,9 @@ void SkMask_FreeImage(uint8_t* image) {
|
||||
}
|
||||
|
||||
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality) {
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin)
|
||||
{
|
||||
if (src.fFormat != SkMask::kA8_Format) {
|
||||
return false;
|
||||
}
|
||||
@ -247,6 +249,9 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
|
||||
int padx = passCount * rx;
|
||||
int pady = passCount * ry;
|
||||
if (margin) {
|
||||
margin->set(padx, pady);
|
||||
}
|
||||
dst->fBounds.set(src.fBounds.fLeft - padx, src.fBounds.fTop - pady,
|
||||
src.fBounds.fRight + padx, src.fBounds.fBottom + pady);
|
||||
dst->fRowBytes = dst->fBounds.width();
|
||||
|
@ -28,7 +28,9 @@ public:
|
||||
kHigh_Quality //!< three pass box blur (similar to gaussian)
|
||||
};
|
||||
|
||||
static bool Blur(SkMask* dst, const SkMask& src, SkScalar radius, Style, Quality quality);
|
||||
static bool Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin = NULL);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -93,16 +93,8 @@ bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
|
||||
(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
|
||||
SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
|
||||
|
||||
if (SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
|
||||
blurQuality)) {
|
||||
if (margin) {
|
||||
// we need to integralize radius for our margin, so take the ceil
|
||||
// just to be safe.
|
||||
margin->set(SkScalarCeil(radius), SkScalarCeil(radius));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return SkBlurMask::Blur(dst, src, radius, (SkBlurMask::Style)fBlurStyle,
|
||||
blurQuality, margin);
|
||||
}
|
||||
|
||||
SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkFlattenableReadBuffer& buffer) {
|
||||
|
@ -7,34 +7,151 @@
|
||||
*/
|
||||
#include "Test.h"
|
||||
#include "SkBlurMaskFilter.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkRandom.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define ILLEGAL_MODE ((SkXfermode::Mode)-1)
|
||||
|
||||
static const int outset = 100;
|
||||
static const SkColor bgColor = SK_ColorWHITE;
|
||||
static const int strokeWidth = 4;
|
||||
|
||||
static void create(SkBitmap* bm, SkIRect bound, SkBitmap::Config config) {
|
||||
bm->setConfig(config, bound.width(), bound.height());
|
||||
bm->allocPixels();
|
||||
}
|
||||
|
||||
static void drawBG(SkCanvas* canvas) {
|
||||
canvas->drawColor(bgColor);
|
||||
}
|
||||
|
||||
|
||||
struct BlurTest {
|
||||
void (*addPath)(SkPath*);
|
||||
int viewLen;
|
||||
SkIRect views[9];
|
||||
};
|
||||
|
||||
//Path Draw Procs
|
||||
//Beware that paths themselves my draw differently depending on the clip.
|
||||
static void draw50x50Rect(SkPath* path) {
|
||||
path->addRect(0, 0, SkIntToScalar(50), SkIntToScalar(50));
|
||||
}
|
||||
|
||||
//Tests
|
||||
static BlurTest tests[] = {
|
||||
{ draw50x50Rect, 3, {
|
||||
//inner half of blur
|
||||
{ 0, 0, 50, 50 },
|
||||
//blur, but no path.
|
||||
{ 50 + strokeWidth/2, 50 + strokeWidth/2, 100, 100 },
|
||||
//just an edge
|
||||
{ 40, strokeWidth, 60, 50 - strokeWidth },
|
||||
}},
|
||||
};
|
||||
|
||||
/** Assumes that the ref draw was completely inside ref canvas --
|
||||
implies that everything outside is "bgColor".
|
||||
Checks that all overlap is the same and that all non-overlap on the
|
||||
ref is "bgColor".
|
||||
*/
|
||||
static bool compare(const SkBitmap& ref, const SkIRect& iref,
|
||||
const SkBitmap& test, const SkIRect& itest)
|
||||
{
|
||||
const int xOff = itest.fLeft - iref.fLeft;
|
||||
const int yOff = itest.fTop - iref.fTop;
|
||||
|
||||
SkAutoLockPixels alpRef(ref);
|
||||
SkAutoLockPixels alpTest(test);
|
||||
|
||||
for (int y = 0; y < test.height(); ++y) {
|
||||
for (int x = 0; x < test.width(); ++x) {
|
||||
SkColor testColor = test.getColor(x, y);
|
||||
int refX = x + xOff;
|
||||
int refY = y + yOff;
|
||||
SkColor refColor;
|
||||
if (refX >= 0 && refX < ref.width() &&
|
||||
refY >= 0 && refY < ref.height())
|
||||
{
|
||||
refColor = ref.getColor(refX, refY);
|
||||
} else {
|
||||
refColor = bgColor;
|
||||
}
|
||||
if (refColor != testColor) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_blur(skiatest::Reporter* reporter) {
|
||||
SkScalar radius = SkIntToScalar(2);
|
||||
|
||||
for (int i = 0; i < SkBlurMaskFilter::kBlurStyleCount; ++i) {
|
||||
SkMaskFilter* filter;
|
||||
SkMaskFilter::BlurInfo info;
|
||||
SkPaint paint;
|
||||
paint.setColor(SK_ColorGRAY);
|
||||
paint.setStyle(SkPaint::kStroke_Style);
|
||||
paint.setStrokeWidth(SkIntToScalar(strokeWidth));
|
||||
|
||||
uint32_t flags = i & 3;
|
||||
SkScalar radius = SkIntToScalar(5);
|
||||
for (int style = 0; style < SkBlurMaskFilter::kBlurStyleCount; ++style) {
|
||||
SkBlurMaskFilter::BlurStyle blurStyle =
|
||||
static_cast<SkBlurMaskFilter::BlurStyle>(style);
|
||||
|
||||
filter = SkBlurMaskFilter::Create(radius, (SkBlurMaskFilter::BlurStyle)i,
|
||||
flags);
|
||||
const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag;
|
||||
for (uint32_t flags = 0; flags < flagPermutations; ++flags) {
|
||||
SkMaskFilter* filter;
|
||||
filter = SkBlurMaskFilter::Create(radius, blurStyle, flags);
|
||||
|
||||
sk_bzero(&info, sizeof(info));
|
||||
SkMaskFilter::BlurType type = filter->asABlur(&info);
|
||||
REPORTER_ASSERT(reporter, type == (SkMaskFilter::BlurType)(i + 1));
|
||||
REPORTER_ASSERT(reporter, info.fRadius == radius);
|
||||
REPORTER_ASSERT(reporter, info.fIgnoreTransform ==
|
||||
SkToBool(flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag));
|
||||
REPORTER_ASSERT(reporter, info.fHighQuality ==
|
||||
SkToBool(flags & SkBlurMaskFilter::kHighQuality_BlurFlag));
|
||||
SkMaskFilter::BlurInfo info;
|
||||
sk_bzero(&info, sizeof(info));
|
||||
SkMaskFilter::BlurType type = filter->asABlur(&info);
|
||||
|
||||
filter->unref();
|
||||
REPORTER_ASSERT(reporter, type ==
|
||||
static_cast<SkMaskFilter::BlurType>(style + 1));
|
||||
REPORTER_ASSERT(reporter, info.fRadius == radius);
|
||||
REPORTER_ASSERT(reporter, info.fIgnoreTransform ==
|
||||
SkToBool(flags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag));
|
||||
REPORTER_ASSERT(reporter, info.fHighQuality ==
|
||||
SkToBool(flags & SkBlurMaskFilter::kHighQuality_BlurFlag));
|
||||
|
||||
paint.setMaskFilter(filter);
|
||||
filter->unref();
|
||||
|
||||
for (int test = 0; test < SK_ARRAY_COUNT(tests); ++test) {
|
||||
SkPath path;
|
||||
tests[test].addPath(&path);
|
||||
SkRect refBound = path.getBounds();
|
||||
refBound.outset(outset, outset);
|
||||
SkIRect iref;
|
||||
refBound.roundOut(&iref);
|
||||
SkBitmap refBitmap;
|
||||
create(&refBitmap, iref, SkBitmap::kARGB_8888_Config);
|
||||
|
||||
SkCanvas refCanvas(refBitmap);
|
||||
refCanvas.translate(SkIntToScalar(-iref.fLeft),
|
||||
SkIntToScalar(-iref.fTop));
|
||||
drawBG(&refCanvas);
|
||||
refCanvas.drawPath(path, paint);
|
||||
|
||||
for (int view = 0; view < tests[test].viewLen; ++view) {
|
||||
SkIRect itest = tests[test].views[view];
|
||||
SkBitmap testBitmap;
|
||||
create(&testBitmap, itest, SkBitmap::kARGB_8888_Config);
|
||||
|
||||
SkCanvas testCanvas(testBitmap);
|
||||
testCanvas.translate(SkIntToScalar(-itest.fLeft),
|
||||
SkIntToScalar(-itest.fTop));
|
||||
drawBG(&testCanvas);
|
||||
testCanvas.drawPath(path, paint);
|
||||
|
||||
REPORTER_ASSERT(reporter,
|
||||
compare(refBitmap, iref, testBitmap, itest));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,11 +104,20 @@ private:
|
||||
|
||||
int main (int argc, char * const argv[]) {
|
||||
SkAutoGraphics ag;
|
||||
|
||||
|
||||
bool androidMode = false;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-android")) {
|
||||
const char* matchStr = NULL;
|
||||
|
||||
char* const* stop = argv + argc;
|
||||
for (++argv; argv < stop; ++argv) {
|
||||
if (strcmp(*argv, "-android") == 0) {
|
||||
androidMode = true;
|
||||
|
||||
} else if (strcmp(*argv, "--match") == 0) {
|
||||
++argv;
|
||||
if (argv < stop && **argv) {
|
||||
matchStr = *argv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,17 +127,24 @@ int main (int argc, char * const argv[]) {
|
||||
|
||||
const int count = Iter::Count();
|
||||
int index = 0;
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
int skipCount = 0;
|
||||
while ((test = iter.next()) != NULL) {
|
||||
reporter.setIndexOfTotal(index, count);
|
||||
successCount += test->run();
|
||||
if (NULL != matchStr && !strstr(test->getName(), matchStr)) {
|
||||
++skipCount;
|
||||
} else {
|
||||
if (!test->run()) {
|
||||
++failCount;
|
||||
}
|
||||
}
|
||||
SkDELETE(test);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
if (!androidMode) {
|
||||
SkDebugf("Finished %d tests, %d failures.\n", count,
|
||||
count - successCount);
|
||||
SkDebugf("Finished %d tests, %d failures, %d skipped.\n",
|
||||
count, failCount, skipCount);
|
||||
}
|
||||
return (count == successCount) ? 0 : 1;
|
||||
return (failCount == 0) ? 0 : 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user