Bug 671302 - Avoid passing large offsets into pixman when drawing repeated background images. r=roc
authorMarkus Stange <mstange@themasta.com>
Fri, 18 Jul 2014 11:48:38 +0200
changeset 216782 0a865eaa597cc1da5d473a417ce8142c73ba5615
parent 216781 3a0e9a83d8c590686ec865b248c903fd009a2f2d
child 216783 c1ddceb19abc60b28624e6efe7099e6715456de9
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs671302
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 671302 - Avoid passing large offsets into pixman when drawing repeated background images. r=roc
gfx/thebes/gfxUtils.cpp
layout/base/nsLayoutUtils.cpp
layout/reftests/backgrounds/background-repeat-large-area-ref.html
layout/reftests/backgrounds/background-repeat-large-area.html
layout/reftests/backgrounds/reftest.list
layout/reftests/image-element/reftest.list
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -602,27 +602,17 @@ gfxUtils::DrawPixelSnapped(gfxContext*  
 
     aFilter = ReduceResamplingFilter(aFilter, aImageRect.Width(), aImageRect.Height(), aSourceRect.Width(), aSourceRect.Height());
 
     gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
 
     // On Mobile, we don't ever want to do this; it has the potential for
     // allocating very large temporary surfaces, especially since we'll
     // do full-page snapshots often (see bug 749426).
-#ifdef MOZ_GFX_OPTIMIZE_MOBILE
-    // If the pattern translation is large we can get into trouble with pixman's
-    // 16 bit coordinate limits. For now, we only do this on platforms where
-    // we know we have the pixman limits. 16384.0 is a somewhat arbitrary
-    // large number to make sure we avoid the expensive fmod when we can, but
-    // still maintain a safe margin from the actual limit
-    if (doTile && (userSpaceToImageSpace._32 > 16384.0 || userSpaceToImageSpace._31 > 16384.0)) {
-        userSpaceToImageSpace._31 = fmod(userSpaceToImageSpace._31, aImageRect.width);
-        userSpaceToImageSpace._32 = fmod(userSpaceToImageSpace._32, aImageRect.height);
-    }
-#else
+#ifndef MOZ_GFX_OPTIMIZE_MOBILE
     // 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
     // nothing to do.
     // XXX if only we had source-clipping in cairo!
     if (aContext->CurrentMatrix().HasNonIntegerTranslation() ||
         aUserSpaceToImageSpace.HasNonIntegerTranslation()) {
         if (doTile || !aSubimage.Contains(aImageRect)) {
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -4904,16 +4904,24 @@ struct SnappedImageDrawingParameters {
    : mUserSpaceToImageSpace(aUserSpaceToImageSpace)
    , mFillRect(aFillRect)
    , mSubimage(aSubimage)
    , mShouldDraw(true)
    , mResetCTM(aResetCTM)
   {}
 };
 
+static nsRect
+TileNearRect(const nsRect& aAnyTile, const nsRect& aTargetRect)
+{
+  nsPoint distance = aTargetRect.TopLeft() - aAnyTile.TopLeft();
+  return aAnyTile + nsPoint(distance.x / aAnyTile.width * aAnyTile.width,
+                            distance.y / aAnyTile.height * aAnyTile.height);
+}
+
 /**
  * Given a set of input parameters, compute certain output parameters
  * for drawing an image with the image snapping algorithm.
  * See https://wiki.mozilla.org/Gecko:Image_Snapping_and_Rendering
  *
  *  @see nsLayoutUtils::DrawImage() for the descriptions of input parameters
  */
 static SnappedImageDrawingParameters
@@ -4924,18 +4932,23 @@ ComputeSnappedImageDrawingParameters(gfx
                                      const nsPoint   aAnchor,
                                      const nsRect    aDirty,
                                      const nsIntSize aImageSize)
 
 {
   if (aDest.IsEmpty() || aFill.IsEmpty() || !aImageSize.width || !aImageSize.height)
     return SnappedImageDrawingParameters();
 
+  // Avoid unnecessarily large offsets.
+  bool doTile = !aDest.Contains(aFill);
+  nsRect dest = doTile ? TileNearRect(aDest, aFill.Intersect(aDirty)) : aDest;
+  nsPoint anchor = aAnchor + (dest.TopLeft() - aDest.TopLeft());
+
   gfxRect devPixelDest =
-    nsLayoutUtils::RectToGfxRect(aDest, aAppUnitsPerDevPixel);
+    nsLayoutUtils::RectToGfxRect(dest, aAppUnitsPerDevPixel);
   gfxRect devPixelFill =
     nsLayoutUtils::RectToGfxRect(aFill, aAppUnitsPerDevPixel);
   gfxRect devPixelDirty =
     nsLayoutUtils::RectToGfxRect(aDirty, aAppUnitsPerDevPixel);
 
   gfxMatrix currentMatrix = aCtx->CurrentMatrix();
   gfxRect fill = devPixelFill;
   bool didSnap;
@@ -4965,18 +4978,18 @@ ComputeSnappedImageDrawingParameters(gfx
   intSubimage.MoveTo(NSToIntFloor(subimageTopLeft.x),
                      NSToIntFloor(subimageTopLeft.y));
   intSubimage.SizeTo(NSToIntCeil(subimageBottomRight.x) - intSubimage.x,
                      NSToIntCeil(subimageBottomRight.y) - intSubimage.y);
 
   // Compute the anchor point and compute final fill rect.
   // This code assumes that pixel-based devices have one pixel per
   // device unit!
-  gfxPoint anchorPoint(gfxFloat(aAnchor.x)/aAppUnitsPerDevPixel,
-                       gfxFloat(aAnchor.y)/aAppUnitsPerDevPixel);
+  gfxPoint anchorPoint(gfxFloat(anchor.x)/aAppUnitsPerDevPixel,
+                       gfxFloat(anchor.y)/aAppUnitsPerDevPixel);
   gfxPoint imageSpaceAnchorPoint =
     MapToFloatImagePixels(imageSize, devPixelDest, anchorPoint);
 
   if (didSnap) {
     imageSpaceAnchorPoint.Round();
     anchorPoint = imageSpaceAnchorPoint;
     anchorPoint = MapToFloatUserPixels(imageSize, devPixelDest, anchorPoint);
     anchorPoint = currentMatrix.Transform(anchorPoint);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-repeat-large-area-ref.html
@@ -0,0 +1,17 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<title>Make sure that repeated background images are painted even at extreme scroll positions</title>
+
+<style>
+
+html {
+  background-image: url(green-8x20-blue-8x20-vertical.png);
+  overflow: hidden;
+}
+
+</style>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/background-repeat-large-area.html
@@ -0,0 +1,42 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html lang="en" class="reftest-wait">
+<meta charset="utf-8">
+<title>Make sure that repeated background images are painted even at extreme scroll positions</title>
+<!-- See https://bugzilla.mozilla.org/show_bug.cgi?id=671302 -->
+
+<style>
+
+html {
+  background-image: url(green-8x20-blue-8x20-vertical.png);
+  overflow: hidden;
+}
+
+html, body {
+  margin: 0;
+}
+
+body {
+  height: 100000px;
+}
+
+div {
+  height: 1000px;
+  background-color: red;
+}
+
+</style>
+
+<div></div>
+
+<script>
+
+window.addEventListener("MozReftestInvalidate", function () {
+  document.documentElement.scrollTop = 16 * 3000; // = 48000 > 32768
+  document.documentElement.removeAttribute("class");
+});
+
+</script>
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -155,8 +155,9 @@ fails-if(Android&&AndroidVersion==15) fu
 == attachment-local-clipping-image-1.html attachment-local-clipping-image-1-ref.html
 == attachment-local-clipping-image-2.html attachment-local-clipping-image-1-ref.html  # Same ref as the previous test.
 == attachment-local-clipping-image-3.html attachment-local-clipping-image-3-ref.html
 fails-if(Android&&AndroidVersion==15) == attachment-local-clipping-image-4.html attachment-local-clipping-image-4-ref.html #Bug 959165
 fails-if(Android&&AndroidVersion==15) == attachment-local-clipping-image-5.html attachment-local-clipping-image-4-ref.html  # Same ref as the previous test. #Bug 959165
 fails-if(Android&&AndroidVersion==15) fuzzy-if(!Android||(Android&&AndroidVersion!=15),80,500) == attachment-local-clipping-image-6.html attachment-local-clipping-image-6-ref.html #Bug 959165
 
 == background-multiple-with-border-radius.html background-multiple-with-border-radius-ref.html
+== background-repeat-large-area.html background-repeat-large-area-ref.html
--- a/layout/reftests/image-element/reftest.list
+++ b/layout/reftests/image-element/reftest.list
@@ -19,17 +19,17 @@ random-if(d2d) == element-paint-transfor
 fuzzy-if(d2d,255,24) == element-paint-transform-03.html element-paint-transform-03-ref.html
 fuzzy-if(B2G,1,5) fuzzy-if(gtk2Widget,1,32) fuzzy-if(cocoaWidget,1,106) == element-paint-native-widget.html element-paint-native-widget-ref.html
 == element-paint-subimage-sampling-restriction.html about:blank
 == element-paint-clippath.html element-paint-clippath-ref.html
 == element-paint-sharpness-01a.html element-paint-sharpness-01b.html
 == element-paint-sharpness-01b.html element-paint-sharpness-01c.html
 == element-paint-sharpness-01c.html element-paint-sharpness-01d.html
 == element-paint-sharpness-02a.html element-paint-sharpness-02b.html
-== element-paint-sharpness-02b.html element-paint-sharpness-02c.html
+fuzzy-if(B2G,11,4) == element-paint-sharpness-02b.html element-paint-sharpness-02c.html
 == element-paint-paintserversize-rounding-01.html element-paint-paintserversize-rounding-01-ref.html
 == element-paint-paintserversize-rounding-02.html element-paint-paintserversize-rounding-02-ref.html
 == element-paint-multiple-backgrounds-01a.html element-paint-multiple-backgrounds-01-ref.html
 skip-if(B2G) == element-paint-multiple-backgrounds-01b.html element-paint-multiple-backgrounds-01-ref.html # bug 773482
 skip-if(B2G) == element-paint-multiple-backgrounds-01c.html element-paint-multiple-backgrounds-01-ref.html # bug 773482
 == gradient-html-01.html gradient-html-01-ref.svg
 == gradient-html-02.html gradient-html-02-ref.svg
 random-if(!cocoaWidget) == gradient-html-03.html gradient-html-03-ref.svg