Bug 1193062 - Don't double-send target APZC confirmations that might race each other. r=kats
authorMarkus Stange <mstange@themasta.com>
Tue, 11 Aug 2015 16:51:46 -0400
changeset 259463 895278844d2cf93a9ef9f433c06fa75c30a51f23
parent 259462 29850f2b5708117911eabe11d6fb6854468dcdc7
child 259464 7fa5473a3593793c6efe74bafb125b94f40fd486
push idunknown
push userunknown
push dateunknown
reviewerskats
bugs1193062
milestone43.0a1
Bug 1193062 - Don't double-send target APZC confirmations that might race each other. r=kats When scrolling an inactive subframe, the target APZC confirmation needs to be sent along with the layers transaction. If a new wheel event comes in while that target APZC notification is in-flight, the subframe will already have a display port, so the confirmation will be sent in a more direct fashion and can arrive at the APZ controller thread before the new APZC for the scroll frame has been created. Then the current input block will have a null target APZC and no scrolling will happen until a new input block is created. (For wheel transactions, a null target APZC ends the transaction, so the next event will create a new input block.)
gfx/layers/apz/util/APZCCallbackHelper.cpp
gfx/layers/apz/util/APZCCallbackHelper.h
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -5,16 +5,17 @@
 
 #include "APZCCallbackHelper.h"
 
 #include "ContentHelper.h"
 #include "gfxPlatform.h" // For gfxPlatform::UseTiling
 #include "gfxPrefs.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/TabParent.h"
+#include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/layers/LayerTransactionChild.h"
 #include "mozilla/layers/ShadowLayers.h"
 #include "mozilla/TouchEvents.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
@@ -27,16 +28,18 @@
 #define APZCCH_LOG(...)
 // #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 using dom::TabParent;
 
+uint64_t APZCCallbackHelper::sLastTargetAPZCNotificationInputBlock = uint64_t(-1);
+
 static void
 AdjustDisplayPortForScrollDelta(mozilla::layers::FrameMetrics& aFrameMetrics,
                                 const CSSPoint& aActualScrollOffset)
 {
     // Correct the display-port by the difference between the requested scroll
     // offset and the resulting scroll offset after setting the requested value.
     ScreenPoint shift =
         (aFrameMetrics.GetScrollOffset() - aActualScrollOffset) *
@@ -736,16 +739,26 @@ APZCCallbackHelper::SendSetTargetAPZCNot
                                                   nsIDocument* aDocument,
                                                   const WidgetGUIEvent& aEvent,
                                                   const ScrollableLayerGuid& aGuid,
                                                   uint64_t aInputBlockId)
 {
   if (!aWidget || !aDocument) {
     return;
   }
+  if (aInputBlockId == sLastTargetAPZCNotificationInputBlock) {
+    // We have already confirmed the target APZC for a previous event of this
+    // input block. If we activated a scroll frame for this input block,
+    // sending another target APZC confirmation would be harmful, as it might
+    // race the original confirmation (which needs to go through a layers
+    // transaction).
+    APZCCH_LOG("Not resending target APZC confirmation for input block %" PRIu64 "\n", aInputBlockId);
+    return;
+  }
+  sLastTargetAPZCNotificationInputBlock = aInputBlockId;
   if (nsIPresShell* shell = aDocument->GetShell()) {
     if (nsIFrame* rootFrame = shell->GetRootFrame()) {
       bool waitForRefresh = false;
       nsTArray<ScrollableLayerGuid> targets;
 
       if (const WidgetTouchEvent* touchEvent = aEvent.AsTouchEvent()) {
         for (size_t i = 0; i < touchEvent->touches.Length(); i++) {
           waitForRefresh |= PrepareForSetTargetAPZCNotification(aWidget, aGuid,
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -168,14 +168,17 @@ public:
     static void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent);
 
     /* Notify content that the repaint flush is complete. */
     static void NotifyFlushComplete();
 
     /* Temporarily ignore the Displayport for better paint performance. */
     static void SuppressDisplayport(const bool& aEnabled);
     static bool IsDisplayportSuppressed();
+
+private:
+  static uint64_t sLastTargetAPZCNotificationInputBlock;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* mozilla_layers_APZCCallbackHelper_h */