Bug 637852. Part 21: Skip invalidation if aRegionToInvalidateIsEmpty (note that ScaleRoundOut on an empty bounds rect can return a non-empty rect). r=tnikkel
authorRobert O'Callahan <robert@ocallahan.org>
Thu, 23 Jun 2011 00:11:28 +1200
changeset 71810 3d7fda340878b309996c11c7cc0c94f1ac7b11aa
parent 71809 c9f644aa2fa58dba7e98639e2df87742be54c222
child 71811 6256bcafbdf27f4b8826f13deb082f76aaf3c14c
push id209
push userbzbarsky@mozilla.com
push dateTue, 05 Jul 2011 17:42:16 +0000
treeherdermozilla-aurora@cc6e30cce8af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs637852
milestone7.0a1
Bug 637852. Part 21: Skip invalidation if aRegionToInvalidateIsEmpty (note that ScaleRoundOut on an empty bounds rect can return a non-empty rect). r=tnikkel
gfx/src/BaseRect.h
gfx/src/nsRect.h
layout/base/FrameLayerBuilder.cpp
--- a/gfx/src/BaseRect.h
+++ b/gfx/src/BaseRect.h
@@ -290,37 +290,54 @@ struct BaseRect {
   T Y() const { return y; }
   T Width() const { return width; }
   T Height() const { return height; }
   T XMost() const { return x + width; }
   T YMost() const { return y + height; }
 
   // Scale 'this' by aScale, converting coordinates to integers so that the result is
   // the smallest integer-coordinate rectangle containing the unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
+  // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
+  // that the result is the smallest integer-coordinate rectangle containing the
+  // unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   void ScaleRoundOut(double aXScale, double aYScale)
   {
     T right = static_cast<T>(NS_ceil(double(XMost()) * aXScale));
     T bottom = static_cast<T>(NS_ceil(double(YMost()) * aYScale));
     x = static_cast<T>(NS_floor(double(x) * aXScale));
     y = static_cast<T>(NS_floor(double(y) * aYScale));
     width = right - x;
     height = bottom - y;
   }
+  // Scale 'this' by aScale, converting coordinates to integers so that the result is
+  // the largest integer-coordinate rectangle contained by the unrounded result.
   void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); }
+  // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
+  // that the result is the largest integer-coordinate rectangle contained by the
+  // unrounded result.
   void ScaleRoundIn(double aXScale, double aYScale)
   {
     T right = static_cast<T>(NS_floor(double(XMost()) * aXScale));
     T bottom = static_cast<T>(NS_floor(double(YMost()) * aYScale));
     x = static_cast<T>(NS_ceil(double(x) * aXScale));
     y = static_cast<T>(NS_ceil(double(y) * aYScale));
     width = NS_MAX<T>(0, right - x);
     height = NS_MAX<T>(0, bottom - y);
   }
+  // Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
+  // the smallest integer-coordinate rectangle containing the unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   void ScaleInverseRoundOut(double aScale) { ScaleInverseRoundOut(aScale, aScale); }
+  // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
+  // that the result is the smallest integer-coordinate rectangle containing the
+  // unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   void ScaleInverseRoundOut(double aXScale, double aYScale)
   {
     T right = static_cast<T>(ceil(double(XMost()) / aXScale));
     T bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
     x = static_cast<T>(floor(double(x) / aXScale));
     y = static_cast<T>(floor(double(y) / aYScale));
     width = right - x;
     height = bottom - y;
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -80,24 +80,27 @@ struct NS_GFX nsRect :
     MOZ_COUNT_DTOR(nsRect);
   }
 #endif
 
   // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
   // In the RoundOut version we make the rect the smallest rect containing the
   // unrounded result. In the RoundIn version we make the rect the largest rect
   // contained in the unrounded result.
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   inline nsRect ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const;
   inline nsRect ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const;
 
   inline nsIntRect ScaleToNearestPixels(float aXScale, float aYScale,
                                         nscoord aAppUnitsPerPixel) const;
   inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const;
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   inline nsIntRect ScaleToOutsidePixels(float aXScale, float aYScale,
                                         nscoord aAppUnitsPerPixel) const;
+  // Note: this can turn an empty rectangle into a non-empty rectangle
   inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
   inline nsIntRect ScaleToInsidePixels(float aXScale, float aYScale,
                                        nscoord aAppUnitsPerPixel) const;
   inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const;
 };
 
 struct NS_GFX nsIntRect :
   public mozilla::BaseRect<PRInt32, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> {
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -2020,22 +2020,24 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
   aContext->Scale(userData->mXScale, userData->mYScale);
   // Apply the residual transform if it has been enabled, to ensure that
   // snapping when we draw into aContext exactly matches the ideal transform.
   // See above for why this is OK.
   aContext->Translate(aLayer->GetResidualTranslation() - gfxPoint(offset.x, offset.y));
 
   nsPresContext* presContext = containerLayerFrame->PresContext();
   PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
-  nsRect r = (aRegionToInvalidate.GetBounds() + offset).
-    ToAppUnits(appUnitsPerDevPixel);
-  r.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
-  containerLayerFrame->InvalidateWithFlags(r,
-      nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
-      nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
+  if (!aRegionToInvalidate.IsEmpty()) {
+    nsRect r = (aRegionToInvalidate.GetBounds() + offset).
+      ToAppUnits(appUnitsPerDevPixel);
+    r.ScaleInverseRoundOut(userData->mXScale, userData->mYScale);
+    containerLayerFrame->InvalidateWithFlags(r,
+        nsIFrame::INVALIDATE_NO_THEBES_LAYERS |
+        nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT);
+  }
 
   PRUint32 i;
   // Update visible regions. We need perform visibility analysis again
   // because we may be asked to draw into part of a ThebesLayer that
   // isn't actually visible in the window (e.g., because a ThebesLayer
   // expanded its visible region to a rectangle internally), in which
   // case the mVisibleRect stored in the display item may be wrong.
   nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);