Bug 1074401 - Ensure that the repaint request is always dispatched from the APZ on the main thread. r=botond, a=bajaj
authorKartikaya Gupta <kgupta@mozilla.com>
Fri, 03 Oct 2014 13:39:37 -0400
changeset 225456 4b7d0647fee6de4e5b49460157fd63d62fe419d6
parent 225455 b2c303ec106a6c4928e5f8837cfa00c6c813b3c5
child 225457 4b8e5cb2bbf5e3133b23efcfcc03badf44a8437a
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, bajaj
bugs1074401
milestone34.0a2
Bug 1074401 - Ensure that the repaint request is always dispatched from the APZ on the main thread. r=botond, a=bajaj
gfx/layers/apz/public/GeckoContentController.h
gfx/layers/apz/src/AsyncPanZoomController.cpp
layout/ipc/RenderFrameParent.cpp
widget/android/APZCCallbackHandler.cpp
widget/cocoa/nsChildView.mm
widget/gonk/ParentProcessController.cpp
widget/windows/winrt/APZController.cpp
--- a/gfx/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -20,16 +20,17 @@ namespace layers {
 class GeckoContentController
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoContentController)
 
   /**
    * Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
    * Implementations per-platform are responsible for actually handling this.
+   * This method will always be called on the Gecko main thread.
    */
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
 
   /**
    * Acknowledges the recipt of a scroll offset update for the scrollable
    * frame with the given scroll id. This is used to maintain consistency
    * between APZ and other sources of scroll changes.
    */
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -2142,17 +2142,22 @@ GetDisplayPortRect(const FrameMetrics& a
 
 void
 AsyncPanZoomController::DispatchRepaintRequest(const FrameMetrics& aFrameMetrics) {
   nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
   if (controller) {
     APZC_LOG_FM(aFrameMetrics, "%p requesting content repaint", this);
     LogRendertraceRect(GetGuid(), "requested displayport", "yellow", GetDisplayPortRect(aFrameMetrics));
 
-    controller->RequestContentRepaint(aFrameMetrics);
+    if (NS_IsMainThread()) {
+      controller->RequestContentRepaint(aFrameMetrics);
+    } else {
+      NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
+        controller, &GeckoContentController::RequestContentRepaint, aFrameMetrics));
+    }
     mLastDispatchedPaintMetrics = aFrameMetrics;
   }
 }
 
 void
 AsyncPanZoomController::FireAsyncScrollOnTimeout()
 {
   if (mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -81,22 +81,21 @@ public:
   explicit RemoteContentController(RenderFrameParent* aRenderFrame)
     : mUILoop(MessageLoop::current())
     , mRenderFrame(aRenderFrame)
     , mHaveZoomConstraints(false)
   { }
 
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) MOZ_OVERRIDE
   {
-    // We always need to post requests into the "UI thread" otherwise the
-    // requests may get processed out of order.
-    mUILoop->PostTask(
-      FROM_HERE,
-      NewRunnableMethod(this, &RemoteContentController::DoRequestContentRepaint,
-                        aFrameMetrics));
+    MOZ_ASSERT(NS_IsMainThread());
+    if (mRenderFrame) {
+      TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
+      browser->UpdateFrame(aFrameMetrics);
+    }
   }
 
   virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                        const uint32_t& aScrollGeneration) MOZ_OVERRIDE
   {
     if (MessageLoop::current() != mUILoop) {
       // We have to send this message from the "UI thread" (main
       // thread).
@@ -256,24 +255,16 @@ public:
     mZoomConstraints = aConstraints;
   }
 
   void SetTouchSensitiveRegion(const nsRegion& aRegion)
   {
     mTouchSensitiveRegion = aRegion;
   }
 private:
-  void DoRequestContentRepaint(const FrameMetrics& aFrameMetrics)
-  {
-    if (mRenderFrame) {
-      TabParent* browser = static_cast<TabParent*>(mRenderFrame->Manager());
-      browser->UpdateFrame(aFrameMetrics);
-    }
-  }
-
   MessageLoop* mUILoop;
   RenderFrameParent* mRenderFrame;
 
   bool mHaveZoomConstraints;
   ZoomConstraints mZoomConstraints;
   nsRegion mTouchSensitiveRegion;
 };
 
--- a/widget/android/APZCCallbackHandler.cpp
+++ b/widget/android/APZCCallbackHandler.cpp
@@ -77,22 +77,16 @@ APZCCallbackHandler::GetDOMWindowUtils()
     }
     nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
     return utils.get();
 }
 
 void
 APZCCallbackHandler::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
 {
-    if (!NS_IsMainThread()) {
-        NS_DispatchToMainThread(NS_NewRunnableMethodWithArg<FrameMetrics>(
-            this, &APZCCallbackHandler::RequestContentRepaint, aFrameMetrics));
-        return;
-    }
-
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aFrameMetrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID);
 
     if (aFrameMetrics.GetIsRoot()) {
         nsIDOMWindowUtils* utils = GetDOMWindowUtils();
         if (utils && APZCCallbackHelper::HasValidPresShellId(utils, aFrameMetrics)) {
             FrameMetrics metrics = aFrameMetrics;
             APZCCallbackHelper::UpdateRootFrame(utils, metrics);
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -390,48 +390,26 @@ protected:
   GLuint mQuadVBO;
 };
 
 class APZCTMController : public mozilla::layers::GeckoContentController
 {
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
 
-  class RequestContentRepaintEvent : public nsRunnable
-  {
-  public:
-    explicit RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics)
-      : mFrameMetrics(aFrameMetrics)
-    {
-    }
-
-    NS_IMETHOD Run()
-    {
-      MOZ_ASSERT(NS_IsMainThread());
-
-      nsCOMPtr<nsIContent> targetContent = nsLayoutUtils::FindContentFor(mFrameMetrics.GetScrollId());
-      if (targetContent) {
-        APZCCallbackHelper::UpdateSubFrame(targetContent, mFrameMetrics);
-      }
-
-      return NS_OK;
-    }
-  protected:
-    FrameMetrics mFrameMetrics;
-  };
-
 public:
   // GeckoContentController interface
   virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics)
   {
-    nsCOMPtr<nsIRunnable> r1 = new RequestContentRepaintEvent(aFrameMetrics);
-    if (!NS_IsMainThread()) {
-      NS_DispatchToMainThread(r1);
-    } else {
-      r1->Run();
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIContent> targetContent = nsLayoutUtils::FindContentFor(aFrameMetrics.GetScrollId());
+    if (targetContent) {
+      FrameMetrics metrics = aFrameMetrics;
+      APZCCallbackHelper::UpdateSubFrame(targetContent, metrics);
     }
   }
 
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) MOZ_OVERRIDE
   {
     MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
   }
 
--- a/widget/gonk/ParentProcessController.cpp
+++ b/widget/gonk/ParentProcessController.cpp
@@ -7,51 +7,29 @@
 #include "nsIContent.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "base/message_loop.h"
 
 namespace mozilla {
 namespace widget {
 
-class RequestContentRepaintEvent : public nsRunnable
-{
-    typedef mozilla::layers::FrameMetrics FrameMetrics;
-
-public:
-    RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics)
-        : mFrameMetrics(aFrameMetrics)
-    {
-    }
-
-    NS_IMETHOD Run() {
-        MOZ_ASSERT(NS_IsMainThread());
-        nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mFrameMetrics.GetScrollId());
-        if (content) {
-            mozilla::layers::APZCCallbackHelper::UpdateSubFrame(content, mFrameMetrics);
-        }
-        return NS_OK;
-    }
-
-protected:
-    FrameMetrics mFrameMetrics;
-};
-
 void
 ParentProcessController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
 {
+    MOZ_ASSERT(NS_IsMainThread());
+
     if (aFrameMetrics.GetScrollId() == FrameMetrics::NULL_SCROLL_ID) {
         return;
     }
 
-    nsCOMPtr<nsIRunnable> r = new RequestContentRepaintEvent(aFrameMetrics);
-    if (!NS_IsMainThread()) {
-        NS_DispatchToMainThread(r);
-    } else {
-        r->Run();
+    nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(aFrameMetrics.GetScrollId());
+    if (content) {
+        FrameMetrics metrics = aFrameMetrics;
+        mozilla::layers::APZCCallbackHelper::UpdateSubFrame(content, metrics);
     }
 }
 
 void
 ParentProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                                  const uint32_t& aScrollGeneration)
 {
     mozilla::layers::APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
--- a/widget/windows/winrt/APZController.cpp
+++ b/widget/windows/winrt/APZController.cpp
@@ -74,80 +74,16 @@ GetDOMTargets(uint64_t aScrollId,
   // a document, vs. an element within a document.
   if (aSubDocument->GetRootElement() == domElement && IsTab(aSubDocument)) {
     aTargetContent = nullptr;
   }
 
   return true;
 }
 
-class RequestContentRepaintEvent : public nsRunnable
-{
-  typedef mozilla::layers::FrameMetrics FrameMetrics;
-
-public:
-  RequestContentRepaintEvent(const FrameMetrics& aFrameMetrics) :
-    mFrameMetrics(aFrameMetrics)
-  {
-  }
-
-  NS_IMETHOD Run() {
-    // This must be on the gecko thread since we access the dom
-    MOZ_ASSERT(NS_IsMainThread());
-
-#ifdef DEBUG_CONTROLLER
-    WinUtils::Log("APZController: mScrollOffset: %f %f", mFrameMetrics.mScrollOffset.x,
-      mFrameMetrics.mScrollOffset.y);
-#endif
-
-    nsCOMPtr<nsIDocument> subDocument;
-    nsCOMPtr<nsIContent> targetContent;
-    if (!GetDOMTargets(mFrameMetrics.GetScrollId(),
-                       subDocument, targetContent)) {
-      return NS_OK;
-    }
-
-    // If we're dealing with a sub frame or content editable element,
-    // call UpdateSubFrame.
-    if (targetContent) {
-#ifdef DEBUG_CONTROLLER
-      WinUtils::Log("APZController: detected subframe or content editable");
-#endif
-      mozilla::layers::APZCCallbackHelper::UpdateSubFrame(targetContent, mFrameMetrics);
-      return NS_OK;
-    }
-
-#ifdef DEBUG_CONTROLLER
-    WinUtils::Log("APZController: detected tab");
-#endif
-
-    // We're dealing with a tab, call UpdateRootFrame.
-    nsCOMPtr<nsIDOMWindowUtils> utils;
-    nsCOMPtr<nsIDOMWindow> window = subDocument->GetDefaultView();
-    if (window) {
-      utils = do_GetInterface(window);
-      if (utils) {
-        mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, mFrameMetrics);
-
-#ifdef DEBUG_CONTROLLER
-        WinUtils::Log("APZController: %I64d mDisplayPortMargins: %0.2f %0.2f %0.2f %0.2f",
-          mFrameMetrics.GetScrollId(),
-          mFrameMetrics.GetDisplayPortMargins().left,
-          mFrameMetrics.GetDisplayPortMargins().top,
-          mFrameMetrics.GetDisplayPortMargins().right,
-          mFrameMetrics.GetDisplayPortMargins().bottom);
-#endif
-      }
-    }
-    return NS_OK;
-  }
-protected:
-  FrameMetrics mFrameMetrics;
-};
-
 void
 APZController::SetPendingResponseFlusher(APZPendingResponseFlusher* aFlusher)
 {
   mFlusher = aFlusher;
 }
 
 void
 APZController::ContentReceivedTouch(const ScrollableLayerGuid& aGuid, bool aPreventDefault)
@@ -193,21 +129,65 @@ APZController::ReceiveInputEvent(WidgetI
 // the scrollable frame the apzc is managing.
 void
 APZController::RequestContentRepaint(const FrameMetrics& aFrameMetrics)
 {
 #ifdef DEBUG_CONTROLLER
   WinUtils::Log("APZController::RequestContentRepaint scrollid=%I64d",
     aFrameMetrics.GetScrollId());
 #endif
-  nsCOMPtr<nsIRunnable> r1 = new RequestContentRepaintEvent(aFrameMetrics);
-  if (!NS_IsMainThread()) {
-    NS_DispatchToMainThread(r1);
-  } else {
-    r1->Run();
+
+  // This must be on the gecko thread since we access the dom
+  MOZ_ASSERT(NS_IsMainThread());
+
+#ifdef DEBUG_CONTROLLER
+  WinUtils::Log("APZController: mScrollOffset: %f %f", aFrameMetrics.mScrollOffset.x,
+    aFrameMetrics.mScrollOffset.y);
+#endif
+
+  nsCOMPtr<nsIDocument> subDocument;
+  nsCOMPtr<nsIContent> targetContent;
+  if (!GetDOMTargets(aFrameMetrics.GetScrollId(),
+                     subDocument, targetContent)) {
+    return NS_OK;
+  }
+
+  // If we're dealing with a sub frame or content editable element,
+  // call UpdateSubFrame.
+  if (targetContent) {
+#ifdef DEBUG_CONTROLLER
+    WinUtils::Log("APZController: detected subframe or content editable");
+#endif
+    FrameMetrics metrics = aFrameMetrics;
+    mozilla::layers::APZCCallbackHelper::UpdateSubFrame(targetContent, metrics);
+    return NS_OK;
+  }
+
+#ifdef DEBUG_CONTROLLER
+  WinUtils::Log("APZController: detected tab");
+#endif
+
+  // We're dealing with a tab, call UpdateRootFrame.
+  nsCOMPtr<nsIDOMWindowUtils> utils;
+  nsCOMPtr<nsIDOMWindow> window = subDocument->GetDefaultView();
+  if (window) {
+    utils = do_GetInterface(window);
+    if (utils) {
+      FrameMetrics metrics = aFrameMetrics;
+      mozilla::layers::APZCCallbackHelper::UpdateRootFrame(utils, metrics);
+
+#ifdef DEBUG_CONTROLLER
+      WinUtils::Log("APZController: %I64d mDisplayPortMargins: %0.2f %0.2f %0.2f %0.2f",
+        metrics.GetScrollId(),
+        metrics.GetDisplayPortMargins().left,
+        metrics.GetDisplayPortMargins().top,
+        metrics.GetDisplayPortMargins().right,
+        metrics.GetDisplayPortMargins().bottom);
+#endif
+    }
   }
 }
 
 void
 APZController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
                                        const uint32_t& aScrollGeneration)
 {
 #ifdef DEBUG_CONTROLLER