tor-browser

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

AccessibleCaretEventHub.cpp (22105B)


      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 "AccessibleCaretEventHub.h"
      8 
      9 #include "AccessibleCaretLogger.h"
     10 #include "AccessibleCaretManager.h"
     11 #include "mozilla/AutoRestore.h"
     12 #include "mozilla/PresShell.h"
     13 #include "mozilla/StaticPrefs_layout.h"
     14 #include "mozilla/StaticPrefs_ui.h"
     15 #include "mozilla/TextEvents.h"
     16 #include "mozilla/TouchEvents.h"
     17 #include "mozilla/dom/Document.h"
     18 #include "mozilla/dom/MouseEventBinding.h"
     19 #include "mozilla/dom/Selection.h"
     20 #include "nsCanvasFrame.h"
     21 #include "nsDocShell.h"
     22 #include "nsFocusManager.h"
     23 #include "nsFrameSelection.h"
     24 #include "nsITimer.h"
     25 #include "nsLayoutUtils.h"
     26 #include "nsPresContext.h"
     27 
     28 using namespace mozilla;
     29 using namespace mozilla::dom;
     30 
     31 namespace mozilla {
     32 
     33 #undef AC_LOG
     34 #define AC_LOG(message, ...) \
     35  AC_LOG_BASE("AccessibleCaretEventHub (%p): " message, this, ##__VA_ARGS__);
     36 
     37 #undef AC_LOGV
     38 #define AC_LOGV(message, ...) \
     39  AC_LOGV_BASE("AccessibleCaretEventHub (%p): " message, this, ##__VA_ARGS__);
     40 
     41 NS_IMPL_ISUPPORTS(AccessibleCaretEventHub, nsIReflowObserver, nsIScrollObserver,
     42                  nsISupportsWeakReference);
     43 
     44 // -----------------------------------------------------------------------------
     45 // NoActionState
     46 //
     47 class AccessibleCaretEventHub::NoActionState
     48    : public AccessibleCaretEventHub::State {
     49 public:
     50  const char* Name() const override { return "NoActionState"; }
     51 
     52  MOZ_CAN_RUN_SCRIPT
     53  nsEventStatus OnPress(AccessibleCaretEventHub* aContext,
     54                        const nsPoint& aPoint, int32_t aTouchId,
     55                        EventClassID aEventClass) override {
     56    nsEventStatus rv = nsEventStatus_eIgnore;
     57 
     58    if (NS_SUCCEEDED(aContext->mManager->PressCaret(aPoint, aEventClass))) {
     59      aContext->SetState(AccessibleCaretEventHub::PressCaretState());
     60      rv = nsEventStatus_eConsumeNoDefault;
     61    } else {
     62      aContext->SetState(AccessibleCaretEventHub::PressNoCaretState());
     63    }
     64 
     65    aContext->mPressPoint = aPoint;
     66    aContext->mActiveTouchId = aTouchId;
     67 
     68    return rv;
     69  }
     70 
     71  MOZ_CAN_RUN_SCRIPT
     72  void OnScrollStart(AccessibleCaretEventHub* aContext) override {
     73    aContext->mManager->OnScrollStart();
     74    aContext->SetState(AccessibleCaretEventHub::ScrollState());
     75  }
     76 
     77  MOZ_CAN_RUN_SCRIPT
     78  void OnScrollPositionChanged(AccessibleCaretEventHub* aContext) override {
     79    aContext->mManager->OnScrollPositionChanged();
     80  }
     81 
     82  MOZ_CAN_RUN_SCRIPT
     83  void OnSelectionChanged(AccessibleCaretEventHub* aContext, Document* aDoc,
     84                          dom::Selection* aSel, int16_t aReason) override {
     85    aContext->mManager->OnSelectionChanged(aDoc, aSel, aReason);
     86  }
     87 
     88  MOZ_CAN_RUN_SCRIPT
     89  void OnBlur(AccessibleCaretEventHub* aContext,
     90              bool aIsLeavingDocument) override {
     91    aContext->mManager->OnBlur();
     92  }
     93 
     94  MOZ_CAN_RUN_SCRIPT
     95  void OnReflow(AccessibleCaretEventHub* aContext) override {
     96    aContext->mManager->OnReflow();
     97  }
     98 
     99  void Enter(AccessibleCaretEventHub* aContext) override {
    100    aContext->mPressPoint = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    101    aContext->mActiveTouchId = kInvalidTouchId;
    102  }
    103 };
    104 
    105 // -----------------------------------------------------------------------------
    106 // PressCaretState: Because we've pressed on the caret, always consume the
    107 // event, both real and synthesized, so that other event handling code won't
    108 // have a chance to do something else to interrupt caret dragging.
    109 //
    110 class AccessibleCaretEventHub::PressCaretState
    111    : public AccessibleCaretEventHub::State {
    112 public:
    113  const char* Name() const override { return "PressCaretState"; }
    114 
    115  MOZ_CAN_RUN_SCRIPT
    116  nsEventStatus OnMove(AccessibleCaretEventHub* aContext, const nsPoint& aPoint,
    117                       WidgetMouseEvent::Reason aReason) override {
    118    if (aReason == WidgetMouseEvent::eReal &&
    119        aContext->MoveDistanceIsLarge(aPoint)) {
    120      if (NS_SUCCEEDED(aContext->mManager->DragCaret(aPoint))) {
    121        aContext->SetState(AccessibleCaretEventHub::DragCaretState());
    122      }
    123    }
    124 
    125    return nsEventStatus_eConsumeNoDefault;
    126  }
    127 
    128  MOZ_CAN_RUN_SCRIPT
    129  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
    130    aContext->mManager->ReleaseCaret();
    131    aContext->mManager->TapCaret(aContext->mPressPoint);
    132    aContext->SetState(AccessibleCaretEventHub::NoActionState());
    133 
    134    return nsEventStatus_eConsumeNoDefault;
    135  }
    136 
    137  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
    138                          const nsPoint& aPoint) override {
    139    return nsEventStatus_eConsumeNoDefault;
    140  }
    141 };
    142 
    143 // -----------------------------------------------------------------------------
    144 // DragCaretState: Because we've pressed on the caret, always consume the event,
    145 // both real and synthesized, so that other event handling code won't have a
    146 // chance to do something else to interrupt caret dragging.
    147 //
    148 class AccessibleCaretEventHub::DragCaretState
    149    : public AccessibleCaretEventHub::State {
    150 public:
    151  const char* Name() const override { return "DragCaretState"; }
    152 
    153  MOZ_CAN_RUN_SCRIPT
    154  nsEventStatus OnMove(AccessibleCaretEventHub* aContext, const nsPoint& aPoint,
    155                       WidgetMouseEvent::Reason aReason) override {
    156    if (aReason == WidgetMouseEvent::eReal) {
    157      aContext->mManager->DragCaret(aPoint);
    158    }
    159 
    160    return nsEventStatus_eConsumeNoDefault;
    161  }
    162 
    163  MOZ_CAN_RUN_SCRIPT
    164  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
    165    aContext->mManager->ReleaseCaret();
    166    aContext->SetState(AccessibleCaretEventHub::NoActionState());
    167 
    168    return nsEventStatus_eConsumeNoDefault;
    169  }
    170 };
    171 
    172 // -----------------------------------------------------------------------------
    173 // PressNoCaretState
    174 //
    175 class AccessibleCaretEventHub::PressNoCaretState
    176    : public AccessibleCaretEventHub::State {
    177 public:
    178  const char* Name() const override { return "PressNoCaretState"; }
    179 
    180  nsEventStatus OnMove(AccessibleCaretEventHub* aContext, const nsPoint& aPoint,
    181                       WidgetMouseEvent::Reason aReason) override {
    182    if (aContext->MoveDistanceIsLarge(aPoint)) {
    183      aContext->SetState(AccessibleCaretEventHub::NoActionState());
    184    }
    185 
    186    return nsEventStatus_eIgnore;
    187  }
    188 
    189  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
    190    aContext->SetState(AccessibleCaretEventHub::NoActionState());
    191 
    192    return nsEventStatus_eIgnore;
    193  }
    194 
    195  MOZ_CAN_RUN_SCRIPT
    196  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
    197                          const nsPoint& aPoint) override {
    198    aContext->SetState(AccessibleCaretEventHub::LongTapState());
    199 
    200    return aContext->GetState()->OnLongTap(aContext, aPoint);
    201  }
    202 
    203  MOZ_CAN_RUN_SCRIPT
    204  void OnScrollStart(AccessibleCaretEventHub* aContext) override {
    205    aContext->mManager->OnScrollStart();
    206    aContext->SetState(AccessibleCaretEventHub::ScrollState());
    207  }
    208 
    209  MOZ_CAN_RUN_SCRIPT
    210  void OnBlur(AccessibleCaretEventHub* aContext,
    211              bool aIsLeavingDocument) override {
    212    aContext->mManager->OnBlur();
    213    if (aIsLeavingDocument) {
    214      aContext->SetState(AccessibleCaretEventHub::NoActionState());
    215    }
    216  }
    217 
    218  MOZ_CAN_RUN_SCRIPT
    219  void OnSelectionChanged(AccessibleCaretEventHub* aContext, Document* aDoc,
    220                          dom::Selection* aSel, int16_t aReason) override {
    221    aContext->mManager->OnSelectionChanged(aDoc, aSel, aReason);
    222  }
    223 
    224  MOZ_CAN_RUN_SCRIPT
    225  void OnReflow(AccessibleCaretEventHub* aContext) override {
    226    aContext->mManager->OnReflow();
    227  }
    228 
    229  void Enter(AccessibleCaretEventHub* aContext) override {
    230    aContext->LaunchLongTapInjector();
    231  }
    232 
    233  void Leave(AccessibleCaretEventHub* aContext) override {
    234    aContext->CancelLongTapInjector();
    235  }
    236 };
    237 
    238 // -----------------------------------------------------------------------------
    239 // ScrollState
    240 //
    241 class AccessibleCaretEventHub::ScrollState
    242    : public AccessibleCaretEventHub::State {
    243 public:
    244  const char* Name() const override { return "ScrollState"; }
    245 
    246  MOZ_CAN_RUN_SCRIPT
    247  void OnScrollEnd(AccessibleCaretEventHub* aContext) override {
    248    aContext->mManager->OnScrollEnd();
    249    aContext->SetState(AccessibleCaretEventHub::NoActionState());
    250  }
    251 
    252  MOZ_CAN_RUN_SCRIPT
    253  void OnScrollPositionChanged(AccessibleCaretEventHub* aContext) override {
    254    aContext->mManager->OnScrollPositionChanged();
    255  }
    256 
    257  MOZ_CAN_RUN_SCRIPT
    258  void OnBlur(AccessibleCaretEventHub* aContext,
    259              bool aIsLeavingDocument) override {
    260    aContext->mManager->OnBlur();
    261    if (aIsLeavingDocument) {
    262      aContext->SetState(AccessibleCaretEventHub::NoActionState());
    263    }
    264  }
    265 };
    266 
    267 // -----------------------------------------------------------------------------
    268 // LongTapState
    269 //
    270 class AccessibleCaretEventHub::LongTapState
    271    : public AccessibleCaretEventHub::State {
    272 public:
    273  const char* Name() const override { return "LongTapState"; }
    274 
    275  MOZ_CAN_RUN_SCRIPT
    276  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
    277                          const nsPoint& aPoint) override {
    278    // In general text selection is lower-priority than the context menu. If
    279    // we consume this long-press event, then it prevents the context menu from
    280    // showing up on desktop Firefox (because that happens on long-tap-up, if
    281    // the long-tap was not cancelled). So we return eIgnore instead.
    282    aContext->mManager->SelectWordOrShortcut(aPoint);
    283    return nsEventStatus_eIgnore;
    284  }
    285 
    286  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
    287    aContext->SetState(AccessibleCaretEventHub::NoActionState());
    288 
    289    // Do not consume the release since the press is not consumed in
    290    // PressNoCaretState either.
    291    return nsEventStatus_eIgnore;
    292  }
    293 
    294  MOZ_CAN_RUN_SCRIPT
    295  void OnScrollStart(AccessibleCaretEventHub* aContext) override {
    296    aContext->mManager->OnScrollStart();
    297    aContext->SetState(AccessibleCaretEventHub::ScrollState());
    298  }
    299 
    300  MOZ_CAN_RUN_SCRIPT
    301  void OnReflow(AccessibleCaretEventHub* aContext) override {
    302    aContext->mManager->OnReflow();
    303  }
    304 };
    305 
    306 // -----------------------------------------------------------------------------
    307 // Implementation of AccessibleCaretEventHub methods
    308 //
    309 AccessibleCaretEventHub::State* AccessibleCaretEventHub::GetState() const {
    310  return mState;
    311 }
    312 
    313 void AccessibleCaretEventHub::SetState(State* aState) {
    314  MOZ_ASSERT(aState);
    315 
    316  AC_LOG("%s -> %s", mState->Name(), aState->Name());
    317 
    318  mState->Leave(this);
    319  mState = aState;
    320  mState->Enter(this);
    321 }
    322 
    323 MOZ_IMPL_STATE_CLASS_GETTER(NoActionState)
    324 MOZ_IMPL_STATE_CLASS_GETTER(PressCaretState)
    325 MOZ_IMPL_STATE_CLASS_GETTER(DragCaretState)
    326 MOZ_IMPL_STATE_CLASS_GETTER(PressNoCaretState)
    327 MOZ_IMPL_STATE_CLASS_GETTER(ScrollState)
    328 MOZ_IMPL_STATE_CLASS_GETTER(LongTapState)
    329 
    330 AccessibleCaretEventHub::AccessibleCaretEventHub(PresShell* aPresShell)
    331    : mPresShell(aPresShell) {}
    332 
    333 void AccessibleCaretEventHub::Init() {
    334  if (mInitialized || !mPresShell) {
    335    return;
    336  }
    337 
    338  // Without nsAutoScriptBlocker, the script might be run after constructing
    339  // mFirstCaret in AccessibleCaretManager's constructor, which might destructs
    340  // the whole frame tree. Therefore we'll fail to construct mSecondCaret
    341  // because we cannot get root frame or canvas frame from mPresShell to inject
    342  // anonymous content. To avoid that, we protect Init() by nsAutoScriptBlocker.
    343  // To reproduce, run "./mach crashtest layout/base/crashtests/897852.html"
    344  // without the following scriptBlocker.
    345  nsAutoScriptBlocker scriptBlocker;
    346 
    347  nsPresContext* presContext = mPresShell->GetPresContext();
    348  MOZ_ASSERT(presContext, "PresContext should be given in PresShell::Init()");
    349 
    350  nsDocShell* docShell = presContext->GetDocShell();
    351  if (!docShell) {
    352    return;
    353  }
    354 
    355  docShell->AddWeakReflowObserver(this);
    356  docShell->AddWeakScrollObserver(this);
    357 
    358  mDocShell = static_cast<nsDocShell*>(docShell);
    359 
    360  if (StaticPrefs::layout_accessiblecaret_use_long_tap_injector()) {
    361    mLongTapInjectorTimer = NS_NewTimer();
    362  }
    363 
    364  mManager = MakeUnique<AccessibleCaretManager>(mPresShell);
    365 
    366  mInitialized = true;
    367 }
    368 
    369 void AccessibleCaretEventHub::Terminate() {
    370  if (!mInitialized) {
    371    return;
    372  }
    373 
    374  if (mDocShell) {
    375    mDocShell->RemoveWeakReflowObserver(this);
    376    mDocShell->RemoveWeakScrollObserver(this);
    377  }
    378 
    379  if (mLongTapInjectorTimer) {
    380    mLongTapInjectorTimer->Cancel();
    381  }
    382 
    383  mManager->Terminate();
    384  mPresShell = nullptr;
    385  mInitialized = false;
    386 }
    387 
    388 nsEventStatus AccessibleCaretEventHub::HandleEvent(WidgetEvent* aEvent) {
    389  nsEventStatus status = nsEventStatus_eIgnore;
    390 
    391  if (!mInitialized) {
    392    return status;
    393  }
    394 
    395  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    396 
    397  switch (aEvent->mClass) {
    398    case ePointerEventClass:
    399      if (!IsPointerEventMessageOriginallyMouseEventMessage(aEvent->mMessage)) {
    400        break;
    401      }
    402      [[fallthrough]];
    403    case eMouseEventClass:
    404      status = HandleMouseEvent(aEvent->AsMouseEvent());
    405      break;
    406 
    407    case eTouchEventClass:
    408      status = HandleTouchEvent(aEvent->AsTouchEvent());
    409      break;
    410 
    411    case eKeyboardEventClass:
    412      status = HandleKeyboardEvent(aEvent->AsKeyboardEvent());
    413      break;
    414 
    415    default:
    416      MOZ_ASSERT_UNREACHABLE(
    417          "PresShell should've filtered unwanted event classes!");
    418      break;
    419  }
    420 
    421  return status;
    422 }
    423 
    424 nsEventStatus AccessibleCaretEventHub::HandleMouseEvent(
    425    WidgetMouseEvent* aEvent) {
    426  nsEventStatus rv = nsEventStatus_eIgnore;
    427 
    428  if (aEvent->mButton != MouseButton::ePrimary) {
    429    return rv;
    430  }
    431 
    432  int32_t id =
    433      (mActiveTouchId == kInvalidTouchId ? kDefaultTouchId : mActiveTouchId);
    434  nsPoint point = GetMouseEventPosition(aEvent);
    435 
    436  if (aEvent->mMessage == eMouseDown || aEvent->mMessage == eMouseUp ||
    437      aEvent->mMessage == ePointerClick ||
    438      aEvent->mMessage == eMouseDoubleClick ||
    439      aEvent->mMessage == eMouseLongTap) {
    440    // Don't reset the source on mouse movement since that can
    441    // happen anytime, even randomly during a touch sequence.
    442    mManager->SetLastInputSource(aEvent->mInputSource);
    443  }
    444 
    445  switch (aEvent->mMessage) {
    446    case eMouseDown:
    447      AC_LOGV("Before eMouseDown, state: %s", mState->Name());
    448      rv = mState->OnPress(this, point, id, eMouseEventClass);
    449      AC_LOGV("After eMouseDown, state: %s, consume: %d", mState->Name(), rv);
    450      break;
    451 
    452    case eMouseMove:
    453      AC_LOGV("Before eMouseMove, state: %s", mState->Name());
    454      // The mouse move events synthesized from the touch move events can have
    455      // wrong point (bug 1549355). Workaround it by ignoring the events when
    456      // dragging the caret because the caret doesn't really need them.
    457      rv = mState->OnMove(this, point, aEvent->mReason);
    458      AC_LOGV("After eMouseMove, state: %s, consume: %d", mState->Name(), rv);
    459      break;
    460 
    461    case eMouseUp:
    462      AC_LOGV("Before eMouseUp, state: %s", mState->Name());
    463      rv = mState->OnRelease(this);
    464      AC_LOGV("After eMouseUp, state: %s, consume: %d", mState->Name(), rv);
    465      break;
    466 
    467    case eMouseLongTap:
    468      AC_LOGV("Before eMouseLongTap, state: %s", mState->Name());
    469      rv = mState->OnLongTap(this, point);
    470      AC_LOGV("After eMouseLongTap, state: %s, consume: %d", mState->Name(),
    471              rv);
    472      break;
    473 
    474    default:
    475      break;
    476  }
    477 
    478  return rv;
    479 }
    480 
    481 nsEventStatus AccessibleCaretEventHub::HandleTouchEvent(
    482    WidgetTouchEvent* aEvent) {
    483  if (aEvent->mTouches.IsEmpty()) {
    484    AC_LOG("%s: Receive a touch event without any touch data!", __FUNCTION__);
    485    return nsEventStatus_eIgnore;
    486  }
    487 
    488  nsEventStatus rv = nsEventStatus_eIgnore;
    489 
    490  int32_t id =
    491      (mActiveTouchId == kInvalidTouchId ? aEvent->mTouches[0]->Identifier()
    492                                         : mActiveTouchId);
    493  nsPoint point = GetTouchEventPosition(aEvent, id);
    494 
    495  mManager->SetLastInputSource(MouseEvent_Binding::MOZ_SOURCE_TOUCH);
    496 
    497  switch (aEvent->mMessage) {
    498    case eTouchStart:
    499      AC_LOGV("Before eTouchStart, state: %s", mState->Name());
    500      rv = mState->OnPress(this, point, id, eTouchEventClass);
    501      AC_LOGV("After eTouchStart, state: %s, consume: %d", mState->Name(), rv);
    502      break;
    503 
    504    case eTouchMove:
    505      AC_LOGV("Before eTouchMove, state: %s", mState->Name());
    506      // There is no synthesized touch move event.
    507      rv = mState->OnMove(this, point, WidgetMouseEvent::eReal);
    508      AC_LOGV("After eTouchMove, state: %s, consume: %d", mState->Name(), rv);
    509      break;
    510 
    511    case eTouchEnd:
    512      AC_LOGV("Before eTouchEnd, state: %s", mState->Name());
    513      rv = mState->OnRelease(this);
    514      AC_LOGV("After eTouchEnd, state: %s, consume: %d", mState->Name(), rv);
    515      break;
    516 
    517    case eTouchCancel:
    518      AC_LOGV("Got eTouchCancel, state: %s", mState->Name());
    519      // Do nothing since we don't really care eTouchCancel anyway.
    520      break;
    521 
    522    default:
    523      break;
    524  }
    525 
    526  return rv;
    527 }
    528 
    529 nsEventStatus AccessibleCaretEventHub::HandleKeyboardEvent(
    530    WidgetKeyboardEvent* aEvent) {
    531  mManager->SetLastInputSource(MouseEvent_Binding::MOZ_SOURCE_KEYBOARD);
    532 
    533  switch (aEvent->mMessage) {
    534    case eKeyUp:
    535      AC_LOGV("eKeyUp, state: %s", mState->Name());
    536      mManager->OnKeyboardEvent();
    537      break;
    538 
    539    case eKeyDown:
    540      AC_LOGV("eKeyDown, state: %s", mState->Name());
    541      mManager->OnKeyboardEvent();
    542      break;
    543 
    544    case eKeyPress:
    545      AC_LOGV("eKeyPress, state: %s", mState->Name());
    546      mManager->OnKeyboardEvent();
    547      break;
    548 
    549    default:
    550      break;
    551  }
    552 
    553  return nsEventStatus_eIgnore;
    554 }
    555 
    556 bool AccessibleCaretEventHub::MoveDistanceIsLarge(const nsPoint& aPoint) const {
    557  nsPoint delta = aPoint - mPressPoint;
    558  return NS_hypot(delta.x, delta.y) >
    559         AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel;
    560 }
    561 
    562 void AccessibleCaretEventHub::LaunchLongTapInjector() {
    563  if (!mLongTapInjectorTimer) {
    564    return;
    565  }
    566 
    567  int32_t longTapDelay = StaticPrefs::ui_click_hold_context_menus_delay();
    568  mLongTapInjectorTimer->InitWithNamedFuncCallback(
    569      FireLongTap, this, longTapDelay, nsITimer::TYPE_ONE_SHOT,
    570      "AccessibleCaretEventHub::LaunchLongTapInjector"_ns);
    571 }
    572 
    573 void AccessibleCaretEventHub::CancelLongTapInjector() {
    574  if (!mLongTapInjectorTimer) {
    575    return;
    576  }
    577 
    578  mLongTapInjectorTimer->Cancel();
    579 }
    580 
    581 /* static */
    582 void AccessibleCaretEventHub::FireLongTap(nsITimer* aTimer,
    583                                          void* aAccessibleCaretEventHub) {
    584  RefPtr<AccessibleCaretEventHub> self =
    585      static_cast<AccessibleCaretEventHub*>(aAccessibleCaretEventHub);
    586  self->mState->OnLongTap(self, self->mPressPoint);
    587 }
    588 
    589 NS_IMETHODIMP
    590 AccessibleCaretEventHub::Reflow(DOMHighResTimeStamp aStart,
    591                                DOMHighResTimeStamp aEnd) {
    592  if (!mInitialized) {
    593    return NS_OK;
    594  }
    595 
    596  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    597 
    598  if (mIsInReflowCallback) {
    599    return NS_OK;
    600  }
    601 
    602  AutoRestore<bool> autoRestoreIsInReflowCallback(mIsInReflowCallback);
    603  mIsInReflowCallback = true;
    604 
    605  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
    606  mState->OnReflow(this);
    607  return NS_OK;
    608 }
    609 
    610 NS_IMETHODIMP
    611 AccessibleCaretEventHub::ReflowInterruptible(DOMHighResTimeStamp aStart,
    612                                             DOMHighResTimeStamp aEnd) {
    613  // Defer the error checking to Reflow().
    614  return Reflow(aStart, aEnd);
    615 }
    616 
    617 void AccessibleCaretEventHub::AsyncPanZoomStarted() {
    618  if (!mInitialized) {
    619    return;
    620  }
    621 
    622  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    623 
    624  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
    625  mState->OnScrollStart(this);
    626 }
    627 
    628 void AccessibleCaretEventHub::AsyncPanZoomStopped() {
    629  if (!mInitialized) {
    630    return;
    631  }
    632 
    633  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    634 
    635  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
    636  mState->OnScrollEnd(this);
    637 }
    638 
    639 void AccessibleCaretEventHub::ScrollPositionChanged() {
    640  if (!mInitialized) {
    641    return;
    642  }
    643 
    644  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    645 
    646  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
    647  mState->OnScrollPositionChanged(this);
    648 }
    649 
    650 void AccessibleCaretEventHub::OnSelectionChange(Document* aDoc,
    651                                                dom::Selection* aSel,
    652                                                int16_t aReason) {
    653  if (!mInitialized) {
    654    return;
    655  }
    656 
    657  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    658 
    659  AC_LOG("%s, state: %s, reason: %d", __FUNCTION__, mState->Name(), aReason);
    660 
    661  // XXX Here we may be in a hot path.  So, if we could avoid this virtual call,
    662  //     we should do so.
    663  mState->OnSelectionChanged(this, aDoc, aSel, aReason);
    664 }
    665 
    666 bool AccessibleCaretEventHub::ShouldDisableApz() const {
    667  return mManager && mManager->ShouldDisableApz();
    668 }
    669 
    670 void AccessibleCaretEventHub::NotifyBlur(bool aIsLeavingDocument) {
    671  if (!mInitialized) {
    672    return;
    673  }
    674 
    675  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
    676 
    677  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
    678  mState->OnBlur(this, aIsLeavingDocument);
    679 }
    680 
    681 nsPoint AccessibleCaretEventHub::GetTouchEventPosition(
    682    WidgetTouchEvent* aEvent, int32_t aIdentifier) const {
    683  for (dom::Touch* touch : aEvent->mTouches) {
    684    if (touch->Identifier() == aIdentifier) {
    685      LayoutDeviceIntPoint touchIntPoint = touch->mRefPoint;
    686 
    687      // Get event coordinate relative to root frame.
    688      nsIFrame* rootFrame = mPresShell->GetRootFrame();
    689      return nsLayoutUtils::GetEventCoordinatesRelativeTo(
    690          aEvent, touchIntPoint, RelativeTo{rootFrame});
    691    }
    692  }
    693  return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
    694 }
    695 
    696 nsPoint AccessibleCaretEventHub::GetMouseEventPosition(
    697    WidgetMouseEvent* aEvent) const {
    698  LayoutDeviceIntPoint mouseIntPoint = aEvent->AsGUIEvent()->mRefPoint;
    699 
    700  // Get event coordinate relative to root frame.
    701  nsIFrame* rootFrame = mPresShell->GetRootFrame();
    702  return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, mouseIntPoint,
    703                                                      RelativeTo{rootFrame});
    704 }
    705 
    706 }  // namespace mozilla