Bug 1277814 - Avoid division-by-zero when the cumulative resolution is zero. r=tnikkel draft
authorBotond Ballo <botond@mozilla.com>
Mon, 06 Jun 2016 18:16:06 -0400
changeset 375892 569276f2edd39600de534183e12b7f8762b917c8
parent 375884 b720fc66767b6cd6f136998dd51cf58e0d59cca8
child 375893 9f334338564ae35b167b73597101fb1d1340f2c8
child 376917 af3fc4753391f112dd917ed96894608775b65269
child 376919 d2f7c22e3148aae47a48cde83ee359fb77479390
push id20420
push userbballo@mozilla.com
push dateMon, 06 Jun 2016 22:18:53 +0000
reviewerstnikkel
bugs1277814
milestone49.0a1
Bug 1277814 - Avoid division-by-zero when the cumulative resolution is zero. r=tnikkel The division-by-zero was introducing NaNs into the displayport calculations, resulting in bad displayports. MozReview-Commit-ID: 5dbqIEOFADS
gfx/layers/FrameMetrics.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
layout/base/nsLayoutUtils.cpp
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -174,21 +174,27 @@ public:
       scrollableRect.height = compSize.height;
     }
 
     return scrollableRect;
   }
 
   CSSSize CalculateCompositedSizeInCssPixels() const
   {
+    if (GetZoom() == CSSToParentLayerScale2D(0, 0)) {
+      return CSSSize();  // avoid division by zero
+    }
     return mCompositionBounds.Size() / GetZoom();
   }
 
   CSSRect CalculateCompositedRectInCssPixels() const
   {
+    if (GetZoom() == CSSToParentLayerScale2D(0, 0)) {
+      return CSSRect();  // avoid division by zero
+    }
     return mCompositionBounds / GetZoom();
   }
 
   CSSSize CalculateBoundedCompositedSizeInCssPixels() const
   {
     CSSSize size = CalculateCompositedSizeInCssPixels();
     size.width = std::min(size.width, mRootCompositionSize.width);
     size.height = std::min(size.height, mRootCompositionSize.height);
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2692,17 +2692,20 @@ const ScreenMargin AsyncPanZoomControlle
 {
   if (aFrameMetrics.IsScrollInfoLayer()) {
     // Don't compute margins. Since we can't asynchronously scroll this frame,
     // we don't want to paint anything more than the composition bounds.
     return ScreenMargin();
   }
 
   CSSSize compositionSize = aFrameMetrics.CalculateBoundedCompositedSizeInCssPixels();
-  CSSPoint velocity = aVelocity / aFrameMetrics.GetZoom();
+  CSSPoint velocity;
+  if (aFrameMetrics.GetZoom() != CSSToParentLayerScale2D(0, 0)) {
+    velocity = aVelocity / aFrameMetrics.GetZoom();  // avoid division by zero
+  }
   CSSRect scrollableRect = aFrameMetrics.GetExpandedScrollableRect();
 
   // Calculate the displayport size based on how fast we're moving along each axis.
   CSSSize displayPortSize = CalculateDisplayPortSize(compositionSize, velocity);
 
   if (gfxPrefs::APZEnlargeDisplayPortWhenClipped()) {
     RedistributeDisplayPortExcess(displayPortSize, scrollableRect);
   }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -995,16 +995,29 @@ GetDisplayPortFromMarginsData(nsIContent
   }
 
   nsPresContext* presContext = frame->PresContext();
   int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
 
   LayoutDeviceToScreenScale2D res(presContext->PresShell()->GetCumulativeResolution()
                                 * nsLayoutUtils::GetTransformToAncestorScale(frame));
 
+  // Calculate the expanded scrollable rect, which we'll be clamping the
+  // displayport to.
+  nsRect expandedScrollableRect =
+    nsLayoutUtils::CalculateExpandedScrollableRect(frame);
+
+  // GetTransformToAncestorScale() can return 0. In this case, just return the
+  // base rect (clamped to the expanded scrollable rect), as other calculations
+  // would run into divisions by zero.
+  if (res == LayoutDeviceToScreenScale2D(0, 0)) {
+    // Make sure the displayport remains within the scrollable rect.
+    return base.MoveInsideAndClamp(expandedScrollableRect - scrollPos);
+  }
+
   // First convert the base rect to screen pixels
   LayoutDeviceToScreenScale2D parentRes = res;
   if (isRoot) {
     // the base rect for root scroll frames is specified in the parent document
     // coordinate space, so it doesn't include the local resolution.
     float localRes = presContext->PresShell()->GetResolution();
     parentRes.xScale /= localRes;
     parentRes.yScale /= localRes;
@@ -1108,18 +1121,16 @@ GetDisplayPortFromMarginsData(nsIContent
 
   // Convert the aligned rect back into app units.
   nsRect result = LayoutDeviceRect::ToAppUnits(screenRect / res, auPerDevPixel);
 
   // Expand it for the low-res buffer if needed
   result = ApplyRectMultiplier(result, aMultiplier);
 
   // Make sure the displayport remains within the scrollable rect.
-  nsRect expandedScrollableRect =
-    nsLayoutUtils::CalculateExpandedScrollableRect(frame);
   result = result.MoveInsideAndClamp(expandedScrollableRect - scrollPos);
 
   return result;
 }
 
 static bool
 ShouldDisableApzForElement(nsIContent* aContent)
 {