Bug 787947. Avoid scaling by 0 when snapping gradient tiles. r=jrmuizel
☠☠ backed out by 8af00f1609b9 ☠ ☠
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 25 Sep 2012 15:25:48 +1200
changeset 115535 a5c50066ecbb2f9f91c8a53a3d0ee198a3045f1e
parent 115534 ee9f796b8416072d1387a625ff07dd613c80b907
child 115536 a85c0f30cdfae5b2283516537b89374165b39810
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs787947
milestone18.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 787947. Avoid scaling by 0 when snapping gradient tiles. r=jrmuizel
layout/base/nsCSSRendering.cpp
layout/reftests/bugs/787947-1-ref.html
layout/reftests/bugs/787947-1.html
layout/reftests/bugs/reftest.list
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -2285,16 +2285,17 @@ nsCSSRendering::PaintGradient(nsPresCont
   // destination, but after pixel-snapping tiles may not all be the same size.
   nsRect dirty;
   if (!dirty.IntersectRect(aDirtyRect, aFillArea))
     return;
 
   gfxRect areaToFill =
     nsLayoutUtils::RectToGfxRect(aFillArea, appUnitsPerPixel);
   gfxMatrix ctm = ctx->CurrentMatrix();
+  bool isCTMPreservingAxisAlignedRectangles = ctm.PreservesAxisAlignedRectangles();
 
   // xStart/yStart are the top-left corner of the top-left tile.
   nscoord xStart = FindTileStart(dirty.x, aOneCellArea.x, aOneCellArea.width);
   nscoord yStart = FindTileStart(dirty.y, aOneCellArea.y, aOneCellArea.height);
   nscoord xEnd = pattern->mCoversTile ? xStart + aOneCellArea.width : dirty.XMost();
   nscoord yEnd = pattern->mCoversTile ? yStart + aOneCellArea.height : dirty.YMost();
 
   // x and y are the top-left corner of the tile to draw
@@ -2304,37 +2305,40 @@ nsCSSRendering::PaintGradient(nsPresCont
       gfxRect tileRect = nsLayoutUtils::RectToGfxRect(
                       nsRect(x, y, aOneCellArea.width, aOneCellArea.height),
                       appUnitsPerPixel);
       // The actual area to fill with this tile is the intersection of this
       // tile with the overall area we're supposed to be filling
       gfxRect fillRect =
         pattern->mCoversTile ? areaToFill : tileRect.Intersect(areaToFill);
       ctx->NewPath();
-      // If we can snap the gradient tile and fill rects, do so, but make sure
-      // that the gradient is scaled precisely to the tile rect.
-      gfxRect fillRectSnapped = fillRect;
-      // Don't snap the tileRect directly since that would lose information
-      // about the orientation of the current transform (i.e. vertical or
-      // horizontal flipping). Instead snap the corners independently so if
-      // the CTM has a flip, our Scale() below preserves the flip.
-      gfxPoint tileRectSnappedTopLeft = tileRect.TopLeft();
-      gfxPoint tileRectSnappedBottomRight = tileRect.BottomRight();
-      if (ctx->UserToDevicePixelSnapped(fillRectSnapped, true) &&
-          ctx->UserToDevicePixelSnapped(tileRectSnappedTopLeft, true) &&
-          ctx->UserToDevicePixelSnapped(tileRectSnappedBottomRight, true)) {
+      // Try snapping the fill rect. Snap its top-left and bottom-right
+      // independently to preserve the orientation.
+      gfxPoint snappedFillRectTopLeft = fillRect.TopLeft();
+      gfxPoint snappedFillRectBottomRight = fillRect.BottomRight();
+      if (isCTMPreservingAxisAlignedRectangles &&
+          ctx->UserToDevicePixelSnapped(snappedFillRectTopLeft, true) &&
+          ctx->UserToDevicePixelSnapped(snappedFillRectBottomRight, true)) {
+        if (snappedFillRectTopLeft.x == snappedFillRectBottomRight.x ||
+            snappedFillRectTopLeft.y == snappedFillRectBottomRight.y) {
+          // Nothing to draw; avoid scaling by zero and other weirdness that
+          // could put the context in an error state.
+          continue;
+        }
+        // Set the context's transform to the transform that maps fillRect to
+        // snappedFillRect. The part of the gradient that was going to
+        // exactly fill fillRect will fill snappedFillRect instead.
         ctx->IdentityMatrix();
-        ctx->Rectangle(fillRectSnapped);
-        ctx->Translate(tileRectSnappedTopLeft);
-        ctx->Scale((tileRectSnappedBottomRight.x - tileRectSnappedTopLeft.x)/tileRect.width,
-                   (tileRectSnappedBottomRight.y - tileRectSnappedTopLeft.y)/tileRect.height);
-      } else {
-        ctx->Rectangle(fillRect);
-        ctx->Translate(tileRect.TopLeft());
+        ctx->Translate(snappedFillRectTopLeft);
+        ctx->Scale((snappedFillRectBottomRight.x - snappedFillRectTopLeft.x)/fillRect.width,
+                   (snappedFillRectBottomRight.y - snappedFillRectTopLeft.y)/fillRect.height);
+        ctx->Translate(-fillRect.TopLeft());
       }
+      ctx->Rectangle(fillRect);
+      ctx->Translate(tileRect.TopLeft());
       ctx->SetPattern(pattern->mPattern);
       ctx->Fill();
       ctx->SetMatrix(ctm);
     }
   }
   // If we could not put the gradient in the gradient cache, make sure to
   // release its resources so we don't leak.
   if (!gradientRegistered) {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/787947-1-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE HTML>
+<body style="background:white;">
+<div style="position:absolute; left:10px; top:10px; width:100px; height:100px; border:1px solid black;"></div>
+<p style="position:absolute; left:10px; z-index:2">Hello
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/787947-1.html
@@ -0,0 +1,4 @@
+<!DOCTYPE HTML>
+<body style="background:white;">
+<div style="position:absolute; left:10px; top:10px; width:100px; height:100px; border:1px solid black; background-image:linear-gradient(30deg, white, rgba(255,255,255,0)); background-size:0.3px 100px;"></div>
+<p style="position:absolute; left:10px; z-index:2">Hello
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1714,8 +1714,9 @@ fuzzy-if(true,17,5859) == 759036-2.html 
 == 776265-1a.html 776265-1-ref.html
 == 776265-1b.html 776265-1-ref.html
 == 776265-1c.html 776265-1-ref.html
 == 776265-1d.html 776265-1-ref.html
 == 776265-2a.html 776265-2-ref.html
 == 776265-2b.html 776265-2-ref.html
 == 776265-2c.html 776265-2-ref.html
 == 776265-2d.html 776265-2-ref.html
+== 787947-1.html 787947-1-ref.html