From e20e784d95cc8c9d6ffd1dc15b14e8fe602ce684 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Fri, 13 Sep 2013 05:34:24 -0500 Subject: [PATCH] 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, bbondy --- widget/windows/winrt/MetroAppShell.cpp | 64 ++++++++++++++++++++++++-- widget/windows/winrt/MetroAppShell.h | 2 + widget/windows/winrt/MetroInput.cpp | 17 +++---- widget/windows/winrt/MetroInput.h | 1 - 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/widget/windows/winrt/MetroAppShell.cpp b/widget/windows/winrt/MetroAppShell.cpp index 58bece2e127..37f521a24da 100644 --- a/widget/windows/winrt/MetroAppShell.cpp +++ b/widget/windows/winrt/MetroAppShell.cpp @@ -42,6 +42,8 @@ extern UINT sAppShellGeckoMsgId; static ComPtr sCoreStatic; static bool sIsDispatching = false; +static bool sWillEmptyThreadQueue = false; +static bool sEmptyingThreadQueue = false; MetroAppShell::~MetroAppShell() { @@ -214,6 +216,43 @@ MetroAppShell::Run(void) 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 dispatching(sEmptyingThreadQueue); + sEmptyingThreadQueue = true; + nsIThread *thread = NS_GetCurrentThread(); + NS_ProcessPendingEvents(thread, 0); +} + static void ProcessNativeEvents(CoreProcessEventsOption eventOption) { @@ -238,16 +277,35 @@ bool MetroAppShell::ProcessOneNativeEventIfPresent() { if (sIsDispatching) { - NS_RUNTIMEABORT("Reentrant call into process events, this is not allowed in Winrt land. Goodbye!"); + // Calling into ProcessNativeEvents is harmless, but won't actually process any + // native events. So we log here so we can spot this and get a handle on the + // corner cases where this can happen. + Log("WARNING: Reentrant call into process events detected, returning early."); + return false; } - AutoRestore dispatching(sIsDispatching); - ProcessNativeEvents(CoreProcessEventsOption::CoreProcessEventsOption_ProcessOneIfPresent); + + { + AutoRestore 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; } diff --git a/widget/windows/winrt/MetroAppShell.h b/widget/windows/winrt/MetroAppShell.h index 93d5468ead3..59c9b87cf30 100644 --- a/widget/windows/winrt/MetroAppShell.h +++ b/widget/windows/winrt/MetroAppShell.h @@ -27,12 +27,14 @@ public: 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; diff --git a/widget/windows/winrt/MetroInput.cpp b/widget/windows/winrt/MetroInput.cpp index 763e1f3e0ba..8ef8cd2fa26 100644 --- a/widget/windows/winrt/MetroInput.cpp +++ b/widget/windows/winrt/MetroInput.cpp @@ -12,6 +12,7 @@ #include "nsIDOMSimpleGestureEvent.h" // Constants for gesture events #include "InputData.h" #include "UIABridgePrivate.h" +#include "MetroAppShell.h" // System headers (alphabetical) #include // ABI::Window::UI::Core namespace @@ -635,6 +636,11 @@ MetroInput::OnPointerReleased(UI::Core::ICoreWindow* aSender, 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; } @@ -1091,17 +1097,6 @@ MetroInput::DeliverNextQueuedEventIgnoreStatus() delete event; } -nsEventStatus -MetroInput::DeliverNextQueuedEvent() -{ - nsGUIEvent* event = static_cast(mInputEventQueue.PopFront()); - MOZ_ASSERT(event); - nsEventStatus status; - mWidget->DispatchEvent(event, status); - delete event; - return status; -} - void MetroInput::DispatchAsyncTouchEventIgnoreStatus(nsTouchEvent* aEvent) { diff --git a/widget/windows/winrt/MetroInput.h b/widget/windows/winrt/MetroInput.h index da14c29740d..4d9eb3d4ae7 100644 --- a/widget/windows/winrt/MetroInput.h +++ b/widget/windows/winrt/MetroInput.h @@ -264,7 +264,6 @@ private: // Async event callbacks void DeliverNextQueuedEventIgnoreStatus(); - nsEventStatus DeliverNextQueuedEvent(); nsEventStatus DeliverNextQueuedTouchEvent(); // Misc. specialty async callbacks