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 191344 c6fc27e68f455521abf328b28555c1ed97556160
parent 191343 f25fb5db8893f3dec09a66c00ded2d546356335b
child 191345 3c9c98992742be0349f65c340fdf53057b2c4fa1
push id474
push userasasaki@mozilla.com
push dateMon, 02 Jun 2014 21:01:02 +0000
treeherdermozilla-release@967f4cf1b31c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs953012
milestone30.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 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);