diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 5247b399d76..504a1cdea12 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -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 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 diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 7e67323eeb9..0d4f68bab47 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -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); /** diff --git a/layout/reftests/backgrounds/reftest.list b/layout/reftests/backgrounds/reftest.list index 5d6d5a8b33c..decd63b2aa5 100644 --- a/layout/reftests/backgrounds/reftest.list +++ b/layout/reftests/backgrounds/reftest.list @@ -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 diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index 06ca0001adc..49ea538204c 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -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);