Bug 750598. Add some heuristics to catch cases when we can use nearest filtering. r=roc

These may need some tuning to get right, but should be an improvement over
just disabling bilinear for backgrounds.

It also expectedly regresses tcheckerboard & tcheck2 because we're now
using bilinear when we were using nearest before.
This commit is contained in:
Jeff Muizelaar 2012-05-01 16:35:04 -04:00
parent 660eafb09e
commit 21d2256bed
4 changed files with 72 additions and 8 deletions

View File

@ -414,6 +414,73 @@ DeviceToImageTransform(gfxContext* aContext,
return gfxMatrix(deviceToUser).Multiply(aUserSpaceToImageSpace);
}
/* These heuristics are based on Source/WebCore/platform/graphics/skia/ImageSkia.cpp:computeResamplingMode() */
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
static gfxPattern::GraphicsFilter ReduceResamplingFilter(gfxPattern::GraphicsFilter aFilter,
int aImgWidth, int aImgHeight,
float aSourceWidth, float aSourceHeight)
{
// Images smaller than this in either direction are considered "small" and
// are not resampled ever (see below).
const int kSmallImageSizeThreshold = 8;
// The amount an image can be stretched in a single direction before we
// say that it is being stretched so much that it must be a line or
// background that doesn't need resampling.
const float kLargeStretch = 3.0f;
if (aImgWidth <= kSmallImageSizeThreshold
|| aImgHeight <= kSmallImageSizeThreshold) {
// Never resample small images. These are often used for borders and
// rules (think 1x1 images used to make lines).
return gfxPattern::FILTER_NEAREST;
}
if (aImgHeight * kLargeStretch <= aSourceHeight || aImgWidth * kLargeStretch <= aSourceWidth) {
// Large image tiling detected.
// Don't resample if it is being tiled a lot in only one direction.
// This is trying to catch cases where somebody has created a border
// (which might be large) and then is stretching it to fill some part
// of the page.
if (fabs(aSourceWidth - aImgWidth)/aImgWidth < 0.5 || fabs(aSourceHeight - aImgHeight)/aImgHeight < 0.5)
return gfxPattern::FILTER_NEAREST;
// The image is growing a lot and in more than one direction. Resampling
// is slow and doesn't give us very much when growing a lot.
return aFilter;
}
/* Some notes on other heuristics:
The Skia backend also uses nearest for backgrounds that are stretched by
a large amount. I'm not sure this is common enough for us to worry about
now. It also uses nearest for backgrounds/avoids high quality for images
that are very slightly scaled. I'm also not sure that very slightly
scaled backgrounds are common enough us to worry about.
We don't currently have much support for doing high quality interpolation.
The only place this currently happens is on Quartz and we don't have as
much control over it as would be needed. Webkit avoids using high quality
resampling during load. It also avoids high quality if the transformation
is not just a scale and translation
WebKit bug #40045 added code to avoid resampling different parts
of an image with different methods by using a resampling hint size.
It currently looks unused in WebKit but it's something to watch out for.
*/
return aFilter;
}
#else
static gfxPattern::GraphicsFilter ReduceResamplingFilter(gfxPattern::GraphicsFilter aFilter,
int aImgWidth, int aImgHeight,
int aSourceWidth, int aSourceHeight)
{
// Just pass the filter through unchanged
return aFilter;
}
#endif
/* static */ void
gfxUtils::DrawPixelSnapped(gfxContext* aContext,
gfxDrawable* aDrawable,
@ -423,7 +490,7 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
const gfxRect& aImageRect,
const gfxRect& aFill,
const gfxImageSurface::gfxImageFormat aFormat,
const gfxPattern::GraphicsFilter& aFilter,
gfxPattern::GraphicsFilter aFilter,
PRUint32 aImageFlags)
{
SAMPLE_LABEL("gfxUtils", "DrawPixelSnapped");
@ -441,6 +508,8 @@ gfxUtils::DrawPixelSnapped(gfxContext* aContext,
nsRefPtr<gfxDrawable> drawable = aDrawable;
aFilter = ReduceResamplingFilter(aFilter, aImageRect.Width(), aImageRect.Height(), aSourceRect.Width(), aSourceRect.Height());
// OK now, the hard part left is to account for the subimage sampling
// restriction. If all the transforms involved are just integer
// translations, then we assume no resampling will occur so there's

View File

@ -90,7 +90,7 @@ public:
const gfxRect& aImageRect,
const gfxRect& aFill,
const gfxImageSurface::gfxImageFormat aFormat,
const gfxPattern::GraphicsFilter& aFilter,
gfxPattern::GraphicsFilter aFilter,
PRUint32 aImageFlags = imgIContainer::FLAG_NONE);
/**

View File

@ -117,8 +117,7 @@ fails-if(Android) == viewport-translucent-color-3.html viewport-translucent-colo
# the image aren't the issue, because they're being obscured to avoid sampling
# algorithm dependencies (at least assuming the sampling algorithm in use
# doesn't sample too far astray from the boundaries).
# Android uses FILTER_NEAREST which doesn't suffer from this issue.
fails-if(!Android) == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
fails == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
# -moz-default-background-color and -moz-default-color (bug 591341)
== background-moz-default-background-color.html background-moz-default-background-color-ref.html

View File

@ -215,11 +215,7 @@ pref("gfx.downloadable_fonts.enabled", true);
pref("gfx.downloadable_fonts.fallback_delay", 3000);
pref("gfx.downloadable_fonts.sanitize", true);
#ifdef ANDROID
pref("gfx.filter.nearest.force-enabled", true);
#else
pref("gfx.filter.nearest.force-enabled", false);
#endif
// whether to always search all font cmaps during system font fallback
pref("gfx.font_rendering.fallback.always_use_cmaps", false);