This patch tries to dispatch ePointerRawUpdate with PresShell::EventHandler::DispatchPrecedingPointerEvent as same as usual pointer events. For using the path, this patch adds 2 internal events, eMouseRawUpdate and eTouchRawUpdate which are never dispatched into the DOM because PresShell::EventHandler::DispatchPrecedingPointerEvent will return false for that and then the caller will stop handling the internal events. There are 3 dispatchers of the internal raw update events. One is PresShell::EnsurePrecedingPointerRawUpdate(). This dispatches the internal event if and only if the coming event of PresShell::HandleEvent will cause ePointerMove. The reason why PresShell::HandleEvent handles the preceding raw-update event is, we should support ePointerRawUpdate events for synthesized events for tests (in-process ones) and in the main process. Additionally, if a pointerrawupdate event may destroy the target <iframe>. In such ase, the following pointermove may need to be dispatched on its parent window or another <iframe> window. Therefore, we need to dispatch the internal raw update event before considering the target window (PresShell) and handling the capturing element. The others are BrowserChild::RecvRealMouseMoveEvent and BrowserChild::RecvRealTouchMoveEvent. They dispatch the internal events when they won't dispatch the received event immediately to coalesce with further similar input. For avoiding to dispatch the internal event for same source event, this adds WidgetPointerHelper::convertToPointerRawUpdate member to check it in PresShell::HandlePrecedingPointerRawUpdate. Differential Revision: https://phabricator.services.mozilla.com/D243404
144 lines
5.4 KiB
C++
144 lines
5.4 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* 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/. */
|
|
|
|
#include "CoalescedTouchData.h"
|
|
#include "BrowserChild.h"
|
|
#include "mozilla/dom/PointerEventHandler.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
|
|
static const uint32_t sMaxTouchMoveIdentifiers = 10;
|
|
|
|
void CoalescedTouchData::CreateCoalescedTouchEvent(
|
|
const WidgetTouchEvent& aEvent) {
|
|
MOZ_ASSERT(IsEmpty());
|
|
mCoalescedInputEvent = MakeUnique<WidgetTouchEvent>(aEvent);
|
|
for (size_t i = 0; i < mCoalescedInputEvent->mTouches.Length(); i++) {
|
|
const RefPtr<Touch>& touch = mCoalescedInputEvent->mTouches[i];
|
|
touch->mCoalescedWidgetEvents = MakeAndAddRef<WidgetPointerEventHolder>();
|
|
// Add an initial event into coalesced events, so
|
|
// the relevant pointer event would at least contain one coalesced event.
|
|
WidgetPointerEvent* event =
|
|
touch->mCoalescedWidgetEvents->mEvents.AppendElement(WidgetPointerEvent(
|
|
aEvent.IsTrusted(), ePointerMove, aEvent.mWidget));
|
|
PointerEventHandler::InitPointerEventFromTouch(*event, aEvent, *touch);
|
|
event->mFlags.mBubbles = false;
|
|
event->mFlags.mCancelable = false;
|
|
event->convertToPointerRawUpdate = false;
|
|
}
|
|
}
|
|
|
|
void CoalescedTouchData::Coalesce(const WidgetTouchEvent& aEvent,
|
|
const ScrollableLayerGuid& aGuid,
|
|
const uint64_t& aInputBlockId,
|
|
const nsEventStatus& aApzResponse) {
|
|
MOZ_ASSERT(aEvent.mMessage == eTouchMove);
|
|
if (IsEmpty()) {
|
|
CreateCoalescedTouchEvent(aEvent);
|
|
mGuid = aGuid;
|
|
mInputBlockId = aInputBlockId;
|
|
mApzResponse = aApzResponse;
|
|
} else {
|
|
MOZ_ASSERT(mGuid == aGuid);
|
|
MOZ_ASSERT(mInputBlockId == aInputBlockId);
|
|
MOZ_ASSERT(mCoalescedInputEvent->mModifiers == aEvent.mModifiers);
|
|
MOZ_ASSERT(mCoalescedInputEvent->mInputSource == aEvent.mInputSource);
|
|
|
|
for (const RefPtr<Touch>& touch : aEvent.mTouches) {
|
|
// Get the same touch in the original event
|
|
const RefPtr<Touch> sameTouch = GetTouch(touch->Identifier());
|
|
// The checks in CoalescedTouchData::CanCoalesce ensure it should never
|
|
// be null.
|
|
MOZ_ASSERT(sameTouch);
|
|
MOZ_ASSERT(sameTouch->mCoalescedWidgetEvents);
|
|
MOZ_ASSERT(!sameTouch->mCoalescedWidgetEvents->mEvents.IsEmpty());
|
|
if (!sameTouch->Equals(touch)) {
|
|
sameTouch->SetSameAs(touch);
|
|
sameTouch->convertToPointerRawUpdate = touch->convertToPointerRawUpdate;
|
|
WidgetPointerEvent* event =
|
|
sameTouch->mCoalescedWidgetEvents->mEvents.AppendElement(
|
|
WidgetPointerEvent(aEvent.IsTrusted(), ePointerMove,
|
|
aEvent.mWidget));
|
|
PointerEventHandler::InitPointerEventFromTouch(*event, aEvent, *touch);
|
|
event->mFlags.mBubbles = false;
|
|
event->mFlags.mCancelable = false;
|
|
}
|
|
}
|
|
|
|
mCoalescedInputEvent->mTimeStamp = aEvent.mTimeStamp;
|
|
}
|
|
}
|
|
|
|
void CoalescedTouchData::NotifyTouchRawUpdateOfHandled(
|
|
const WidgetTouchEvent& aEvent) {
|
|
if (IsEmpty()) {
|
|
return;
|
|
}
|
|
for (const RefPtr<Touch>& touch : aEvent.mTouches) {
|
|
if (const RefPtr<Touch> sameTouch = GetTouch(touch->Identifier())) {
|
|
sameTouch->convertToPointerRawUpdate = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CoalescedTouchData::CanCoalesce(const WidgetTouchEvent& aEvent,
|
|
const ScrollableLayerGuid& aGuid,
|
|
const uint64_t& aInputBlockId,
|
|
const nsEventStatus& aApzResponse) {
|
|
MOZ_ASSERT(!IsEmpty());
|
|
if (mGuid != aGuid || mInputBlockId != aInputBlockId ||
|
|
mCoalescedInputEvent->mModifiers != aEvent.mModifiers ||
|
|
mCoalescedInputEvent->mInputSource != aEvent.mInputSource ||
|
|
aEvent.mTouches.Length() > sMaxTouchMoveIdentifiers) {
|
|
return false;
|
|
}
|
|
|
|
// Ensures both touchmove events have the same touches
|
|
if (aEvent.mTouches.Length() != mCoalescedInputEvent->mTouches.Length()) {
|
|
return false;
|
|
}
|
|
for (const RefPtr<Touch>& touch : aEvent.mTouches) {
|
|
if (!GetTouch(touch->Identifier())) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// If one of them is eIgnore and the other one is eConsumeDoDefault,
|
|
// we always coalesce them to eConsumeDoDefault.
|
|
if (mApzResponse != aApzResponse) {
|
|
if (mApzResponse == nsEventStatus::nsEventStatus_eIgnore &&
|
|
aApzResponse == nsEventStatus::nsEventStatus_eConsumeDoDefault) {
|
|
mApzResponse = aApzResponse;
|
|
} else if (mApzResponse != nsEventStatus::nsEventStatus_eConsumeDoDefault ||
|
|
aApzResponse != nsEventStatus::nsEventStatus_eIgnore) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Touch* CoalescedTouchData::GetTouch(int32_t aIdentifier) {
|
|
for (const RefPtr<Touch>& touch : mCoalescedInputEvent->mTouches) {
|
|
if (touch->Identifier() == aIdentifier) {
|
|
return touch;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void CoalescedTouchMoveFlusher::WillRefresh(mozilla::TimeStamp aTime) {
|
|
MOZ_ASSERT(mRefreshDriver);
|
|
mBrowserChild->ProcessPendingCoalescedTouchData();
|
|
}
|
|
|
|
CoalescedTouchMoveFlusher::CoalescedTouchMoveFlusher(
|
|
BrowserChild* aBrowserChild)
|
|
: CoalescedInputFlusher(aBrowserChild) {}
|
|
|
|
CoalescedTouchMoveFlusher::~CoalescedTouchMoveFlusher() { RemoveObserver(); }
|