Bug 629857 - When invalidating transformed items, round the original area out to the nearest pixel. r=roc a=roc
authorMatt Woodrow <mwoodrow@mozilla.com>
Fri, 25 Feb 2011 11:55:23 +1300
changeset 63072 8fdc73f3e1ea00eee9886a91063159f7f22c06eb
parent 63071 87e29a9b00965b1e5d44fdfedb0749d7c692e3b6
child 63073 285a09f4cc4915fad29e71df0bb1ccd566c91238
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, roc
bugs629857
milestone2.0b13pre
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 629857 - When invalidating transformed items, round the original area out to the nearest pixel. r=roc a=roc
gfx/src/nsCoord.h
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
--- a/gfx/src/nsCoord.h
+++ b/gfx/src/nsCoord.h
@@ -444,16 +444,21 @@ inline float NSAppUnitsToFloatPixels(nsc
   return (float(aAppUnits) / aAppUnitsPerPixel);
 }
 
 inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, nscoord aAppUnitsPerPixel)
 {
   return (double(aAppUnits) / double(aAppUnitsPerPixel));
 }
 
+inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
+{
+  return (double(aAppUnits) / aAppUnitsPerPixel);
+}
+
 inline PRInt32 NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
 {
   return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
 }
 
 inline float NSCoordScale(nscoord aCoord, PRInt32 aFromAPP, PRInt32 aToAPP)
 {
   return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2401,16 +2401,32 @@ nsRect nsDisplayTransform::TransformRect
 
   float factor = nsPresContext::AppUnitsPerCSSPixel();
   return nsLayoutUtils::MatrixTransformRect
     (aUntransformedBounds,
      GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
      factor);
 }
 
+nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds,
+                                            const nsIFrame* aFrame,
+                                            const nsPoint &aOrigin,
+                                            const nsRect* aBoundsOverride)
+{
+  NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
+  NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
+                  "Cannot transform a rectangle if there's no transformation!");
+
+  float factor = nsPresContext::AppUnitsPerCSSPixel();
+  return nsLayoutUtils::MatrixTransformRectOut
+    (aUntransformedBounds,
+     GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
+     factor);
+}
+
 nsRect nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
                                            const nsIFrame* aFrame,
                                            const nsPoint &aOrigin)
 {
   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
   NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
                   "Cannot transform a rectangle if there's no transformation!");
 
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -2044,16 +2044,21 @@ public:
    *        bounding rect as frame bounds, use this rectangle instead.  Pass
    *        nsnull (or nothing at all) to use the default.
    */
   static nsRect TransformRect(const nsRect &aUntransformedBounds, 
                               const nsIFrame* aFrame,
                               const nsPoint &aOrigin,
                               const nsRect* aBoundsOverride = nsnull);
 
+  static nsRect TransformRectOut(const nsRect &aUntransformedBounds, 
+                                 const nsIFrame* aFrame,
+                                 const nsPoint &aOrigin,
+                                 const nsRect* aBoundsOverride = nsnull);
+
   /* UntransformRect is like TransformRect, except that it inverts the
    * transform.
    */
   static nsRect UntransformRect(const nsRect &aUntransformedBounds, 
                                 const nsIFrame* aFrame,
                                 const nsPoint &aOrigin);
 
   /**
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1005,23 +1005,36 @@ nsLayoutUtils::RoundedRectIntersectRect(
   r2.IntersectRect(rectFullWidth, aContainedRect);
 
   nsRegion result;
   result.Or(r1, r2);
   return result;
 }
 
 nsRect
+nsLayoutUtils::MatrixTransformRectOut(const nsRect &aBounds,
+                                      const gfxMatrix &aMatrix, float aFactor)
+{
+  nsRect outside = aBounds;
+  outside.ScaleRoundOut(1/aFactor);
+  gfxRect image = aMatrix.TransformBounds(gfxRect(outside.x,
+                                                  outside.y,
+                                                  outside.width,
+                                                  outside.height));
+  return RoundGfxRectToAppRect(image, aFactor);
+}
+
+nsRect
 nsLayoutUtils::MatrixTransformRect(const nsRect &aBounds,
                                    const gfxMatrix &aMatrix, float aFactor)
 {
-  gfxRect image = aMatrix.TransformBounds(gfxRect(NSAppUnitsToFloatPixels(aBounds.x, aFactor),
-                                                  NSAppUnitsToFloatPixels(aBounds.y, aFactor),
-                                                  NSAppUnitsToFloatPixels(aBounds.width, aFactor),
-                                                  NSAppUnitsToFloatPixels(aBounds.height, aFactor)));
+  gfxRect image = aMatrix.TransformBounds(gfxRect(NSAppUnitsToDoublePixels(aBounds.x, aFactor),
+                                                  NSAppUnitsToDoublePixels(aBounds.y, aFactor),
+                                                  NSAppUnitsToDoublePixels(aBounds.width, aFactor),
+                                                  NSAppUnitsToDoublePixels(aBounds.height, aFactor)));
 
   return RoundGfxRectToAppRect(image, aFactor);
 }
 
 nsPoint
 nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
                                     const gfxMatrix &aMatrix, float aFactor)
 {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -517,16 +517,28 @@ public:
    * @param aMatrix The matrix to transform it with.
    * @param aFactor The number of app units per graphics unit.
    * @return The smallest rect that contains the image of aBounds.
    */
   static nsRect MatrixTransformRect(const nsRect &aBounds,
                                     const gfxMatrix &aMatrix, float aFactor);
 
   /**
+   * Helper function that, given a rectangle and a matrix, returns the smallest
+   * rectangle containing the image of the source rectangle rounded out to the nearest
+   * pixel value.
+   *
+   * @param aBounds The rectangle to transform.
+   * @param aMatrix The matrix to transform it with.
+   * @param aFactor The number of app units per graphics unit.
+   * @return The smallest rect that contains the image of aBounds.
+   */
+  static nsRect MatrixTransformRectOut(const nsRect &aBounds,
+                                    const gfxMatrix &aMatrix, float aFactor);
+  /**
    * Helper function that, given a point and a matrix, returns the image
    * of that point under the matrix transform.
    *
    * @param aPoint The point to transform.
    * @param aMatrix The matrix to transform it with.
    * @param aFactor The number of app units per graphics unit.
    * @return The image of the point under the transform.
    */
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4127,17 +4127,17 @@ nsIFrame::InvalidateInternalAfterResize(
     // Don't need to invalidate any more Thebes layers
     aFlags |= INVALIDATE_NO_THEBES_LAYERS;
     if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
       return;
     }
   }
   if (IsTransformed()) {
     nsRect newDamageRect;
-    newDamageRect.UnionRect(nsDisplayTransform::TransformRect
+    newDamageRect.UnionRect(nsDisplayTransform::TransformRectOut
                             (aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
     GetParent()->
       InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
                          aFlags);
   }
   else 
     GetParent()->
       InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);