Bug 839641 - Add a syncFrameMetrics code path to push viewport changes from APZC to Java. r=Cwiiis, BenWa
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 26 Apr 2013 13:26:39 -0400
changeset 130077 4b2b6c39adf9a941c1411ef7076708fa2c5dfb6e
parent 130076 984977c00f0772267d707ad892c6a60a02aede93
child 130078 e2152cf53805540839a6a74d77f583560e880ac2
push id27165
push userkgupta@mozilla.com
push dateFri, 26 Apr 2013 17:27:14 +0000
treeherdermozilla-inbound@5884664a5961 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersCwiiis, BenWa
bugs839641
milestone23.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 839641 - Add a syncFrameMetrics code path to push viewport changes from APZC to Java. r=Cwiiis, BenWa
gfx/layers/ipc/AsyncPanZoomController.cpp
gfx/layers/ipc/AsyncPanZoomController.h
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
mobile/android/base/gfx/GeckoLayerClient.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/android/nsWindow.cpp
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -1107,17 +1107,18 @@ AsyncPanZoomController::FireAsyncScrollO
     MonitorAutoLock monitor(mMonitor);
     SendAsyncScrollEvent();
   }
   mAsyncScrollTimeoutTask = nullptr;
 }
 
 bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                                             ContainerLayer* aLayer,
-                                                            ViewTransform* aNewTransform) {
+                                                            ViewTransform* aNewTransform,
+                                                            gfxPoint* aScrollOffset) {
   // The eventual return value of this function. The compositor needs to know
   // whether or not to advance by a frame as soon as it can. For example, if a
   // fling is happening, it has to keep compositing so that the animation is
   // smooth. If an animation frame is requested, it is the compositor's
   // responsibility to schedule a composite.
   bool requestAnimationFrame = false;
 
   const gfx3DMatrix& currentTransform = aLayer->GetTransform();
@@ -1216,16 +1217,17 @@ bool AsyncPanZoomController::SampleConte
     MessageLoop::current()->PostDelayedTask(FROM_HERE,
                                             mAsyncScrollTimeoutTask,
                                             mAsyncScrollTimeout);
   }
 
   gfxPoint scrollCompensation(
     (scrollOffset / rootScale - metricsScrollOffset) * localScale);
   *aNewTransform = ViewTransform(-scrollCompensation, localScale);
+  *aScrollOffset = scrollOffset * localScale;
 
   mLastSampleTime = aSampleTime;
 
   return requestAnimationFrame;
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint) {
   MonitorAutoLock monitor(mMonitor);
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -172,17 +172,18 @@ public:
    * this internally with |aLayer|'s transform).
    *
    * Return value indicates whether or not any currently running animation
    * should continue. That is, if true, the compositor should schedule another
    * composite.
    */
   bool SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                       ContainerLayer* aLayer,
-                                      ViewTransform* aTransform);
+                                      ViewTransform* aNewTransform,
+                                      gfxPoint* aScrollOffset);
 
   /**
    * A shadow layer update has arrived. |aViewportFrame| is the new FrameMetrics
    * for the top-level frame. |aIsFirstPaint| is a flag passed from the shadow
    * layers code indicating that the frame metrics being sent with this call are
    * the initial metrics and the initial paint of the frame has just happened.
    */
   void NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint);
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -841,34 +841,45 @@ CompositorParent::ApplyAsyncContentTrans
   if (!container) {
     return appliedTransform;
   }
 
   if (AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController()) {
     LayerComposite* layerComposite = aLayer->AsLayerComposite();
 
     ViewTransform treeTransform;
+    gfxPoint scrollOffset;
     *aWantNextFrame |=
       controller->SampleContentTransformForFrame(aCurrentFrame,
                                                  container,
-                                                 &treeTransform);
+                                                 &treeTransform,
+                                                 &scrollOffset);
+
+    gfx::Margin fixedLayerMargins(0, 0, 0, 0);
+    float offsetX = 0, offsetY = 0;
+    SyncFrameMetrics(aLayer, treeTransform, scrollOffset, fixedLayerMargins,
+                     offsetX, offsetY, mIsFirstPaint, mLayersUpdated);
+    mIsFirstPaint = false;
+    mLayersUpdated = false;
+
+    // Apply the render offset
+    mLayerManager->GetCompositor()->SetScreenRenderOffset(gfx::Point(offsetX, offsetY));
 
     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.
     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);
 
-    gfx::Margin fixedLayerMargins(0, 0, 0, 0);
     TransformFixedLayers(
       aLayer,
       -treeTransform.mTranslation / treeTransform.mScale,
       treeTransform.mScale,
       fixedLayerMargins);
 
     appliedTransform = true;
   }
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -176,16 +176,22 @@ protected:
   virtual void ScheduleTask(CancelableTask*, int);
   virtual void Composite();
   virtual void ComposeToTarget(gfxContext* aTarget);
   virtual void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect);
   virtual void SetPageRect(const gfx::Rect& aCssPageRect);
   virtual void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                                 nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                                 gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY);
+  virtual void SyncFrameMetrics(Layer* aLayer, const ViewTransform& aTreeTransform,
+                                const gfxPoint& aScrollOffset, gfx::Margin& aFixedLayerMargins,
+                                float& aOffsetX, float& aOffsetY,
+                                bool aIsFirstPaint, bool aLayersUpdated) {
+  }
+
   void SetEGLSurfaceSize(int width, int height);
 
 private:
   void PauseComposition();
   void ResumeComposition();
   void ResumeCompositionAndResize(int width, int height);
   void ForceComposition();
 
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -652,16 +652,31 @@ public class GeckoLayerClient implements
         if (layersUpdated && mDrawListener != null) {
             /* Used by robocop for testing purposes */
             mDrawListener.drawFinished();
         }
 
         return mCurrentViewTransform;
     }
 
+    /* Invoked by JNI from the compositor thread */
+    public ViewTransform syncFrameMetrics(float offsetX, float offsetY, float zoom,
+                float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom,
+                boolean layersUpdated, int x, int y, int width, int height, float resolution,
+                boolean isFirstPaint)
+    {
+        if (isFirstPaint) {
+            RectF pageRect = RectUtils.scale(new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom), zoom);
+            setFirstPaintViewport(offsetX, offsetY, zoom, pageRect.left, pageRect.top, pageRect.right,
+                    pageRect.bottom, cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
+        }
+
+        return syncViewportInfo(x, y, width, height, resolution, layersUpdated);
+    }
+
     /** This function is invoked by Gecko via JNI; be careful when modifying signature. */
     public LayerRenderer.Frame createFrame() {
         // Create the shaders and textures if necessary.
         if (!mLayerRendererInitialized) {
             mLayerRenderer.checkMonitoringEnabled();
             mLayerRenderer.createDefaultProgram();
             mLayerRendererInitialized = true;
         }
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -2115,16 +2115,29 @@ AndroidBridge::SyncViewportInfo(const ns
     if (!client)
         return;
 
     client->SyncViewportInfo(aDisplayPort, aDisplayResolution, aLayersUpdated,
                              aScrollOffset, aScaleX, aScaleY, aFixedLayerMargins,
                              aOffsetX, aOffsetY);
 }
 
+void AndroidBridge::SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect,
+                                     bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
+                                     bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY)
+{
+    AndroidGeckoLayerClient *client = mLayerClient;
+    if (!client)
+        return;
+
+    client->SyncFrameMetrics(aOffset, aZoom, aCssPageRect,
+                             aLayersUpdated, aDisplayPort, aDisplayResolution,
+                             aIsFirstPaint, aFixedLayerMargins, aOffsetX, aOffsetY);
+}
+
 AndroidBridge::AndroidBridge()
   : mLayerClient(NULL),
     mNativePanZoomController(NULL)
 {
 }
 
 AndroidBridge::~AndroidBridge()
 {
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -339,16 +339,19 @@ public:
     void EnableNetworkNotifications();
     void DisableNetworkNotifications();
 
     void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect);
     void SetPageRect(const gfx::Rect& aCssPageRect);
     void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                           gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY);
+    void SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect,
+                          bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
+                          bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY);
 
     void AddPluginView(jobject view, const gfxRect& rect, bool isFullScreen);
     void RemovePluginView(jobject view, bool isFullScreen);
 
     // These methods don't use a ScreenOrientation because it's an
     // enum and that would require including the header which requires
     // include IPC headers which requires including basictypes.h which
     // requires a lot of changes...
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -84,16 +84,17 @@ jmethodID AndroidLocation::jGetSpeedMeth
 jmethodID AndroidLocation::jGetTimeMethod = 0;
 
 jclass AndroidGeckoLayerClient::jGeckoLayerClientClass = 0;
 jclass AndroidGeckoLayerClient::jViewportClass = 0;
 jclass AndroidGeckoLayerClient::jDisplayportClass = 0;
 jmethodID AndroidGeckoLayerClient::jSetFirstPaintViewport = 0;
 jmethodID AndroidGeckoLayerClient::jSetPageRect = 0;
 jmethodID AndroidGeckoLayerClient::jSyncViewportInfoMethod = 0;
+jmethodID AndroidGeckoLayerClient::jSyncFrameMetricsMethod = 0;
 jmethodID AndroidGeckoLayerClient::jCreateFrameMethod = 0;
 jmethodID AndroidGeckoLayerClient::jActivateProgramMethod = 0;
 jmethodID AndroidGeckoLayerClient::jDeactivateProgramMethod = 0;
 jmethodID AndroidGeckoLayerClient::jGetDisplayPort = 0;
 jmethodID AndroidGeckoLayerClient::jViewportCtor = 0;
 jfieldID AndroidGeckoLayerClient::jDisplayportPosition = 0;
 jfieldID AndroidGeckoLayerClient::jDisplayportResolution = 0;
 jmethodID AndroidGeckoLayerClient::jProgressiveUpdateCallbackMethod = 0;
@@ -344,16 +345,18 @@ AndroidGeckoLayerClient::InitGeckoLayerC
     initInit();
 
     jGeckoLayerClientClass = getClassGlobalRef("org/mozilla/gecko/gfx/GeckoLayerClient");
 
     jSetFirstPaintViewport = getMethod("setFirstPaintViewport", "(FFFFFFFFFFF)V");
     jSetPageRect = getMethod("setPageRect", "(FFFF)V");
     jSyncViewportInfoMethod = getMethod("syncViewportInfo",
                                         "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
+    jSyncFrameMetricsMethod = getMethod("syncFrameMetrics",
+                                        "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
     jCreateFrameMethod = getMethod("createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
     jActivateProgramMethod = getMethod("activateProgram", "()V");
     jDeactivateProgramMethod = getMethod("deactivateProgram", "()V");
     jGetDisplayPort = getMethod("getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;");
 
     jViewportClass = GetClassGlobalRef(jEnv, "org/mozilla/gecko/gfx/ImmutableViewportMetrics");
     jViewportCtor = GetMethodID(jEnv, jViewportClass, "<init>", "(FFFFFFFFFFFFF)V");
 
@@ -906,16 +909,52 @@ AndroidGeckoLayerClient::SyncViewportInf
     aScrollOffset = nsIntPoint(viewTransform.GetX(env), viewTransform.GetY(env));
     aScaleX = aScaleY = viewTransform.GetScale(env);
     viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins);
 
     aOffsetX = viewTransform.GetOffsetX(env);
     aOffsetY = viewTransform.GetOffsetY(env);
 }
 
+void
+AndroidGeckoLayerClient::SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect,
+                                          bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
+                                          bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY)
+{
+    NS_ASSERTION(!isNull(), "SyncFrameMetrics called on null layer client!");
+    JNIEnv *env = GetJNIForThread();    // this is called on the compositor thread
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env);
+
+    // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels
+    int dpX = NS_lround((aDisplayPort.x * aDisplayResolution) + aOffset.x);
+    int dpY = NS_lround((aDisplayPort.y * aDisplayResolution) + aOffset.y);
+    int dpW = NS_lround(aDisplayPort.width * aDisplayResolution);
+    int dpH = NS_lround(aDisplayPort.height * aDisplayResolution);
+
+    jobject viewTransformJObj = env->CallObjectMethod(wrapped_obj, jSyncFrameMetricsMethod,
+            aOffset.x, aOffset.y, aZoom,
+            aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
+            aLayersUpdated, dpX, dpY, dpW, dpH, aDisplayResolution,
+            aIsFirstPaint);
+
+    if (jniFrame.CheckForException())
+        return;
+
+    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
+
+    AndroidViewTransform viewTransform;
+    viewTransform.Init(viewTransformJObj);
+    viewTransform.GetFixedLayerMargins(env, aFixedLayerMargins);
+    aOffsetX = viewTransform.GetOffsetX(env);
+    aOffsetY = viewTransform.GetOffsetY(env);
+}
+
 bool
 AndroidGeckoLayerClient::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
                                                    const gfx::Rect& aDisplayPort,
                                                    float aDisplayResolution,
                                                    bool aDrawingCritical,
                                                    gfx::Rect& aViewport,
                                                    float& aScaleX,
                                                    float& aScaleY)
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -267,27 +267,31 @@ public:
     AndroidGeckoLayerClient() {}
     AndroidGeckoLayerClient(jobject jobj) { Init(jobj); }
 
     void SetFirstPaintViewport(const nsIntPoint& aOffset, float aZoom, const nsIntRect& aPageRect, const gfx::Rect& aCssPageRect);
     void SetPageRect(const gfx::Rect& aCssPageRect);
     void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated,
                           nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY,
                           gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY);
+    void SyncFrameMetrics(const gfx::Point& aOffset, float aZoom, const gfx::Rect& aCssPageRect,
+                          bool aLayersUpdated, const gfx::Rect& aDisplayPort, float aDisplayResolution,
+                          bool aIsFirstPaint, gfx::Margin& aFixedLayerMargins, float& aOffsetX, float& aOffsetY);
     bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const gfx::Rect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY);
     bool CreateFrame(AutoLocalJNIFrame *jniFrame, AndroidLayerRendererFrame& aFrame);
     bool ActivateProgram(AutoLocalJNIFrame *jniFrame);
     bool DeactivateProgram(AutoLocalJNIFrame *jniFrame);
     void GetDisplayPort(AutoLocalJNIFrame *jniFrame, bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
 
 protected:
     static jclass jGeckoLayerClientClass;
     static jmethodID jSetFirstPaintViewport;
     static jmethodID jSetPageRect;
     static jmethodID jSyncViewportInfoMethod;
+    static jmethodID jSyncFrameMetricsMethod;
     static jmethodID jCreateFrameMethod;
     static jmethodID jActivateProgramMethod;
     static jmethodID jDeactivateProgramMethod;
     static jmethodID jGetDisplayPort;
     static jmethodID jProgressiveUpdateCallbackMethod;
 
 public:
     static jclass jViewportClass;
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2486,16 +2486,34 @@ public:
         CompositorParent::ShadowLayersUpdated(aLayerTree, aTargetConfig, isFirstPaint);
         Layer* targetLayer = GetLayerManager()->GetPrimaryScrollableLayer();
         AsyncPanZoomController* controller = nsWindow::GetPanZoomController();
         if (targetLayer && targetLayer->AsContainerLayer() && controller) {
             targetLayer->SetAsyncPanZoomController(controller);
             controller->NotifyLayersUpdated(targetLayer->AsContainerLayer()->GetFrameMetrics(), isFirstPaint);
         }
     }
+
+    virtual void SyncFrameMetrics(Layer* aLayer, const ViewTransform& aTreeTransform,
+                                  const gfxPoint& aScrollOffset, mozilla::gfx::Margin& aFixedLayerMargins,
+                                  float& aOffsetX, float& aOffsetY,
+                                  bool aIsFirstPaint, bool aLayersUpdated) MOZ_OVERRIDE
+    {
+        const gfx3DMatrix& rootTransform = GetLayerManager()->GetRoot()->GetTransform();
+        ContainerLayer* container = aLayer->AsContainerLayer();
+        const FrameMetrics& metrics = container->GetFrameMetrics();
+
+        mozilla::gfx::Rect displayPortLayersPixels(metrics.mCriticalDisplayPort.IsEmpty() ?
+                                          metrics.mDisplayPort : metrics.mCriticalDisplayPort);
+        mozilla::gfx::Point scrollOffset(aScrollOffset.x, aScrollOffset.y);
+
+        AndroidBridge::Bridge()->SyncFrameMetrics(scrollOffset, aTreeTransform.mScale.width, metrics.mScrollableRect,
+                                                  aLayersUpdated, displayPortLayersPixels, 1 / rootTransform.GetXScale(),
+                                                  aIsFirstPaint, aFixedLayerMargins, aOffsetX, aOffsetY);
+    }
 };
 
 CompositorParent*
 nsWindow::NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight)
 {
     return new AndroidCompositorParent(this, true, aSurfaceWidth, aSurfaceHeight);
 }