Bug 988882 - Special-case handling of root composition bounds calculation on Android when the toolbar is perma-visible. r=tn
☠☠ backed out by 57547c682f35 ☠ ☠
authorBotond Ballo <botond@mozilla.com>
Wed, 02 Apr 2014 01:35:25 -0400
changeset 177081 bae32cf47dec16497f9ddf0b52f76ee07808cbb6
parent 177080 5f964391ed1391b9fdacd7bbc2fee2696258bb5d
child 177082 f1f9fc68fcf4af0ea947837db4b9d34abdfdd322
push id26541
push userryanvm@gmail.com
push dateFri, 04 Apr 2014 18:50:44 +0000
treeherdermozilla-central@2a069087bed1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs988882
milestone31.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 988882 - Special-case handling of root composition bounds calculation on Android when the toolbar is perma-visible. r=tn
layout/base/UnitTransforms.h
layout/base/nsDisplayList.cpp
layout/base/nsLayoutUtils.cpp
--- a/layout/base/UnitTransforms.h
+++ b/layout/base/UnitTransforms.h
@@ -44,16 +44,24 @@ gfx::PointTyped<TargetUnits> ViewAs(cons
 template <class TargetUnits>
 gfx::RectTyped<TargetUnits> ViewAs(const gfxRect& aRect) {
   return gfx::RectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
 }
 template <class TargetUnits>
 gfx::IntSizeTyped<TargetUnits> ViewAs(const nsIntSize& aSize) {
   return gfx::IntSizeTyped<TargetUnits>(aSize.width, aSize.height);
 }
+template <class TargetUnits>
+gfx::IntPointTyped<TargetUnits> ViewAs(const nsIntPoint& aPoint) {
+  return gfx::IntPointTyped<TargetUnits>(aPoint.x, aPoint.y);
+}
+template <class TargetUnits>
+gfx::IntRectTyped<TargetUnits> ViewAs(const nsIntRect& aRect) {
+  return gfx::IntRectTyped<TargetUnits>(aRect.x, aRect.y, aRect.width, aRect.height);
+}
 
 // Convenience functions for casting typed entities to untyped entities.
 // Using these functions does not require a justification, but once we convert
 // all code to use strongly typed units they should not be needed any longer.
 template <class SourceUnits>
 gfxPoint ViewAsUntyped(const gfx::PointTyped<SourceUnits>& aPoint) {
   return gfxPoint(aPoint.x, aPoint.y);
 }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -637,40 +637,47 @@ CalculateRootCompositionSize(FrameMetric
   LayerSize rootCompositionSize;
   nsPresContext* rootPresContext =
     aPresContext->GetToplevelContentDocumentPresContext();
   if (!rootPresContext) {
     rootPresContext = aPresContext->GetRootPresContext();
   }
   nsIPresShell* rootPresShell = nullptr;
   if (rootPresContext) {
+    // See the comments in the code that calculates the root
+    // composition bounds in RecordFrameMetrics.
+    // TODO: Reuse that code here.
     nsIPresShell* rootPresShell = rootPresContext->PresShell();
     if (nsIFrame* rootFrame = rootPresShell->GetRootFrame()) {
       if (nsView* view = rootFrame->GetView()) {
-        nsIWidget* widget = view->GetWidget();
-  #ifdef MOZ_WIDGET_ANDROID
-        // Android hack - temporary workaround for bug 983208 until we figure
-        // out what a proper fix is.
-        if (!widget) {
-          widget = rootFrame->GetNearestWidget();
-        }
-  #endif
+        LayoutDeviceToParentLayerScale parentResolution(
+          rootPresShell->GetCumulativeResolution().width
+          / rootPresShell->GetResolution().width);
+        int32_t rootAUPerDevPixel = rootPresContext->AppUnitsPerDevPixel();
+        nsRect viewBounds = view->GetBounds();
+        LayerSize viewSize = ViewAs<LayerPixel>(
+          (LayoutDeviceRect::FromAppUnits(viewBounds, rootAUPerDevPixel)
+           * parentResolution).Size(), PixelCastJustification::ParentLayerToLayerForRootComposition);
+        nsIWidget* widget =
+#ifdef MOZ_WIDGET_ANDROID
+            rootFrame->GetNearestWidget();
+#else
+            view->GetWidget();
+#endif
         if (widget) {
-          nsIntRect bounds;
-          widget->GetBounds(bounds);
-          rootCompositionSize = LayerSize(ViewAs<LayerPixel>(bounds.Size()));
+          nsIntRect widgetBounds;
+          widget->GetBounds(widgetBounds);
+          rootCompositionSize = LayerSize(ViewAs<LayerPixel>(widgetBounds.Size()));
+#ifdef MOZ_WIDGET_ANDROID
+          if (viewSize.height < rootCompositionSize.height) {
+            rootCompositionSize.height = viewSize.height;
+          }
+#endif
         } else {
-          LayoutDeviceToParentLayerScale parentResolution(
-            rootPresShell->GetCumulativeResolution().width
-            / rootPresShell->GetResolution().width);
-          int32_t rootAUPerDevPixel = rootPresContext->AppUnitsPerDevPixel();
-          nsRect viewBounds = view->GetBounds();
-          rootCompositionSize = ViewAs<LayerPixel>(
-            (LayoutDeviceRect::FromAppUnits(viewBounds, rootAUPerDevPixel)
-             * parentResolution).Size(), PixelCastJustification::ParentLayerToLayerForRootComposition);
+          rootCompositionSize = viewSize;
         }
       }
     }
   } else {
     nsIWidget* widget = (aScrollFrame ? aScrollFrame : aForFrame)->GetNearestWidget();
     nsIntRect bounds;
     widget->GetBounds(bounds);
     rootCompositionSize = LayerSize(ViewAs<LayerPixel>(bounds.Size()));
@@ -788,48 +795,60 @@ static void RecordFrameMetrics(nsIFrame*
   // Calculate the composition bounds as the size of the scroll frame and
   // its origin relative to the reference frame.
   // If aScrollFrame is null, we are in a document without a root scroll frame,
   // so it's a xul document. In this case, use the size of the viewport frame.
   nsIFrame* frameForCompositionBoundsCalculation = aScrollFrame ? aScrollFrame : aForFrame;
   nsRect compositionBounds(frameForCompositionBoundsCalculation->GetOffsetToCrossDoc(aReferenceFrame),
                            frameForCompositionBoundsCalculation->GetSize());
   metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(compositionBounds, auPerDevPixel)
-                             * metrics.GetParentResolution());
+                                            * metrics.GetParentResolution());
 
   // For the root scroll frame of the root content document, the above calculation
   // will yield the size of the viewport frame as the composition bounds, which
   // doesn't actually correspond to what is visible when
   // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
   // the prescontext that the viewport frame is reflowed into. In that case if our
   // document has a widget then the widget's bounds will correspond to what is
   // visible. If we don't have a widget the root view's bounds correspond to what
   // would be visible because they don't get modified by setCSSViewport.
   bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
                                       && aScrollFrame == presShell->GetRootScrollFrame();
   if (isRootContentDocRootScrollFrame) {
     if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
       if (nsView* view = rootFrame->GetView()) {
-        nsIWidget* widget = view->GetWidget();
+        nsRect viewBoundsAppUnits = view->GetBounds() + rootFrame->GetOffsetToCrossDoc(aReferenceFrame);
+        ParentLayerIntRect viewBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(viewBoundsAppUnits, auPerDevPixel)
+                                                     * metrics.GetParentResolution());
+        // On Android, we need to do things a bit differently to get things
+        // right (see bug 983208, bug 988882). We use the bounds of the nearest
+        // widget, but clamp the height to the view bounds height. This clamping
+        // is done to get correct results for a page where the page is sized to
+        // the screen and thus the dynamic toolbar never disappears. In such a
+        // case, we want the composition bounds to exclude the toolbar height,
+        // but the widget bounds includes it. We don't currently have a good way
+        // of knowing about the toolbar height, but clamping to the view bounds
+        // height gives the correct answer in the cases we care about.
+        nsIWidget* widget =
 #ifdef MOZ_WIDGET_ANDROID
-        // Android hack - temporary workaround for bug 983208 until we figure
-        // out what a proper fix is.
-        if (!widget) {
-          widget = rootFrame->GetNearestWidget();
-        }
+            rootFrame->GetNearestWidget();
+#else
+            view->GetWidget();
 #endif
         if (widget) {
-          nsIntRect bounds;
-          widget->GetBounds(bounds);
-          metrics.mCompositionBounds = ParentLayerIntRect::FromUnknownRect(mozilla::gfx::IntRect(
-              bounds.x, bounds.y, bounds.width, bounds.height));
+          nsIntRect widgetBounds;
+          widget->GetBounds(widgetBounds);
+          metrics.mCompositionBounds = ViewAs<ParentLayerPixel>(widgetBounds);
+#ifdef MOZ_WIDGET_ANDROID
+          if (viewBounds.height < metrics.mCompositionBounds.height) {
+            metrics.mCompositionBounds.height = viewBounds.height;
+          }
+#endif
         } else {
-          nsRect viewBounds = view->GetBounds() + rootFrame->GetOffsetToCrossDoc(aReferenceFrame);
-          metrics.mCompositionBounds = RoundedToInt(LayoutDeviceRect::FromAppUnits(viewBounds, auPerDevPixel)
-                                     * metrics.GetParentResolution());
+          metrics.mCompositionBounds = viewBounds;
         }
       }
     }
   }
 
   // Adjust composition bounds for the size of scroll bars.
   if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
     nsMargin sizes = scrollableFrame->GetActualScrollbarSizes();
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6120,46 +6120,44 @@ nsLayoutUtils::UpdateImageVisibilityForF
 /* static */ nsSize
 nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame)
 {
   nsSize size(aFrame->GetSize());
 
   nsPresContext* presContext = aFrame->PresContext();
   nsIPresShell* presShell = presContext->PresShell();
 
-  // For the root scroll frame of the root content document, the above calculation
-  // will yield the size of the viewport frame as the composition bounds, which
-  // doesn't actually correspond to what is visible when
-  // nsIDOMWindowUtils::setCSSViewport has been called to modify the visible area of
-  // the prescontext that the viewport frame is reflowed into. In that case if our
-  // document has a widget then the widget's bounds will correspond to what is
-  // visible. If we don't have a widget the root view's bounds correspond to what
-  // would be visible because they don't get modified by setCSSViewport.
+  // See the comments in the code that calculates the root
+  // composition bounds in RecordFrameMetrics.
+  // TODO: Reuse that code here.
   bool isRootContentDocRootScrollFrame = presContext->IsRootContentDocument()
                                       && aFrame == presShell->GetRootScrollFrame();
   if (isRootContentDocRootScrollFrame) {
     if (nsIFrame* rootFrame = presShell->GetRootFrame()) {
       if (nsView* view = rootFrame->GetView()) {
-        nsIWidget* widget = view->GetWidget();
+        nsSize viewSize = view->GetBounds().Size();
+        nsIWidget* widget =
 #ifdef MOZ_WIDGET_ANDROID
-        // Android hack - temporary workaround for bug 983208 until we figure
-        // out what a proper fix is.
-        if (!widget) {
-          widget = rootFrame->GetNearestWidget();
-        }
+            rootFrame->GetNearestWidget();
+#else
+            view->GetWidget();
 #endif
         if (widget) {
-          nsIntRect bounds;
-          widget->GetBounds(bounds);
+          nsIntRect widgetBounds;
+          widget->GetBounds(widgetBounds);
           int32_t auPerDevPixel = presContext->AppUnitsPerDevPixel();
-          size = nsSize(bounds.width * auPerDevPixel,
-                        bounds.height * auPerDevPixel);
+          size = nsSize(widgetBounds.width * auPerDevPixel,
+                        widgetBounds.height * auPerDevPixel);
+#ifdef MOZ_WIDGET_ANDROID
+          if (viewSize.height < size.height) {
+            size.height = viewSize.height;
+          }
+#endif
         } else {
-          nsRect viewBounds = view->GetBounds();
-          size = nsSize(viewBounds.width, viewBounds.height);
+          size = viewSize;
         }
       }
     }
   }
 
   // Adjust composition bounds for the size of scroll bars.
   nsIScrollableFrame* scrollableFrame = aFrame->GetScrollTargetFrame();
   if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {