Bug 814435 - Apply a shadow transform to scrollbar layers to keep them in sync with async transforms. r=BenWa
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 09 Dec 2013 22:14:54 -0500
changeset 159661 75178cf263ae1fb9836095c72c8dfbbf64fec523
parent 159660 4c81aaa4763e9df29f704ddcd8c29b4d6e661d13
child 159662 c25e3a7c7e2ffbc2cc34e7bd9d305213e5bf23c1
push id25809
push userryanvm@gmail.com
push dateTue, 10 Dec 2013 20:38:57 +0000
treeherdermozilla-central@ece822a8cc7b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa
bugs814435
milestone29.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 814435 - Apply a shadow transform to scrollbar layers to keep them in sync with async transforms. r=BenWa
gfx/layers/composite/AsyncCompositionManager.cpp
gfx/layers/composite/AsyncCompositionManager.h
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -496,19 +496,19 @@ AsyncCompositionManager::ApplyAsyncConte
 
     mIsFirstPaint = false;
     mLayersUpdated = false;
 
     // Apply the render offset
     mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
 
     gfx3DMatrix transform(gfx3DMatrix(treeTransform) * aLayer->GetTransform());
-    // The transform already takes the resolution scale into account.  Since we
-    // will apply the resolution scale again when computing the effective
-    // transform, we must apply the inverse resolution scale here.
+    // GetTransform already takes the pre- and post-scale into account.  Since we
+    // will apply the pre- and post-scale again when computing the effective
+    // transform, we must apply the inverses here.
     transform.Scale(1.0f/container->GetPreXScale(),
                     1.0f/container->GetPreYScale(),
                     1);
     transform.ScalePost(1.0f/aLayer->GetPostXScale(),
                         1.0f/aLayer->GetPostYScale(),
                         1);
     layerComposite->SetShadowTransform(transform);
     NS_ASSERTION(!layerComposite->GetShadowTransformSetByAnimation(),
@@ -519,20 +519,80 @@ AsyncCompositionManager::ApplyAsyncConte
     LayoutDeviceToLayerScale resolution = metrics.mCumulativeResolution;
     oldTransform.Scale(resolution.scale, resolution.scale, 1);
 
     AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
 
     appliedTransform = true;
   }
 
+  if (container->GetIsScrollbar()) {
+    ApplyAsyncTransformToScrollbar(container);
+  }
   return appliedTransform;
 }
 
 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.
+  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;
+    }
+
+    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;
+      scrollbarTransform.ScalePost(1.f, 1.f / transientTransform.GetYScale(), 1.f);
+      scrollbarTransform.TranslatePost(gfxPoint3D(0, -transientTransform._42 * scale, 0));
+    }
+    if (aLayer->GetScrollbarDirection() == Layer::HORIZONTAL) {
+      float scale = metrics.CalculateCompositedRectInCssPixels().width / metrics.mScrollableRect.width;
+      scrollbarTransform.ScalePost(1.f / transientTransform.GetXScale(), 1.f, 1.f);
+      scrollbarTransform.TranslatePost(gfxPoint3D(-transientTransform._41 * scale, 0, 0));
+    }
+
+    gfx3DMatrix transform = scrollbarTransform * aLayer->GetTransform();
+    // GetTransform already takes the pre- and post-scale into account.  Since we
+    // will apply the pre- and post-scale again when computing the effective
+    // transform, we must apply the inverses here.
+    transform.Scale(1.0f/aLayer->GetPreXScale(),
+                    1.0f/aLayer->GetPreYScale(),
+                    1);
+    transform.ScalePost(1.0f/aLayer->GetPostXScale(),
+                        1.0f/aLayer->GetPostYScale(),
+                        1);
+    aLayer->AsLayerComposite()->SetShadowTransform(transform);
+
+    return;
+  }
+}
+
+void
 AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
 {
   LayerComposite* layerComposite = aLayer->AsLayerComposite();
   ContainerLayer* container = aLayer->AsContainerLayer();
 
   const FrameMetrics& metrics = container->GetFrameMetrics();
   // We must apply the resolution scale before a pan/zoom transform, so we call
   // GetTransform here.
--- a/gfx/layers/composite/AsyncCompositionManager.h
+++ b/gfx/layers/composite/AsyncCompositionManager.h
@@ -118,16 +118,21 @@ public:
 
 private:
   void TransformScrollableLayer(Layer* aLayer);
   // Return true if an AsyncPanZoomController content transform was
   // applied for |aLayer|.  *aWantNextFrame is set to true if the
   // controller wants another animation frame.
   bool ApplyAsyncContentTransformToTree(TimeStamp aCurrentFrame, Layer* aLayer,
                                         bool* aWantNextFrame);
+  /**
+   * Update the shadow trasnform for aLayer assuming that is a scrollbar,
+   * so that it stays in sync with the content that is being scrolled by APZ.
+   */
+  void ApplyAsyncTransformToScrollbar(ContainerLayer* aLayer);
 
   void SetFirstPaintViewport(const LayerIntPoint& aOffset,
                              const CSSToLayerScale& aZoom,
                              const CSSRect& aCssPageRect);
   void SetPageRect(const CSSRect& aCssPageRect);
   void SyncViewportInfo(const LayerIntRect& aDisplayPort,
                         const CSSToLayerScale& aDisplayResolution,
                         bool aLayersUpdated,