summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/util/APZEventState.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /gfx/layers/apz/util/APZEventState.cpp
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/apz/util/APZEventState.cpp')
-rw-r--r--gfx/layers/apz/util/APZEventState.cpp567
1 files changed, 567 insertions, 0 deletions
diff --git a/gfx/layers/apz/util/APZEventState.cpp b/gfx/layers/apz/util/APZEventState.cpp
new file mode 100644
index 0000000000..7384296f45
--- /dev/null
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -0,0 +1,567 @@
+/* -*- 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 "APZEventState.h"
+
+#include <utility>
+
+#include "APZCCallbackHelper.h"
+#include "ActiveElementManager.h"
+#include "TouchManager.h"
+#include "mozilla/Assertions.h"
+#include "mozilla/BasicEvents.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/EventForwards.h"
+#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/PositionedEventTargeting.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/StaticPrefs_dom.h"
+#include "mozilla/StaticPrefs_ui.h"
+#include "mozilla/ToString.h"
+#include "mozilla/TouchEvents.h"
+#include "mozilla/ViewportUtils.h"
+#include "mozilla/dom/BrowserChild.h"
+#include "mozilla/dom/MouseEventBinding.h"
+#include "mozilla/layers/APZCCallbackHelper.h"
+#include "mozilla/layers/IAPZCTreeManager.h"
+#include "mozilla/widget/nsAutoRollup.h"
+#include "nsCOMPtr.h"
+#include "nsContentUtils.h"
+#include "nsDocShell.h"
+#include "nsIDOMWindowUtils.h"
+#include "nsINamed.h"
+#include "nsIScrollableFrame.h"
+#include "nsIScrollbarMediator.h"
+#include "nsIWeakReferenceUtils.h"
+#include "nsIWidget.h"
+#include "nsLayoutUtils.h"
+#include "nsQueryFrame.h"
+
+static mozilla::LazyLogModule sApzEvtLog("apz.eventstate");
+#define APZES_LOG(...) MOZ_LOG(sApzEvtLog, LogLevel::Debug, (__VA_ARGS__))
+
+// Static helper functions
+namespace {
+
+int32_t WidgetModifiersToDOMModifiers(mozilla::Modifiers aModifiers) {
+ int32_t result = 0;
+ if (aModifiers & mozilla::MODIFIER_SHIFT) {
+ result |= nsIDOMWindowUtils::MODIFIER_SHIFT;
+ }
+ if (aModifiers & mozilla::MODIFIER_CONTROL) {
+ result |= nsIDOMWindowUtils::MODIFIER_CONTROL;
+ }
+ if (aModifiers & mozilla::MODIFIER_ALT) {
+ result |= nsIDOMWindowUtils::MODIFIER_ALT;
+ }
+ if (aModifiers & mozilla::MODIFIER_META) {
+ result |= nsIDOMWindowUtils::MODIFIER_META;
+ }
+ if (aModifiers & mozilla::MODIFIER_ALTGRAPH) {
+ result |= nsIDOMWindowUtils::MODIFIER_ALTGRAPH;
+ }
+ if (aModifiers & mozilla::MODIFIER_CAPSLOCK) {
+ result |= nsIDOMWindowUtils::MODIFIER_CAPSLOCK;
+ }
+ if (aModifiers & mozilla::MODIFIER_FN) {
+ result |= nsIDOMWindowUtils::MODIFIER_FN;
+ }
+ if (aModifiers & mozilla::MODIFIER_FNLOCK) {
+ result |= nsIDOMWindowUtils::MODIFIER_FNLOCK;
+ }
+ if (aModifiers & mozilla::MODIFIER_NUMLOCK) {
+ result |= nsIDOMWindowUtils::MODIFIER_NUMLOCK;
+ }
+ if (aModifiers & mozilla::MODIFIER_SCROLLLOCK) {
+ result |= nsIDOMWindowUtils::MODIFIER_SCROLLLOCK;
+ }
+ if (aModifiers & mozilla::MODIFIER_SYMBOL) {
+ result |= nsIDOMWindowUtils::MODIFIER_SYMBOL;
+ }
+ if (aModifiers & mozilla::MODIFIER_SYMBOLLOCK) {
+ result |= nsIDOMWindowUtils::MODIFIER_SYMBOLLOCK;
+ }
+ return result;
+}
+
+} // namespace
+
+namespace mozilla {
+namespace layers {
+
+APZEventState::APZEventState(nsIWidget* aWidget,
+ ContentReceivedInputBlockCallback&& aCallback)
+ : mWidget(nullptr) // initialized in constructor body
+ ,
+ mActiveElementManager(new ActiveElementManager()),
+ mContentReceivedInputBlockCallback(std::move(aCallback)),
+ mPendingTouchPreventedResponse(false),
+ mPendingTouchPreventedBlockId(0),
+ mEndTouchIsClick(false),
+ mFirstTouchCancelled(false),
+ mTouchEndCancelled(false),
+ mReceivedNonTouchStart(false),
+ mTouchStartPrevented(false),
+ mLastTouchIdentifier(0) {
+ nsresult rv;
+ mWidget = do_GetWeakReference(aWidget, &rv);
+ MOZ_ASSERT(NS_SUCCEEDED(rv),
+ "APZEventState constructed with a widget that"
+ " does not support weak references. APZ will NOT work!");
+}
+
+APZEventState::~APZEventState() = default;
+
+void APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
+ const CSSToLayoutDeviceScale& aScale,
+ Modifiers aModifiers, int32_t aClickCount,
+ uint64_t aInputBlockId) {
+ APZES_LOG("Handling single tap at %s with %d\n", ToString(aPoint).c_str(),
+ mTouchEndCancelled);
+
+ RefPtr<nsIContent> touchRollup = GetTouchRollup();
+ mTouchRollup = nullptr;
+
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return;
+ }
+
+ if (mTouchEndCancelled) {
+ return;
+ }
+
+ nsCOMPtr<nsIWidget> localWidget = do_QueryReferent(mWidget);
+ if (localWidget) {
+ widget::nsAutoRollup rollup(touchRollup);
+ APZCCallbackHelper::FireSingleTapEvent(aPoint * aScale, aModifiers,
+ aClickCount, localWidget);
+ }
+
+ mActiveElementManager->ProcessSingleTap();
+}
+
+PreventDefaultResult APZEventState::FireContextmenuEvents(
+ PresShell* aPresShell, const CSSPoint& aPoint,
+ const CSSToLayoutDeviceScale& aScale, Modifiers aModifiers,
+ const nsCOMPtr<nsIWidget>& aWidget) {
+ // Suppress retargeting for mouse events generated by a long-press
+ EventRetargetSuppression suppression;
+
+ // Synthesize mousemove event for allowing users to emulate to move mouse
+ // cursor over the element. As a result, users can open submenu UI which
+ // is opened when mouse cursor is moved over a link (i.e., it's a case that
+ // users cannot stay in the page after tapping it). So, this improves
+ // accessibility in websites which are designed for desktop.
+ // Note that we don't need to check whether mousemove event is consumed or
+ // not because Chrome also ignores the result.
+ APZCCallbackHelper::DispatchSynthesizedMouseEvent(
+ eMouseMove, aPoint * aScale, aModifiers, 0 /* clickCount */, aWidget);
+
+ // Converting the modifiers to DOM format for the DispatchMouseEvent call
+ // is the most useless thing ever because nsDOMWindowUtils::SendMouseEvent
+ // just converts them back to widget format, but that API has many callers,
+ // including in JS code, so it's not trivial to change.
+ CSSPoint point = CSSPoint::FromAppUnits(
+ ViewportUtils::VisualToLayout(CSSPoint::ToAppUnits(aPoint), aPresShell));
+ PreventDefaultResult preventDefaultResult =
+ APZCCallbackHelper::DispatchMouseEvent(
+ aPresShell, u"contextmenu"_ns, point, 2, 1,
+ WidgetModifiersToDOMModifiers(aModifiers),
+ dom::MouseEvent_Binding::MOZ_SOURCE_TOUCH,
+ 0 /* Use the default value here. */);
+
+ APZES_LOG("Contextmenu event %s\n", ToString(preventDefaultResult).c_str());
+ if (preventDefaultResult != PreventDefaultResult::No) {
+ // If the contextmenu event was handled then we're showing a contextmenu,
+ // and so we should remove any activation
+ mActiveElementManager->ClearActivation();
+#ifndef XP_WIN
+ } else {
+ // If the contextmenu wasn't consumed, fire the eMouseLongTap event.
+ nsEventStatus status = APZCCallbackHelper::DispatchSynthesizedMouseEvent(
+ eMouseLongTap, aPoint * aScale, aModifiers,
+ /*clickCount*/ 1, aWidget);
+ APZES_LOG("eMouseLongTap event %s\n", ToString(status).c_str());
+#endif
+ }
+
+ return preventDefaultResult;
+}
+
+void APZEventState::ProcessLongTap(PresShell* aPresShell,
+ const CSSPoint& aPoint,
+ const CSSToLayoutDeviceScale& aScale,
+ Modifiers aModifiers,
+ uint64_t aInputBlockId) {
+ APZES_LOG("Handling long tap at %s block id %" PRIu64 "\n",
+ ToString(aPoint).c_str(), aInputBlockId);
+
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (!widget) {
+ return;
+ }
+
+ // If the touch block is waiting for a content response, send one now.
+ // Bug 1848736: Why is a content response needed here? Can it be removed?
+ // However, do not clear |mPendingTouchPreventedResponse|, because APZ will
+ // wait for an additional content response before processing touch-move
+ // events (since the first touch-move could still be prevented, and that
+ // should prevent the touch block from being processed).
+ if (mPendingTouchPreventedResponse) {
+ APZES_LOG("Sending response %d for pending guid: %s block id: %" PRIu64
+ " due to long tap\n",
+ false, ToString(mPendingTouchPreventedGuid).c_str(),
+ mPendingTouchPreventedBlockId);
+ mContentReceivedInputBlockCallback(mPendingTouchPreventedBlockId, false);
+ }
+
+#ifdef XP_WIN
+ // On Windows, we fire the contextmenu events when the user lifts their
+ // finger, in keeping with the platform convention. This happens in the
+ // ProcessLongTapUp function. However, we still fire the eMouseLongTap event
+ // at this time, because things like text selection or dragging may want
+ // to know about it.
+ APZCCallbackHelper::DispatchSynthesizedMouseEvent(
+ eMouseLongTap, aPoint * aScale, aModifiers, /*clickCount*/ 1, widget);
+#else
+ PreventDefaultResult preventDefaultResult =
+ FireContextmenuEvents(aPresShell, aPoint, aScale, aModifiers, widget);
+#endif
+
+ const bool contextmenuOpen =
+#ifdef XP_WIN
+ // On Windows context menu will never be opened by long tap events, the
+ // menu will open after the user lifts their finger.
+ false;
+#elif defined(MOZ_WIDGET_ANDROID)
+ // On Android, GeckoView calls preventDefault() in a JSActor
+ // (ContentDelegateChild.jsm) when opening context menu so that we can
+ // tell whether contextmenu opens in response to the contextmenu event by
+ // checking where preventDefault() got called.
+ preventDefaultResult == PreventDefaultResult::ByChrome;
+#else
+ // On desktop platforms (other than Windows) unlike Android, context menu
+ // can be opened anywhere even if, for example, there's no link under the
+ // touch point. So we can assume that "not preventDefault" means a context
+ // menu is open.
+ preventDefaultResult == PreventDefaultResult::No;
+#endif
+ // Assuming that contextmenuOpen=true here means a context menu was opened, it
+ // will be treated as "preventDefaulted" in APZ.
+ mContentReceivedInputBlockCallback(aInputBlockId, contextmenuOpen);
+
+ if (contextmenuOpen) {
+ // Also send a touchcancel to content
+ // a) on Android if browser's contextmenu is open
+ // b) on desktop platforms other than Windows if browser's contextmenu is
+ // open
+ // so that listeners that might be waiting for a touchend don't trigger.
+ WidgetTouchEvent cancelTouchEvent(true, eTouchCancel, widget.get());
+ cancelTouchEvent.mModifiers = aModifiers;
+ auto ldPoint = LayoutDeviceIntPoint::Round(aPoint * aScale);
+ cancelTouchEvent.mTouches.AppendElement(new mozilla::dom::Touch(
+ mLastTouchIdentifier, ldPoint, LayoutDeviceIntPoint(), 0, 0));
+ APZCCallbackHelper::DispatchWidgetEvent(cancelTouchEvent);
+ }
+}
+
+void APZEventState::ProcessLongTapUp(PresShell* aPresShell,
+ const CSSPoint& aPoint,
+ const CSSToLayoutDeviceScale& aScale,
+ Modifiers aModifiers) {
+#ifdef XP_WIN
+ nsCOMPtr<nsIWidget> widget = GetWidget();
+ if (widget) {
+ FireContextmenuEvents(aPresShell, aPoint, aScale, aModifiers, widget);
+ }
+#endif
+}
+
+void APZEventState::ProcessTouchEvent(
+ const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
+ uint64_t aInputBlockId, nsEventStatus aApzResponse,
+ nsEventStatus aContentResponse,
+ nsTArray<TouchBehaviorFlags>&& aAllowedTouchBehaviors) {
+ if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() > 0) {
+ mActiveElementManager->SetTargetElement(
+ aEvent.mTouches[0]->GetOriginalTarget());
+ mLastTouchIdentifier = aEvent.mTouches[0]->Identifier();
+ }
+ if (aEvent.mMessage == eTouchStart) {
+ // We get the allowed touch behaviors on a touchstart, but may not actually
+ // use them until the first touchmove, so we stash them in a member
+ // variable.
+ mTouchBlockAllowedBehaviors = std::move(aAllowedTouchBehaviors);
+ }
+
+ bool isTouchPrevented = aContentResponse == nsEventStatus_eConsumeNoDefault;
+ bool mayNeedPointerCancelEvent = false;
+ APZES_LOG("Handling event type %d isPrevented=%d\n", aEvent.mMessage,
+ isTouchPrevented);
+ switch (aEvent.mMessage) {
+ case eTouchStart: {
+ mTouchEndCancelled = false;
+ mReceivedNonTouchStart = false;
+ mTouchRollup = do_GetWeakReference(widget::nsAutoRollup::GetLastRollup());
+
+ SendPendingTouchPreventedResponse(false);
+ // The above call may have sent a message to APZ if we get two
+ // TOUCH_STARTs in a row and just responded to the first one.
+
+ // We're about to send a response back to APZ, but we should only do it
+ // for events that went through APZ (which should be all of them).
+ MOZ_ASSERT(aEvent.mFlags.mHandledByAPZ);
+
+ // If the first touchstart event was preventDefaulted, ensure that any
+ // subsequent additional touchstart events also get preventDefaulted. This
+ // ensures that e.g. pinch zooming is prevented even if just the first
+ // touchstart was prevented by content.
+ if (mTouchCounter.GetActiveTouchCount() == 0) {
+ mFirstTouchCancelled = isTouchPrevented;
+ } else {
+ if (mFirstTouchCancelled && !isTouchPrevented) {
+ APZES_LOG(
+ "Propagating prevent-default from first-touch for block %" PRIu64
+ "\n",
+ aInputBlockId);
+ }
+ isTouchPrevented |= mFirstTouchCancelled;
+ }
+
+ mTouchStartPrevented = isTouchPrevented;
+ if (isTouchPrevented) {
+ mContentReceivedInputBlockCallback(aInputBlockId, isTouchPrevented);
+ } else {
+ APZES_LOG("Event not prevented; pending response for %" PRIu64 " %s\n",
+ aInputBlockId, ToString(aGuid).c_str());
+ mPendingTouchPreventedResponse = true;
+ mPendingTouchPreventedGuid = aGuid;
+ mPendingTouchPreventedBlockId = aInputBlockId;
+ }
+ break;
+ }
+
+ case eTouchEnd:
+ if (isTouchPrevented) {
+ mTouchEndCancelled = true;
+ mEndTouchIsClick = false;
+ }
+ [[fallthrough]];
+ case eTouchCancel:
+ mActiveElementManager->HandleTouchEndEvent(mEndTouchIsClick);
+ [[fallthrough]];
+ case eTouchMove: {
+ if (!mReceivedNonTouchStart) {
+ // In the case where `touchstart` was preventDefaulted,
+ // pointercancel event should NOT be fired.
+ mayNeedPointerCancelEvent = !isTouchPrevented && !mTouchStartPrevented;
+ mReceivedNonTouchStart = true;
+ }
+
+ if (mPendingTouchPreventedResponse) {
+ MOZ_ASSERT(aGuid == mPendingTouchPreventedGuid);
+ if (aEvent.mMessage == eTouchCancel) {
+ // If we received a touch-cancel and we were waiting for the
+ // first touch-move to send a content response, make the content
+ // response be preventDefault=true. This is the safer choice
+ // because content might have prevented the first touch-move,
+ // and even though the touch-cancel means any subsequent touch-moves
+ // will not be processed, the content response still influences
+ // the InputResult sent to GeckoView.
+ isTouchPrevented = true;
+ }
+ mContentReceivedInputBlockCallback(aInputBlockId, isTouchPrevented);
+ mPendingTouchPreventedResponse = false;
+ }
+ break;
+ }
+
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown touch event type");
+ break;
+ }
+
+ mTouchCounter.Update(aEvent);
+ if (mTouchCounter.GetActiveTouchCount() == 0) {
+ mFirstTouchCancelled = false;
+ }
+
+ APZES_LOG("Pointercancel if %d %d %d %d\n", mayNeedPointerCancelEvent,
+ !isTouchPrevented, aApzResponse == nsEventStatus_eConsumeDoDefault,
+ MainThreadAgreesEventsAreConsumableByAPZ());
+ // From https://w3c.github.io/pointerevents/#the-pointercancel-event;
+ // The user agent MUST fire a pointer event named pointercancel when it
+ // detects a scenario to suppress a pointer event stream.
+ //
+ // And "suppress a pointer event steam" is defined in
+ // https://w3c.github.io/pointerevents/#suppressing-a-pointer-event-stream .
+ //
+ // There are four scenarios when the user agent fires a pointercancel event in
+ // the spec. Below code corresponds to one of the scenarios (the third bullet
+ // point);
+ // The pointer is subsequently used by the user agent to manipulate the page
+ // viewport (e.g. panning or zooming).
+ if (mayNeedPointerCancelEvent &&
+ aApzResponse == nsEventStatus_eConsumeDoDefault &&
+ MainThreadAgreesEventsAreConsumableByAPZ()) {
+ WidgetTouchEvent cancelEvent(aEvent);
+ cancelEvent.mMessage = eTouchPointerCancel;
+ cancelEvent.mFlags.mCancelable = false; // mMessage != eTouchCancel;
+ for (uint32_t i = 0; i < cancelEvent.mTouches.Length(); ++i) {
+ if (mozilla::dom::Touch* touch = cancelEvent.mTouches[i]) {
+ touch->convertToPointer = true;
+ }
+ }
+ nsEventStatus status;
+ cancelEvent.mWidget->DispatchEvent(&cancelEvent, status);
+ }
+}
+
+bool APZEventState::MainThreadAgreesEventsAreConsumableByAPZ() const {
+ // APZ errs on the side of saying it can consume touch events to perform
+ // default user-agent behaviours. In particular it may say this if it hasn't
+ // received accurate touch-action information. Here we double-check using
+ // accurate touch-action information. This code is kinda-sorta the main
+ // thread equivalent of AsyncPanZoomController::ArePointerEventsConsumable().
+
+ switch (mTouchBlockAllowedBehaviors.Length()) {
+ case 0:
+ // If we don't have any touch-action (e.g. because it is disabled) then
+ // APZ has no restrictions.
+ return true;
+
+ case 1: {
+ // If there's one touch point in this touch block, then check the pan-x
+ // and pan-y flags. If neither is allowed, then we disagree with APZ and
+ // say that it can't do anything with this touch block. Note that it would
+ // be even better if we could check the allowed scroll directions of the
+ // scrollframe at this point and refine this further.
+ TouchBehaviorFlags flags = mTouchBlockAllowedBehaviors[0];
+ return (flags & AllowedTouchBehavior::HORIZONTAL_PAN) ||
+ (flags & AllowedTouchBehavior::VERTICAL_PAN);
+ }
+
+ case 2: {
+ // If there's two touch points in this touch block, check that they both
+ // allow zooming.
+ for (const auto& allowed : mTouchBlockAllowedBehaviors) {
+ if (!(allowed & AllowedTouchBehavior::PINCH_ZOOM)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ default:
+ // More than two touch points? APZ shouldn't be doing anything with this,
+ // so APZ shouldn't be consuming them.
+ return false;
+ }
+}
+
+void APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
+ uint64_t aInputBlockId) {
+ // If this event starts a swipe, indicate that it shouldn't result in a
+ // scroll by setting defaultPrevented to true.
+ bool defaultPrevented = aEvent.DefaultPrevented() || aEvent.TriggersSwipe();
+ mContentReceivedInputBlockCallback(aInputBlockId, defaultPrevented);
+}
+
+void APZEventState::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
+ uint64_t aInputBlockId) {
+ bool defaultPrevented = false;
+ mContentReceivedInputBlockCallback(aInputBlockId, defaultPrevented);
+}
+
+void APZEventState::ProcessAPZStateChange(ViewID aViewId,
+ APZStateChange aChange, int aArg,
+ Maybe<uint64_t> aInputBlockId) {
+ switch (aChange) {
+ case APZStateChange::eTransformBegin: {
+ nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
+ if (sf) {
+ sf->SetTransformingByAPZ(true);
+ sf->ScrollbarActivityStarted();
+ }
+
+ nsIContent* content = nsLayoutUtils::FindContentFor(aViewId);
+ dom::Document* doc = content ? content->GetComposedDoc() : nullptr;
+ nsCOMPtr<nsIDocShell> docshell(doc ? doc->GetDocShell() : nullptr);
+ if (docshell && sf) {
+ nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
+ nsdocshell->NotifyAsyncPanZoomStarted();
+ }
+ break;
+ }
+ case APZStateChange::eTransformEnd: {
+ nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aViewId);
+ if (sf) {
+ sf->SetTransformingByAPZ(false);
+ sf->ScrollbarActivityStopped();
+ }
+
+ nsIContent* content = nsLayoutUtils::FindContentFor(aViewId);
+ dom::Document* doc = content ? content->GetComposedDoc() : nullptr;
+ nsCOMPtr<nsIDocShell> docshell(doc ? doc->GetDocShell() : nullptr);
+ if (docshell && sf) {
+ nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
+ nsdocshell->NotifyAsyncPanZoomStopped();
+ }
+ break;
+ }
+ case APZStateChange::eStartTouch: {
+ bool canBePan = aArg;
+ mActiveElementManager->HandleTouchStart(canBePan);
+ // If this is a non-scrollable content, set a timer for the amount of
+ // time specified by ui.touch_activation.duration_ms to clear the
+ // active element state.
+ APZES_LOG("%s: can-be-pan=%d", __FUNCTION__, aArg);
+ if (!canBePan) {
+ MOZ_ASSERT(aInputBlockId.isSome());
+ }
+ break;
+ }
+ case APZStateChange::eStartPanning: {
+ // The user started to pan, so we don't want anything to be :active.
+ mActiveElementManager->ClearActivation();
+ break;
+ }
+ case APZStateChange::eEndTouch: {
+ mEndTouchIsClick = aArg;
+ mActiveElementManager->HandleTouchEnd();
+ break;
+ }
+ }
+}
+
+void APZEventState::Destroy() { mActiveElementManager->Destroy(); }
+
+void APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault) {
+ if (mPendingTouchPreventedResponse) {
+ APZES_LOG("Sending response %d for pending guid: %s block id: %" PRIu64
+ "\n",
+ aPreventDefault, ToString(mPendingTouchPreventedGuid).c_str(),
+ mPendingTouchPreventedBlockId);
+ mContentReceivedInputBlockCallback(mPendingTouchPreventedBlockId,
+ aPreventDefault);
+ mPendingTouchPreventedResponse = false;
+ }
+}
+
+already_AddRefed<nsIWidget> APZEventState::GetWidget() const {
+ nsCOMPtr<nsIWidget> result = do_QueryReferent(mWidget);
+ return result.forget();
+}
+
+already_AddRefed<nsIContent> APZEventState::GetTouchRollup() const {
+ nsCOMPtr<nsIContent> result = do_QueryReferent(mTouchRollup);
+ return result.forget();
+}
+
+} // namespace layers
+} // namespace mozilla