tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

APZEventState.cpp (22167B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "APZEventState.h"
      8 
      9 #include <utility>
     10 
     11 #include "APZCCallbackHelper.h"
     12 #include "ElementStateManager.h"
     13 #include "TouchManager.h"
     14 #include "mozilla/Assertions.h"
     15 #include "mozilla/BasicEvents.h"
     16 #include "mozilla/dom/Document.h"
     17 #include "mozilla/EventForwards.h"
     18 #include "mozilla/IntegerPrintfMacros.h"
     19 #include "mozilla/PositionedEventTargeting.h"
     20 #include "mozilla/Preferences.h"
     21 #include "mozilla/PresShell.h"
     22 #include "mozilla/ScrollContainerFrame.h"
     23 #include "mozilla/StaticPrefs_dom.h"
     24 #include "mozilla/StaticPrefs_ui.h"
     25 #include "mozilla/ToString.h"
     26 #include "mozilla/TouchEvents.h"
     27 #include "mozilla/ViewportUtils.h"
     28 #include "mozilla/dom/BrowserChild.h"
     29 #include "mozilla/dom/MouseEventBinding.h"
     30 #include "mozilla/dom/PointerEventHandler.h"
     31 #include "mozilla/layers/APZCCallbackHelper.h"
     32 #include "mozilla/layers/APZUtils.h"
     33 #include "mozilla/layers/IAPZCTreeManager.h"
     34 #include "mozilla/widget/nsAutoRollup.h"
     35 #include "nsCOMPtr.h"
     36 #include "nsContentUtils.h"
     37 #include "nsDocShell.h"
     38 #include "nsIDOMWindowUtils.h"
     39 #include "nsINamed.h"
     40 #include "nsIScrollbarMediator.h"
     41 #include "nsIWeakReferenceUtils.h"
     42 #include "nsIWidget.h"
     43 #include "nsLayoutUtils.h"
     44 #include "nsQueryFrame.h"
     45 
     46 static mozilla::LazyLogModule sApzEvtLog("apz.eventstate");
     47 #define APZES_LOG(...) MOZ_LOG(sApzEvtLog, LogLevel::Debug, (__VA_ARGS__))
     48 
     49 namespace mozilla {
     50 namespace layers {
     51 
     52 APZEventState::APZEventState(nsIWidget* aWidget,
     53                             ContentReceivedInputBlockCallback&& aCallback)
     54    : mWidget(nullptr)  // initialized in constructor body
     55      ,
     56      mElementStateManager(new ElementStateManager()),
     57      mContentReceivedInputBlockCallback(std::move(aCallback)),
     58      mPendingTouchPreventedBlockId(0),
     59      mEndTouchState(apz::SingleTapState::NotClick) {
     60  nsresult rv;
     61  mWidget = do_GetWeakReference(aWidget, &rv);
     62  MOZ_ASSERT(NS_SUCCEEDED(rv),
     63             "APZEventState constructed with a widget that"
     64             " does not support weak references. APZ will NOT work!");
     65 }
     66 
     67 APZEventState::~APZEventState() = default;
     68 
     69 void APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
     70                                     const CSSToLayoutDeviceScale& aScale,
     71                                     Modifiers aModifiers, int32_t aClickCount,
     72                                     uint64_t aInputBlockId) {
     73  APZES_LOG("Handling single tap at %s with %d\n", ToString(aPoint).c_str(),
     74            mTouchEndCancelled);
     75 
     76  RefPtr<nsIContent> touchRollup = GetTouchRollup();
     77  mTouchRollup = nullptr;
     78 
     79  nsCOMPtr<nsIWidget> widget = GetWidget();
     80  if (!widget) {
     81    return;
     82  }
     83 
     84  if (mTouchEndCancelled) {
     85    return;
     86  }
     87 
     88  nsCOMPtr<nsIWidget> localWidget = do_QueryReferent(mWidget);
     89  if (localWidget) {
     90    widget::nsAutoRollup rollup(touchRollup);
     91    APZCCallbackHelper::FireSingleTapEvent(
     92        aPoint * aScale, mLastTouchIdentifier, aModifiers, aClickCount,
     93        mPrecedingPointerDownState, localWidget, mLastTouchSynthesizedForTests);
     94  }
     95 
     96  mElementStateManager->ProcessSingleTap();
     97 }
     98 
     99 PreventDefaultResult APZEventState::FireContextmenuEvents(
    100    PresShell* aPresShell, const CSSPoint& aPoint,
    101    const CSSToLayoutDeviceScale& aScale, uint32_t aPointerId,
    102    Modifiers aModifiers, const nsCOMPtr<nsIWidget>& aWidget,
    103    SynthesizeForTests aSynthesizeForTests) {
    104  // Suppress retargeting for mouse events generated by a long-press
    105  EventRetargetSuppression suppression;
    106 
    107  // Synthesize mousemove event for allowing users to emulate to move mouse
    108  // cursor over the element.  As a result, users can open submenu UI which
    109  // is opened when mouse cursor is moved over a link (i.e., it's a case that
    110  // users cannot stay in the page after tapping it).  So, this improves
    111  // accessibility in websites which are designed for desktop.
    112  // Note that we don't need to check whether mousemove event is consumed or
    113  // not because Chrome also ignores the result.
    114  APZCCallbackHelper::DispatchSynthesizedMouseEvent(
    115      eMouseMove, aPoint * aScale, aPointerId, aModifiers, 0 /* clickCount */,
    116      mPrecedingPointerDownState, aWidget, aSynthesizeForTests);
    117 
    118  PreventDefaultResult preventDefaultResult =
    119      APZCCallbackHelper::DispatchSynthesizedContextmenuEvent(
    120          aPoint * aScale, aPointerId, aModifiers, aWidget,
    121          aSynthesizeForTests);
    122 
    123  APZES_LOG("Contextmenu event %s\n", ToString(preventDefaultResult).c_str());
    124  if (preventDefaultResult != PreventDefaultResult::No) {
    125    // If the contextmenu event was handled then we're showing a contextmenu,
    126    // and so we should remove any activation
    127    mElementStateManager->ClearActivation();
    128 #ifndef XP_WIN
    129  } else {
    130    // If the contextmenu wasn't consumed, fire the eMouseLongTap event.
    131    nsEventStatus status = APZCCallbackHelper::DispatchSynthesizedMouseEvent(
    132        eMouseLongTap, aPoint * aScale, aPointerId, aModifiers,
    133        /*clickCount*/ 1, mPrecedingPointerDownState, aWidget,
    134        aSynthesizeForTests);
    135    APZES_LOG("eMouseLongTap event %s\n", ToString(status).c_str());
    136 #endif
    137  }
    138 
    139  return preventDefaultResult;
    140 }
    141 
    142 void APZEventState::ProcessLongTap(PresShell* aPresShell,
    143                                   const CSSPoint& aPoint,
    144                                   const CSSToLayoutDeviceScale& aScale,
    145                                   Modifiers aModifiers,
    146                                   uint64_t aInputBlockId) {
    147  APZES_LOG("Handling long tap at %s block id %" PRIu64 "\n",
    148            ToString(aPoint).c_str(), aInputBlockId);
    149 
    150  nsCOMPtr<nsIWidget> widget = GetWidget();
    151  if (!widget) {
    152    return;
    153  }
    154 
    155  // If the touch block is waiting for a content response, send one now.
    156  // Bug 1848736: Why is a content response needed here? Can it be removed?
    157  // However, do not clear |mPendingTouchPreventedResponse|, because APZ will
    158  // wait for an additional content response before processing touch-move
    159  // events (since the first touch-move could still be prevented, and that
    160  // should prevent the touch block from being processed).
    161  if (mPendingTouchPreventedResponse) {
    162    APZES_LOG("Sending response %d for pending guid: %s block id: %" PRIu64
    163              " due to long tap\n",
    164              false, ToString(mPendingTouchPreventedGuid).c_str(),
    165              mPendingTouchPreventedBlockId);
    166    mContentReceivedInputBlockCallback(mPendingTouchPreventedBlockId, false);
    167  }
    168 
    169 #ifdef XP_WIN
    170  // On Windows, we fire the contextmenu events when the user lifts their
    171  // finger, in keeping with the platform convention. This happens in the
    172  // ProcessLongTapUp function. However, we still fire the eMouseLongTap event
    173  // at this time, because things like text selection or dragging may want
    174  // to know about it.
    175  APZCCallbackHelper::DispatchSynthesizedMouseEvent(
    176      eMouseLongTap, aPoint * aScale, mLastTouchIdentifier, aModifiers,
    177      /*clickCount*/ 1, mPrecedingPointerDownState, widget,
    178      mLastTouchSynthesizedForTests);
    179 #else
    180  PreventDefaultResult preventDefaultResult =
    181      FireContextmenuEvents(aPresShell, aPoint, aScale, mLastTouchIdentifier,
    182                            aModifiers, widget, mLastTouchSynthesizedForTests);
    183 #endif
    184 
    185  const bool contextmenuOpen =
    186 #ifdef XP_WIN
    187      // On Windows context menu will never be opened by long tap events, the
    188      // menu will open after the user lifts their finger.
    189      false;
    190 #elif defined(MOZ_WIDGET_ANDROID)
    191      // On Android, GeckoView calls preventDefault() in a JSActor
    192      // (ContentDelegateChild.sys.mjs) when opening context menu so that we can
    193      // tell whether contextmenu opens in response to the contextmenu event by
    194      // checking where preventDefault() got called.
    195      preventDefaultResult == PreventDefaultResult::ByChrome;
    196 #else
    197      // On desktop platforms (other than Windows) unlike Android, context menu
    198      // can be opened anywhere even if, for example, there's no link under the
    199      // touch point. So we can assume that "not preventDefault" means a context
    200      // menu is open.
    201      preventDefaultResult == PreventDefaultResult::No;
    202 #endif
    203  // Assuming that contextmenuOpen=true here means a context menu was opened, it
    204  // will be treated as "preventDefaulted" in APZ.
    205  mContentReceivedInputBlockCallback(aInputBlockId, contextmenuOpen);
    206 
    207  if (contextmenuOpen) {
    208    // Also send a touchcancel to content
    209    //  a) on Android if browser's contextmenu is open
    210    //  b) on desktop platforms other than Windows if browser's contextmenu is
    211    //     open
    212    // so that listeners that might be waiting for a touchend don't trigger.
    213    WidgetTouchEvent cancelTouchEvent(true, eTouchCancel, widget.get());
    214    cancelTouchEvent.mFlags.mIsSynthesizedForTests =
    215        static_cast<bool>(mLastTouchSynthesizedForTests);
    216    cancelTouchEvent.mModifiers = aModifiers;
    217    auto ldPoint = LayoutDeviceIntPoint::Round(aPoint * aScale);
    218    cancelTouchEvent.mTouches.AppendElement(new mozilla::dom::Touch(
    219        mLastTouchIdentifier, ldPoint, LayoutDeviceIntPoint(), 0, 0));
    220    APZCCallbackHelper::DispatchWidgetEvent(cancelTouchEvent);
    221  }
    222 }
    223 
    224 void APZEventState::ProcessLongTapUp(PresShell* aPresShell,
    225                                     const CSSPoint& aPoint,
    226                                     const CSSToLayoutDeviceScale& aScale,
    227                                     Modifiers aModifiers) {
    228 #ifdef XP_WIN
    229  nsCOMPtr<nsIWidget> widget = GetWidget();
    230  if (widget) {
    231    FireContextmenuEvents(aPresShell, aPoint, aScale, mLastTouchIdentifier,
    232                          aModifiers, widget, mLastTouchSynthesizedForTests);
    233  }
    234 #endif
    235 }
    236 
    237 void APZEventState::ProcessTouchEvent(
    238    const WidgetTouchEvent& aEvent, const ScrollableLayerGuid& aGuid,
    239    uint64_t aInputBlockId, nsEventStatus aApzResponse,
    240    nsEventStatus aContentResponse,
    241    nsTArray<TouchBehaviorFlags>&& aAllowedTouchBehaviors) {
    242  bool isTouchPrevented = aContentResponse == nsEventStatus_eConsumeNoDefault;
    243  if (aEvent.mMessage == eTouchStart && aEvent.mTouches.Length() > 0) {
    244    mElementStateManager->SetTargetElement(
    245        aEvent.mTouches[0]->GetOriginalTarget(),
    246        ElementStateManager::PreventDefault{isTouchPrevented});
    247    mLastTouchIdentifier = aEvent.mTouches[0]->Identifier();
    248    mLastTouchSynthesizedForTests =
    249        static_cast<SynthesizeForTests>(aEvent.mFlags.mIsSynthesizedForTests);
    250  }
    251  if (aEvent.mMessage == eTouchStart) {
    252    // We get the allowed touch behaviors on a touchstart, but may not actually
    253    // use them until the first touchmove, so we stash them in a member
    254    // variable.
    255    mTouchBlockAllowedBehaviors = std::move(aAllowedTouchBehaviors);
    256  }
    257 
    258  bool mayNeedPointerCancelEvent = false;
    259  APZES_LOG("Handling event type %d isPrevented=%d\n", aEvent.mMessage,
    260            isTouchPrevented);
    261  switch (aEvent.mMessage) {
    262    case eTouchStart: {
    263      mTouchEndCancelled = false;
    264      mReceivedNonTouchStart = false;
    265      mTouchRollup = do_GetWeakReference(widget::nsAutoRollup::GetLastRollup());
    266 
    267      SendPendingTouchPreventedResponse(false);
    268      // The above call may have sent a message to APZ if we get two
    269      // TOUCH_STARTs in a row and just responded to the first one.
    270 
    271      // We're about to send a response back to APZ, but we should only do it
    272      // for events that went through APZ (which should be all of them).
    273      MOZ_ASSERT(aEvent.mFlags.mHandledByAPZ);
    274 
    275      // If the first touchstart event was preventDefaulted, ensure that any
    276      // subsequent additional touchstart events also get preventDefaulted. This
    277      // ensures that e.g. pinch zooming is prevented even if just the first
    278      // touchstart was prevented by content.
    279      if (mTouchCounter.GetActiveTouchCount() == 0) {
    280        mFirstTouchCancelled = isTouchPrevented;
    281        const PointerInfo* pointerInfo =
    282            !aEvent.mTouches.IsEmpty() ? PointerEventHandler::GetPointerInfo(
    283                                             aEvent.mTouches[0]->Identifier())
    284                                       : nullptr;
    285        mPrecedingPointerDownState =
    286            pointerInfo && pointerInfo->mPreventMouseEventByContent
    287                ? PrecedingPointerDown::ConsumedByContent
    288                : PrecedingPointerDown::NotConsumed;
    289      } else {
    290        if (mFirstTouchCancelled && !isTouchPrevented) {
    291          APZES_LOG(
    292              "Propagating prevent-default from first-touch for block %" PRIu64
    293              "\n",
    294              aInputBlockId);
    295        }
    296        isTouchPrevented |= mFirstTouchCancelled;
    297      }
    298 
    299      mTouchStartPrevented = isTouchPrevented;
    300      if (isTouchPrevented) {
    301        mContentReceivedInputBlockCallback(aInputBlockId, isTouchPrevented);
    302      } else {
    303        APZES_LOG("Event not prevented; pending response for %" PRIu64 " %s\n",
    304                  aInputBlockId, ToString(aGuid).c_str());
    305        mPendingTouchPreventedResponse = true;
    306        mPendingTouchPreventedGuid = aGuid;
    307        mPendingTouchPreventedBlockId = aInputBlockId;
    308      }
    309      break;
    310    }
    311 
    312    case eTouchEnd:
    313      if (isTouchPrevented) {
    314        mTouchEndCancelled = true;
    315        mEndTouchState = apz::SingleTapState::NotClick;
    316      }
    317      [[fallthrough]];
    318    case eTouchCancel:
    319      if (mElementStateManager->HandleTouchEndEvent(mEndTouchState)) {
    320        mEndTouchState = apz::SingleTapState::NotClick;
    321      }
    322      [[fallthrough]];
    323    case eTouchMove: {
    324      if (!mReceivedNonTouchStart) {
    325        // In the case where `touchstart` was preventDefaulted,
    326        // pointercancel event should NOT be fired.
    327        mayNeedPointerCancelEvent = !isTouchPrevented && !mTouchStartPrevented;
    328        mReceivedNonTouchStart = true;
    329      }
    330 
    331      if (mPendingTouchPreventedResponse) {
    332        MOZ_ASSERT(aGuid == mPendingTouchPreventedGuid);
    333        if (aEvent.mMessage == eTouchCancel) {
    334          // If we received a touch-cancel and we were waiting for the
    335          // first touch-move to send a content response, make the content
    336          // response be preventDefault=true. This is the safer choice
    337          // because content might have prevented the first touch-move,
    338          // and even though the touch-cancel means any subsequent touch-moves
    339          // will not be processed, the content response still influences
    340          // the InputResult sent to GeckoView.
    341          isTouchPrevented = true;
    342        }
    343        mContentReceivedInputBlockCallback(aInputBlockId, isTouchPrevented);
    344        mPendingTouchPreventedResponse = false;
    345      }
    346      break;
    347    }
    348 
    349    case eTouchRawUpdate:
    350      break;
    351 
    352    default:
    353      MOZ_ASSERT_UNREACHABLE("Unknown touch event type");
    354      break;
    355  }
    356 
    357  mTouchCounter.Update(aEvent);
    358  if (mTouchCounter.GetActiveTouchCount() == 0) {
    359    mFirstTouchCancelled = false;
    360  }
    361 
    362  APZES_LOG("Pointercancel if %d %d %d %d\n", mayNeedPointerCancelEvent,
    363            !isTouchPrevented, aApzResponse == nsEventStatus_eConsumeDoDefault,
    364            MainThreadAgreesEventsAreConsumableByAPZ());
    365  // From https://w3c.github.io/pointerevents/#the-pointercancel-event;
    366  //  The user agent MUST fire a pointer event named pointercancel when it
    367  //  detects a scenario to suppress a pointer event stream.
    368  //
    369  // And "suppress a pointer event steam" is defined in
    370  // https://w3c.github.io/pointerevents/#suppressing-a-pointer-event-stream .
    371  //
    372  // There are four scenarios when the user agent fires a pointercancel event in
    373  // the spec. Below code corresponds to one of the scenarios (the third bullet
    374  // point);
    375  //  The pointer is subsequently used by the user agent to manipulate the page
    376  //  viewport (e.g. panning or zooming).
    377  if (mayNeedPointerCancelEvent &&
    378      aApzResponse == nsEventStatus_eConsumeDoDefault &&
    379      MainThreadAgreesEventsAreConsumableByAPZ()) {
    380    WidgetTouchEvent cancelEvent(aEvent);
    381    cancelEvent.mFlags.mIsSynthesizedForTests =
    382        aEvent.mFlags.mIsSynthesizedForTests;
    383    cancelEvent.mMessage = eTouchPointerCancel;
    384    cancelEvent.mFlags.mCancelable = false;  // mMessage != eTouchCancel;
    385    for (uint32_t i = 0; i < cancelEvent.mTouches.Length(); ++i) {
    386      if (mozilla::dom::Touch* touch = cancelEvent.mTouches[i]) {
    387        touch->convertToPointer = true;
    388      }
    389    }
    390    cancelEvent.mWidget->DispatchEvent(&cancelEvent);
    391  }
    392 }
    393 
    394 bool APZEventState::MainThreadAgreesEventsAreConsumableByAPZ() const {
    395  // APZ errs on the side of saying it can consume touch events to perform
    396  // default user-agent behaviours. In particular it may say this if it hasn't
    397  // received accurate touch-action information. Here we double-check using
    398  // accurate touch-action information. This code is kinda-sorta the main
    399  // thread equivalent of AsyncPanZoomController::ArePointerEventsConsumable().
    400 
    401  switch (mTouchBlockAllowedBehaviors.Length()) {
    402    case 0:
    403      // If we don't have any touch-action (e.g. because it is disabled) then
    404      // APZ has no restrictions.
    405      return true;
    406 
    407    case 1: {
    408      // If there's one touch point in this touch block, then check the pan-x
    409      // and pan-y flags. If neither is allowed, then we disagree with APZ and
    410      // say that it can't do anything with this touch block. Note that it would
    411      // be even better if we could check the allowed scroll directions of the
    412      // scrollframe at this point and refine this further.
    413      TouchBehaviorFlags flags = mTouchBlockAllowedBehaviors[0];
    414      return (flags & AllowedTouchBehavior::HORIZONTAL_PAN) ||
    415             (flags & AllowedTouchBehavior::VERTICAL_PAN);
    416    }
    417 
    418    case 2: {
    419      // If there's two touch points in this touch block, check that they both
    420      // allow zooming.
    421      for (const auto& allowed : mTouchBlockAllowedBehaviors) {
    422        if (!(allowed & AllowedTouchBehavior::PINCH_ZOOM)) {
    423          return false;
    424        }
    425      }
    426      return true;
    427    }
    428 
    429    default:
    430      // More than two touch points? APZ shouldn't be doing anything with this,
    431      // so APZ shouldn't be consuming them.
    432      return false;
    433  }
    434 }
    435 
    436 void APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
    437                                      uint64_t aInputBlockId) {
    438  // If this event starts a swipe, indicate that it shouldn't result in a
    439  // scroll by setting defaultPrevented to true.
    440  bool defaultPrevented = aEvent.DefaultPrevented() || aEvent.TriggersSwipe();
    441  mContentReceivedInputBlockCallback(aInputBlockId, defaultPrevented);
    442 }
    443 
    444 void APZEventState::ProcessMouseEvent(const WidgetMouseEvent& aEvent,
    445                                      uint64_t aInputBlockId) {
    446  bool defaultPrevented = false;
    447  mContentReceivedInputBlockCallback(aInputBlockId, defaultPrevented);
    448 }
    449 
    450 void APZEventState::ProcessAPZStateChange(ViewID aViewId,
    451                                          APZStateChange aChange, int aArg,
    452                                          Maybe<uint64_t> aInputBlockId) {
    453  switch (aChange) {
    454    case APZStateChange::eTransformBegin: {
    455      ScrollContainerFrame* sf =
    456          nsLayoutUtils::FindScrollContainerFrameFor(aViewId);
    457      if (sf) {
    458        sf->SetTransformingByAPZ(true);
    459      }
    460 
    461      nsIContent* content = nsLayoutUtils::FindContentFor(aViewId);
    462      dom::Document* doc = content ? content->GetComposedDoc() : nullptr;
    463      nsCOMPtr<nsIDocShell> docshell(doc ? doc->GetDocShell() : nullptr);
    464      if (docshell && sf) {
    465        nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
    466        nsdocshell->NotifyAsyncPanZoomStarted();
    467      }
    468      break;
    469    }
    470    case APZStateChange::eTransformEnd: {
    471      ScrollContainerFrame* sf =
    472          nsLayoutUtils::FindScrollContainerFrameFor(aViewId);
    473      if (sf) {
    474        sf->SetTransformingByAPZ(false);
    475      }
    476 
    477      nsIContent* content = nsLayoutUtils::FindContentFor(aViewId);
    478      dom::Document* doc = content ? content->GetComposedDoc() : nullptr;
    479      nsCOMPtr<nsIDocShell> docshell(doc ? doc->GetDocShell() : nullptr);
    480      if (docshell && sf) {
    481        nsDocShell* nsdocshell = static_cast<nsDocShell*>(docshell.get());
    482        nsdocshell->NotifyAsyncPanZoomStopped();
    483      }
    484      break;
    485    }
    486    case APZStateChange::eStartTouch: {
    487      bool canBePanOrZoom = aArg;
    488      mElementStateManager->HandleTouchStart(canBePanOrZoom);
    489      // If this is a non-scrollable content, set a timer for the amount of
    490      // time specified by ui.touch_activation.duration_ms to clear the
    491      // active element state.
    492      APZES_LOG("%s: can-be-pan-or-zoom=%d", __FUNCTION__, aArg);
    493      if (!canBePanOrZoom) {
    494        MOZ_ASSERT(aInputBlockId.isSome());
    495      }
    496      break;
    497    }
    498    case APZStateChange::eStartPanning: {
    499      // The user started to pan, so we don't want anything to be :active.
    500      mElementStateManager->HandleStartPanning();
    501      break;
    502    }
    503    case APZStateChange::eEndTouch: {
    504      mEndTouchState = static_cast<apz::SingleTapState>(aArg);
    505      if (mElementStateManager->HandleTouchEnd(mEndTouchState)) {
    506        mEndTouchState = apz::SingleTapState::NotClick;
    507      }
    508      break;
    509    }
    510  }
    511 }
    512 
    513 void APZEventState::Destroy() { mElementStateManager->Destroy(); }
    514 
    515 void APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault) {
    516  if (mPendingTouchPreventedResponse) {
    517    APZES_LOG("Sending response %d for pending guid: %s block id: %" PRIu64
    518              "\n",
    519              aPreventDefault, ToString(mPendingTouchPreventedGuid).c_str(),
    520              mPendingTouchPreventedBlockId);
    521    mContentReceivedInputBlockCallback(mPendingTouchPreventedBlockId,
    522                                       aPreventDefault);
    523    mPendingTouchPreventedResponse = false;
    524  }
    525 }
    526 
    527 already_AddRefed<nsIWidget> APZEventState::GetWidget() const {
    528  nsCOMPtr<nsIWidget> result = do_QueryReferent(mWidget);
    529  return result.forget();
    530 }
    531 
    532 already_AddRefed<nsIContent> APZEventState::GetTouchRollup() const {
    533  nsCOMPtr<nsIContent> result = do_QueryReferent(mTouchRollup);
    534  return result.forget();
    535 }
    536 
    537 }  // namespace layers
    538 }  // namespace mozilla