Bug 1242690 - If a drag block is interrupted by something else, have it create a new drag block when it resumes. r=rbarker
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 10 Mar 2016 18:25:49 -0500
changeset 288131 26bc425fa2a95bd7ad65a6352b39f8c592fc59ac
parent 288130 415cd146145d23bc386f196cb5b1f8f692376d3a
child 288132 6c37fd20f04d5bb5efb70cdafdebfee1f7aae6dc
push id73317
push userkgupta@mozilla.com
push dateThu, 10 Mar 2016 23:26:59 +0000
treeherdermozilla-inbound@1d931aacb061 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrbarker
bugs1242690
milestone48.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 1242690 - If a drag block is interrupted by something else, have it create a new drag block when it resumes. r=rbarker MozReview-Commit-ID: K06S3X5XEej
gfx/layers/apz/src/DragTracker.cpp
gfx/layers/apz/src/DragTracker.h
gfx/layers/apz/src/InputQueue.cpp
gfx/layers/apz/src/InputQueue.h
gfx/layers/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/DragTracker.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DragTracker.h"
+
+#include "InputData.h"
+
+namespace mozilla {
+namespace layers {
+
+DragTracker::DragTracker()
+  : mInDrag(false)
+{
+}
+
+/*static*/ bool
+DragTracker::StartsDrag(const MouseInput& aInput)
+{
+  return aInput.IsLeftButton() && aInput.mType == MouseInput::MOUSE_DOWN;
+}
+
+/*static*/ bool
+DragTracker::EndsDrag(const MouseInput& aInput)
+{
+  return aInput.IsLeftButton() && aInput.mType == MouseInput::MOUSE_UP;
+}
+
+void
+DragTracker::Update(const MouseInput& aInput)
+{
+  if (StartsDrag(aInput)) {
+    mInDrag = true;
+  } else if (EndsDrag(aInput)) {
+    mInDrag = false;
+  }
+}
+
+bool
+DragTracker::InDrag() const
+{
+  return mInDrag;
+}
+
+} // namespace layers
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/DragTracker.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_layers_DragTracker_h
+#define mozilla_layers_DragTracker_h
+
+#include "mozilla/EventForwards.h"
+
+namespace mozilla {
+
+class MouseInput;
+
+namespace layers {
+
+// DragTracker simply tracks a sequence of mouse inputs and allows us to tell
+// if we are in a drag or not (i.e. the left mouse button went down and hasn't
+// gone up yet).
+class DragTracker
+{
+public:
+  DragTracker();
+  static bool StartsDrag(const MouseInput& aInput);
+  static bool EndsDrag(const MouseInput& aInput);
+  void Update(const MouseInput& aInput);
+  bool InDrag() const;
+
+private:
+  bool mInDrag;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif /* mozilla_layers_DragTracker_h */
--- a/gfx/layers/apz/src/InputQueue.cpp
+++ b/gfx/layers/apz/src/InputQueue.cpp
@@ -180,27 +180,37 @@ nsEventStatus
 InputQueue::ReceiveMouseInput(const RefPtr<AsyncPanZoomController>& aTarget,
                               bool aTargetConfirmed,
                               const MouseInput& aEvent,
                               uint64_t* aOutInputBlockId) {
   MOZ_ASSERT(!aTargetConfirmed); // We wont know the target until content tells us
 
   // On a new mouse down we can have a new target so we must force a new block
   // with a new target.
-  bool newBlock = aEvent.mType == MouseInput::MOUSE_DOWN && aEvent.IsLeftButton();
+  bool newBlock = DragTracker::StartsDrag(aEvent);
 
   DragBlockState* block = nullptr;
   if (!newBlock && !mInputBlockQueue.IsEmpty()) {
     block = mInputBlockQueue.LastElement()->AsDragBlock();
   }
 
   if (block && block->HasReceivedMouseUp()) {
     block = nullptr;
   }
 
+  if (!block && mDragTracker.InDrag()) {
+    // If there's no current drag block, but we're getting a move with a button
+    // down, we need to start a new drag block because we're obviously already
+    // in the middle of a drag (it probably got interrupted by something else).
+    INPQ_LOG("got a drag event outside a drag block, need to create a block to hold it\n");
+    newBlock = true;
+  }
+
+  mDragTracker.Update(aEvent);
+
   if (!newBlock && !block) {
     return nsEventStatus_eConsumeDoDefault;
   }
 
   if (!block) {
     MOZ_ASSERT(newBlock);
     block = new DragBlockState(aTarget, aTargetConfirmed, aEvent);
     if (aOutInputBlockId) {
@@ -225,18 +235,17 @@ InputQueue::ReceiveMouseInput(const RefP
   if (aOutInputBlockId) {
     *aOutInputBlockId = block->GetBlockId();
   }
 
   if (!MaybeHandleCurrentBlock(block, aEvent)) {
     block->AddEvent(aEvent.AsMouseInput());
   }
 
-  bool mouseUp = aEvent.mType == MouseInput::MOUSE_UP && aEvent.IsLeftButton();
-  if (mouseUp) {
+  if (DragTracker::EndsDrag(aEvent)) {
     block->MarkMouseUpReceived();
   }
 
   // If we're not the first event then we need to wait for the confirmation of
   // the block.
   return nsEventStatus_eConsumeDoDefault;
 }
 
--- a/gfx/layers/apz/src/InputQueue.h
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_layers_InputQueue_h
 #define mozilla_layers_InputQueue_h
 
 #include "APZUtils.h"
+#include "DragTracker.h"
 #include "InputData.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 
@@ -177,14 +178,17 @@ private:
   // This member must only be accessed on the controller/UI thread.
   nsTArray<UniquePtr<CancelableBlockState>> mInputBlockQueue;
 
   // The APZC to which the last event was delivered
   RefPtr<AsyncPanZoomController> mLastActiveApzc;
 
   // Track touches so we know when to clear mLastActiveApzc
   TouchCounter mTouchCounter;
+
+  // Track mouse inputs so we know if we're in a drag or not
+  DragTracker mDragTracker;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_InputQueue_h
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -254,16 +254,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
         'ipc/ShadowLayerUtilsGralloc.cpp',
     ]
 
 UNIFIED_SOURCES += [
     'apz/src/APZCTreeManager.cpp',
     'apz/src/AsyncPanZoomController.cpp',
     'apz/src/Axis.cpp',
     'apz/src/CheckerboardEvent.cpp',
+    'apz/src/DragTracker.cpp',
     'apz/src/GestureEventListener.cpp',
     'apz/src/HitTestingTreeNode.cpp',
     'apz/src/InputBlockState.cpp',
     'apz/src/InputQueue.cpp',
     'apz/src/OverscrollHandoffState.cpp',
     'apz/src/PotentialCheckerboardDurationTracker.cpp',
     'apz/src/TouchCounter.cpp',
     'apz/src/WheelScrollAnimation.cpp',