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
--- 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)
{