Bug 758620 - Respect the Layers' anchor points in CompositorParent. r=ajuma
authorChris Lord <chrislord.net@gmail.com>
Tue, 26 Jun 2012 14:43:18 +0100
changeset 97693 ddd519d0767ed613df103591e62d5412aee02aa0
parent 97692 9b952d9249536576a90b41b95bc60ab367607b97
child 97694 de70e79ced32b414eca99e219430c20d73b16500
push id22993
push useremorley@mozilla.com
push dateWed, 27 Jun 2012 10:31:27 +0000
treeherdermozilla-central@1a56f1f011c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersajuma
bugs758620
milestone16.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 758620 - Respect the Layers' anchor points in CompositorParent. r=ajuma When asynchronously zooming, respect a Layer's anchor point so that it stays in the correct position.
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -308,37 +308,45 @@ CompositorParent::GetPrimaryScrollableLa
 static void
 Translate2D(gfx3DMatrix& aTransform, const gfxPoint& aOffset)
 {
   aTransform._41 += aOffset.x;
   aTransform._42 += aOffset.y;
 }
 
 void
-CompositorParent::TranslateFixedLayers(Layer* aLayer,
-                                       const gfxPoint& aTranslation)
+CompositorParent::TransformFixedLayers(Layer* aLayer,
+                                       const gfxPoint& aTranslation,
+                                       const gfxPoint& aScaleDiff)
 {
   if (aLayer->GetIsFixedPosition() &&
       !aLayer->GetParent()->GetIsFixedPosition()) {
+    // When a scale has been applied to a layer, it focuses around (0,0).
+    // The anchor position is used here as a scale focus point (assuming that
+    // aScaleDiff has already been applied) to re-focus the scale.
+    const gfxPoint& anchor = aLayer->GetFixedPositionAnchor();
+    gfxPoint translation(aTranslation.x - (anchor.x - anchor.x / aScaleDiff.x),
+                         aTranslation.y - (anchor.y - anchor.y / aScaleDiff.y));
+
     gfx3DMatrix layerTransform = aLayer->GetTransform();
-    Translate2D(layerTransform, aTranslation);
+    Translate2D(layerTransform, translation);
     ShadowLayer* shadow = aLayer->AsShadowLayer();
     shadow->SetShadowTransform(layerTransform);
 
     const nsIntRect* clipRect = aLayer->GetClipRect();
     if (clipRect) {
       nsIntRect transformedClipRect(*clipRect);
-      transformedClipRect.MoveBy(aTranslation.x, aTranslation.y);
+      transformedClipRect.MoveBy(translation.x, translation.y);
       shadow->SetShadowClipRect(&transformedClipRect);
     }
   }
 
   for (Layer* child = aLayer->GetFirstChild();
        child; child = child->GetNextSibling()) {
-    TranslateFixedLayers(child, aTranslation);
+    TransformFixedLayers(child, aTranslation, aScaleDiff);
   }
 }
 
 // Go down shadow layer tree, setting properties to match their non-shadow
 // counterparts.
 static void
 SetShadowProperties(Layer* aLayer)
 {
@@ -406,26 +414,40 @@ CompositorParent::TransformShadowTree()
     metricsScrollOffset = metrics.mViewportScrollOffset;
 
   nsIntPoint scrollCompensation(
     (mScrollOffset.x / tempScaleDiffX - metricsScrollOffset.x) * mXScale,
     (mScrollOffset.y / tempScaleDiffY - metricsScrollOffset.y) * mYScale);
   ViewTransform treeTransform(-scrollCompensation, mXScale, mYScale);
   shadow->SetShadowTransform(gfx3DMatrix(treeTransform) * currentTransform);
 
-  // Alter the scroll offset so that fixed position layers remain within
-  // the page area.
-  float offsetX = mScrollOffset.x / tempScaleDiffX;
-  float offsetY = mScrollOffset.y / tempScaleDiffY;
-  offsetX = NS_MAX((float)mContentRect.x, NS_MIN(offsetX, (float)(mContentRect.XMost() - mWidgetSize.width)));
-  offsetY = NS_MAX((float)mContentRect.y, NS_MIN(offsetY, (float)(mContentRect.YMost() - mWidgetSize.height)));
-  gfxPoint reverseViewTranslation(offsetX - metricsScrollOffset.x,
-                                  offsetY - metricsScrollOffset.y);
+  // Translate fixed position layers so that they stay in the correct position
+  // when mScrollOffset and metricsScrollOffset differ.
+  gfxPoint scaleDiff(tempScaleDiffX, tempScaleDiffY);
+  gfxPoint offset(clamped(mScrollOffset.x / tempScaleDiffX, mContentRect.x / tempScaleDiffX,
+                          (mContentRect.XMost() - mWidgetSize.width / tempScaleDiffX)) -
+                  metricsScrollOffset.x,
+                  clamped(mScrollOffset.y / tempScaleDiffY, mContentRect.y / tempScaleDiffY,
+                          (mContentRect.YMost() - mWidgetSize.height / tempScaleDiffY)) -
+                  metricsScrollOffset.y);
 
-  TranslateFixedLayers(layer, reverseViewTranslation);
+  // If the contents can fit entirely within the widget area on a particular
+  // dimenson, we need to translate and scale so that the fixed layers remain
+  // within the page boundaries.
+  if (mContentRect.width * tempScaleDiffX < mWidgetSize.width) {
+    offset.x = -metricsScrollOffset.x;
+    scaleDiff.x = NS_MIN(1.0f, mWidgetSize.width / (float)mContentRect.width);
+  }
+
+  if (mContentRect.height * tempScaleDiffY < mWidgetSize.height) {
+    offset.y = -metricsScrollOffset.y;
+    scaleDiff.y = NS_MIN(1.0f, mWidgetSize.height / (float)mContentRect.height);
+  }
+
+  TransformFixedLayers(layer, offset, scaleDiff);
 }
 
 void
 CompositorParent::SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom,
                                         const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect)
 {
 #ifdef MOZ_WIDGET_ANDROID
   mozilla::AndroidBridge::Bridge()->SetFirstPaintViewport(aOffset, aZoom, aPageRect, aCssPageRect);
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -102,20 +102,25 @@ private:
   // Platform specific functions
   /**
    * Does a breadth-first search to find the first layer in the tree with a
    * displayport set.
    */
   Layer* GetPrimaryScrollableLayer();
 
   /**
-   * Recursively applies the given translation to all fixed position layers
-   * that aren't children of other fixed position layers.
+   * Recursively applies the given translation to all top-level fixed position
+   * layers that are descendants of the given layer.
+   * aScaleDiff is considered to be the scale transformation applied when
+   * displaying the layers, and is used to make sure the anchor points of
+   * fixed position layers remain in the same position.
    */
-  void TranslateFixedLayers(Layer* aLayer, const gfxPoint& aTranslation);
+  void TransformFixedLayers(Layer* aLayer,
+                            const gfxPoint& aTranslation,
+                            const gfxPoint& aScaleDiff);
 
   nsRefPtr<LayerManager> mLayerManager;
   nsIWidget* mWidget;
   CancelableTask *mCurrentCompositeTask;
   TimeStamp mLastCompose;
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp mExpectedComposeTime;
 #endif