Files
tubestation/dom/ipc/CoalescedTouchData.cpp
Masayuki Nakano 90cd469f14 Bug 1550462 - part 2: Make PresShell::HandleEvent dispatch preceding pointerrawupdate event r=smaug,dom-core,edgar
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
2025-05-16 09:53:52 +00:00

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(); }