Bug 953012 - Opening a new tab using the overlay while a website is loading creates two about:start tabs r=jimm
☠☠ backed out by 48680af02f8f ☠ ☠
authorRodrigo Silveira <rsilveira@mozilla.com>
Wed, 26 Feb 2014 21:42:49 -0800
changeset 173066 c6fc27e68f455521abf328b28555c1ed97556160
parent 173065 f25fb5db8893f3dec09a66c00ded2d546356335b
child 173067 3c9c98992742be0349f65c340fdf53057b2c4fa1
push id5594
push userrsilveira@mozilla.com
push dateTue, 11 Mar 2014 20:46:01 +0000
treeherderfx-team@c6fc27e68f45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs953012
milestone30.0a1
Bug 953012 - Opening a new tab using the overlay while a website is loading creates two about:start tabs r=jimm
widget/windows/winrt/MetroInput.cpp
widget/windows/winrt/MetroInput.h
--- a/widget/windows/winrt/MetroInput.cpp
+++ b/widget/windows/winrt/MetroInput.cpp
@@ -9,25 +9,23 @@
 #include "MetroWidget.h" // MetroInput::mWidget
 #include "mozilla/dom/Touch.h"  // Touch
 #include "nsTArray.h" // Touch lists
 #include "nsIDOMSimpleGestureEvent.h" // Constants for gesture events
 #include "InputData.h"
 #include "UIABridgePrivate.h"
 #include "MetroAppShell.h"
 #include "mozilla/MouseEvents.h"
-#include "mozilla/TouchEvents.h"
 #include "mozilla/Preferences.h"  // for Preferences
 #include "WinUtils.h"
 #include "nsIPresShell.h"
 #include "nsEventStateManager.h"
 
 // System headers (alphabetical)
 #include <windows.ui.core.h> // ABI::Window::UI::Core namespace
-#include <windows.ui.input.h> // ABI::Window::UI::Input namespace
 
 //#define DEBUG_INPUT
 
 // Using declarations
 using namespace ABI::Windows; // UI, System, Foundation namespaces
 using namespace Microsoft; // WRL namespace (ComPtr, possibly others)
 using namespace mozilla;
 using namespace mozilla::widget;
@@ -233,30 +231,16 @@ namespace {
                aData->mRotationAngle,
                aData->mForce);
     copy->tiltX = aData->tiltX;
     copy->tiltY = aData->tiltY;
     touches->AppendElement(copy);
     aData->mChanged = false;
     return PL_DHASH_NEXT;
   }
-
-  // Helper for making sure event ptrs get freed.
-  class AutoDeleteEvent
-  {
-  public:
-    AutoDeleteEvent(WidgetGUIEvent* aPtr) :
-      mPtr(aPtr) {}
-    ~AutoDeleteEvent() {
-      if (mPtr) {
-        delete mPtr;
-      }
-    }
-    WidgetGUIEvent* mPtr;
-  };
 }
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 
 MetroInput::InputPrecisionLevel MetroInput::sCurrentInputLevel =
   MetroInput::InputPrecisionLevel::LEVEL_IMPRECISE;
@@ -535,39 +519,39 @@ MetroInput::IsTouchBehaviorForbidden(con
 HRESULT
 MetroInput::OnPointerPressed(UI::Core::ICoreWindow* aSender,
                              UI::Core::IPointerEventArgs* aArgs)
 {
 #ifdef DEBUG_INPUT
   LogFunction();
 #endif
 
-  WRL::ComPtr<UI::Input::IPointerPoint> currentPoint;
+  UI::Input::IPointerPoint* currentPoint;
   WRL::ComPtr<Devices::Input::IPointerDevice> device;
   Devices::Input::PointerDeviceType deviceType;
 
-  aArgs->get_CurrentPoint(currentPoint.GetAddressOf());
+  aArgs->get_CurrentPoint(&currentPoint);
   currentPoint->get_PointerDevice(device.GetAddressOf());
   device->get_PointerDeviceType(&deviceType);
 
   // For mouse and pen input, simply call our helper function
   if (deviceType !=
           Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
-    OnPointerNonTouch(currentPoint.Get());
-    mGestureRecognizer->ProcessDownEvent(currentPoint.Get());
+    OnPointerNonTouch(currentPoint);
+    mGestureRecognizer->ProcessDownEvent(currentPoint);
     return S_OK;
   }
 
   // This is touch input.
   UpdateInputLevel(LEVEL_IMPRECISE);
 
   // Create the new touch point and add it to our event.
   uint32_t pointerId;
   currentPoint->get_PointerId(&pointerId);
-  nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint.Get());
+  nsRefPtr<Touch> touch = CreateDOMTouch(currentPoint);
   touch->mChanged = true;
   mTouches.Put(pointerId, touch);
 
   WidgetTouchEvent* touchEvent =
     new WidgetTouchEvent(true, NS_TOUCH_START, mWidget.Get());
 
   if (mTouches.Count() == 1) {
     // If this is the first touchstart of a touch session reset some
@@ -577,35 +561,41 @@ MetroInput::OnPointerPressed(UI::Core::I
     mRecognizerWantsEvents = true;
     mCancelable = true;
     mCanceledIds.Clear();
   } else {
     mCancelable = false;
   }
 
   InitTouchEventTouchList(touchEvent);
-  DispatchAsyncTouchEvent(touchEvent);
+  DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, currentPoint));
 
-  if (ShouldDeliverInputToRecognizer()) {
-    mGestureRecognizer->ProcessDownEvent(currentPoint.Get());
-  }
   return S_OK;
 }
 
 void
-MetroInput::AddPointerMoveDataToRecognizer(UI::Core::IPointerEventArgs* aArgs)
+MetroInput::AddPointerMoveDataToRecognizer(IPointerEventArgs* aArgs)
 {
   if (ShouldDeliverInputToRecognizer()) {
-    WRL::ComPtr<Foundation::Collections::IVector<UI::Input::PointerPoint*>>
-        pointerPoints;
+    WRL::ComPtr<PointerPointVector> pointerPoints;
     aArgs->GetIntermediatePoints(pointerPoints.GetAddressOf());
     mGestureRecognizer->ProcessMoveEvents(pointerPoints.Get());
   }
 }
 
+void
+MetroInput::DeliverNextQueuedNoMoveTouch() {
+  nsAutoPtr<TouchEventQueueEntry> queueEntry =
+    static_cast<TouchEventQueueEntry*>(mInputEventQueue.PopFront());
+
+  if (ShouldDeliverInputToRecognizer()) {
+    mGestureRecognizer->ProcessMoveEvents(queueEntry->GetPointerPoints());
+  }
+}
+
 // This event is raised when the user moves the mouse, moves a pen that is
 // in contact with the surface, or moves a finger that is in contact with
 // a touch screen.
 HRESULT
 MetroInput::OnPointerMoved(UI::Core::ICoreWindow* aSender,
                            UI::Core::IPointerEventArgs* aArgs)
 {
 #ifdef DEBUG_INPUT
@@ -639,94 +629,98 @@ MetroInput::OnPointerMoved(UI::Core::ICo
   // Some old drivers cause us to receive a PointerMoved event for a touchId
   // after we've already received a PointerReleased event for that touchId.
   // To work around those busted drivers, we simply ignore TouchMoved events
   // for touchIds that we are not currently tracking.  See bug 819223.
   if (!touch) {
     return S_OK;
   }
 
-  AddPointerMoveDataToRecognizer(aArgs);
+  PointerPointVector* pointerPoints;
+  aArgs->GetIntermediatePoints(&pointerPoints);
 
   // If the point hasn't moved, filter it out per the spec. Pres shell does
   // this as well, but we need to know when our first touchmove is going to
   // get delivered so we can check the result.
   if (!HasPointMoved(touch, currentPoint.Get())) {
+    // Even when the pointer has not moved, the gesture recognizer requires it.
+    // Doing it asynchronously to keep the event's order.
+    mInputEventQueue.Push(new TouchEventQueueEntry(nullptr, pointerPoints));
+    nsCOMPtr<nsIRunnable> runnable =
+      NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedNoMoveTouch);
+    NS_DispatchToCurrentThread(runnable);
     return S_OK;
   }
 
   touch = CreateDOMTouch(currentPoint.Get());
   touch->mChanged = true;
   // replacing old touch point in mTouches map
   mTouches.Put(pointerId, touch);
 
   WidgetTouchEvent* touchEvent =
     new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
   InitTouchEventTouchList(touchEvent);
-  DispatchAsyncTouchEvent(touchEvent);
+
+  DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, pointerPoints));
 
   return S_OK;
 }
 
 // This event is raised when the user lifts the left mouse button, lifts a
 // pen from the surface, or lifts her/his finger from a touch screen.
 HRESULT
 MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender,
                               UI::Core::IPointerEventArgs* aArgs)
 {
 #ifdef DEBUG_INPUT
   LogFunction();
 #endif
 
-  WRL::ComPtr<UI::Input::IPointerPoint> currentPoint;
+  UI::Input::IPointerPoint* currentPoint;
   WRL::ComPtr<Devices::Input::IPointerDevice> device;
   Devices::Input::PointerDeviceType deviceType;
 
-  aArgs->get_CurrentPoint(currentPoint.GetAddressOf());
+  aArgs->get_CurrentPoint(&currentPoint);
   currentPoint->get_PointerDevice(device.GetAddressOf());
   device->get_PointerDeviceType(&deviceType);
 
   // For mouse and pen input, simply call our helper function
   if (deviceType !=
           Devices::Input::PointerDeviceType::PointerDeviceType_Touch) {
-    OnPointerNonTouch(currentPoint.Get());
-    mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
+    OnPointerNonTouch(currentPoint);
+    mGestureRecognizer->ProcessUpEvent(currentPoint);
     return S_OK;
   }
 
   // This is touch input.
   UpdateInputLevel(LEVEL_IMPRECISE);
 
   // Get the touch associated with this touch point.
   uint32_t pointerId;
   currentPoint->get_PointerId(&pointerId);
   nsRefPtr<Touch> touch = mTouches.Get(pointerId);
 
   // Purge any pending moves for this pointer
   if (touch->mChanged) {
     WidgetTouchEvent* touchEvent =
       new WidgetTouchEvent(true, NS_TOUCH_MOVE, mWidget.Get());
     InitTouchEventTouchList(touchEvent);
-    DispatchAsyncTouchEvent(touchEvent);
+    DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, (IPointerPoint*)nullptr));
   }
 
   // Remove this touch point from our map. Eventually all touch points are
   // removed for this session since we receive released events for every
   // point.
   mTouches.Remove(pointerId);
 
   // touchend events only have a single touch; the touch that has been removed
   WidgetTouchEvent* touchEvent =
     new WidgetTouchEvent(true, NS_TOUCH_END, mWidget.Get());
-  touchEvent->touches.AppendElement(CreateDOMTouch(currentPoint.Get()));
-  DispatchAsyncTouchEvent(touchEvent);
-
-  if (ShouldDeliverInputToRecognizer()) {
-    mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
-  }
+  touchEvent->touches.AppendElement(CreateDOMTouch(currentPoint));
+  DispatchAsyncTouchEvent(new TouchEventQueueEntry(touchEvent, currentPoint));
 
   return S_OK;
 }
 
 // Tests for chrome vs. content target so we know whether input coordinates need
 // to be transformed through the apz. Eventually this hit testing should move
 // into the apz (bug 918288).
 bool
@@ -1131,22 +1125,23 @@ MetroInput::DeliverNextQueuedEventIgnore
     nsEventStateManager* esm = presShell->GetPresContext()->EventStateManager();
     if (esm) {
       esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
     }
   }
 }
 
 void
-MetroInput::DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent)
+MetroInput::DispatchAsyncTouchEvent(TouchEventQueueEntry* queueEntry)
 {
-  aEvent->time = ::GetMessageTime();
+  WidgetTouchEvent* event = queueEntry->GetEvent();
+  event->time = ::GetMessageTime();
   mModifierKeyState.Update();
-  mModifierKeyState.InitInputEvent(*aEvent);
-  mInputEventQueue.Push(aEvent);
+  mModifierKeyState.InitInputEvent(*event);
+  mInputEventQueue.Push(queueEntry);
   nsCOMPtr<nsIRunnable> runnable =
     NS_NewRunnableMethod(this, &MetroInput::DeliverNextQueuedTouchEvent);
   NS_DispatchToCurrentThread(runnable);
 }
 
 static void DumpTouchIds(const char* aTarget, WidgetTouchEvent* aEvent)
 {
   // comment out for touch moves
@@ -1347,22 +1342,23 @@ MetroInput::DeliverNextQueuedTouchEvent(
    *  the events we can save ourselves the overhead of delivering dom events.
    *
    * Notes:
    * - never rely on the contents of mTouches here, since this is a delayed
    *   callback. mTouches will likely have been modified.
    */
   nsEventStatus status = nsEventStatus_eIgnore;
 
-  WidgetTouchEvent* event =
-    static_cast<WidgetTouchEvent*>(mInputEventQueue.PopFront());
+  nsAutoPtr<TouchEventQueueEntry> queueEntry =
+    static_cast<TouchEventQueueEntry*>(mInputEventQueue.PopFront());
+  
+  WidgetTouchEvent* event = queueEntry->GetEvent();
+
   MOZ_ASSERT(event);
 
-  AutoDeleteEvent wrap(event);
-
   // Test for non-apz vs. apz target. To do this we only use the first touch
   // point since that will be the input batch target. Cache this for touch events
   // since HitTestChrome has to send a dom event.
   if (mCancelable && event->message == NS_TOUCH_START) {
     nsRefPtr<Touch> touch = event->touches[0];
     LayoutDeviceIntPoint pt = LayoutDeviceIntPoint::FromUntyped(touch->mRefPoint);
     // This is currently a general contained rect hit test, it may produce a false
     // positive for overlay chrome elements. Also, some content pages won't support
@@ -1382,16 +1378,35 @@ MetroInput::DeliverNextQueuedTouchEvent(
       if (nsEventStatus_eConsumeNoDefault == status) {
         mRecognizerWantsEvents = false;
         mGestureRecognizer->CompleteGesture();
       }
       if (event->message == NS_TOUCH_MOVE) {
         mCancelable = false;
       }
     }
+  }
+
+  if (ShouldDeliverInputToRecognizer()) {
+    switch (event->message) {
+    case NS_TOUCH_START:
+      mGestureRecognizer->ProcessDownEvent(queueEntry->GetPointerPoint());
+      break;
+    case NS_TOUCH_END:
+      mGestureRecognizer->ProcessUpEvent(queueEntry->GetPointerPoint());
+      break;
+    case NS_TOUCH_MOVE:
+      if (queueEntry->GetPointerPoints()) {
+        mGestureRecognizer->ProcessMoveEvents(queueEntry->GetPointerPoints());
+      }
+      break;
+    }
+  }
+
+  if (mNonApzTargetForTouch) {
     return;
   }
 
   if (mCancelable && event->message == NS_TOUCH_START) {
     HandleFirstTouchStartEvent(event);
     return;
   } else if (mCancelable && event->message == NS_TOUCH_MOVE) {
     HandleFirstTouchMoveEvent(event);
--- a/widget/windows/winrt/MetroInput.h
+++ b/widget/windows/winrt/MetroInput.h
@@ -3,25 +3,27 @@
  * 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/. */
 
 #pragma once
 
 // Moz headers (alphabetical)
 #include "keyboardlayout.h"   // mModifierKeyState
 #include "nsBaseHashtable.h"  // mTouches
+#include "nsDeque.h"
 #include "nsHashKeys.h"       // type of key for mTouches
-#include "mozwrlbase.h"
-#include "nsDeque.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/TouchEvents.h"
+#include "mozwrlbase.h"
 
 // System headers (alphabetical)
 #include <EventToken.h>     // EventRegistrationToken
 #include <stdint.h>         // uint32_t
+#include <windows.ui.input.h> // ABI::Window::UI::Input namespace
 #include <wrl\client.h>     // Microsoft::WRL::ComPtr class
 #include <wrl\implements.h> // Microsoft::WRL::InspectableClass macro
 
 // Moz forward declarations
 class MetroWidget;
 struct nsIntPoint;
 
 namespace mozilla {
@@ -63,30 +65,62 @@ namespace ABI {
     };
   };
 };
 
 namespace mozilla {
 namespace widget {
 namespace winrt {
 
+class TouchEventQueueEntry {
+private:
+  typedef ABI::Windows::UI::Input::IPointerPoint IPointerPoint;
+  typedef ABI::Windows::UI::Input::PointerPoint PointerPoint;
+  typedef ABI::Windows::Foundation::Collections::IVector<PointerPoint*> PointerPointVector;
+
+  Microsoft::WRL::ComPtr<PointerPointVector> mPointerPoints;
+  Microsoft::WRL::ComPtr<IPointerPoint> mPointerPoint;
+  nsAutoPtr<WidgetTouchEvent> mTouchEvent;
+
+public:
+  TouchEventQueueEntry(WidgetTouchEvent* aTouchEvent, IPointerPoint* aPointerPoint)
+    : mTouchEvent(aTouchEvent), mPointerPoint(aPointerPoint)
+  {
+  }
+
+  TouchEventQueueEntry(WidgetTouchEvent* aTouchEvent, PointerPointVector* aPointerPoints)
+    : mTouchEvent(aTouchEvent), mPointerPoints(aPointerPoints)
+  {
+  }
+
+  IPointerPoint* GetPointerPoint() {
+    return mPointerPoint.Get();
+  }
+
+  PointerPointVector* GetPointerPoints() {
+    return mPointerPoints.Get();
+  }
+
+  WidgetTouchEvent* GetEvent() {
+    return mTouchEvent;
+  }
+};
+
+
 class MetroInput : public Microsoft::WRL::RuntimeClass<IInspectable>
 {
   InspectableClass(L"MetroInput", BaseTrust);
 
 private:
   typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
   typedef uint32_t TouchBehaviorFlags;
 
   // Devices
   typedef ABI::Windows::Devices::Input::PointerDeviceType PointerDeviceType;
 
-  // Foundation
-  typedef ABI::Windows::Foundation::Point Point;
-
   // UI::Core
   typedef ABI::Windows::UI::Core::ICoreWindow ICoreWindow;
   typedef ABI::Windows::UI::Core::IAcceleratorKeyEventArgs \
                                   IAcceleratorKeyEventArgs;
   typedef ABI::Windows::UI::Core::IKeyEventArgs IKeyEventArgs;
   typedef ABI::Windows::UI::Core::IPointerEventArgs IPointerEventArgs;
 
   // UI::Input
@@ -98,16 +132,21 @@ private:
   typedef ABI::Windows::UI::Input::IManipulationStartedEventArgs \
                                    IManipulationStartedEventArgs;
   typedef ABI::Windows::UI::Input::IManipulationUpdatedEventArgs \
                                    IManipulationUpdatedEventArgs;
   typedef ABI::Windows::UI::Input::IPointerPoint IPointerPoint;
   typedef ABI::Windows::UI::Input::IRightTappedEventArgs IRightTappedEventArgs;
   typedef ABI::Windows::UI::Input::ITappedEventArgs ITappedEventArgs;
   typedef ABI::Windows::UI::Input::ManipulationDelta ManipulationDelta;
+  typedef ABI::Windows::UI::Input::PointerPoint PointerPoint;
+
+  // Foundation
+  typedef ABI::Windows::Foundation::Point Point;
+  typedef ABI::Windows::Foundation::Collections::IVector<PointerPoint*> PointerPointVector;
 
   typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
 
 public:
   MetroInput(MetroWidget* aWidget,
              ICoreWindow* aWindow);
   virtual ~MetroInput();
 
@@ -278,21 +317,22 @@ private:
   // on the ui thread via a native event dispatch call get bounced through
   // the gecko thread event queue using runnables. Most events can be sent
   // async without the need to see the status result. Those that do have
   // specialty callbacks. Note any event that arrives to us on the ui thread
   // that originates from another thread is safe to send sync.
 
   // Async event dispatching
   void DispatchAsyncEventIgnoreStatus(WidgetInputEvent* aEvent);
-  void DispatchAsyncTouchEvent(WidgetTouchEvent* aEvent);
+  void DispatchAsyncTouchEvent(TouchEventQueueEntry* queueEntry);
 
   // Async event callbacks
   void DeliverNextQueuedEventIgnoreStatus();
   void DeliverNextQueuedTouchEvent();
+  void DeliverNextQueuedNoMoveTouch();
 
   void HandleFirstTouchStartEvent(WidgetTouchEvent* aEvent);
   void HandleFirstTouchMoveEvent(WidgetTouchEvent* aEvent);
 
   // Sync event dispatching
   void DispatchEventIgnoreStatus(WidgetGUIEvent* aEvent);
   void DispatchTouchCancel(WidgetTouchEvent* aEvent);