Bug 914331 - On pointer released make sure all gecko touch events are delivered to insure dom state via accessibility is up to date. r=tabraldes
authorJim Mathies <jmathies@mozilla.com>
Wed, 11 Sep 2013 06:06:00 -0500
changeset 159577 414c4654393196cfee6e1a43d521ce4b886d0175
parent 159576 19c8f5a267fae5fda3b8a0a55b9b77ee9bb149a6
child 159578 d4d34d4d06e762abafea07aa1c83c32704defe70
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstabraldes
bugs914331
milestone26.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 914331 - On pointer released make sure all gecko touch events are delivered to insure dom state via accessibility is up to date. r=tabraldes
widget/windows/winrt/MetroAppShell.cpp
widget/windows/winrt/MetroAppShell.h
widget/windows/winrt/MetroInput.cpp
widget/windows/winrt/MetroInput.h
--- a/widget/windows/winrt/MetroAppShell.cpp
+++ b/widget/windows/winrt/MetroAppShell.cpp
@@ -37,16 +37,18 @@ extern ComPtr<FrameworkView> sFrameworkV
 namespace mozilla {
 namespace widget {
 // pulled from win32 app shell
 extern UINT sAppShellGeckoMsgId;
 } }
 
 static ComPtr<ICoreWindowStatic> sCoreStatic;
 static bool sIsDispatching = false;
+static bool sWillEmptyThreadQueue = false;
+static bool sEmptyingThreadQueue = false;
 
 MetroAppShell::~MetroAppShell()
 {
   if (mEventWnd) {
     SendMessage(mEventWnd, WM_CLOSE, 0, 0);
   }
 }
 
@@ -209,16 +211,53 @@ MetroAppShell::Run(void)
       sMetroApp->CoreExit();
     }
     break;
   }
 
   return rv;
 }
 
+// Called in certain cases where we have async input events in the thread
+// queue and need to make sure they get dispatched before the stack unwinds.
+void // static
+MetroAppShell::MarkEventQueueForPurge()
+{
+  LogFunction();
+  sWillEmptyThreadQueue = true;
+
+  // If we're dispatching native events, wait until the dispatcher is
+  // off the stack.
+  if (sIsDispatching) {
+    return;
+  }
+
+  // Safe to process pending events now
+  DispatchAllGeckoEvents();
+}
+
+// static
+void
+MetroAppShell::DispatchAllGeckoEvents()
+{
+  if (!sWillEmptyThreadQueue) {
+    return;
+  }
+
+  LogFunction();
+  NS_ASSERTION(NS_IsMainThread(), "DispatchAllXPCOMEvents should be called on the main thread");
+
+  sWillEmptyThreadQueue = false;
+
+  AutoRestore<bool> dispatching(sEmptyingThreadQueue);
+  sEmptyingThreadQueue = true;
+  nsIThread *thread = NS_GetCurrentThread();
+  NS_ProcessPendingEvents(thread, 0);
+}
+
 static void
 ProcessNativeEvents(CoreProcessEventsOption eventOption)
 {
   HRESULT hr;
   if (!sCoreStatic) {
     hr = GetActivationFactory(HStringReference(L"Windows.UI.Core.CoreWindow").Get(), sCoreStatic.GetAddressOf());
     NS_ASSERTION(SUCCEEDED(hr), "GetActivationFactory failed?");
     AssertHRESULT(hr);
@@ -235,24 +274,39 @@ ProcessNativeEvents(CoreProcessEventsOpt
 
 // static
 bool
 MetroAppShell::ProcessOneNativeEventIfPresent()
 {
   if (sIsDispatching) {
     NS_RUNTIMEABORT("Reentrant call into process events, this is not allowed in Winrt land. Goodbye!");
   }
-  AutoRestore<bool> dispatching(sIsDispatching);
-  ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessOneIfPresent);
+
+  {
+    AutoRestore<bool> dispatching(sIsDispatching);
+    sIsDispatching = true;
+    ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessOneIfPresent);
+  }
+
+  DispatchAllGeckoEvents();
+
   return !!HIWORD(::GetQueueStatus(MOZ_QS_ALLEVENT));
 }
 
 bool
 MetroAppShell::ProcessNextNativeEvent(bool mayWait)
 {
+  // NS_ProcessPendingEvents will process thread events *and* call
+  // nsBaseAppShell::OnProcessNextEvent to process native events. However
+  // we do not want native events getting dispatched while we are in
+  // DispatchAllGeckoEvents.
+  if (sEmptyingThreadQueue) {
+    return false;
+  }
+
   if (ProcessOneNativeEventIfPresent()) {
     return true;
   }
   if (mayWait) {
     DWORD result = ::MsgWaitForMultipleObjectsEx(0, NULL, MSG_WAIT_TIMEOUT, MOZ_QS_ALLEVENT,
                                                  MWMO_INPUTAVAILABLE|MWMO_ALERTABLE);
     NS_WARN_IF_FALSE(result != WAIT_FAILED, "Wait failed");
   }
--- a/widget/windows/winrt/MetroAppShell.h
+++ b/widget/windows/winrt/MetroAppShell.h
@@ -22,20 +22,22 @@ public:
   }
 
   nsresult Init();
   void DoProcessMoreGeckoEvents();
   void NativeCallback();
 
   static LRESULT CALLBACK EventWindowProc(HWND, UINT, WPARAM, LPARAM);
   static bool ProcessOneNativeEventIfPresent();
+  static void MarkEventQueueForPurge();
 
 protected:
   NS_IMETHOD Run();
 
   virtual void ScheduleNativeEventCallback();
   virtual bool ProcessNextNativeEvent(bool mayWait);
+  static void DispatchAllGeckoEvents();
   virtual ~MetroAppShell();
 
   HWND mEventWnd;
   nsAutoHandle mPowerRequest;
   ULONG mPowerRequestCount;
 };
--- a/widget/windows/winrt/MetroInput.cpp
+++ b/widget/windows/winrt/MetroInput.cpp
@@ -7,16 +7,17 @@
 #include "MetroInput.h"
 #include "MetroUtils.h" // Logging, POINT_CEIL_*, ActivateGenericInstance, etc
 #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"
 
 // 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
@@ -544,22 +545,18 @@ MetroInput::OnPointerMoved(UI::Core::ICo
   }
 
   return S_OK;
 }
 
 void
 MetroInput::OnFirstPointerMoveCallback()
 {
-  nsTouchEvent* event = static_cast<nsTouchEvent*>(mInputEventQueue.PopFront());
-  MOZ_ASSERT(event);
-  nsEventStatus status;
-  mWidget->DispatchEvent(event, status);
+  nsEventStatus status = DeliverNextQueuedTouchEvent();
   mTouchMoveDefaultPrevented = (nsEventStatus_eConsumeNoDefault == status);
-  delete event;
 }
 
 // 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)
 {
@@ -609,16 +606,21 @@ MetroInput::OnPointerReleased(UI::Core::
   DispatchAsyncTouchEventIgnoreStatus(touchEvent);
 
   // If content didn't cancel the first touchstart feed touchend data to the
   // recognizer.
   if (!mTouchStartDefaultPrevented) {
     mGestureRecognizer->ProcessUpEvent(currentPoint.Get());
   }
 
+  // Make sure all gecko events are dispatched and the dom is up to date
+  // so that when ui automation comes in looking for focus info it gets
+  // the right information.
+  MetroAppShell::MarkEventQueueForPurge();
+
   return S_OK;
 }
 
 void
 MetroInput::InitGeckoMouseEventFromPointerPoint(
                                   nsMouseEvent* aEvent,
                                   UI::Input::IPointerPoint* aPointerPoint) {
   NS_ASSERTION(aPointerPoint, "InitGeckoMouseEventFromPointerPoint "
@@ -1065,27 +1067,16 @@ void
 MetroInput::DeliverNextQueuedEventIgnoreStatus()
 {
   nsGUIEvent* event = static_cast<nsGUIEvent*>(mInputEventQueue.PopFront());
   MOZ_ASSERT(event);
   DispatchEventIgnoreStatus(event);
   delete event;
 }
 
-nsEventStatus
-MetroInput::DeliverNextQueuedEvent()
-{
-  nsGUIEvent* event = static_cast<nsGUIEvent*>(mInputEventQueue.PopFront());
-  MOZ_ASSERT(event);
-  nsEventStatus status;
-  mWidget->DispatchEvent(event, status);
-  delete event;
-  return status;
-}
-
 void
 MetroInput::DispatchAsyncTouchEventIgnoreStatus(nsTouchEvent* aEvent)
 {
   aEvent->time = ::GetMessageTime();
   mModifierKeyState.Update();
   mModifierKeyState.InitInputEvent(*aEvent);
   mInputEventQueue.Push(aEvent);
   nsCOMPtr<nsIRunnable> runnable =
--- a/widget/windows/winrt/MetroInput.h
+++ b/widget/windows/winrt/MetroInput.h
@@ -257,17 +257,16 @@ private:
 
   // Async event dispatching
   void DispatchAsyncEventIgnoreStatus(nsInputEvent* aEvent);
   void DispatchAsyncTouchEventIgnoreStatus(nsTouchEvent* aEvent);
   void DispatchAsyncTouchEventWithCallback(nsTouchEvent* aEvent, void (MetroInput::*Callback)());
 
   // Async event callbacks
   void DeliverNextQueuedEventIgnoreStatus();
-  nsEventStatus DeliverNextQueuedEvent();
   nsEventStatus DeliverNextQueuedTouchEvent();
 
   // Misc. specialty async callbacks
   void OnPointerPressedCallback();
   void OnFirstPointerMoveCallback();
 
   // Sync event dispatching
   void DispatchEventIgnoreStatus(nsGUIEvent *aEvent);