Bug 958549 - Don't move scroll indicators for empty container layers. r=kats, a=1.3+
authorChris Lord <chrislord.net@gmail.com>
Wed, 22 Jan 2014 14:25:44 +0000
changeset 175947 243d1045401aa255d0588f13d8c78586ea361cf0
parent 175946 b3cfcb0fe2efdda059e7c01af996743dbeb2f1d3
child 175948 a57e9a4224f2b628d0fe3b6a86ceca2fccddbe96
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats, 1.3
bugs958549
milestone28.0a2
Bug 958549 - Don't move scroll indicators for empty container layers. r=kats, a=1.3+ If we've applied an async transform to an empty container layer (e.g. a layer that corresponds to an nsDisplayScrollInfo display item), don't use that transform on the corresponding scrollbar.
gfx/layers/composite/AsyncCompositionManager.cpp
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -535,40 +535,62 @@ AsyncCompositionManager::ApplyAsyncConte
   }
 
   if (container->GetScrollbarDirection() != Layer::NONE) {
     ApplyAsyncTransformToScrollbar(container);
   }
   return appliedTransform;
 }
 
+static bool
+LayerHasNonContainerDescendants(ContainerLayer* aContainer)
+{
+  for (Layer* child = aContainer->GetFirstChild();
+       child; child = child->GetNextSibling()) {
+    ContainerLayer* container = child->AsContainerLayer();
+    if (!container || LayerHasNonContainerDescendants(container)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 void
 AsyncCompositionManager::ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer)
 {
   // If this layer corresponds to a scrollbar, then search backwards through the
   // siblings until we find the container layer with the right ViewID; this is
   // the content that this scrollbar is for. Pick up the transient async transform
   // from that layer and use it to update the scrollbar position.
   // Note that it is possible that the content layer is no longer there; in
   // this case we don't need to do anything because there can't be an async
   // transform on the content.
+  // We only apply the transform if the scroll-target layer has non-container
+  // children (i.e. when it has some possibly-visible content). This is to
+  // avoid moving scroll-bars in the situation that only a scroll information
+  // layer has been built for a scroll frame, as this would result in a
+  // disparity between scrollbars and visible content.
   for (Layer* scrollTarget = aLayer->GetPrevSibling();
        scrollTarget;
        scrollTarget = scrollTarget->GetPrevSibling()) {
     if (!scrollTarget->AsContainerLayer()) {
       continue;
     }
     AsyncPanZoomController* apzc = scrollTarget->AsContainerLayer()->GetAsyncPanZoomController();
     if (!apzc) {
       continue;
     }
     const FrameMetrics& metrics = scrollTarget->AsContainerLayer()->GetFrameMetrics();
     if (metrics.mScrollId != aLayer->GetScrollbarTargetContainerId()) {
       continue;
     }
+    if (!LayerHasNonContainerDescendants(scrollTarget->AsContainerLayer())) {
+      return;
+    }
 
     gfx3DMatrix asyncTransform = gfx3DMatrix(apzc->GetCurrentAsyncTransform());
     gfx3DMatrix nontransientTransform = apzc->GetNontransientAsyncTransform();
     gfx3DMatrix transientTransform = asyncTransform * nontransientTransform.Inverse();
 
     gfx3DMatrix scrollbarTransform;
     if (aLayer->GetScrollbarDirection() == Layer::VERTICAL) {
       float scale = metrics.CalculateCompositedRectInCssPixels().height / metrics.mScrollableRect.height;