mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
Bug 1407700 Part2: Handle the case to re-entry event loop for mousemove coalescing. r=smaug.
MozReview-Commit-ID: DcHVokf6boL
This commit is contained in:
parent
69ed33396c
commit
98ed53bd59
@ -29,6 +29,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void RetrieveDataFrom(CoalescedInputData& aSource)
|
||||
{
|
||||
mCoalescedInputEvent = Move(aSource.mCoalescedInputEvent);
|
||||
mGuid = aSource.mGuid;
|
||||
mInputBlockId = aSource.mInputBlockId;
|
||||
}
|
||||
|
||||
bool IsEmpty()
|
||||
{
|
||||
return !mCoalescedInputEvent;
|
||||
|
@ -55,8 +55,8 @@ void
|
||||
CoalescedMouseMoveFlusher::WillRefresh(mozilla::TimeStamp aTime)
|
||||
{
|
||||
MOZ_ASSERT(mRefreshDriver);
|
||||
mTabChild->MaybeDispatchCoalescedMouseMoveEvents();
|
||||
RemoveObserver();
|
||||
mTabChild->FlushAllCoalescedMouseData();
|
||||
mTabChild->ProcessPendingCoalescedMouseDataAndDispatchEvents();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1059,6 +1059,15 @@ TabChild::DestroyWindow()
|
||||
mCoalescedMouseEventFlusher->RemoveObserver();
|
||||
mCoalescedMouseEventFlusher = nullptr;
|
||||
}
|
||||
|
||||
// In case we don't have chance to process all entries, clean all data in
|
||||
// the queue.
|
||||
while (mToBeDispatchedMouseData.GetSize() > 0) {
|
||||
UniquePtr<CoalescedMouseData> data(
|
||||
static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
|
||||
data.reset();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
|
||||
if (baseWindow)
|
||||
baseWindow->Destroy();
|
||||
@ -1591,27 +1600,62 @@ TabChild::RecvMouseEvent(const nsString& aType,
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::MaybeDispatchCoalescedMouseMoveEvents()
|
||||
TabChild::ProcessPendingCoalescedMouseDataAndDispatchEvents()
|
||||
{
|
||||
if (!mCoalesceMouseMoveEvents) {
|
||||
if (!mCoalesceMouseMoveEvents || !mCoalescedMouseEventFlusher) {
|
||||
// We don't enable mouse coalescing or we are destroying TabChild.
|
||||
return;
|
||||
}
|
||||
|
||||
// We may reentry the event loop and push more data to
|
||||
// mToBeDispatchedMouseData while dispatching an event.
|
||||
|
||||
// We may have some pending coalesced data while dispatch an event and reentry
|
||||
// the event loop. In that case we don't have chance to consume the remainding
|
||||
// pending data until we get new mouse events. Get some helps from
|
||||
// mCoalescedMouseEventFlusher to trigger it.
|
||||
mCoalescedMouseEventFlusher->StartObserver();
|
||||
|
||||
while (mToBeDispatchedMouseData.GetSize() > 0) {
|
||||
UniquePtr<CoalescedMouseData> data(
|
||||
static_cast<CoalescedMouseData*>(mToBeDispatchedMouseData.PopFront()));
|
||||
|
||||
UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent();
|
||||
if (event) {
|
||||
// Dispatch the pending events. Using HandleRealMouseButtonEvent
|
||||
// to bypass the coalesce handling in RecvRealMouseMoveEvent. Can't use
|
||||
// RecvRealMouseButtonEvent because we may also put some mouse events
|
||||
// other than mousemove.
|
||||
HandleRealMouseButtonEvent(*event,
|
||||
data->GetScrollableLayerGuid(),
|
||||
data->GetInputBlockId());
|
||||
}
|
||||
}
|
||||
// mCoalescedMouseEventFlusher may be destroyed when reentrying the event
|
||||
// loop.
|
||||
if (mCoalescedMouseEventFlusher) {
|
||||
mCoalescedMouseEventFlusher->RemoveObserver();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::FlushAllCoalescedMouseData()
|
||||
{
|
||||
MOZ_ASSERT(mCoalesceMouseMoveEvents);
|
||||
|
||||
// Move all entries from mCoalescedMouseData to mToBeDispatchedMouseData.
|
||||
for (auto iter = mCoalescedMouseData.Iter(); !iter.Done(); iter.Next()) {
|
||||
CoalescedMouseData* data = iter.UserData();
|
||||
if (!data || data->IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
UniquePtr<WidgetMouseEvent> event = data->TakeCoalescedEvent();
|
||||
MOZ_ASSERT(event);
|
||||
// Dispatch the coalesced mousemove event. Using RecvRealMouseButtonEvent to
|
||||
// bypass the coalesce handling in RecvRealMouseMoveEvent.
|
||||
RecvRealMouseButtonEvent(*event,
|
||||
data->GetScrollableLayerGuid(),
|
||||
data->GetInputBlockId());
|
||||
}
|
||||
if (mCoalescedMouseEventFlusher) {
|
||||
mCoalescedMouseEventFlusher->RemoveObserver();
|
||||
UniquePtr<CoalescedMouseData> dispatchData =
|
||||
MakeUnique<CoalescedMouseData>();
|
||||
|
||||
dispatchData->RetrieveDataFrom(*data);
|
||||
mToBeDispatchedMouseData.Push(dispatchData.release());
|
||||
}
|
||||
mCoalescedMouseData.Clear();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
@ -1631,10 +1675,23 @@ TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& aEvent,
|
||||
mCoalescedMouseEventFlusher->StartObserver();
|
||||
return IPC_OK();
|
||||
}
|
||||
// Can't coalesce current mousemove event. Dispatch the coalesced mousemove
|
||||
// event and coalesce the current one.
|
||||
MaybeDispatchCoalescedMouseMoveEvents();
|
||||
data->Coalesce(aEvent, aGuid, aInputBlockId);
|
||||
// Can't coalesce current mousemove event. Put the coalesced mousemove data
|
||||
// with the same pointer id to mToBeDispatchedMouseData, coalesce the
|
||||
// current one, and process all pending data in mToBeDispatchedMouseData.
|
||||
MOZ_ASSERT(data);
|
||||
UniquePtr<CoalescedMouseData> dispatchData =
|
||||
MakeUnique<CoalescedMouseData>();
|
||||
|
||||
dispatchData->RetrieveDataFrom(*data);
|
||||
mToBeDispatchedMouseData.Push(dispatchData.release());
|
||||
|
||||
// Put new data to replace the old one in the hash table.
|
||||
CoalescedMouseData* newData = new CoalescedMouseData();
|
||||
mCoalescedMouseData.Put(aEvent.pointerId, newData);
|
||||
newData->Coalesce(aEvent, aGuid, aInputBlockId);
|
||||
|
||||
// Dispatch all pending mouse events.
|
||||
ProcessPendingCoalescedMouseDataAndDispatchEvents();
|
||||
mCoalescedMouseEventFlusher->StartObserver();
|
||||
} else if (!RecvRealMouseButtonEvent(aEvent, aGuid, aInputBlockId)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
@ -1674,16 +1731,35 @@ TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
const uint64_t& aInputBlockId)
|
||||
{
|
||||
if (aEvent.mMessage != eMouseMove) {
|
||||
// Flush the coalesced mousemove event before dispatching other mouse
|
||||
// events.
|
||||
MaybeDispatchCoalescedMouseMoveEvents();
|
||||
if (aEvent.mMessage == eMouseEnterIntoWidget) {
|
||||
mCoalescedMouseData.Put(aEvent.pointerId, new CoalescedMouseData());
|
||||
} else if (aEvent.mMessage == eMouseExitFromWidget) {
|
||||
mCoalescedMouseData.Remove(aEvent.pointerId);
|
||||
}
|
||||
if (mCoalesceMouseMoveEvents && mCoalescedMouseEventFlusher &&
|
||||
aEvent.mMessage != eMouseMove) {
|
||||
// When receiving a mouse event other than mousemove, we have to dispatch
|
||||
// all coalesced events before it. However, we can't dispatch all pending
|
||||
// coalesced events directly because we may reentry the event loop while
|
||||
// dispatching. To make sure we won't dispatch disorder events, we move all
|
||||
// coalesced mousemove events and current event to a deque to dispatch them.
|
||||
// When reentrying the event loop and dispatching more events, we put new
|
||||
// events in the end of the nsQueue and dispatch events from the beginning.
|
||||
FlushAllCoalescedMouseData();
|
||||
|
||||
UniquePtr<CoalescedMouseData> dispatchData =
|
||||
MakeUnique<CoalescedMouseData>();
|
||||
|
||||
dispatchData->Coalesce(aEvent, aGuid, aInputBlockId);
|
||||
mToBeDispatchedMouseData.Push(dispatchData.release());
|
||||
|
||||
ProcessPendingCoalescedMouseDataAndDispatchEvents();
|
||||
return IPC_OK();
|
||||
}
|
||||
HandleRealMouseButtonEvent(aEvent, aGuid, aInputBlockId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
TabChild::HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
const uint64_t& aInputBlockId)
|
||||
{
|
||||
// Mouse events like eMouseEnterIntoWidget, that are created in the parent
|
||||
// process EventStateManager code, have an input block id which they get from
|
||||
// the InputAPZContext in the parent process stack. However, they did not
|
||||
@ -1713,7 +1789,6 @@ TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
|
||||
if (aInputBlockId && aEvent.mFlags.mHandledByAPZ) {
|
||||
mAPZEventState->ProcessMouseEvent(aEvent, aGuid, aInputBlockId);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "AudioChannelService.h"
|
||||
#include "PuppetWidget.h"
|
||||
#include "mozilla/layers/GeckoContentController.h"
|
||||
#include "nsDeque.h"
|
||||
#include "nsISHistoryListener.h"
|
||||
#include "nsIPartialSHistoryListener.h"
|
||||
|
||||
@ -761,8 +762,17 @@ public:
|
||||
return mWidgetNativeData;
|
||||
}
|
||||
|
||||
// Prepare to dispatch all coalesced mousemove events. We'll move all data
|
||||
// in mCoalescedMouseData to a nsDeque; then we start processing them. We
|
||||
// can't fetch the coalesced event one by one and dispatch it because we may
|
||||
// reentry the event loop and access to the same hashtable. It's called when
|
||||
// dispatching some mouse events other than mousemove.
|
||||
void FlushAllCoalescedMouseData();
|
||||
void ProcessPendingCoalescedMouseDataAndDispatchEvents();
|
||||
|
||||
void MaybeDispatchCoalescedMouseMoveEvents();
|
||||
void HandleRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
|
||||
const ScrollableLayerGuid& aGuid,
|
||||
const uint64_t& aInputBlockId);
|
||||
|
||||
static bool HasActiveTabs()
|
||||
{
|
||||
@ -948,7 +958,12 @@ private:
|
||||
// takes time, some repeated events can be skipped to not flood child process.
|
||||
mozilla::TimeStamp mLastWheelProcessedTimeFromParent;
|
||||
mozilla::TimeDuration mLastWheelProcessingDuration;
|
||||
|
||||
// Hash table to track coalesced mousemove events for different pointers.
|
||||
nsClassHashtable<nsUint32HashKey, CoalescedMouseData> mCoalescedMouseData;
|
||||
|
||||
nsDeque mToBeDispatchedMouseData;
|
||||
|
||||
CoalescedWheelData mCoalescedWheelData;
|
||||
RefPtr<CoalescedMouseMoveFlusher> mCoalescedMouseEventFlusher;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user