Bug 607417 - Reconcile async scrolling for fixed position layers. r=ajuma
☠☠ backed out by 32a8564667a5 ☠ ☠
authorChris Lord <chrislord.net@gmail.com>
Fri, 04 May 2012 17:04:15 +1200
changeset 93137 5c35cd6f3ea46f7380f507d6d52f69c330cae5b4
parent 93136 ba39b0822992dec1a16ed00647ee14a334cd5791
child 93138 72a7230e978e917e03793976ed49f07af0871dfc
push id22611
push usereakhgari@mozilla.com
push dateFri, 04 May 2012 20:23:57 +0000
treeherdermozilla-central@dc93a3faa54e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersajuma
bugs607417
milestone15.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 607417 - Reconcile async scrolling for fixed position layers. r=ajuma Untranslate fixed position layers when doing async scrolling so that they don't jump about as content re-renders them in the correct place.
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
mobile/android/base/GeckoAppShell.java
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -161,16 +161,18 @@ CompositorParent::ResumeComposition()
   static_cast<LayerManagerOGL*>(mLayerManager.get())->gl()->RenewSurface();
 #endif
 }
 
 void
 CompositorParent::ResumeCompositionAndResize(int width, int height)
 {
   static_cast<LayerManagerOGL*>(mLayerManager.get())->SetSurfaceSize(width, height);
+  mWidgetSize.width = width;
+  mWidgetSize.height = height;
   ResumeComposition();
 }
 
 void
 CompositorParent::SchedulePauseOnCompositorThread()
 {
   CancelableTask *pauseTask = NewRunnableMethod(this,
                                                 &CompositorParent::PauseComposition);
@@ -287,16 +289,43 @@ CompositorParent::GetPrimaryScrollableLa
       queue.AppendElement(child);
       child = child->GetNextSibling();
     }
   }
 
   return root;
 }
 
+static void
+ReverseViewTranslation(gfx3DMatrix& aTransform,
+                       const ViewTransform& aViewTransform)
+{
+  aTransform._41 -= aViewTransform.mTranslation.x / aViewTransform.mXScale;
+  aTransform._42 -= aViewTransform.mTranslation.y / aViewTransform.mYScale;
+}
+
+void
+CompositorParent::UntranslateFixedLayers(Layer* aLayer,
+                                         const ViewTransform& aTransform)
+{
+  if (aLayer->GetIsFixedPosition() &&
+      !aLayer->GetParent()->GetIsFixedPosition()) {
+    gfx3DMatrix layerTransform = aLayer->GetTransform();
+    ReverseViewTranslation(layerTransform, aTransform);
+
+    ShadowLayer* shadow = aLayer->AsShadowLayer();
+    shadow->SetShadowTransform(layerTransform);
+  }
+
+  for (Layer* child = aLayer->GetFirstChild();
+       child; child = child->GetNextSibling()) {
+    UntranslateFixedLayers(child, aTransform);
+  }
+}
+
 // Go down shadow layer tree, setting properties to match their non-shadow
 // counterparts.
 static void
 SetShadowProperties(Layer* aLayer)
 {
   // FIXME: Bug 717688 -- Do these updates in ShadowLayersParent::RecvUpdate.
   ShadowLayer* shadow = aLayer->AsShadowLayer();
   shadow->SetShadowTransform(aLayer->GetTransform());
@@ -369,16 +398,27 @@ CompositorParent::TransformShadowTree()
     if (metrics->IsScrollable())
       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.
+    int offsetX = NS_MAX(0, NS_MIN(mScrollOffset.x, mContentSize.width - mWidgetSize.width));
+    int offsetY = NS_MAX(0, NS_MIN(mScrollOffset.y, mContentSize.height - mWidgetSize.height));
+    treeTransform.mTranslation.x =
+      -(offsetX / tempScaleDiffX - metricsScrollOffset.x) * mXScale;
+    treeTransform.mTranslation.y =
+      -(offsetY / tempScaleDiffY - metricsScrollOffset.y) * mYScale;
+
+    UntranslateFixedLayers(layer, treeTransform);
   } else {
     ViewTransform treeTransform(nsIntPoint(0,0), mXScale, mYScale);
     shadow->SetShadowTransform(gfx3DMatrix(treeTransform) * currentTransform);
   }
 }
 
 void
 CompositorParent::SetFirstPaintViewport(float aOffsetX, float aOffsetY, float aZoom,
@@ -428,24 +468,28 @@ CompositorParent::ShadowLayersUpdated(bo
   }
   ScheduleComposition();
 }
 
 PLayersParent*
 CompositorParent::AllocPLayers(const LayersBackend &backendType)
 {
   if (backendType == LayerManager::LAYERS_OPENGL) {
-#ifdef MOZ_JAVA_COMPOSITOR
     nsIntRect rect;
     mWidget->GetBounds(rect);
+    mWidgetSize.width = rect.width;
+    mWidgetSize.height = rect.height;
+#ifdef MOZ_JAVA_COMPOSITOR
     nsRefPtr<LayerManagerOGL> layerManager =
       new LayerManagerOGL(mWidget, rect.width, rect.height, true);
 #else
     nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(mWidget);
 #endif
+    // mWidget doesn't belong to the compositor thread, so set it to NULL here
+    // to avoid accessing it.
     mWidget = NULL;
     mLayerManager = layerManager;
 
     if (!layerManager->Initialize()) {
       NS_ERROR("Failed to init OGL Layers");
       return NULL;
     }
 
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -132,29 +132,37 @@ private:
 
   // Platform specific functions
   /**
    * Does a breadth-first search to find the first layer in the tree with a
    * displayport set.
    */
   Layer* GetPrimaryScrollableLayer();
 
+  /**
+   * Recursively reverses the translation portion of the given ViewTransform on
+   * all fixed position layers that aren't children of other fixed position
+   * layers.
+   */
+  void UntranslateFixedLayers(Layer* aLayer, const ViewTransform& aTransform);
+
   nsRefPtr<LayerManager> mLayerManager;
   nsIWidget* mWidget;
   CancelableTask *mCurrentCompositeTask;
   TimeStamp mLastCompose;
 #ifdef COMPOSITOR_PERFORMANCE_WARNING
   TimeStamp mExpectedComposeTime;
 #endif
 
   bool mPaused;
   float mXScale;
   float mYScale;
   nsIntPoint mScrollOffset;
   nsIntSize mContentSize;
+  nsIntSize mWidgetSize;
 
   // When this flag is set, the next composition will be the first for a
   // particular document (i.e. the document displayed on the screen will change).
   // This happens when loading a new page or switching tabs. We notify the
   // front-end (e.g. Java on Android) about this so that it take the new page
   // size and zoom into account when providing us with the next view transform.
   bool mIsFirstPaint;
 
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -406,16 +406,19 @@ public class GeckoAppShell
         if (!f.exists())
             f.mkdirs();
         GeckoAppShell.putenv("TMPDIR=" + f.getPath());
 
         // setup the downloads path
         f = Environment.getDownloadCacheDirectory();
         GeckoAppShell.putenv("EXTERNAL_STORAGE=" + f.getPath());
 
+        // Enable fixed position layers
+        GeckoAppShell.putenv("MOZ_ENABLE_FIXED_POSITION_LAYERS=1");
+
         putLocaleEnv();
     }
 
     /* This method is referenced by Robocop via reflection. */
     public static void loadSQLiteLibs(Context context, String apkName) {
         if (sSQLiteLibsLoaded)
             return;
         synchronized(sSQLiteLibsLoaded) {