Blame layout/base/AccessibleCaretEventHub.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
Packit f0b94e
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "AccessibleCaretEventHub.h"
Packit f0b94e
Packit f0b94e
#include "AccessibleCaretLogger.h"
Packit f0b94e
#include "AccessibleCaretManager.h"
Packit f0b94e
#include "Layers.h"
Packit f0b94e
#include "gfxPrefs.h"
Packit f0b94e
#include "mozilla/AutoRestore.h"
Packit f0b94e
#include "mozilla/MouseEvents.h"
Packit f0b94e
#include "mozilla/TextEvents.h"
Packit f0b94e
#include "mozilla/TouchEvents.h"
Packit f0b94e
#include "mozilla/Preferences.h"
Packit f0b94e
#include "nsCanvasFrame.h"
Packit f0b94e
#include "nsDocShell.h"
Packit f0b94e
#include "nsFocusManager.h"
Packit f0b94e
#include "nsFrameSelection.h"
Packit f0b94e
#include "nsITimer.h"
Packit f0b94e
#include "nsPresContext.h"
Packit f0b94e
Packit f0b94e
namespace mozilla {
Packit f0b94e
Packit f0b94e
#undef AC_LOG
Packit f0b94e
#define AC_LOG(message, ...) \
Packit f0b94e
  AC_LOG_BASE("AccessibleCaretEventHub (%p): " message, this, ##__VA_ARGS__);
Packit f0b94e
Packit f0b94e
#undef AC_LOGV
Packit f0b94e
#define AC_LOGV(message, ...) \
Packit f0b94e
  AC_LOGV_BASE("AccessibleCaretEventHub (%p): " message, this, ##__VA_ARGS__);
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS(AccessibleCaretEventHub, nsIReflowObserver, nsIScrollObserver,
Packit f0b94e
                  nsISelectionListener, nsISupportsWeakReference);
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// NoActionState
Packit f0b94e
//
Packit f0b94e
class AccessibleCaretEventHub::NoActionState
Packit f0b94e
    : public AccessibleCaretEventHub::State {
Packit f0b94e
 public:
Packit f0b94e
  const char* Name() const override { return "NoActionState"; }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnPress(AccessibleCaretEventHub* aContext,
Packit f0b94e
                        const nsPoint& aPoint, int32_t aTouchId,
Packit f0b94e
                        EventClassID aEventClass) override {
Packit f0b94e
    nsEventStatus rv = nsEventStatus_eIgnore;
Packit f0b94e
Packit f0b94e
    if (NS_SUCCEEDED(aContext->mManager->PressCaret(aPoint, aEventClass))) {
Packit f0b94e
      aContext->SetState(aContext->PressCaretState());
Packit f0b94e
      rv = nsEventStatus_eConsumeNoDefault;
Packit f0b94e
    } else {
Packit f0b94e
      aContext->SetState(aContext->PressNoCaretState());
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    aContext->mPressPoint = aPoint;
Packit f0b94e
    aContext->mActiveTouchId = aTouchId;
Packit f0b94e
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnScrollStart(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnScrollStart();
Packit f0b94e
    aContext->SetState(aContext->ScrollState());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnScrollPositionChanged(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnScrollPositionChanged();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnSelectionChanged(AccessibleCaretEventHub* aContext,
Packit f0b94e
                          nsIDOMDocument* aDoc, nsISelection* aSel,
Packit f0b94e
                          int16_t aReason) override {
Packit f0b94e
    aContext->mManager->OnSelectionChanged(aDoc, aSel, aReason);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnBlur(AccessibleCaretEventHub* aContext,
Packit f0b94e
              bool aIsLeavingDocument) override {
Packit f0b94e
    aContext->mManager->OnBlur();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnReflow(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnReflow();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void Enter(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mPressPoint = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
Packit f0b94e
    aContext->mActiveTouchId = kInvalidTouchId;
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// PressCaretState: Always consume the event since we've pressed on the caret.
Packit f0b94e
//
Packit f0b94e
class AccessibleCaretEventHub::PressCaretState
Packit f0b94e
    : public AccessibleCaretEventHub::State {
Packit f0b94e
 public:
Packit f0b94e
  const char* Name() const override { return "PressCaretState"; }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnMove(AccessibleCaretEventHub* aContext,
Packit f0b94e
                       const nsPoint& aPoint) override {
Packit f0b94e
    if (aContext->MoveDistanceIsLarge(aPoint)) {
Packit f0b94e
      if (NS_SUCCEEDED(aContext->mManager->DragCaret(aPoint))) {
Packit f0b94e
        aContext->SetState(aContext->DragCaretState());
Packit f0b94e
      }
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    return nsEventStatus_eConsumeNoDefault;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->ReleaseCaret();
Packit f0b94e
    aContext->mManager->TapCaret(aContext->mPressPoint);
Packit f0b94e
    aContext->SetState(aContext->NoActionState());
Packit f0b94e
Packit f0b94e
    return nsEventStatus_eConsumeNoDefault;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
Packit f0b94e
                          const nsPoint& aPoint) override {
Packit f0b94e
    return nsEventStatus_eConsumeNoDefault;
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// DragCaretState: Always consume the event since we've pressed on the caret.
Packit f0b94e
//
Packit f0b94e
class AccessibleCaretEventHub::DragCaretState
Packit f0b94e
    : public AccessibleCaretEventHub::State {
Packit f0b94e
 public:
Packit f0b94e
  const char* Name() const override { return "DragCaretState"; }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnMove(AccessibleCaretEventHub* aContext,
Packit f0b94e
                       const nsPoint& aPoint) override {
Packit f0b94e
    aContext->mManager->DragCaret(aPoint);
Packit f0b94e
Packit f0b94e
    return nsEventStatus_eConsumeNoDefault;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->ReleaseCaret();
Packit f0b94e
    aContext->SetState(aContext->NoActionState());
Packit f0b94e
Packit f0b94e
    return nsEventStatus_eConsumeNoDefault;
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// PressNoCaretState
Packit f0b94e
//
Packit f0b94e
class AccessibleCaretEventHub::PressNoCaretState
Packit f0b94e
    : public AccessibleCaretEventHub::State {
Packit f0b94e
 public:
Packit f0b94e
  const char* Name() const override { return "PressNoCaretState"; }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnMove(AccessibleCaretEventHub* aContext,
Packit f0b94e
                       const nsPoint& aPoint) override {
Packit f0b94e
    if (aContext->MoveDistanceIsLarge(aPoint)) {
Packit f0b94e
      aContext->SetState(aContext->NoActionState());
Packit f0b94e
    }
Packit f0b94e
Packit f0b94e
    return nsEventStatus_eIgnore;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->SetState(aContext->NoActionState());
Packit f0b94e
Packit f0b94e
    return nsEventStatus_eIgnore;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
Packit f0b94e
                          const nsPoint& aPoint) override {
Packit f0b94e
    aContext->SetState(aContext->LongTapState());
Packit f0b94e
Packit f0b94e
    return aContext->GetState()->OnLongTap(aContext, aPoint);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnScrollStart(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnScrollStart();
Packit f0b94e
    aContext->SetState(aContext->ScrollState());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnBlur(AccessibleCaretEventHub* aContext,
Packit f0b94e
              bool aIsLeavingDocument) override {
Packit f0b94e
    aContext->mManager->OnBlur();
Packit f0b94e
    if (aIsLeavingDocument) {
Packit f0b94e
      aContext->SetState(aContext->NoActionState());
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnSelectionChanged(AccessibleCaretEventHub* aContext,
Packit f0b94e
                          nsIDOMDocument* aDoc, nsISelection* aSel,
Packit f0b94e
                          int16_t aReason) override {
Packit f0b94e
    aContext->mManager->OnSelectionChanged(aDoc, aSel, aReason);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnReflow(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnReflow();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void Enter(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->LaunchLongTapInjector();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void Leave(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->CancelLongTapInjector();
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// ScrollState
Packit f0b94e
//
Packit f0b94e
class AccessibleCaretEventHub::ScrollState
Packit f0b94e
    : public AccessibleCaretEventHub::State {
Packit f0b94e
 public:
Packit f0b94e
  const char* Name() const override { return "ScrollState"; }
Packit f0b94e
Packit f0b94e
  void OnScrollEnd(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnScrollEnd();
Packit f0b94e
    aContext->SetState(aContext->NoActionState());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnScrollPositionChanged(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnScrollPositionChanged();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnBlur(AccessibleCaretEventHub* aContext,
Packit f0b94e
              bool aIsLeavingDocument) override {
Packit f0b94e
    aContext->mManager->OnBlur();
Packit f0b94e
    if (aIsLeavingDocument) {
Packit f0b94e
      aContext->SetState(aContext->NoActionState());
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// LongTapState
Packit f0b94e
//
Packit f0b94e
class AccessibleCaretEventHub::LongTapState
Packit f0b94e
    : public AccessibleCaretEventHub::State {
Packit f0b94e
 public:
Packit f0b94e
  const char* Name() const override { return "LongTapState"; }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnLongTap(AccessibleCaretEventHub* aContext,
Packit f0b94e
                          const nsPoint& aPoint) override {
Packit f0b94e
    // In general text selection is lower-priority than the context menu. If
Packit f0b94e
    // we consume this long-press event, then it prevents the context menu from
Packit f0b94e
    // showing up on desktop Firefox (because that happens on long-tap-up, if
Packit f0b94e
    // the long-tap was not cancelled). So we return eIgnore instead.
Packit f0b94e
    aContext->mManager->SelectWordOrShortcut(aPoint);
Packit f0b94e
    return nsEventStatus_eIgnore;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus OnRelease(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->SetState(aContext->NoActionState());
Packit f0b94e
Packit f0b94e
    // Do not consume the release since the press is not consumed in
Packit f0b94e
    // PressNoCaretState either.
Packit f0b94e
    return nsEventStatus_eIgnore;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnScrollStart(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnScrollStart();
Packit f0b94e
    aContext->SetState(aContext->ScrollState());
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  void OnReflow(AccessibleCaretEventHub* aContext) override {
Packit f0b94e
    aContext->mManager->OnReflow();
Packit f0b94e
  }
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// -----------------------------------------------------------------------------
Packit f0b94e
// Implementation of AccessibleCaretEventHub methods
Packit f0b94e
//
Packit f0b94e
AccessibleCaretEventHub::State* AccessibleCaretEventHub::GetState() const {
Packit f0b94e
  return mState;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::SetState(State* aState) {
Packit f0b94e
  MOZ_ASSERT(aState);
Packit f0b94e
Packit f0b94e
  AC_LOG("%s -> %s", mState->Name(), aState->Name());
Packit f0b94e
Packit f0b94e
  mState->Leave(this);
Packit f0b94e
  mState = aState;
Packit f0b94e
  mState->Enter(this);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
MOZ_IMPL_STATE_CLASS_GETTER(NoActionState)
Packit f0b94e
MOZ_IMPL_STATE_CLASS_GETTER(PressCaretState)
Packit f0b94e
MOZ_IMPL_STATE_CLASS_GETTER(DragCaretState)
Packit f0b94e
MOZ_IMPL_STATE_CLASS_GETTER(PressNoCaretState)
Packit f0b94e
MOZ_IMPL_STATE_CLASS_GETTER(ScrollState)
Packit f0b94e
MOZ_IMPL_STATE_CLASS_GETTER(LongTapState)
Packit f0b94e
Packit f0b94e
bool AccessibleCaretEventHub::sUseLongTapInjector = false;
Packit f0b94e
Packit f0b94e
AccessibleCaretEventHub::AccessibleCaretEventHub(nsIPresShell* aPresShell)
Packit f0b94e
    : mPresShell(aPresShell) {
Packit f0b94e
  static bool prefsAdded = false;
Packit f0b94e
  if (!prefsAdded) {
Packit f0b94e
    Preferences::AddBoolVarCache(
Packit f0b94e
        &sUseLongTapInjector, "layout.accessiblecaret.use_long_tap_injector");
Packit f0b94e
    prefsAdded = true;
Packit f0b94e
  }
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::Init() {
Packit f0b94e
  if (mInitialized && mManager) {
Packit f0b94e
    mManager->OnFrameReconstruction();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (mInitialized || !mPresShell || !mPresShell->GetCanvasFrame() ||
Packit f0b94e
      !mPresShell->GetCanvasFrame()->GetCustomContentContainer()) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  // Without nsAutoScriptBlocker, the script might be run after constructing
Packit f0b94e
  // mFirstCaret in AccessibleCaretManager's constructor, which might destructs
Packit f0b94e
  // the whole frame tree. Therefore we'll fail to construct mSecondCaret
Packit f0b94e
  // because we cannot get root frame or canvas frame from mPresShell to inject
Packit f0b94e
  // anonymous content. To avoid that, we protect Init() by nsAutoScriptBlocker.
Packit f0b94e
  // To reproduce, run "./mach crashtest layout/base/crashtests/897852.html"
Packit f0b94e
  // without the following scriptBlocker.
Packit f0b94e
  nsAutoScriptBlocker scriptBlocker;
Packit f0b94e
Packit f0b94e
  nsPresContext* presContext = mPresShell->GetPresContext();
Packit f0b94e
  MOZ_ASSERT(presContext, "PresContext should be given in PresShell::Init()");
Packit f0b94e
Packit f0b94e
  nsIDocShell* docShell = presContext->GetDocShell();
Packit f0b94e
  if (!docShell) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  docShell->AddWeakReflowObserver(this);
Packit f0b94e
  docShell->AddWeakScrollObserver(this);
Packit f0b94e
Packit f0b94e
  mDocShell = static_cast<nsDocShell*>(docShell);
Packit f0b94e
Packit f0b94e
  if (sUseLongTapInjector) {
Packit f0b94e
    mLongTapInjectorTimer = NS_NewTimer();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  mManager = MakeUnique<AccessibleCaretManager>(mPresShell);
Packit f0b94e
Packit f0b94e
  mInitialized = true;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::Terminate() {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  RefPtr<nsDocShell> docShell(mDocShell.get());
Packit f0b94e
  if (docShell) {
Packit f0b94e
    docShell->RemoveWeakReflowObserver(this);
Packit f0b94e
    docShell->RemoveWeakScrollObserver(this);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  if (mLongTapInjectorTimer) {
Packit f0b94e
    mLongTapInjectorTimer->Cancel();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  mManager->Terminate();
Packit f0b94e
  mPresShell = nullptr;
Packit f0b94e
  mInitialized = false;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsEventStatus AccessibleCaretEventHub::HandleEvent(WidgetEvent* aEvent) {
Packit f0b94e
  nsEventStatus status = nsEventStatus_eIgnore;
Packit f0b94e
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return status;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  switch (aEvent->mClass) {
Packit f0b94e
    case eMouseEventClass:
Packit f0b94e
      status = HandleMouseEvent(aEvent->AsMouseEvent());
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eTouchEventClass:
Packit f0b94e
      status = HandleTouchEvent(aEvent->AsTouchEvent());
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eKeyboardEventClass:
Packit f0b94e
      status = HandleKeyboardEvent(aEvent->AsKeyboardEvent());
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    default:
Packit f0b94e
      break;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return status;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsEventStatus AccessibleCaretEventHub::HandleMouseEvent(
Packit f0b94e
    WidgetMouseEvent* aEvent) {
Packit f0b94e
  nsEventStatus rv = nsEventStatus_eIgnore;
Packit f0b94e
Packit f0b94e
  if (aEvent->button != WidgetMouseEvent::eLeftButton) {
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  int32_t id =
Packit f0b94e
      (mActiveTouchId == kInvalidTouchId ? kDefaultTouchId : mActiveTouchId);
Packit f0b94e
  nsPoint point = GetMouseEventPosition(aEvent);
Packit f0b94e
Packit f0b94e
  if (aEvent->mMessage == eMouseDown || aEvent->mMessage == eMouseUp ||
Packit f0b94e
      aEvent->mMessage == eMouseClick ||
Packit f0b94e
      aEvent->mMessage == eMouseDoubleClick ||
Packit f0b94e
      aEvent->mMessage == eMouseLongTap) {
Packit f0b94e
    // Don't reset the source on mouse movement since that can
Packit f0b94e
    // happen anytime, even randomly during a touch sequence.
Packit f0b94e
    mManager->SetLastInputSource(aEvent->inputSource);
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  switch (aEvent->mMessage) {
Packit f0b94e
    case eMouseDown:
Packit f0b94e
      AC_LOGV("Before eMouseDown, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnPress(this, point, id, eMouseEventClass);
Packit f0b94e
      AC_LOGV("After eMouseDown, state: %s, consume: %d", mState->Name(), rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eMouseMove:
Packit f0b94e
      AC_LOGV("Before eMouseMove, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnMove(this, point);
Packit f0b94e
      AC_LOGV("After eMouseMove, state: %s, consume: %d", mState->Name(), rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eMouseUp:
Packit f0b94e
      AC_LOGV("Before eMouseUp, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnRelease(this);
Packit f0b94e
      AC_LOGV("After eMouseUp, state: %s, consume: %d", mState->Name(), rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eMouseLongTap:
Packit f0b94e
      AC_LOGV("Before eMouseLongTap, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnLongTap(this, point);
Packit f0b94e
      AC_LOGV("After eMouseLongTap, state: %s, consume: %d", mState->Name(),
Packit f0b94e
              rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    default:
Packit f0b94e
      break;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return rv;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsEventStatus AccessibleCaretEventHub::HandleTouchEvent(
Packit f0b94e
    WidgetTouchEvent* aEvent) {
Packit f0b94e
  if (aEvent->mTouches.IsEmpty()) {
Packit f0b94e
    AC_LOG("%s: Receive a touch event without any touch data!", __FUNCTION__);
Packit f0b94e
    return nsEventStatus_eIgnore;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  nsEventStatus rv = nsEventStatus_eIgnore;
Packit f0b94e
Packit f0b94e
  int32_t id =
Packit f0b94e
      (mActiveTouchId == kInvalidTouchId ? aEvent->mTouches[0]->Identifier()
Packit f0b94e
                                         : mActiveTouchId);
Packit f0b94e
  nsPoint point = GetTouchEventPosition(aEvent, id);
Packit f0b94e
Packit f0b94e
  mManager->SetLastInputSource(nsIDOMMouseEvent::MOZ_SOURCE_TOUCH);
Packit f0b94e
Packit f0b94e
  switch (aEvent->mMessage) {
Packit f0b94e
    case eTouchStart:
Packit f0b94e
      AC_LOGV("Before eTouchStart, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnPress(this, point, id, eTouchEventClass);
Packit f0b94e
      AC_LOGV("After eTouchStart, state: %s, consume: %d", mState->Name(), rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eTouchMove:
Packit f0b94e
      AC_LOGV("Before eTouchMove, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnMove(this, point);
Packit f0b94e
      AC_LOGV("After eTouchMove, state: %s, consume: %d", mState->Name(), rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eTouchEnd:
Packit f0b94e
      AC_LOGV("Before eTouchEnd, state: %s", mState->Name());
Packit f0b94e
      rv = mState->OnRelease(this);
Packit f0b94e
      AC_LOGV("After eTouchEnd, state: %s, consume: %d", mState->Name(), rv);
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eTouchCancel:
Packit f0b94e
      AC_LOGV("Got eTouchCancel, state: %s", mState->Name());
Packit f0b94e
      // Do nothing since we don't really care eTouchCancel anyway.
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    default:
Packit f0b94e
      break;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return rv;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsEventStatus AccessibleCaretEventHub::HandleKeyboardEvent(
Packit f0b94e
    WidgetKeyboardEvent* aEvent) {
Packit f0b94e
  mManager->SetLastInputSource(nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD);
Packit f0b94e
Packit f0b94e
  switch (aEvent->mMessage) {
Packit f0b94e
    case eKeyUp:
Packit f0b94e
      AC_LOGV("eKeyUp, state: %s", mState->Name());
Packit f0b94e
      mManager->OnKeyboardEvent();
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eKeyDown:
Packit f0b94e
      AC_LOGV("eKeyDown, state: %s", mState->Name());
Packit f0b94e
      mManager->OnKeyboardEvent();
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    case eKeyPress:
Packit f0b94e
      AC_LOGV("eKeyPress, state: %s", mState->Name());
Packit f0b94e
      mManager->OnKeyboardEvent();
Packit f0b94e
      break;
Packit f0b94e
Packit f0b94e
    default:
Packit f0b94e
      break;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return nsEventStatus_eIgnore;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool AccessibleCaretEventHub::MoveDistanceIsLarge(const nsPoint& aPoint) const {
Packit f0b94e
  nsPoint delta = aPoint - mPressPoint;
Packit f0b94e
  return NS_hypot(delta.x, delta.y) >
Packit f0b94e
         nsPresContext::AppUnitsPerCSSPixel() * kMoveStartToleranceInPixel;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::LaunchLongTapInjector() {
Packit f0b94e
  if (!mLongTapInjectorTimer) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  int32_t longTapDelay = gfxPrefs::UiClickHoldContextMenusDelay();
Packit f0b94e
  mLongTapInjectorTimer->InitWithNamedFuncCallback(
Packit f0b94e
      FireLongTap, this, longTapDelay, nsITimer::TYPE_ONE_SHOT,
Packit f0b94e
      "AccessibleCaretEventHub::LaunchLongTapInjector");
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::CancelLongTapInjector() {
Packit f0b94e
  if (!mLongTapInjectorTimer) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  mLongTapInjectorTimer->Cancel();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
/* static */ void AccessibleCaretEventHub::FireLongTap(
Packit f0b94e
    nsITimer* aTimer, void* aAccessibleCaretEventHub) {
Packit f0b94e
  RefPtr<AccessibleCaretEventHub> self =
Packit f0b94e
      static_cast<AccessibleCaretEventHub*>(aAccessibleCaretEventHub);
Packit f0b94e
  self->mState->OnLongTap(self, self->mPressPoint);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
AccessibleCaretEventHub::Reflow(DOMHighResTimeStamp aStart,
Packit f0b94e
                                DOMHighResTimeStamp aEnd) {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  if (mIsInReflowCallback) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  AutoRestore<bool> autoRestoreIsInReflowCallback(mIsInReflowCallback);
Packit f0b94e
  mIsInReflowCallback = true;
Packit f0b94e
Packit f0b94e
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
Packit f0b94e
  mState->OnReflow(this);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
AccessibleCaretEventHub::ReflowInterruptible(DOMHighResTimeStamp aStart,
Packit f0b94e
                                             DOMHighResTimeStamp aEnd) {
Packit f0b94e
  // Defer the error checking to Reflow().
Packit f0b94e
  return Reflow(aStart, aEnd);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::AsyncPanZoomStarted() {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
Packit f0b94e
  mState->OnScrollStart(this);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::AsyncPanZoomStopped() {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
Packit f0b94e
  mState->OnScrollEnd(this);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::ScrollPositionChanged() {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
Packit f0b94e
  mState->OnScrollPositionChanged(this);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsresult AccessibleCaretEventHub::NotifySelectionChanged(nsIDOMDocument* aDoc,
Packit f0b94e
                                                         nsISelection* aSel,
Packit f0b94e
                                                         int16_t aReason) {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return NS_OK;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  AC_LOG("%s, state: %s, reason: %d", __FUNCTION__, mState->Name(), aReason);
Packit f0b94e
  mState->OnSelectionChanged(this, aDoc, aSel, aReason);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void AccessibleCaretEventHub::NotifyBlur(bool aIsLeavingDocument) {
Packit f0b94e
  if (!mInitialized) {
Packit f0b94e
    return;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  MOZ_ASSERT(mRefCnt.get() > 1, "Expect caller holds us as well!");
Packit f0b94e
Packit f0b94e
  AC_LOG("%s, state: %s", __FUNCTION__, mState->Name());
Packit f0b94e
  mState->OnBlur(this, aIsLeavingDocument);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsPoint AccessibleCaretEventHub::GetTouchEventPosition(
Packit f0b94e
    WidgetTouchEvent* aEvent, int32_t aIdentifier) const {
Packit f0b94e
  for (dom::Touch* touch : aEvent->mTouches) {
Packit f0b94e
    if (touch->Identifier() == aIdentifier) {
Packit f0b94e
      LayoutDeviceIntPoint touchIntPoint = touch->mRefPoint;
Packit f0b94e
Packit f0b94e
      // Get event coordinate relative to root frame.
Packit f0b94e
      nsIFrame* rootFrame = mPresShell->GetRootFrame();
Packit f0b94e
      return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, touchIntPoint,
Packit f0b94e
                                                          rootFrame);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
nsPoint AccessibleCaretEventHub::GetMouseEventPosition(
Packit f0b94e
    WidgetMouseEvent* aEvent) const {
Packit f0b94e
  LayoutDeviceIntPoint mouseIntPoint = aEvent->AsGUIEvent()->mRefPoint;
Packit f0b94e
Packit f0b94e
  // Get event coordinate relative to root frame.
Packit f0b94e
  nsIFrame* rootFrame = mPresShell->GetRootFrame();
Packit f0b94e
  return nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, mouseIntPoint,
Packit f0b94e
                                                      rootFrame);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace mozilla