dom/events/EventStateManager.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/events/EventStateManager.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,5523 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 sw=2 et tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "mozilla/Attributes.h"
    1.11 +#include "mozilla/EventDispatcher.h"
    1.12 +#include "mozilla/EventStateManager.h"
    1.13 +#include "mozilla/EventStates.h"
    1.14 +#include "mozilla/IMEStateManager.h"
    1.15 +#include "mozilla/MiscEvents.h"
    1.16 +#include "mozilla/MathAlgorithms.h"
    1.17 +#include "mozilla/MouseEvents.h"
    1.18 +#include "mozilla/TextComposition.h"
    1.19 +#include "mozilla/TextEvents.h"
    1.20 +#include "mozilla/TouchEvents.h"
    1.21 +#include "mozilla/dom/Event.h"
    1.22 +#include "mozilla/dom/TabParent.h"
    1.23 +#include "mozilla/dom/UIEvent.h"
    1.24 +
    1.25 +#include "ContentEventHandler.h"
    1.26 +#include "IMEContentObserver.h"
    1.27 +#include "WheelHandlingHelper.h"
    1.28 +
    1.29 +#include "nsCOMPtr.h"
    1.30 +#include "nsFocusManager.h"
    1.31 +#include "nsIContent.h"
    1.32 +#include "nsINodeInfo.h"
    1.33 +#include "nsIDocument.h"
    1.34 +#include "nsIFrame.h"
    1.35 +#include "nsIWidget.h"
    1.36 +#include "nsPresContext.h"
    1.37 +#include "nsIPresShell.h"
    1.38 +#include "nsGkAtoms.h"
    1.39 +#include "nsIFormControl.h"
    1.40 +#include "nsIComboboxControlFrame.h"
    1.41 +#include "nsIScrollableFrame.h"
    1.42 +#include "nsIDOMHTMLElement.h"
    1.43 +#include "nsIDOMXULControlElement.h"
    1.44 +#include "nsNameSpaceManager.h"
    1.45 +#include "nsIBaseWindow.h"
    1.46 +#include "nsISelection.h"
    1.47 +#include "nsITextControlElement.h"
    1.48 +#include "nsFrameSelection.h"
    1.49 +#include "nsPIDOMWindow.h"
    1.50 +#include "nsPIWindowRoot.h"
    1.51 +#include "nsIWebNavigation.h"
    1.52 +#include "nsIContentViewer.h"
    1.53 +#include "nsFrameManager.h"
    1.54 +
    1.55 +#include "nsIDOMXULElement.h"
    1.56 +#include "nsIDOMKeyEvent.h"
    1.57 +#include "nsIObserverService.h"
    1.58 +#include "nsIDocShell.h"
    1.59 +#include "nsIMarkupDocumentViewer.h"
    1.60 +#include "nsIDOMWheelEvent.h"
    1.61 +#include "nsIDOMDragEvent.h"
    1.62 +#include "nsIDOMUIEvent.h"
    1.63 +#include "nsIMozBrowserFrame.h"
    1.64 +
    1.65 +#include "nsSubDocumentFrame.h"
    1.66 +#include "nsLayoutUtils.h"
    1.67 +#include "nsIInterfaceRequestorUtils.h"
    1.68 +#include "nsUnicharUtils.h"
    1.69 +#include "nsContentUtils.h"
    1.70 +
    1.71 +#include "imgIContainer.h"
    1.72 +#include "nsIProperties.h"
    1.73 +#include "nsISupportsPrimitives.h"
    1.74 +
    1.75 +#include "nsServiceManagerUtils.h"
    1.76 +#include "nsITimer.h"
    1.77 +#include "nsFontMetrics.h"
    1.78 +#include "nsIDOMXULDocument.h"
    1.79 +#include "nsIDragService.h"
    1.80 +#include "nsIDragSession.h"
    1.81 +#include "mozilla/dom/DataTransfer.h"
    1.82 +#include "nsContentAreaDragDrop.h"
    1.83 +#ifdef MOZ_XUL
    1.84 +#include "nsTreeBodyFrame.h"
    1.85 +#endif
    1.86 +#include "nsIController.h"
    1.87 +#include "nsICommandParams.h"
    1.88 +#include "mozilla/Services.h"
    1.89 +#include "mozilla/dom/HTMLLabelElement.h"
    1.90 +
    1.91 +#include "mozilla/Preferences.h"
    1.92 +#include "mozilla/LookAndFeel.h"
    1.93 +#include "GeckoProfiler.h"
    1.94 +#include "Units.h"
    1.95 +
    1.96 +#ifdef XP_MACOSX
    1.97 +#import <ApplicationServices/ApplicationServices.h>
    1.98 +#endif
    1.99 +
   1.100 +namespace mozilla {
   1.101 +
   1.102 +using namespace dom;
   1.103 +
   1.104 +//#define DEBUG_DOCSHELL_FOCUS
   1.105 +
   1.106 +#define NS_USER_INTERACTION_INTERVAL 5000 // ms
   1.107 +
   1.108 +static const LayoutDeviceIntPoint kInvalidRefPoint = LayoutDeviceIntPoint(-1,-1);
   1.109 +
   1.110 +static uint32_t gMouseOrKeyboardEventCounter = 0;
   1.111 +static nsITimer* gUserInteractionTimer = nullptr;
   1.112 +static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
   1.113 +
   1.114 +static inline int32_t
   1.115 +RoundDown(double aDouble)
   1.116 +{
   1.117 +  return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble)) :
   1.118 +                         static_cast<int32_t>(ceil(aDouble));
   1.119 +}
   1.120 +
   1.121 +#ifdef DEBUG_DOCSHELL_FOCUS
   1.122 +static void
   1.123 +PrintDocTree(nsIDocShellTreeItem* aParentItem, int aLevel)
   1.124 +{
   1.125 +  for (int32_t i=0;i<aLevel;i++) printf("  ");
   1.126 +
   1.127 +  int32_t childWebshellCount;
   1.128 +  aParentItem->GetChildCount(&childWebshellCount);
   1.129 +  nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentItem));
   1.130 +  int32_t type = aParentItem->ItemType();
   1.131 +  nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
   1.132 +  nsRefPtr<nsPresContext> presContext;
   1.133 +  parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
   1.134 +  nsCOMPtr<nsIContentViewer> cv;
   1.135 +  parentAsDocShell->GetContentViewer(getter_AddRefs(cv));
   1.136 +  nsCOMPtr<nsIDOMDocument> domDoc;
   1.137 +  if (cv)
   1.138 +    cv->GetDOMDocument(getter_AddRefs(domDoc));
   1.139 +  nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
   1.140 +  nsCOMPtr<nsIDOMWindow> domwin = doc ? doc->GetWindow() : nullptr;
   1.141 +  nsIURI* uri = doc ? doc->GetDocumentURI() : nullptr;
   1.142 +
   1.143 +  printf("DS %p  Type %s  Cnt %d  Doc %p  DW %p  EM %p%c",
   1.144 +    static_cast<void*>(parentAsDocShell.get()),
   1.145 +    type==nsIDocShellTreeItem::typeChrome?"Chrome":"Content",
   1.146 +    childWebshellCount, static_cast<void*>(doc.get()),
   1.147 +    static_cast<void*>(domwin.get()),
   1.148 +    static_cast<void*>(presContext ? presContext->EventStateManager() : nullptr),
   1.149 +    uri ? ' ' : '\n');
   1.150 +  if (uri) {
   1.151 +    nsAutoCString spec;
   1.152 +    uri->GetSpec(spec);
   1.153 +    printf("\"%s\"\n", spec.get());
   1.154 +  }
   1.155 +
   1.156 +  if (childWebshellCount > 0) {
   1.157 +    for (int32_t i = 0; i < childWebshellCount; i++) {
   1.158 +      nsCOMPtr<nsIDocShellTreeItem> child;
   1.159 +      aParentItem->GetChildAt(i, getter_AddRefs(child));
   1.160 +      PrintDocTree(child, aLevel + 1);
   1.161 +    }
   1.162 +  }
   1.163 +}
   1.164 +
   1.165 +static void
   1.166 +PrintDocTreeAll(nsIDocShellTreeItem* aItem)
   1.167 +{
   1.168 +  nsCOMPtr<nsIDocShellTreeItem> item = aItem;
   1.169 +  for(;;) {
   1.170 +    nsCOMPtr<nsIDocShellTreeItem> parent;
   1.171 +    item->GetParent(getter_AddRefs(parent));
   1.172 +    if (!parent)
   1.173 +      break;
   1.174 +    item = parent;
   1.175 +  }
   1.176 +
   1.177 +  PrintDocTree(item, 0);
   1.178 +}
   1.179 +#endif
   1.180 +
   1.181 +// mask values for ui.key.chromeAccess and ui.key.contentAccess
   1.182 +#define NS_MODIFIER_SHIFT    1
   1.183 +#define NS_MODIFIER_CONTROL  2
   1.184 +#define NS_MODIFIER_ALT      4
   1.185 +#define NS_MODIFIER_META     8
   1.186 +#define NS_MODIFIER_OS       16
   1.187 +
   1.188 +static nsIDocument *
   1.189 +GetDocumentFromWindow(nsIDOMWindow *aWindow)
   1.190 +{
   1.191 +  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow);
   1.192 +  return win ? win->GetExtantDoc() : nullptr;
   1.193 +}
   1.194 +
   1.195 +/******************************************************************/
   1.196 +/* mozilla::UITimerCallback                                       */
   1.197 +/******************************************************************/
   1.198 +
   1.199 +class UITimerCallback MOZ_FINAL : public nsITimerCallback
   1.200 +{
   1.201 +public:
   1.202 +  UITimerCallback() : mPreviousCount(0) {}
   1.203 +  NS_DECL_ISUPPORTS
   1.204 +  NS_DECL_NSITIMERCALLBACK
   1.205 +private:
   1.206 +  uint32_t mPreviousCount;
   1.207 +};
   1.208 +
   1.209 +NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback)
   1.210 +
   1.211 +// If aTimer is nullptr, this method always sends "user-interaction-inactive"
   1.212 +// notification.
   1.213 +NS_IMETHODIMP
   1.214 +UITimerCallback::Notify(nsITimer* aTimer)
   1.215 +{
   1.216 +  nsCOMPtr<nsIObserverService> obs =
   1.217 +    mozilla::services::GetObserverService();
   1.218 +  if (!obs)
   1.219 +    return NS_ERROR_FAILURE;
   1.220 +  if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
   1.221 +    gMouseOrKeyboardEventCounter = 0;
   1.222 +    obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
   1.223 +    if (gUserInteractionTimer) {
   1.224 +      gUserInteractionTimer->Cancel();
   1.225 +      NS_RELEASE(gUserInteractionTimer);
   1.226 +    }
   1.227 +  } else {
   1.228 +    obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
   1.229 +    EventStateManager::UpdateUserActivityTimer();
   1.230 +  }
   1.231 +  mPreviousCount = gMouseOrKeyboardEventCounter;
   1.232 +  return NS_OK;
   1.233 +}
   1.234 +
   1.235 +/******************************************************************/
   1.236 +/* mozilla::OverOutElementsWrapper                                */
   1.237 +/******************************************************************/
   1.238 +
   1.239 +OverOutElementsWrapper::OverOutElementsWrapper()
   1.240 +  : mLastOverFrame(nullptr)
   1.241 +{
   1.242 +}
   1.243 +
   1.244 +OverOutElementsWrapper::~OverOutElementsWrapper()
   1.245 +{
   1.246 +}
   1.247 +
   1.248 +NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper,
   1.249 +                         mLastOverElement,
   1.250 +                         mFirstOverEventElement,
   1.251 +                         mFirstOutEventElement)
   1.252 +NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)
   1.253 +NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)
   1.254 +
   1.255 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)
   1.256 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.257 +NS_INTERFACE_MAP_END
   1.258 +
   1.259 +/******************************************************************/
   1.260 +/* mozilla::EventStateManager                                     */
   1.261 +/******************************************************************/
   1.262 +
   1.263 +static uint32_t sESMInstanceCount = 0;
   1.264 +
   1.265 +int32_t EventStateManager::sUserInputEventDepth = 0;
   1.266 +bool EventStateManager::sNormalLMouseEventInProcess = false;
   1.267 +EventStateManager* EventStateManager::sActiveESM = nullptr;
   1.268 +nsIDocument* EventStateManager::sMouseOverDocument = nullptr;
   1.269 +nsWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
   1.270 +LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
   1.271 +nsIntPoint EventStateManager::sLastScreenPoint = nsIntPoint(0, 0);
   1.272 +LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
   1.273 +CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
   1.274 +bool EventStateManager::sIsPointerLocked = false;
   1.275 +// Reference to the pointer locked element.
   1.276 +nsWeakPtr EventStateManager::sPointerLockedElement;
   1.277 +// Reference to the document which requested pointer lock.
   1.278 +nsWeakPtr EventStateManager::sPointerLockedDoc;
   1.279 +nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
   1.280 +TimeStamp EventStateManager::sHandlingInputStart;
   1.281 +
   1.282 +EventStateManager::WheelPrefs*
   1.283 +  EventStateManager::WheelPrefs::sInstance = nullptr;
   1.284 +EventStateManager::DeltaAccumulator*
   1.285 +  EventStateManager::DeltaAccumulator::sInstance = nullptr;
   1.286 +
   1.287 +EventStateManager::EventStateManager()
   1.288 +  : mLockCursor(0)
   1.289 +  , mPreLockPoint(0,0)
   1.290 +  , mCurrentTarget(nullptr)
   1.291 +    // init d&d gesture state machine variables
   1.292 +  , mGestureDownPoint(0,0)
   1.293 +  , mPresContext(nullptr)
   1.294 +  , mLClickCount(0)
   1.295 +  , mMClickCount(0)
   1.296 +  , mRClickCount(0)
   1.297 +  , m_haveShutdown(false)
   1.298 +{
   1.299 +  if (sESMInstanceCount == 0) {
   1.300 +    gUserInteractionTimerCallback = new UITimerCallback();
   1.301 +    if (gUserInteractionTimerCallback)
   1.302 +      NS_ADDREF(gUserInteractionTimerCallback);
   1.303 +    UpdateUserActivityTimer();
   1.304 +  }
   1.305 +  ++sESMInstanceCount;
   1.306 +}
   1.307 +
   1.308 +nsresult
   1.309 +EventStateManager::UpdateUserActivityTimer()
   1.310 +{
   1.311 +  if (!gUserInteractionTimerCallback)
   1.312 +    return NS_OK;
   1.313 +
   1.314 +  if (!gUserInteractionTimer)
   1.315 +    CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
   1.316 +
   1.317 +  if (gUserInteractionTimer) {
   1.318 +    gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
   1.319 +                                            NS_USER_INTERACTION_INTERVAL,
   1.320 +                                            nsITimer::TYPE_ONE_SHOT);
   1.321 +  }
   1.322 +  return NS_OK;
   1.323 +}
   1.324 +
   1.325 +nsresult
   1.326 +EventStateManager::Init()
   1.327 +{
   1.328 +  nsCOMPtr<nsIObserverService> observerService =
   1.329 +    mozilla::services::GetObserverService();
   1.330 +  if (!observerService)
   1.331 +    return NS_ERROR_FAILURE;
   1.332 +
   1.333 +  observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
   1.334 +
   1.335 +  if (sESMInstanceCount == 1) {
   1.336 +    Prefs::Init();
   1.337 +  }
   1.338 +
   1.339 +  return NS_OK;
   1.340 +}
   1.341 +
   1.342 +EventStateManager::~EventStateManager()
   1.343 +{
   1.344 +  ReleaseCurrentIMEContentObserver();
   1.345 +
   1.346 +  if (sActiveESM == this) {
   1.347 +    sActiveESM = nullptr;
   1.348 +  }
   1.349 +  if (Prefs::ClickHoldContextMenu())
   1.350 +    KillClickHoldTimer();
   1.351 +
   1.352 +  if (mDocument == sMouseOverDocument)
   1.353 +    sMouseOverDocument = nullptr;
   1.354 +
   1.355 +  --sESMInstanceCount;
   1.356 +  if(sESMInstanceCount == 0) {
   1.357 +    WheelTransaction::Shutdown();
   1.358 +    if (gUserInteractionTimerCallback) {
   1.359 +      gUserInteractionTimerCallback->Notify(nullptr);
   1.360 +      NS_RELEASE(gUserInteractionTimerCallback);
   1.361 +    }
   1.362 +    if (gUserInteractionTimer) {
   1.363 +      gUserInteractionTimer->Cancel();
   1.364 +      NS_RELEASE(gUserInteractionTimer);
   1.365 +    }
   1.366 +    Prefs::Shutdown();
   1.367 +    WheelPrefs::Shutdown();
   1.368 +    DeltaAccumulator::Shutdown();
   1.369 +  }
   1.370 +
   1.371 +  if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
   1.372 +    sDragOverContent = nullptr;
   1.373 +  }
   1.374 +
   1.375 +  if (!m_haveShutdown) {
   1.376 +    Shutdown();
   1.377 +
   1.378 +    // Don't remove from Observer service in Shutdown because Shutdown also
   1.379 +    // gets called from xpcom shutdown observer.  And we don't want to remove
   1.380 +    // from the service in that case.
   1.381 +
   1.382 +    nsCOMPtr<nsIObserverService> observerService =
   1.383 +      mozilla::services::GetObserverService();
   1.384 +    if (observerService) {
   1.385 +      observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
   1.386 +    }
   1.387 +  }
   1.388 +
   1.389 +}
   1.390 +
   1.391 +nsresult
   1.392 +EventStateManager::Shutdown()
   1.393 +{
   1.394 +  m_haveShutdown = true;
   1.395 +  return NS_OK;
   1.396 +}
   1.397 +
   1.398 +NS_IMETHODIMP
   1.399 +EventStateManager::Observe(nsISupports* aSubject,
   1.400 +                           const char* aTopic,
   1.401 +                           const char16_t *someData)
   1.402 +{
   1.403 +  if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
   1.404 +    Shutdown();
   1.405 +  }
   1.406 +
   1.407 +  return NS_OK;
   1.408 +}
   1.409 +
   1.410 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)
   1.411 +   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
   1.412 +   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   1.413 +   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   1.414 +NS_INTERFACE_MAP_END
   1.415 +
   1.416 +NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)
   1.417 +NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)
   1.418 +
   1.419 +NS_IMPL_CYCLE_COLLECTION(EventStateManager,
   1.420 +                         mCurrentTargetContent,
   1.421 +                         mGestureDownContent,
   1.422 +                         mGestureDownFrameOwner,
   1.423 +                         mLastLeftMouseDownContent,
   1.424 +                         mLastLeftMouseDownContentParent,
   1.425 +                         mLastMiddleMouseDownContent,
   1.426 +                         mLastMiddleMouseDownContentParent,
   1.427 +                         mLastRightMouseDownContent,
   1.428 +                         mLastRightMouseDownContentParent,
   1.429 +                         mActiveContent,
   1.430 +                         mHoverContent,
   1.431 +                         mURLTargetContent,
   1.432 +                         mMouseEnterLeaveHelper,
   1.433 +                         mPointersEnterLeaveHelper,
   1.434 +                         mDocument,
   1.435 +                         mIMEContentObserver,
   1.436 +                         mAccessKeys)
   1.437 +
   1.438 +void
   1.439 +EventStateManager::ReleaseCurrentIMEContentObserver()
   1.440 +{
   1.441 +  if (mIMEContentObserver) {
   1.442 +    mIMEContentObserver->DisconnectFromEventStateManager();
   1.443 +  }
   1.444 +  mIMEContentObserver = nullptr;
   1.445 +}
   1.446 +
   1.447 +void
   1.448 +EventStateManager::OnStartToObserveContent(
   1.449 +                     IMEContentObserver* aIMEContentObserver)
   1.450 +{
   1.451 +  ReleaseCurrentIMEContentObserver();
   1.452 +  mIMEContentObserver = aIMEContentObserver;
   1.453 +}
   1.454 +
   1.455 +void
   1.456 +EventStateManager::OnStopObservingContent(
   1.457 +                     IMEContentObserver* aIMEContentObserver)
   1.458 +{
   1.459 +  aIMEContentObserver->DisconnectFromEventStateManager();
   1.460 +  NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver);
   1.461 +  mIMEContentObserver = nullptr;
   1.462 +}
   1.463 +
   1.464 +nsresult
   1.465 +EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
   1.466 +                                  WidgetEvent* aEvent,
   1.467 +                                  nsIFrame* aTargetFrame,
   1.468 +                                  nsEventStatus* aStatus)
   1.469 +{
   1.470 +  NS_ENSURE_ARG_POINTER(aStatus);
   1.471 +  NS_ENSURE_ARG(aPresContext);
   1.472 +  if (!aEvent) {
   1.473 +    NS_ERROR("aEvent is null.  This should never happen.");
   1.474 +    return NS_ERROR_NULL_POINTER;
   1.475 +  }
   1.476 +
   1.477 +  mCurrentTarget = aTargetFrame;
   1.478 +  mCurrentTargetContent = nullptr;
   1.479 +
   1.480 +  // Focus events don't necessarily need a frame.
   1.481 +  if (NS_EVENT_NEEDS_FRAME(aEvent)) {
   1.482 +    NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null.  this should not happen.  see bug #13007");
   1.483 +    if (!mCurrentTarget) return NS_ERROR_NULL_POINTER;
   1.484 +  }
   1.485 +#ifdef DEBUG
   1.486 +  if (aEvent->HasDragEventMessage() && sIsPointerLocked) {
   1.487 +    NS_ASSERTION(sIsPointerLocked,
   1.488 +      "sIsPointerLocked is true. Drag events should be suppressed when the pointer is locked.");
   1.489 +  }
   1.490 +#endif
   1.491 +  // Store last known screenPoint and clientPoint so pointer lock
   1.492 +  // can use these values as constants.
   1.493 +  WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   1.494 +  if (aEvent->mFlags.mIsTrusted &&
   1.495 +      ((mouseEvent && mouseEvent->IsReal()) ||
   1.496 +       aEvent->eventStructType == NS_WHEEL_EVENT) &&
   1.497 +      !sIsPointerLocked) {
   1.498 +    sLastScreenPoint =
   1.499 +      UIEvent::CalculateScreenPoint(aPresContext, aEvent);
   1.500 +    sLastClientPoint =
   1.501 +      UIEvent::CalculateClientPoint(aPresContext, aEvent, nullptr);
   1.502 +  }
   1.503 +
   1.504 +  // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
   1.505 +  // when user is not active doesn't change the state to active.
   1.506 +  if (aEvent->mFlags.mIsTrusted &&
   1.507 +      ((mouseEvent && mouseEvent->IsReal() &&
   1.508 +        mouseEvent->message != NS_MOUSE_ENTER &&
   1.509 +        mouseEvent->message != NS_MOUSE_EXIT) ||
   1.510 +       aEvent->eventStructType == NS_WHEEL_EVENT ||
   1.511 +       aEvent->eventStructType == NS_KEY_EVENT)) {
   1.512 +    if (gMouseOrKeyboardEventCounter == 0) {
   1.513 +      nsCOMPtr<nsIObserverService> obs =
   1.514 +        mozilla::services::GetObserverService();
   1.515 +      if (obs) {
   1.516 +        obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
   1.517 +        UpdateUserActivityTimer();
   1.518 +      }
   1.519 +    }
   1.520 +    ++gMouseOrKeyboardEventCounter;
   1.521 +  }
   1.522 +
   1.523 +  *aStatus = nsEventStatus_eIgnore;
   1.524 +
   1.525 +  WheelTransaction::OnEvent(aEvent);
   1.526 +
   1.527 +  switch (aEvent->message) {
   1.528 +  case NS_MOUSE_BUTTON_DOWN: {
   1.529 +    switch (mouseEvent->button) {
   1.530 +    case WidgetMouseEvent::eLeftButton:
   1.531 +      BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
   1.532 +      mLClickCount = mouseEvent->clickCount;
   1.533 +      SetClickCount(aPresContext, mouseEvent, aStatus);
   1.534 +      sNormalLMouseEventInProcess = true;
   1.535 +      break;
   1.536 +    case WidgetMouseEvent::eMiddleButton:
   1.537 +      mMClickCount = mouseEvent->clickCount;
   1.538 +      SetClickCount(aPresContext, mouseEvent, aStatus);
   1.539 +      break;
   1.540 +    case WidgetMouseEvent::eRightButton:
   1.541 +      mRClickCount = mouseEvent->clickCount;
   1.542 +      SetClickCount(aPresContext, mouseEvent, aStatus);
   1.543 +      break;
   1.544 +    }
   1.545 +    break;
   1.546 +  }
   1.547 +  case NS_MOUSE_BUTTON_UP: {
   1.548 +    switch (mouseEvent->button) {
   1.549 +      case WidgetMouseEvent::eLeftButton:
   1.550 +        if (Prefs::ClickHoldContextMenu()) {
   1.551 +          KillClickHoldTimer();
   1.552 +        }
   1.553 +        StopTrackingDragGesture();
   1.554 +        sNormalLMouseEventInProcess = false;
   1.555 +        // then fall through...
   1.556 +      case WidgetMouseEvent::eRightButton:
   1.557 +      case WidgetMouseEvent::eMiddleButton:
   1.558 +        SetClickCount(aPresContext, mouseEvent, aStatus);
   1.559 +        break;
   1.560 +    }
   1.561 +    break;
   1.562 +  }
   1.563 +  case NS_POINTER_CANCEL:
   1.564 +  {
   1.565 +    GenerateMouseEnterExit(mouseEvent);
   1.566 +    break;
   1.567 +  }
   1.568 +  case NS_MOUSE_EXIT:
   1.569 +    // If the event is not a top-level window exit, then it's not
   1.570 +    // really an exit --- we may have traversed widget boundaries but
   1.571 +    // we're still in our toplevel window.
   1.572 +    if (mouseEvent->exit != WidgetMouseEvent::eTopLevel) {
   1.573 +      // Treat it as a synthetic move so we don't generate spurious
   1.574 +      // "exit" or "move" events.  Any necessary "out" or "over" events
   1.575 +      // will be generated by GenerateMouseEnterExit
   1.576 +      mouseEvent->message = NS_MOUSE_MOVE;
   1.577 +      mouseEvent->reason = WidgetMouseEvent::eSynthesized;
   1.578 +      // then fall through...
   1.579 +    } else {
   1.580 +      GenerateMouseEnterExit(mouseEvent);
   1.581 +      //This is a window level mouse exit event and should stop here
   1.582 +      aEvent->message = 0;
   1.583 +      break;
   1.584 +    }
   1.585 +  case NS_MOUSE_MOVE:
   1.586 +  case NS_POINTER_DOWN:
   1.587 +  case NS_POINTER_MOVE: {
   1.588 +    // on the Mac, GenerateDragGesture() may not return until the drag
   1.589 +    // has completed and so |aTargetFrame| may have been deleted (moving
   1.590 +    // a bookmark, for example).  If this is the case, however, we know
   1.591 +    // that ClearFrameRefs() has been called and it cleared out
   1.592 +    // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
   1.593 +    // into UpdateCursor().
   1.594 +    GenerateDragGesture(aPresContext, mouseEvent);
   1.595 +    UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
   1.596 +    GenerateMouseEnterExit(mouseEvent);
   1.597 +    // Flush pending layout changes, so that later mouse move events
   1.598 +    // will go to the right nodes.
   1.599 +    FlushPendingEvents(aPresContext);
   1.600 +    break;
   1.601 +  }
   1.602 +  case NS_DRAGDROP_GESTURE:
   1.603 +    if (Prefs::ClickHoldContextMenu()) {
   1.604 +      // an external drag gesture event came in, not generated internally
   1.605 +      // by Gecko. Make sure we get rid of the click-hold timer.
   1.606 +      KillClickHoldTimer();
   1.607 +    }
   1.608 +    break;
   1.609 +  case NS_DRAGDROP_OVER:
   1.610 +    // NS_DRAGDROP_DROP is fired before NS_DRAGDROP_DRAGDROP so send
   1.611 +    // the enter/exit events before NS_DRAGDROP_DROP.
   1.612 +    GenerateDragDropEnterExit(aPresContext, aEvent->AsDragEvent());
   1.613 +    break;
   1.614 +
   1.615 +  case NS_KEY_PRESS:
   1.616 +    {
   1.617 +      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
   1.618 +
   1.619 +      int32_t modifierMask = 0;
   1.620 +      if (keyEvent->IsShift())
   1.621 +        modifierMask |= NS_MODIFIER_SHIFT;
   1.622 +      if (keyEvent->IsControl())
   1.623 +        modifierMask |= NS_MODIFIER_CONTROL;
   1.624 +      if (keyEvent->IsAlt())
   1.625 +        modifierMask |= NS_MODIFIER_ALT;
   1.626 +      if (keyEvent->IsMeta())
   1.627 +        modifierMask |= NS_MODIFIER_META;
   1.628 +      if (keyEvent->IsOS())
   1.629 +        modifierMask |= NS_MODIFIER_OS;
   1.630 +
   1.631 +      // Prevent keyboard scrolling while an accesskey modifier is in use.
   1.632 +      if (modifierMask &&
   1.633 +          (modifierMask == Prefs::ChromeAccessModifierMask() ||
   1.634 +           modifierMask == Prefs::ContentAccessModifierMask())) {
   1.635 +        HandleAccessKey(aPresContext, keyEvent, aStatus, nullptr,
   1.636 +                        eAccessKeyProcessingNormal, modifierMask);
   1.637 +      }
   1.638 +    }
   1.639 +    // then fall through...
   1.640 +  case NS_KEY_DOWN:
   1.641 +  case NS_KEY_UP:
   1.642 +    {
   1.643 +      nsIContent* content = GetFocusedContent();
   1.644 +      if (content)
   1.645 +        mCurrentTargetContent = content;
   1.646 +
   1.647 +      // NOTE: Don't refer TextComposition::IsComposing() since DOM Level 3
   1.648 +      //       Events defines that KeyboardEvent.isComposing is true when it's
   1.649 +      //       dispatched after compositionstart and compositionend.
   1.650 +      //       TextComposition::IsComposing() is false even before
   1.651 +      //       compositionend if there is no composing string.
   1.652 +      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
   1.653 +      nsRefPtr<TextComposition> composition =
   1.654 +        IMEStateManager::GetTextCompositionFor(keyEvent);
   1.655 +      keyEvent->mIsComposing = !!composition;
   1.656 +    }
   1.657 +    break;
   1.658 +  case NS_WHEEL_WHEEL:
   1.659 +  case NS_WHEEL_START:
   1.660 +  case NS_WHEEL_STOP:
   1.661 +    {
   1.662 +      NS_ASSERTION(aEvent->mFlags.mIsTrusted,
   1.663 +                   "Untrusted wheel event shouldn't be here");
   1.664 +
   1.665 +      nsIContent* content = GetFocusedContent();
   1.666 +      if (content) {
   1.667 +        mCurrentTargetContent = content;
   1.668 +      }
   1.669 +
   1.670 +      if (aEvent->message != NS_WHEEL_WHEEL) {
   1.671 +        break;
   1.672 +      }
   1.673 +
   1.674 +      WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
   1.675 +      WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
   1.676 +
   1.677 +      // If we won't dispatch a DOM event for this event, nothing to do anymore.
   1.678 +      if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
   1.679 +        break;
   1.680 +      }
   1.681 +
   1.682 +      // Init lineOrPageDelta values for line scroll events for some devices
   1.683 +      // on some platforms which might dispatch wheel events which don't have
   1.684 +      // lineOrPageDelta values.  And also, if delta values are customized by
   1.685 +      // prefs, this recomputes them.
   1.686 +      DeltaAccumulator::GetInstance()->
   1.687 +        InitLineOrPageDelta(aTargetFrame, this, wheelEvent);
   1.688 +    }
   1.689 +    break;
   1.690 +  case NS_QUERY_SELECTED_TEXT:
   1.691 +    DoQuerySelectedText(aEvent->AsQueryContentEvent());
   1.692 +    break;
   1.693 +  case NS_QUERY_TEXT_CONTENT:
   1.694 +    {
   1.695 +      if (RemoteQueryContentEvent(aEvent)) {
   1.696 +        break;
   1.697 +      }
   1.698 +      ContentEventHandler handler(mPresContext);
   1.699 +      handler.OnQueryTextContent(aEvent->AsQueryContentEvent());
   1.700 +    }
   1.701 +    break;
   1.702 +  case NS_QUERY_CARET_RECT:
   1.703 +    {
   1.704 +      if (RemoteQueryContentEvent(aEvent)) {
   1.705 +        break;
   1.706 +      }
   1.707 +      ContentEventHandler handler(mPresContext);
   1.708 +      handler.OnQueryCaretRect(aEvent->AsQueryContentEvent());
   1.709 +    }
   1.710 +    break;
   1.711 +  case NS_QUERY_TEXT_RECT:
   1.712 +    {
   1.713 +      if (RemoteQueryContentEvent(aEvent)) {
   1.714 +        break;
   1.715 +      }
   1.716 +      ContentEventHandler handler(mPresContext);
   1.717 +      handler.OnQueryTextRect(aEvent->AsQueryContentEvent());
   1.718 +    }
   1.719 +    break;
   1.720 +  case NS_QUERY_EDITOR_RECT:
   1.721 +    {
   1.722 +      // XXX remote event
   1.723 +      ContentEventHandler handler(mPresContext);
   1.724 +      handler.OnQueryEditorRect(aEvent->AsQueryContentEvent());
   1.725 +    }
   1.726 +    break;
   1.727 +  case NS_QUERY_CONTENT_STATE:
   1.728 +    {
   1.729 +      // XXX remote event
   1.730 +      ContentEventHandler handler(mPresContext);
   1.731 +      handler.OnQueryContentState(aEvent->AsQueryContentEvent());
   1.732 +    }
   1.733 +    break;
   1.734 +  case NS_QUERY_SELECTION_AS_TRANSFERABLE:
   1.735 +    {
   1.736 +      // XXX remote event
   1.737 +      ContentEventHandler handler(mPresContext);
   1.738 +      handler.OnQuerySelectionAsTransferable(aEvent->AsQueryContentEvent());
   1.739 +    }
   1.740 +    break;
   1.741 +  case NS_QUERY_CHARACTER_AT_POINT:
   1.742 +    {
   1.743 +      // XXX remote event
   1.744 +      ContentEventHandler handler(mPresContext);
   1.745 +      handler.OnQueryCharacterAtPoint(aEvent->AsQueryContentEvent());
   1.746 +    }
   1.747 +    break;
   1.748 +  case NS_QUERY_DOM_WIDGET_HITTEST:
   1.749 +    {
   1.750 +      // XXX remote event
   1.751 +      ContentEventHandler handler(mPresContext);
   1.752 +      handler.OnQueryDOMWidgetHittest(aEvent->AsQueryContentEvent());
   1.753 +    }
   1.754 +    break;
   1.755 +  case NS_SELECTION_SET:
   1.756 +    {
   1.757 +      WidgetSelectionEvent* selectionEvent = aEvent->AsSelectionEvent();
   1.758 +      if (IsTargetCrossProcess(selectionEvent)) {
   1.759 +        // Will not be handled locally, remote the event
   1.760 +        if (GetCrossProcessTarget()->SendSelectionEvent(*selectionEvent)) {
   1.761 +          selectionEvent->mSucceeded = true;
   1.762 +        }
   1.763 +        break;
   1.764 +      }
   1.765 +      ContentEventHandler handler(mPresContext);
   1.766 +      handler.OnSelectionEvent(selectionEvent);
   1.767 +    }
   1.768 +    break;
   1.769 +  case NS_CONTENT_COMMAND_CUT:
   1.770 +  case NS_CONTENT_COMMAND_COPY:
   1.771 +  case NS_CONTENT_COMMAND_PASTE:
   1.772 +  case NS_CONTENT_COMMAND_DELETE:
   1.773 +  case NS_CONTENT_COMMAND_UNDO:
   1.774 +  case NS_CONTENT_COMMAND_REDO:
   1.775 +  case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE:
   1.776 +    {
   1.777 +      DoContentCommandEvent(aEvent->AsContentCommandEvent());
   1.778 +    }
   1.779 +    break;
   1.780 +  case NS_CONTENT_COMMAND_SCROLL:
   1.781 +    {
   1.782 +      DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
   1.783 +    }
   1.784 +    break;
   1.785 +  case NS_TEXT_TEXT:
   1.786 +    {
   1.787 +      WidgetTextEvent *textEvent = aEvent->AsTextEvent();
   1.788 +      if (IsTargetCrossProcess(textEvent)) {
   1.789 +        // Will not be handled locally, remote the event
   1.790 +        if (GetCrossProcessTarget()->SendTextEvent(*textEvent)) {
   1.791 +          // Cancel local dispatching
   1.792 +          aEvent->mFlags.mPropagationStopped = true;
   1.793 +        }
   1.794 +      }
   1.795 +    }
   1.796 +    break;
   1.797 +  case NS_COMPOSITION_START:
   1.798 +    if (aEvent->mFlags.mIsTrusted) {
   1.799 +      // If the event is trusted event, set the selected text to data of
   1.800 +      // composition event.
   1.801 +      WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
   1.802 +      WidgetQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT,
   1.803 +                                           compositionEvent->widget);
   1.804 +      DoQuerySelectedText(&selectedText);
   1.805 +      NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
   1.806 +      compositionEvent->data = selectedText.mReply.mString;
   1.807 +    }
   1.808 +    // through to compositionend handling
   1.809 +  case NS_COMPOSITION_UPDATE:
   1.810 +  case NS_COMPOSITION_END:
   1.811 +    {
   1.812 +      WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
   1.813 +      if (IsTargetCrossProcess(compositionEvent)) {
   1.814 +        // Will not be handled locally, remote the event
   1.815 +        if (GetCrossProcessTarget()->SendCompositionEvent(*compositionEvent)) {
   1.816 +          // Cancel local dispatching
   1.817 +          aEvent->mFlags.mPropagationStopped = true;
   1.818 +        }
   1.819 +      }
   1.820 +    }
   1.821 +    break;
   1.822 +  }
   1.823 +  return NS_OK;
   1.824 +}
   1.825 +
   1.826 +// static
   1.827 +int32_t
   1.828 +EventStateManager::GetAccessModifierMaskFor(nsISupports* aDocShell)
   1.829 +{
   1.830 +  nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
   1.831 +  if (!treeItem)
   1.832 +    return -1; // invalid modifier
   1.833 +
   1.834 +  switch (treeItem->ItemType()) {
   1.835 +  case nsIDocShellTreeItem::typeChrome:
   1.836 +    return Prefs::ChromeAccessModifierMask();
   1.837 +
   1.838 +  case nsIDocShellTreeItem::typeContent:
   1.839 +    return Prefs::ContentAccessModifierMask();
   1.840 +
   1.841 +  default:
   1.842 +    return -1; // invalid modifier
   1.843 +  }
   1.844 +}
   1.845 +
   1.846 +static bool
   1.847 +IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsAString& aKey)
   1.848 +{
   1.849 +  // Use GetAttr because we want Unicode case=insensitive matching
   1.850 +  // XXXbz shouldn't this be case-sensitive, per spec?
   1.851 +  nsString contentKey;
   1.852 +  if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, contentKey) ||
   1.853 +      !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator()))
   1.854 +    return false;
   1.855 +
   1.856 +  nsCOMPtr<nsIDOMXULDocument> xulDoc =
   1.857 +    do_QueryInterface(aContent->OwnerDoc());
   1.858 +  if (!xulDoc && !aContent->IsXUL())
   1.859 +    return true;
   1.860 +
   1.861 +    // For XUL we do visibility checks.
   1.862 +  if (!aFrame)
   1.863 +    return false;
   1.864 +
   1.865 +  if (aFrame->IsFocusable())
   1.866 +    return true;
   1.867 +
   1.868 +  if (!aFrame->IsVisibleConsideringAncestors())
   1.869 +    return false;
   1.870 +
   1.871 +  // XUL controls can be activated.
   1.872 +  nsCOMPtr<nsIDOMXULControlElement> control(do_QueryInterface(aContent));
   1.873 +  if (control)
   1.874 +    return true;
   1.875 +
   1.876 +  if (aContent->IsHTML()) {
   1.877 +    nsIAtom* tag = aContent->Tag();
   1.878 +
   1.879 +    // HTML area, label and legend elements are never focusable, so
   1.880 +    // we need to check for them explicitly before giving up.
   1.881 +    if (tag == nsGkAtoms::area ||
   1.882 +        tag == nsGkAtoms::label ||
   1.883 +        tag == nsGkAtoms::legend)
   1.884 +      return true;
   1.885 +
   1.886 +  } else if (aContent->IsXUL()) {
   1.887 +    // XUL label elements are never focusable, so we need to check for them
   1.888 +    // explicitly before giving up.
   1.889 +    if (aContent->Tag() == nsGkAtoms::label)
   1.890 +      return true;
   1.891 +  }
   1.892 +
   1.893 +  return false;
   1.894 +}
   1.895 +
   1.896 +bool
   1.897 +EventStateManager::ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
   1.898 +                                    bool aIsTrustedEvent)
   1.899 +{
   1.900 +  int32_t count, start = -1;
   1.901 +  nsIContent* focusedContent = GetFocusedContent();
   1.902 +  if (focusedContent) {
   1.903 +    start = mAccessKeys.IndexOf(focusedContent);
   1.904 +    if (start == -1 && focusedContent->GetBindingParent())
   1.905 +      start = mAccessKeys.IndexOf(focusedContent->GetBindingParent());
   1.906 +  }
   1.907 +  nsIContent *content;
   1.908 +  nsIFrame *frame;
   1.909 +  int32_t length = mAccessKeys.Count();
   1.910 +  for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
   1.911 +    uint32_t ch = aAccessCharCodes[i];
   1.912 +    nsAutoString accessKey;
   1.913 +    AppendUCS4ToUTF16(ch, accessKey);
   1.914 +    for (count = 1; count <= length; ++count) {
   1.915 +      content = mAccessKeys[(start + count) % length];
   1.916 +      frame = content->GetPrimaryFrame();
   1.917 +      if (IsAccessKeyTarget(content, frame, accessKey)) {
   1.918 +        bool shouldActivate = Prefs::KeyCausesActivation();
   1.919 +        while (shouldActivate && ++count <= length) {
   1.920 +          nsIContent *oc = mAccessKeys[(start + count) % length];
   1.921 +          nsIFrame *of = oc->GetPrimaryFrame();
   1.922 +          if (IsAccessKeyTarget(oc, of, accessKey))
   1.923 +            shouldActivate = false;
   1.924 +        }
   1.925 +        if (shouldActivate)
   1.926 +          content->PerformAccesskey(shouldActivate, aIsTrustedEvent);
   1.927 +        else {
   1.928 +          nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   1.929 +          if (fm) {
   1.930 +            nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
   1.931 +            fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
   1.932 +          }
   1.933 +        }
   1.934 +        return true;
   1.935 +      }
   1.936 +    }
   1.937 +  }
   1.938 +  return false;
   1.939 +}
   1.940 +
   1.941 +bool
   1.942 +EventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix)
   1.943 +{
   1.944 +  aPrefix.Truncate();
   1.945 +  nsAutoString separator, modifierText;
   1.946 +  nsContentUtils::GetModifierSeparatorText(separator);
   1.947 +
   1.948 +  nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak();
   1.949 +  int32_t modifierMask = GetAccessModifierMaskFor(container);
   1.950 +
   1.951 +  if (modifierMask & NS_MODIFIER_CONTROL) {
   1.952 +    nsContentUtils::GetControlText(modifierText);
   1.953 +    aPrefix.Append(modifierText + separator);
   1.954 +  }
   1.955 +  if (modifierMask & NS_MODIFIER_META) {
   1.956 +    nsContentUtils::GetMetaText(modifierText);
   1.957 +    aPrefix.Append(modifierText + separator);
   1.958 +  }
   1.959 +  if (modifierMask & NS_MODIFIER_OS) {
   1.960 +    nsContentUtils::GetOSText(modifierText);
   1.961 +    aPrefix.Append(modifierText + separator);
   1.962 +  }
   1.963 +  if (modifierMask & NS_MODIFIER_ALT) {
   1.964 +    nsContentUtils::GetAltText(modifierText);
   1.965 +    aPrefix.Append(modifierText + separator);
   1.966 +  }
   1.967 +  if (modifierMask & NS_MODIFIER_SHIFT) {
   1.968 +    nsContentUtils::GetShiftText(modifierText);
   1.969 +    aPrefix.Append(modifierText + separator);
   1.970 +  }
   1.971 +  return !aPrefix.IsEmpty();
   1.972 +}
   1.973 +
   1.974 +void
   1.975 +EventStateManager::HandleAccessKey(nsPresContext* aPresContext,
   1.976 +                                   WidgetKeyboardEvent* aEvent,
   1.977 +                                   nsEventStatus* aStatus,
   1.978 +                                   nsIDocShellTreeItem* aBubbledFrom,
   1.979 +                                   ProcessingAccessKeyState aAccessKeyState,
   1.980 +                                   int32_t aModifierMask)
   1.981 +{
   1.982 +  nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
   1.983 +
   1.984 +  // Alt or other accesskey modifier is down, we may need to do an accesskey
   1.985 +  if (mAccessKeys.Count() > 0 &&
   1.986 +      aModifierMask == GetAccessModifierMaskFor(docShell)) {
   1.987 +    // Someone registered an accesskey.  Find and activate it.
   1.988 +    nsAutoTArray<uint32_t, 10> accessCharCodes;
   1.989 +    nsContentUtils::GetAccessKeyCandidates(aEvent, accessCharCodes);
   1.990 +    if (ExecuteAccessKey(accessCharCodes, aEvent->mFlags.mIsTrusted)) {
   1.991 +      *aStatus = nsEventStatus_eConsumeNoDefault;
   1.992 +      return;
   1.993 +    }
   1.994 +  }
   1.995 +
   1.996 +  // after the local accesskey handling
   1.997 +  if (nsEventStatus_eConsumeNoDefault != *aStatus) {
   1.998 +    // checking all sub docshells
   1.999 +
  1.1000 +    if (!docShell) {
  1.1001 +      NS_WARNING("no docShellTreeNode for presContext");
  1.1002 +      return;
  1.1003 +    }
  1.1004 +
  1.1005 +    int32_t childCount;
  1.1006 +    docShell->GetChildCount(&childCount);
  1.1007 +    for (int32_t counter = 0; counter < childCount; counter++) {
  1.1008 +      // Not processing the child which bubbles up the handling
  1.1009 +      nsCOMPtr<nsIDocShellTreeItem> subShellItem;
  1.1010 +      docShell->GetChildAt(counter, getter_AddRefs(subShellItem));
  1.1011 +      if (aAccessKeyState == eAccessKeyProcessingUp &&
  1.1012 +          subShellItem == aBubbledFrom)
  1.1013 +        continue;
  1.1014 +
  1.1015 +      nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
  1.1016 +      if (subDS && IsShellVisible(subDS)) {
  1.1017 +        nsCOMPtr<nsIPresShell> subPS = subDS->GetPresShell();
  1.1018 +
  1.1019 +        // Docshells need not have a presshell (eg. display:none
  1.1020 +        // iframes, docshells in transition between documents, etc).
  1.1021 +        if (!subPS) {
  1.1022 +          // Oh, well.  Just move on to the next child
  1.1023 +          continue;
  1.1024 +        }
  1.1025 +
  1.1026 +        nsPresContext *subPC = subPS->GetPresContext();
  1.1027 +
  1.1028 +        EventStateManager* esm =
  1.1029 +          static_cast<EventStateManager*>(subPC->EventStateManager());
  1.1030 +
  1.1031 +        if (esm)
  1.1032 +          esm->HandleAccessKey(subPC, aEvent, aStatus, nullptr,
  1.1033 +                               eAccessKeyProcessingDown, aModifierMask);
  1.1034 +
  1.1035 +        if (nsEventStatus_eConsumeNoDefault == *aStatus)
  1.1036 +          break;
  1.1037 +      }
  1.1038 +    }
  1.1039 +  }// if end . checking all sub docshell ends here.
  1.1040 +
  1.1041 +  // bubble up the process to the parent docshell if necessary
  1.1042 +  if (eAccessKeyProcessingDown != aAccessKeyState && nsEventStatus_eConsumeNoDefault != *aStatus) {
  1.1043 +    if (!docShell) {
  1.1044 +      NS_WARNING("no docShellTreeItem for presContext");
  1.1045 +      return;
  1.1046 +    }
  1.1047 +
  1.1048 +    nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
  1.1049 +    docShell->GetParent(getter_AddRefs(parentShellItem));
  1.1050 +    nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
  1.1051 +    if (parentDS) {
  1.1052 +      nsCOMPtr<nsIPresShell> parentPS = parentDS->GetPresShell();
  1.1053 +      NS_ASSERTION(parentPS, "Our PresShell exists but the parent's does not?");
  1.1054 +
  1.1055 +      nsPresContext *parentPC = parentPS->GetPresContext();
  1.1056 +      NS_ASSERTION(parentPC, "PresShell without PresContext");
  1.1057 +
  1.1058 +      EventStateManager* esm =
  1.1059 +        static_cast<EventStateManager*>(parentPC->EventStateManager());
  1.1060 +
  1.1061 +      if (esm)
  1.1062 +        esm->HandleAccessKey(parentPC, aEvent, aStatus, docShell,
  1.1063 +                             eAccessKeyProcessingUp, aModifierMask);
  1.1064 +    }
  1.1065 +  }// if end. bubble up process
  1.1066 +}// end of HandleAccessKey
  1.1067 +
  1.1068 +bool
  1.1069 +EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
  1.1070 +                                             nsFrameLoader* aFrameLoader,
  1.1071 +                                             nsEventStatus *aStatus) {
  1.1072 +  PBrowserParent* remoteBrowser = aFrameLoader->GetRemoteBrowser();
  1.1073 +  TabParent* remote = static_cast<TabParent*>(remoteBrowser);
  1.1074 +  if (!remote) {
  1.1075 +    return false;
  1.1076 +  }
  1.1077 +
  1.1078 +  switch (aEvent->eventStructType) {
  1.1079 +  case NS_MOUSE_EVENT: {
  1.1080 +    return remote->SendRealMouseEvent(*aEvent->AsMouseEvent());
  1.1081 +  }
  1.1082 +  case NS_KEY_EVENT: {
  1.1083 +    return remote->SendRealKeyEvent(*aEvent->AsKeyboardEvent());
  1.1084 +  }
  1.1085 +  case NS_WHEEL_EVENT: {
  1.1086 +    return remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
  1.1087 +  }
  1.1088 +  case NS_TOUCH_EVENT: {
  1.1089 +    // Let the child process synthesize a mouse event if needed, and
  1.1090 +    // ensure we don't synthesize one in this process.
  1.1091 +    *aStatus = nsEventStatus_eConsumeNoDefault;
  1.1092 +    return remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
  1.1093 +  }
  1.1094 +  default: {
  1.1095 +    MOZ_CRASH("Attempt to send non-whitelisted event?");
  1.1096 +  }
  1.1097 +  }
  1.1098 +}
  1.1099 +
  1.1100 +bool
  1.1101 +EventStateManager::IsRemoteTarget(nsIContent* target) {
  1.1102 +  if (!target) {
  1.1103 +    return false;
  1.1104 +  }
  1.1105 +
  1.1106 +  // <browser/iframe remote=true> from XUL
  1.1107 +  if ((target->Tag() == nsGkAtoms::browser ||
  1.1108 +       target->Tag() == nsGkAtoms::iframe) &&
  1.1109 +      target->IsXUL() &&
  1.1110 +      target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
  1.1111 +                          nsGkAtoms::_true, eIgnoreCase)) {
  1.1112 +    return true;
  1.1113 +  }
  1.1114 +
  1.1115 +  // <frame/iframe mozbrowser/mozapp>
  1.1116 +  nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(target);
  1.1117 +  if (browserFrame && browserFrame->GetReallyIsBrowserOrApp()) {
  1.1118 +    return !!TabParent::GetFrom(target);
  1.1119 +  }
  1.1120 +
  1.1121 +  return false;
  1.1122 +}
  1.1123 +
  1.1124 +/*static*/ LayoutDeviceIntPoint
  1.1125 +EventStateManager::GetChildProcessOffset(nsFrameLoader* aFrameLoader,
  1.1126 +                                         const WidgetEvent& aEvent)
  1.1127 +{
  1.1128 +  // The "toplevel widget" in child processes is always at position
  1.1129 +  // 0,0.  Map the event coordinates to match that.
  1.1130 +  nsIFrame* targetFrame = aFrameLoader->GetPrimaryFrameOfOwningContent();
  1.1131 +  if (!targetFrame) {
  1.1132 +    return LayoutDeviceIntPoint();
  1.1133 +  }
  1.1134 +  nsPresContext* presContext = targetFrame->PresContext();
  1.1135 +
  1.1136 +  // Find out how far we're offset from the nearest widget.
  1.1137 +  nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(&aEvent,
  1.1138 +                                                            targetFrame);
  1.1139 +  return LayoutDeviceIntPoint::FromAppUnitsToNearest(pt, presContext->AppUnitsPerDevPixel());
  1.1140 +}
  1.1141 +
  1.1142 +bool
  1.1143 +CrossProcessSafeEvent(const WidgetEvent& aEvent)
  1.1144 +{
  1.1145 +  switch (aEvent.eventStructType) {
  1.1146 +  case NS_KEY_EVENT:
  1.1147 +  case NS_WHEEL_EVENT:
  1.1148 +    return true;
  1.1149 +  case NS_MOUSE_EVENT:
  1.1150 +    switch (aEvent.message) {
  1.1151 +    case NS_MOUSE_BUTTON_DOWN:
  1.1152 +    case NS_MOUSE_BUTTON_UP:
  1.1153 +    case NS_MOUSE_MOVE:
  1.1154 +    case NS_CONTEXTMENU:
  1.1155 +      return true;
  1.1156 +    default:
  1.1157 +      return false;
  1.1158 +    }
  1.1159 +  case NS_TOUCH_EVENT:
  1.1160 +    switch (aEvent.message) {
  1.1161 +    case NS_TOUCH_START:
  1.1162 +    case NS_TOUCH_MOVE:
  1.1163 +    case NS_TOUCH_END:
  1.1164 +    case NS_TOUCH_CANCEL:
  1.1165 +      return true;
  1.1166 +    default:
  1.1167 +      return false;
  1.1168 +    }
  1.1169 +  default:
  1.1170 +    return false;
  1.1171 +  }
  1.1172 +}
  1.1173 +
  1.1174 +bool
  1.1175 +EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
  1.1176 +                                           nsIFrame* aTargetFrame,
  1.1177 +                                           nsEventStatus *aStatus) {
  1.1178 +  if (*aStatus == nsEventStatus_eConsumeNoDefault ||
  1.1179 +      aEvent->mFlags.mNoCrossProcessBoundaryForwarding ||
  1.1180 +      !CrossProcessSafeEvent(*aEvent)) {
  1.1181 +    return false;
  1.1182 +  }
  1.1183 +
  1.1184 +  // Collect the remote event targets we're going to forward this
  1.1185 +  // event to.
  1.1186 +  //
  1.1187 +  // NB: the elements of |targets| must be unique, for correctness.
  1.1188 +  nsAutoTArray<nsCOMPtr<nsIContent>, 1> targets;
  1.1189 +  if (aEvent->eventStructType != NS_TOUCH_EVENT ||
  1.1190 +      aEvent->message == NS_TOUCH_START) {
  1.1191 +    // If this event only has one target, and it's remote, add it to
  1.1192 +    // the array.
  1.1193 +    nsIFrame* frame = GetEventTarget();
  1.1194 +    nsIContent* target = frame ? frame->GetContent() : nullptr;
  1.1195 +    if (IsRemoteTarget(target)) {
  1.1196 +      targets.AppendElement(target);
  1.1197 +    }
  1.1198 +  } else {
  1.1199 +    // This is a touch event with possibly multiple touch points.
  1.1200 +    // Each touch point may have its own target.  So iterate through
  1.1201 +    // all of them and collect the unique set of targets for event
  1.1202 +    // forwarding.
  1.1203 +    //
  1.1204 +    // This loop is similar to the one used in
  1.1205 +    // PresShell::DispatchTouchEvent().
  1.1206 +    const nsTArray< nsRefPtr<Touch> >& touches =
  1.1207 +      aEvent->AsTouchEvent()->touches;
  1.1208 +    for (uint32_t i = 0; i < touches.Length(); ++i) {
  1.1209 +      Touch* touch = touches[i];
  1.1210 +      // NB: the |mChanged| check is an optimization, subprocesses can
  1.1211 +      // compute this for themselves.  If the touch hasn't changed, we
  1.1212 +      // may be able to avoid forwarding the event entirely (which is
  1.1213 +      // not free).
  1.1214 +      if (!touch || !touch->mChanged) {
  1.1215 +        continue;
  1.1216 +      }
  1.1217 +      nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
  1.1218 +      if (!targetPtr) {
  1.1219 +        continue;
  1.1220 +      }
  1.1221 +      nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
  1.1222 +      if (IsRemoteTarget(target) && !targets.Contains(target)) {
  1.1223 +        targets.AppendElement(target);
  1.1224 +      }
  1.1225 +    }
  1.1226 +  }
  1.1227 +
  1.1228 +  if (targets.Length() == 0) {
  1.1229 +    return false;
  1.1230 +  }
  1.1231 +
  1.1232 +  // Look up the frame loader for all the remote targets we found, and
  1.1233 +  // then dispatch the event to the remote content they represent.
  1.1234 +  bool dispatched = false;
  1.1235 +  for (uint32_t i = 0; i < targets.Length(); ++i) {
  1.1236 +    nsIContent* target = targets[i];
  1.1237 +    nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target);
  1.1238 +    if (!loaderOwner) {
  1.1239 +      continue;
  1.1240 +    }
  1.1241 +
  1.1242 +    nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
  1.1243 +    if (!frameLoader) {
  1.1244 +      continue;
  1.1245 +    }
  1.1246 +
  1.1247 +    uint32_t eventMode;
  1.1248 +    frameLoader->GetEventMode(&eventMode);
  1.1249 +    if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) {
  1.1250 +      continue;
  1.1251 +    }
  1.1252 +
  1.1253 +    dispatched |= DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
  1.1254 +  }
  1.1255 +  return dispatched;
  1.1256 +}
  1.1257 +
  1.1258 +//
  1.1259 +// CreateClickHoldTimer
  1.1260 +//
  1.1261 +// Fire off a timer for determining if the user wants click-hold. This timer
  1.1262 +// is a one-shot that will be cancelled when the user moves enough to fire
  1.1263 +// a drag.
  1.1264 +//
  1.1265 +void
  1.1266 +EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
  1.1267 +                                        nsIFrame* inDownFrame,
  1.1268 +                                        WidgetGUIEvent* inMouseDownEvent)
  1.1269 +{
  1.1270 +  if (!inMouseDownEvent->mFlags.mIsTrusted || IsRemoteTarget(mGestureDownContent))
  1.1271 +    return;
  1.1272 +
  1.1273 +  // just to be anal (er, safe)
  1.1274 +  if (mClickHoldTimer) {
  1.1275 +    mClickHoldTimer->Cancel();
  1.1276 +    mClickHoldTimer = nullptr;
  1.1277 +  }
  1.1278 +
  1.1279 +  // if content clicked on has a popup, don't even start the timer
  1.1280 +  // since we'll end up conflicting and both will show.
  1.1281 +  if (mGestureDownContent) {
  1.1282 +    // check for the |popup| attribute
  1.1283 +    if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
  1.1284 +                                        nsGkAtoms::popup))
  1.1285 +      return;
  1.1286 +    
  1.1287 +    // check for a <menubutton> like bookmarks
  1.1288 +    if (mGestureDownContent->Tag() == nsGkAtoms::menubutton)
  1.1289 +      return;
  1.1290 +  }
  1.1291 +
  1.1292 +  mClickHoldTimer = do_CreateInstance("@mozilla.org/timer;1");
  1.1293 +  if (mClickHoldTimer) {
  1.1294 +    int32_t clickHoldDelay =
  1.1295 +      Preferences::GetInt("ui.click_hold_context_menus.delay", 500);
  1.1296 +    mClickHoldTimer->InitWithFuncCallback(sClickHoldCallback, this,
  1.1297 +                                          clickHoldDelay,
  1.1298 +                                          nsITimer::TYPE_ONE_SHOT);
  1.1299 +  }
  1.1300 +} // CreateClickHoldTimer
  1.1301 +
  1.1302 +
  1.1303 +//
  1.1304 +// KillClickHoldTimer
  1.1305 +//
  1.1306 +// Stop the timer that would show the context menu dead in its tracks
  1.1307 +//
  1.1308 +void
  1.1309 +EventStateManager::KillClickHoldTimer()
  1.1310 +{
  1.1311 +  if (mClickHoldTimer) {
  1.1312 +    mClickHoldTimer->Cancel();
  1.1313 +    mClickHoldTimer = nullptr;
  1.1314 +  }
  1.1315 +}
  1.1316 +
  1.1317 +
  1.1318 +//
  1.1319 +// sClickHoldCallback
  1.1320 +//
  1.1321 +// This fires after the mouse has been down for a certain length of time.
  1.1322 +//
  1.1323 +void
  1.1324 +EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM)
  1.1325 +{
  1.1326 +  nsRefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
  1.1327 +  if (self) {
  1.1328 +    self->FireContextClick();
  1.1329 +  }
  1.1330 +
  1.1331 +  // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
  1.1332 +
  1.1333 +} // sAutoHideCallback
  1.1334 +
  1.1335 +
  1.1336 +//
  1.1337 +// FireContextClick
  1.1338 +//
  1.1339 +// If we're this far, our timer has fired, which means the mouse has been down
  1.1340 +// for a certain period of time and has not moved enough to generate a dragGesture.
  1.1341 +// We can be certain the user wants a context-click at this stage, so generate
  1.1342 +// a dom event and fire it in.
  1.1343 +//
  1.1344 +// After the event fires, check if PreventDefault() has been set on the event which
  1.1345 +// means that someone either ate the event or put up a context menu. This is our cue
  1.1346 +// to stop tracking the drag gesture. If we always did this, draggable items w/out
  1.1347 +// a context menu wouldn't be draggable after a certain length of time, which is
  1.1348 +// _not_ what we want.
  1.1349 +//
  1.1350 +void
  1.1351 +EventStateManager::FireContextClick()
  1.1352 +{
  1.1353 +  if (!mGestureDownContent || !mPresContext) {
  1.1354 +    return;
  1.1355 +  }
  1.1356 +
  1.1357 +#ifdef XP_MACOSX
  1.1358 +  // Hack to ensure that we don't show a context menu when the user
  1.1359 +  // let go of the mouse after a long cpu-hogging operation prevented
  1.1360 +  // us from handling any OS events. See bug 117589.
  1.1361 +  if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft))
  1.1362 +    return;
  1.1363 +#endif
  1.1364 +
  1.1365 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.1366 +
  1.1367 +  // Dispatch to the DOM. We have to fake out the ESM and tell it that the
  1.1368 +  // current target frame is actually where the mouseDown occurred, otherwise it
  1.1369 +  // will use the frame the mouse is currently over which may or may not be
  1.1370 +  // the same. (Note: saari and I have decided that we don't have to reset |mCurrentTarget|
  1.1371 +  // when we're through because no one else is doing anything more with this
  1.1372 +  // event and it will get reset on the very next event to the correct frame).
  1.1373 +  mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
  1.1374 +  // make sure the widget sticks around
  1.1375 +  nsCOMPtr<nsIWidget> targetWidget;
  1.1376 +  if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
  1.1377 +    NS_ASSERTION(mPresContext == mCurrentTarget->PresContext(),
  1.1378 +                 "a prescontext returned a primary frame that didn't belong to it?");
  1.1379 +
  1.1380 +    // before dispatching, check that we're not on something that
  1.1381 +    // doesn't get a context menu
  1.1382 +    nsIAtom *tag = mGestureDownContent->Tag();
  1.1383 +    bool allowedToDispatch = true;
  1.1384 +
  1.1385 +    if (mGestureDownContent->IsXUL()) {
  1.1386 +      if (tag == nsGkAtoms::scrollbar ||
  1.1387 +          tag == nsGkAtoms::scrollbarbutton ||
  1.1388 +          tag == nsGkAtoms::button)
  1.1389 +        allowedToDispatch = false;
  1.1390 +      else if (tag == nsGkAtoms::toolbarbutton) {
  1.1391 +        // a <toolbarbutton> that has the container attribute set
  1.1392 +        // will already have its own dropdown.
  1.1393 +        if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent,
  1.1394 +                kNameSpaceID_None, nsGkAtoms::container)) {
  1.1395 +          allowedToDispatch = false;
  1.1396 +        } else {
  1.1397 +          // If the toolbar button has an open menu, don't attempt to open
  1.1398 +            // a second menu
  1.1399 +          if (mGestureDownContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
  1.1400 +                                               nsGkAtoms::_true, eCaseMatters)) {
  1.1401 +            allowedToDispatch = false;
  1.1402 +          }
  1.1403 +        }
  1.1404 +      }
  1.1405 +    }
  1.1406 +    else if (mGestureDownContent->IsHTML()) {
  1.1407 +      nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent));
  1.1408 +
  1.1409 +      if (formCtrl) {
  1.1410 +        allowedToDispatch = formCtrl->IsTextControl(false) ||
  1.1411 +                            formCtrl->GetType() == NS_FORM_INPUT_FILE;
  1.1412 +      }
  1.1413 +      else if (tag == nsGkAtoms::applet ||
  1.1414 +               tag == nsGkAtoms::embed  ||
  1.1415 +               tag == nsGkAtoms::object) {
  1.1416 +        allowedToDispatch = false;
  1.1417 +      }
  1.1418 +    }
  1.1419 +
  1.1420 +    if (allowedToDispatch) {
  1.1421 +      // init the event while mCurrentTarget is still good
  1.1422 +      WidgetMouseEvent event(true, NS_CONTEXTMENU, targetWidget,
  1.1423 +                             WidgetMouseEvent::eReal);
  1.1424 +      event.clickCount = 1;
  1.1425 +      FillInEventFromGestureDown(&event);
  1.1426 +        
  1.1427 +      // stop selection tracking, we're in control now
  1.1428 +      if (mCurrentTarget)
  1.1429 +      {
  1.1430 +        nsRefPtr<nsFrameSelection> frameSel =
  1.1431 +          mCurrentTarget->GetFrameSelection();
  1.1432 +        
  1.1433 +        if (frameSel && frameSel->GetMouseDownState()) {
  1.1434 +          // note that this can cause selection changed events to fire if we're in
  1.1435 +          // a text field, which will null out mCurrentTarget
  1.1436 +          frameSel->SetMouseDownState(false);
  1.1437 +        }
  1.1438 +      }
  1.1439 +
  1.1440 +      nsIDocument* doc = mGestureDownContent->GetCurrentDoc();
  1.1441 +      AutoHandlingUserInputStatePusher userInpStatePusher(true, &event, doc);
  1.1442 +
  1.1443 +      // dispatch to DOM
  1.1444 +      EventDispatcher::Dispatch(mGestureDownContent, mPresContext, &event,
  1.1445 +                                nullptr, &status);
  1.1446 +
  1.1447 +      // We don't need to dispatch to frame handling because no frames
  1.1448 +      // watch NS_CONTEXTMENU except for nsMenuFrame and that's only for
  1.1449 +      // dismissal. That's just as well since we don't really know
  1.1450 +      // which frame to send it to.
  1.1451 +    }
  1.1452 +  }
  1.1453 +
  1.1454 +  // now check if the event has been handled. If so, stop tracking a drag
  1.1455 +  if (status == nsEventStatus_eConsumeNoDefault) {
  1.1456 +    StopTrackingDragGesture();
  1.1457 +  }
  1.1458 +
  1.1459 +  KillClickHoldTimer();
  1.1460 +
  1.1461 +} // FireContextClick
  1.1462 +
  1.1463 +
  1.1464 +//
  1.1465 +// BeginTrackingDragGesture
  1.1466 +//
  1.1467 +// Record that the mouse has gone down and that we should move to TRACKING state
  1.1468 +// of d&d gesture tracker.
  1.1469 +//
  1.1470 +// We also use this to track click-hold context menus. When the mouse goes down,
  1.1471 +// fire off a short timer. If the timer goes off and we have yet to fire the
  1.1472 +// drag gesture (ie, the mouse hasn't moved a certain distance), then we can
  1.1473 +// assume the user wants a click-hold, so fire a context-click event. We only
  1.1474 +// want to cancel the drag gesture if the context-click event is handled.
  1.1475 +//
  1.1476 +void
  1.1477 +EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
  1.1478 +                                            WidgetMouseEvent* inDownEvent,
  1.1479 +                                            nsIFrame* inDownFrame)
  1.1480 +{
  1.1481 +  if (!inDownEvent->widget)
  1.1482 +    return;
  1.1483 +
  1.1484 +  // Note that |inDownEvent| could be either a mouse down event or a
  1.1485 +  // synthesized mouse move event.
  1.1486 +  mGestureDownPoint = inDownEvent->refPoint +
  1.1487 +    LayoutDeviceIntPoint::FromUntyped(inDownEvent->widget->WidgetToScreenOffset());
  1.1488 +
  1.1489 +  inDownFrame->GetContentForEvent(inDownEvent,
  1.1490 +                                  getter_AddRefs(mGestureDownContent));
  1.1491 +
  1.1492 +  mGestureDownFrameOwner = inDownFrame->GetContent();
  1.1493 +  mGestureModifiers = inDownEvent->modifiers;
  1.1494 +  mGestureDownButtons = inDownEvent->buttons;
  1.1495 +
  1.1496 +  if (Prefs::ClickHoldContextMenu()) {
  1.1497 +    // fire off a timer to track click-hold
  1.1498 +    CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
  1.1499 +  }
  1.1500 +}
  1.1501 +
  1.1502 +
  1.1503 +//
  1.1504 +// StopTrackingDragGesture
  1.1505 +//
  1.1506 +// Record that the mouse has gone back up so that we should leave the TRACKING
  1.1507 +// state of d&d gesture tracker and return to the START state.
  1.1508 +//
  1.1509 +void
  1.1510 +EventStateManager::StopTrackingDragGesture()
  1.1511 +{
  1.1512 +  mGestureDownContent = nullptr;
  1.1513 +  mGestureDownFrameOwner = nullptr;
  1.1514 +}
  1.1515 +
  1.1516 +void
  1.1517 +EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent)
  1.1518 +{
  1.1519 +  NS_ASSERTION(aEvent->widget == mCurrentTarget->GetNearestWidget(),
  1.1520 +               "Incorrect widget in event");
  1.1521 +
  1.1522 +  // Set the coordinates in the new event to the coordinates of
  1.1523 +  // the old event, adjusted for the fact that the widget might be
  1.1524 +  // different
  1.1525 +  aEvent->refPoint = mGestureDownPoint -
  1.1526 +    LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
  1.1527 +  aEvent->modifiers = mGestureModifiers;
  1.1528 +  aEvent->buttons = mGestureDownButtons;
  1.1529 +}
  1.1530 +
  1.1531 +//
  1.1532 +// GenerateDragGesture
  1.1533 +//
  1.1534 +// If we're in the TRACKING state of the d&d gesture tracker, check the current position
  1.1535 +// of the mouse in relation to the old one. If we've moved a sufficient amount from
  1.1536 +// the mouse down, then fire off a drag gesture event.
  1.1537 +void
  1.1538 +EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
  1.1539 +                                       WidgetMouseEvent* aEvent)
  1.1540 +{
  1.1541 +  NS_ASSERTION(aPresContext, "This shouldn't happen.");
  1.1542 +  if (IsTrackingDragGesture()) {
  1.1543 +    mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
  1.1544 +
  1.1545 +    if (!mCurrentTarget) {
  1.1546 +      StopTrackingDragGesture();
  1.1547 +      return;
  1.1548 +    }
  1.1549 +
  1.1550 +    // Check if selection is tracking drag gestures, if so
  1.1551 +    // don't interfere!
  1.1552 +    if (mCurrentTarget)
  1.1553 +    {
  1.1554 +      nsRefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
  1.1555 +      if (frameSel && frameSel->GetMouseDownState()) {
  1.1556 +        StopTrackingDragGesture();
  1.1557 +        return;
  1.1558 +      }
  1.1559 +    }
  1.1560 +
  1.1561 +    // If non-native code is capturing the mouse don't start a drag.
  1.1562 +    if (nsIPresShell::IsMouseCapturePreventingDrag()) {
  1.1563 +      StopTrackingDragGesture();
  1.1564 +      return;
  1.1565 +    }
  1.1566 +
  1.1567 +    static int32_t pixelThresholdX = 0;
  1.1568 +    static int32_t pixelThresholdY = 0;
  1.1569 +
  1.1570 +    if (!pixelThresholdX) {
  1.1571 +      pixelThresholdX =
  1.1572 +        LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 0);
  1.1573 +      pixelThresholdY =
  1.1574 +        LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0);
  1.1575 +      if (!pixelThresholdX)
  1.1576 +        pixelThresholdX = 5;
  1.1577 +      if (!pixelThresholdY)
  1.1578 +        pixelThresholdY = 5;
  1.1579 +    }
  1.1580 +
  1.1581 +    // fire drag gesture if mouse has moved enough
  1.1582 +    LayoutDeviceIntPoint pt = aEvent->refPoint +
  1.1583 +      LayoutDeviceIntPoint::FromUntyped(aEvent->widget->WidgetToScreenOffset());
  1.1584 +    if (DeprecatedAbs(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
  1.1585 +        DeprecatedAbs(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
  1.1586 +      if (Prefs::ClickHoldContextMenu()) {
  1.1587 +        // stop the click-hold before we fire off the drag gesture, in case
  1.1588 +        // it takes a long time
  1.1589 +        KillClickHoldTimer();
  1.1590 +      }
  1.1591 +
  1.1592 +      nsCOMPtr<nsISupports> container = aPresContext->GetContainerWeak();
  1.1593 +      nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(container);
  1.1594 +      if (!window)
  1.1595 +        return;
  1.1596 +
  1.1597 +      nsRefPtr<DataTransfer> dataTransfer =
  1.1598 +        new DataTransfer(window, NS_DRAGDROP_START, false, -1);
  1.1599 +
  1.1600 +      nsCOMPtr<nsISelection> selection;
  1.1601 +      nsCOMPtr<nsIContent> eventContent, targetContent;
  1.1602 +      mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
  1.1603 +      if (eventContent)
  1.1604 +        DetermineDragTarget(window, eventContent, dataTransfer,
  1.1605 +                            getter_AddRefs(selection), getter_AddRefs(targetContent));
  1.1606 +
  1.1607 +      // Stop tracking the drag gesture now. This should stop us from
  1.1608 +      // reentering GenerateDragGesture inside DOM event processing.
  1.1609 +      StopTrackingDragGesture();
  1.1610 +
  1.1611 +      if (!targetContent)
  1.1612 +        return;
  1.1613 +
  1.1614 +      // Use our targetContent, now that we've determined it, as the
  1.1615 +      // parent object of the DataTransfer.
  1.1616 +      dataTransfer->SetParentObject(targetContent);
  1.1617 +
  1.1618 +      sLastDragOverFrame = nullptr;
  1.1619 +      nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
  1.1620 +
  1.1621 +      // get the widget from the target frame
  1.1622 +      WidgetDragEvent startEvent(aEvent->mFlags.mIsTrusted,
  1.1623 +                                 NS_DRAGDROP_START, widget);
  1.1624 +      FillInEventFromGestureDown(&startEvent);
  1.1625 +
  1.1626 +      WidgetDragEvent gestureEvent(aEvent->mFlags.mIsTrusted,
  1.1627 +                                   NS_DRAGDROP_GESTURE, widget);
  1.1628 +      FillInEventFromGestureDown(&gestureEvent);
  1.1629 +
  1.1630 +      startEvent.dataTransfer = gestureEvent.dataTransfer = dataTransfer;
  1.1631 +      startEvent.inputSource = gestureEvent.inputSource = aEvent->inputSource;
  1.1632 +
  1.1633 +      // Dispatch to the DOM. By setting mCurrentTarget we are faking
  1.1634 +      // out the ESM and telling it that the current target frame is
  1.1635 +      // actually where the mouseDown occurred, otherwise it will use
  1.1636 +      // the frame the mouse is currently over which may or may not be
  1.1637 +      // the same. (Note: saari and I have decided that we don't have
  1.1638 +      // to reset |mCurrentTarget| when we're through because no one
  1.1639 +      // else is doing anything more with this event and it will get
  1.1640 +      // reset on the very next event to the correct frame).
  1.1641 +
  1.1642 +      // Hold onto old target content through the event and reset after.
  1.1643 +      nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
  1.1644 +
  1.1645 +      // Set the current target to the content for the mouse down
  1.1646 +      mCurrentTargetContent = targetContent;
  1.1647 +
  1.1648 +      // Dispatch both the dragstart and draggesture events to the DOM. For
  1.1649 +      // elements in an editor, only fire the draggesture event so that the
  1.1650 +      // editor code can handle it but content doesn't see a dragstart.
  1.1651 +      nsEventStatus status = nsEventStatus_eIgnore;
  1.1652 +      EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent,
  1.1653 +                                nullptr, &status);
  1.1654 +
  1.1655 +      WidgetDragEvent* event = &startEvent;
  1.1656 +      if (status != nsEventStatus_eConsumeNoDefault) {
  1.1657 +        status = nsEventStatus_eIgnore;
  1.1658 +        EventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent,
  1.1659 +                                  nullptr, &status);
  1.1660 +        event = &gestureEvent;
  1.1661 +      }
  1.1662 +
  1.1663 +      nsCOMPtr<nsIObserverService> observerService =
  1.1664 +        mozilla::services::GetObserverService();
  1.1665 +      // Emit observer event to allow addons to modify the DataTransfer object.
  1.1666 +      if (observerService) {
  1.1667 +        observerService->NotifyObservers(dataTransfer,
  1.1668 +                                         "on-datatransfer-available",
  1.1669 +                                         nullptr);
  1.1670 +      }
  1.1671 +
  1.1672 +      // now that the dataTransfer has been updated in the dragstart and
  1.1673 +      // draggesture events, make it read only so that the data doesn't
  1.1674 +      // change during the drag.
  1.1675 +      dataTransfer->SetReadOnly();
  1.1676 +
  1.1677 +      if (status != nsEventStatus_eConsumeNoDefault) {
  1.1678 +        bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
  1.1679 +                                              targetContent, selection);
  1.1680 +        if (dragStarted) {
  1.1681 +          sActiveESM = nullptr;
  1.1682 +          aEvent->mFlags.mPropagationStopped = true;
  1.1683 +        }
  1.1684 +      }
  1.1685 +
  1.1686 +      // Note that frame event handling doesn't care about NS_DRAGDROP_GESTURE,
  1.1687 +      // which is just as well since we don't really know which frame to
  1.1688 +      // send it to
  1.1689 +
  1.1690 +      // Reset mCurretTargetContent to what it was
  1.1691 +      mCurrentTargetContent = targetBeforeEvent;
  1.1692 +    }
  1.1693 +
  1.1694 +    // Now flush all pending notifications, for better responsiveness
  1.1695 +    // while dragging.
  1.1696 +    FlushPendingEvents(aPresContext);
  1.1697 +  }
  1.1698 +} // GenerateDragGesture
  1.1699 +
  1.1700 +void
  1.1701 +EventStateManager::DetermineDragTarget(nsPIDOMWindow* aWindow,
  1.1702 +                                       nsIContent* aSelectionTarget,
  1.1703 +                                       DataTransfer* aDataTransfer,
  1.1704 +                                       nsISelection** aSelection,
  1.1705 +                                       nsIContent** aTargetNode)
  1.1706 +{
  1.1707 +  *aTargetNode = nullptr;
  1.1708 +
  1.1709 +  // GetDragData determines if a selection, link or image in the content
  1.1710 +  // should be dragged, and places the data associated with the drag in the
  1.1711 +  // data transfer.
  1.1712 +  // mGestureDownContent is the node where the mousedown event for the drag
  1.1713 +  // occurred, and aSelectionTarget is the node to use when a selection is used
  1.1714 +  bool canDrag;
  1.1715 +  nsCOMPtr<nsIContent> dragDataNode;
  1.1716 +  bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
  1.1717 +  nsresult rv = nsContentAreaDragDrop::GetDragData(aWindow, mGestureDownContent,
  1.1718 +                                                   aSelectionTarget, wasAlt,
  1.1719 +                                                   aDataTransfer, &canDrag, aSelection,
  1.1720 +                                                   getter_AddRefs(dragDataNode));
  1.1721 +  if (NS_FAILED(rv) || !canDrag)
  1.1722 +    return;
  1.1723 +
  1.1724 +  // if GetDragData returned a node, use that as the node being dragged.
  1.1725 +  // Otherwise, if a selection is being dragged, use the node within the
  1.1726 +  // selection that was dragged. Otherwise, just use the mousedown target.
  1.1727 +  nsIContent* dragContent = mGestureDownContent;
  1.1728 +  if (dragDataNode)
  1.1729 +    dragContent = dragDataNode;
  1.1730 +  else if (*aSelection)
  1.1731 +    dragContent = aSelectionTarget;
  1.1732 +
  1.1733 +  nsIContent* originalDragContent = dragContent;
  1.1734 +
  1.1735 +  // If a selection isn't being dragged, look for an ancestor with the
  1.1736 +  // draggable property set. If one is found, use that as the target of the
  1.1737 +  // drag instead of the node that was clicked on. If a draggable node wasn't
  1.1738 +  // found, just use the clicked node.
  1.1739 +  if (!*aSelection) {
  1.1740 +    while (dragContent) {
  1.1741 +      nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(dragContent);
  1.1742 +      if (htmlElement) {
  1.1743 +        bool draggable = false;
  1.1744 +        htmlElement->GetDraggable(&draggable);
  1.1745 +        if (draggable)
  1.1746 +          break;
  1.1747 +      }
  1.1748 +      else {
  1.1749 +        nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(dragContent);
  1.1750 +        if (xulElement) {
  1.1751 +          // All XUL elements are draggable, so if a XUL element is
  1.1752 +          // encountered, stop looking for draggable nodes and just use the
  1.1753 +          // original clicked node instead.
  1.1754 +          // XXXndeakin
  1.1755 +          // In the future, we will want to improve this so that XUL has a
  1.1756 +          // better way to specify whether something is draggable than just
  1.1757 +          // on/off.
  1.1758 +          dragContent = mGestureDownContent;
  1.1759 +          break;
  1.1760 +        }
  1.1761 +        // otherwise, it's not an HTML or XUL element, so just keep looking
  1.1762 +      }
  1.1763 +      dragContent = dragContent->GetParent();
  1.1764 +    }
  1.1765 +  }
  1.1766 +
  1.1767 +  // if no node in the hierarchy was found to drag, but the GetDragData method
  1.1768 +  // returned a node, use that returned node. Otherwise, nothing is draggable.
  1.1769 +  if (!dragContent && dragDataNode)
  1.1770 +    dragContent = dragDataNode;
  1.1771 +
  1.1772 +  if (dragContent) {
  1.1773 +    // if an ancestor node was used instead, clear the drag data
  1.1774 +    // XXXndeakin rework this a bit. Find a way to just not call GetDragData if we don't need to.
  1.1775 +    if (dragContent != originalDragContent)
  1.1776 +      aDataTransfer->ClearAll();
  1.1777 +    *aTargetNode = dragContent;
  1.1778 +    NS_ADDREF(*aTargetNode);
  1.1779 +  }
  1.1780 +}
  1.1781 +
  1.1782 +bool
  1.1783 +EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
  1.1784 +                                      WidgetDragEvent* aDragEvent,
  1.1785 +                                      DataTransfer* aDataTransfer,
  1.1786 +                                      nsIContent* aDragTarget,
  1.1787 +                                      nsISelection* aSelection)
  1.1788 +{
  1.1789 +  nsCOMPtr<nsIDragService> dragService =
  1.1790 +    do_GetService("@mozilla.org/widget/dragservice;1");
  1.1791 +  if (!dragService)
  1.1792 +    return false;
  1.1793 +
  1.1794 +  // Default handling for the draggesture/dragstart event.
  1.1795 +  //
  1.1796 +  // First, check if a drag session already exists. This means that the drag
  1.1797 +  // service was called directly within a draggesture handler. In this case,
  1.1798 +  // don't do anything more, as it is assumed that the handler is managing
  1.1799 +  // drag and drop manually. Make sure to return true to indicate that a drag
  1.1800 +  // began.
  1.1801 +  nsCOMPtr<nsIDragSession> dragSession;
  1.1802 +  dragService->GetCurrentSession(getter_AddRefs(dragSession));
  1.1803 +  if (dragSession)
  1.1804 +    return true;
  1.1805 +
  1.1806 +  // No drag session is currently active, so check if a handler added
  1.1807 +  // any items to be dragged. If not, there isn't anything to drag.
  1.1808 +  uint32_t count = 0;
  1.1809 +  if (aDataTransfer)
  1.1810 +    aDataTransfer->GetMozItemCount(&count);
  1.1811 +  if (!count)
  1.1812 +    return false;
  1.1813 +
  1.1814 +  // Get the target being dragged, which may not be the same as the
  1.1815 +  // target of the mouse event. If one wasn't set in the
  1.1816 +  // aDataTransfer during the event handler, just use the original
  1.1817 +  // target instead.
  1.1818 +  nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
  1.1819 +  if (!dragTarget) {
  1.1820 +    dragTarget = aDragTarget;
  1.1821 +    if (!dragTarget)
  1.1822 +      return false;
  1.1823 +  }
  1.1824 +
  1.1825 +  // check which drag effect should initially be used. If the effect was not
  1.1826 +  // set, just use all actions, otherwise Windows won't allow a drop.
  1.1827 +  uint32_t action;
  1.1828 +  aDataTransfer->GetEffectAllowedInt(&action);
  1.1829 +  if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
  1.1830 +    action = nsIDragService::DRAGDROP_ACTION_COPY |
  1.1831 +             nsIDragService::DRAGDROP_ACTION_MOVE |
  1.1832 +             nsIDragService::DRAGDROP_ACTION_LINK;
  1.1833 +
  1.1834 +  // get any custom drag image that was set
  1.1835 +  int32_t imageX, imageY;
  1.1836 +  Element* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
  1.1837 +
  1.1838 +  nsCOMPtr<nsISupportsArray> transArray =
  1.1839 +    aDataTransfer->GetTransferables(dragTarget->AsDOMNode());
  1.1840 +  if (!transArray)
  1.1841 +    return false;
  1.1842 +
  1.1843 +  // XXXndeakin don't really want to create a new drag DOM event
  1.1844 +  // here, but we need something to pass to the InvokeDragSession
  1.1845 +  // methods.
  1.1846 +  nsCOMPtr<nsIDOMEvent> domEvent;
  1.1847 +  NS_NewDOMDragEvent(getter_AddRefs(domEvent), dragTarget,
  1.1848 +                     aPresContext, aDragEvent);
  1.1849 +
  1.1850 +  nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent);
  1.1851 +  // if creating a drag event failed, starting a drag session will
  1.1852 +  // just fail.
  1.1853 +
  1.1854 +  // Use InvokeDragSessionWithSelection if a selection is being dragged,
  1.1855 +  // such that the image can be generated from the selected text. However,
  1.1856 +  // use InvokeDragSessionWithImage if a custom image was set or something
  1.1857 +  // other than a selection is being dragged.
  1.1858 +  if (!dragImage && aSelection) {
  1.1859 +    dragService->InvokeDragSessionWithSelection(aSelection, transArray,
  1.1860 +                                                action, domDragEvent,
  1.1861 +                                                aDataTransfer);
  1.1862 +  }
  1.1863 +  else {
  1.1864 +    // if dragging within a XUL tree and no custom drag image was
  1.1865 +    // set, the region argument to InvokeDragSessionWithImage needs
  1.1866 +    // to be set to the area encompassing the selected rows of the
  1.1867 +    // tree to ensure that the drag feedback gets clipped to those
  1.1868 +    // rows. For other content, region should be null.
  1.1869 +    nsCOMPtr<nsIScriptableRegion> region;
  1.1870 +#ifdef MOZ_XUL
  1.1871 +    if (dragTarget && !dragImage) {
  1.1872 +      if (dragTarget->NodeInfo()->Equals(nsGkAtoms::treechildren,
  1.1873 +                                         kNameSpaceID_XUL)) {
  1.1874 +        nsTreeBodyFrame* treeBody =
  1.1875 +          do_QueryFrame(dragTarget->GetPrimaryFrame());
  1.1876 +        if (treeBody) {
  1.1877 +          treeBody->GetSelectionRegion(getter_AddRefs(region));
  1.1878 +        }
  1.1879 +      }
  1.1880 +    }
  1.1881 +#endif
  1.1882 +
  1.1883 +    dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(), transArray,
  1.1884 +                                            region, action,
  1.1885 +                                            dragImage ? dragImage->AsDOMNode() :
  1.1886 +                                                        nullptr,
  1.1887 +                                            imageX,
  1.1888 +                                            imageY, domDragEvent,
  1.1889 +                                            aDataTransfer);
  1.1890 +  }
  1.1891 +
  1.1892 +  return true;
  1.1893 +}
  1.1894 +
  1.1895 +nsresult
  1.1896 +EventStateManager::GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv)
  1.1897 +{
  1.1898 +  *aMv = nullptr;
  1.1899 +
  1.1900 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.1901 +  if(!fm) return NS_ERROR_FAILURE;
  1.1902 +
  1.1903 +  nsCOMPtr<nsIDOMWindow> focusedWindow;
  1.1904 +  fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
  1.1905 +
  1.1906 +  nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(focusedWindow);
  1.1907 +  if(!ourWindow) return NS_ERROR_FAILURE;
  1.1908 +
  1.1909 +  nsIDOMWindow *rootWindow = ourWindow->GetPrivateRoot();
  1.1910 +  if(!rootWindow) return NS_ERROR_FAILURE;
  1.1911 +
  1.1912 +  nsCOMPtr<nsIDOMWindow> contentWindow;
  1.1913 +  rootWindow->GetContent(getter_AddRefs(contentWindow));
  1.1914 +  if(!contentWindow) return NS_ERROR_FAILURE;
  1.1915 +
  1.1916 +  nsIDocument *doc = GetDocumentFromWindow(contentWindow);
  1.1917 +  if(!doc) return NS_ERROR_FAILURE;
  1.1918 +
  1.1919 +  nsIPresShell *presShell = doc->GetShell();
  1.1920 +  if(!presShell) return NS_ERROR_FAILURE;
  1.1921 +  nsPresContext *presContext = presShell->GetPresContext();
  1.1922 +  if(!presContext) return NS_ERROR_FAILURE;
  1.1923 +
  1.1924 +  nsCOMPtr<nsIDocShell> docshell(presContext->GetDocShell());
  1.1925 +  if(!docshell) return NS_ERROR_FAILURE;
  1.1926 +
  1.1927 +  nsCOMPtr<nsIContentViewer> cv;
  1.1928 +  docshell->GetContentViewer(getter_AddRefs(cv));
  1.1929 +  if(!cv) return NS_ERROR_FAILURE;
  1.1930 +
  1.1931 +  nsCOMPtr<nsIMarkupDocumentViewer> mv(do_QueryInterface(cv));
  1.1932 +  if(!mv) return NS_ERROR_FAILURE;
  1.1933 +
  1.1934 +  *aMv = mv;
  1.1935 +  NS_IF_ADDREF(*aMv);
  1.1936 +
  1.1937 +  return NS_OK;
  1.1938 +}
  1.1939 +
  1.1940 +nsresult
  1.1941 +EventStateManager::ChangeTextSize(int32_t change)
  1.1942 +{
  1.1943 +  nsCOMPtr<nsIMarkupDocumentViewer> mv;
  1.1944 +  nsresult rv = GetMarkupDocumentViewer(getter_AddRefs(mv));
  1.1945 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1946 +
  1.1947 +  float textzoom;
  1.1948 +  float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100;
  1.1949 +  float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100;
  1.1950 +  mv->GetTextZoom(&textzoom);
  1.1951 +  textzoom += ((float)change) / 10;
  1.1952 +  if (textzoom < zoomMin)
  1.1953 +    textzoom = zoomMin;
  1.1954 +  else if (textzoom > zoomMax)
  1.1955 +    textzoom = zoomMax;
  1.1956 +  mv->SetTextZoom(textzoom);
  1.1957 +
  1.1958 +  return NS_OK;
  1.1959 +}
  1.1960 +
  1.1961 +nsresult
  1.1962 +EventStateManager::ChangeFullZoom(int32_t change)
  1.1963 +{
  1.1964 +  nsCOMPtr<nsIMarkupDocumentViewer> mv;
  1.1965 +  nsresult rv = GetMarkupDocumentViewer(getter_AddRefs(mv));
  1.1966 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1967 +
  1.1968 +  float fullzoom;
  1.1969 +  float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100;
  1.1970 +  float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100;
  1.1971 +  mv->GetFullZoom(&fullzoom);
  1.1972 +  fullzoom += ((float)change) / 10;
  1.1973 +  if (fullzoom < zoomMin)
  1.1974 +    fullzoom = zoomMin;
  1.1975 +  else if (fullzoom > zoomMax)
  1.1976 +    fullzoom = zoomMax;
  1.1977 +  mv->SetFullZoom(fullzoom);
  1.1978 +
  1.1979 +  return NS_OK;
  1.1980 +}
  1.1981 +
  1.1982 +void
  1.1983 +EventStateManager::DoScrollHistory(int32_t direction)
  1.1984 +{
  1.1985 +  nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
  1.1986 +  if (pcContainer) {
  1.1987 +    nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
  1.1988 +    if (webNav) {
  1.1989 +      // positive direction to go back one step, nonpositive to go forward
  1.1990 +      if (direction > 0)
  1.1991 +        webNav->GoBack();
  1.1992 +      else
  1.1993 +        webNav->GoForward();
  1.1994 +    }
  1.1995 +  }
  1.1996 +}
  1.1997 +
  1.1998 +void
  1.1999 +EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
  1.2000 +                                int32_t adjustment)
  1.2001 +{
  1.2002 +  // Exclude form controls and content in chrome docshells.
  1.2003 +  nsIContent *content = aTargetFrame->GetContent();
  1.2004 +  if (content &&
  1.2005 +      !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
  1.2006 +      !nsContentUtils::IsInChromeDocshell(content->OwnerDoc()))
  1.2007 +    {
  1.2008 +      // positive adjustment to decrease zoom, negative to increase
  1.2009 +      int32_t change = (adjustment > 0) ? -1 : 1;
  1.2010 +
  1.2011 +      if (Preferences::GetBool("browser.zoom.full") || content->GetCurrentDoc()->IsSyntheticDocument()) {
  1.2012 +        ChangeFullZoom(change);
  1.2013 +      } else {
  1.2014 +        ChangeTextSize(change);
  1.2015 +      }
  1.2016 +    }
  1.2017 +}
  1.2018 +
  1.2019 +static nsIFrame*
  1.2020 +GetParentFrameToScroll(nsIFrame* aFrame)
  1.2021 +{
  1.2022 +  if (!aFrame)
  1.2023 +    return nullptr;
  1.2024 +
  1.2025 +  if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
  1.2026 +      nsLayoutUtils::IsReallyFixedPos(aFrame))
  1.2027 +    return aFrame->PresContext()->GetPresShell()->GetRootScrollFrame();
  1.2028 +
  1.2029 +  return aFrame->GetParent();
  1.2030 +}
  1.2031 +
  1.2032 +void
  1.2033 +EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
  1.2034 +                                                   WidgetWheelEvent* aEvent,
  1.2035 +                                                   nsEventStatus* aStatus)
  1.2036 +{
  1.2037 +  MOZ_ASSERT(aEvent);
  1.2038 +  MOZ_ASSERT(aStatus);
  1.2039 +
  1.2040 +  if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
  1.2041 +    return;
  1.2042 +  }
  1.2043 +
  1.2044 +  // Ignore mouse wheel transaction for computing legacy mouse wheel
  1.2045 +  // events' delta value.
  1.2046 +  nsIScrollableFrame* scrollTarget =
  1.2047 +    ComputeScrollTarget(aTargetFrame, aEvent,
  1.2048 +                        COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
  1.2049 +
  1.2050 +  nsIFrame* scrollFrame = do_QueryFrame(scrollTarget);
  1.2051 +  nsPresContext* pc =
  1.2052 +    scrollFrame ? scrollFrame->PresContext() : aTargetFrame->PresContext();
  1.2053 +
  1.2054 +  // DOM event's delta vales are computed from CSS pixels.
  1.2055 +  nsSize scrollAmount = GetScrollAmount(pc, aEvent, scrollTarget);
  1.2056 +  nsIntSize scrollAmountInCSSPixels(
  1.2057 +    nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),
  1.2058 +    nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height));
  1.2059 +
  1.2060 +  // XXX We don't deal with fractional amount in legacy event, though the
  1.2061 +  //     default action handler (DoScrollText()) deals with it.
  1.2062 +  //     If we implemented such strict computation, we would need additional
  1.2063 +  //     accumulated delta values. It would made the code more complicated.
  1.2064 +  //     And also it would computes different delta values from older version.
  1.2065 +  //     It doesn't make sense to implement such code for legacy events and
  1.2066 +  //     rare cases.
  1.2067 +  int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
  1.2068 +  switch (aEvent->deltaMode) {
  1.2069 +    case nsIDOMWheelEvent::DOM_DELTA_PAGE:
  1.2070 +      scrollDeltaX =
  1.2071 +        !aEvent->lineOrPageDeltaX ? 0 :
  1.2072 +          (aEvent->lineOrPageDeltaX > 0  ? nsIDOMUIEvent::SCROLL_PAGE_DOWN :
  1.2073 +                                           nsIDOMUIEvent::SCROLL_PAGE_UP);
  1.2074 +      scrollDeltaY =
  1.2075 +        !aEvent->lineOrPageDeltaY ? 0 :
  1.2076 +          (aEvent->lineOrPageDeltaY > 0  ? nsIDOMUIEvent::SCROLL_PAGE_DOWN :
  1.2077 +                                           nsIDOMUIEvent::SCROLL_PAGE_UP);
  1.2078 +      pixelDeltaX = RoundDown(aEvent->deltaX * scrollAmountInCSSPixels.width);
  1.2079 +      pixelDeltaY = RoundDown(aEvent->deltaY * scrollAmountInCSSPixels.height);
  1.2080 +      break;
  1.2081 +
  1.2082 +    case nsIDOMWheelEvent::DOM_DELTA_LINE:
  1.2083 +      scrollDeltaX = aEvent->lineOrPageDeltaX;
  1.2084 +      scrollDeltaY = aEvent->lineOrPageDeltaY;
  1.2085 +      pixelDeltaX = RoundDown(aEvent->deltaX * scrollAmountInCSSPixels.width);
  1.2086 +      pixelDeltaY = RoundDown(aEvent->deltaY * scrollAmountInCSSPixels.height);
  1.2087 +      break;
  1.2088 +
  1.2089 +    case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
  1.2090 +      scrollDeltaX = aEvent->lineOrPageDeltaX;
  1.2091 +      scrollDeltaY = aEvent->lineOrPageDeltaY;
  1.2092 +      pixelDeltaX = RoundDown(aEvent->deltaX);
  1.2093 +      pixelDeltaY = RoundDown(aEvent->deltaY);
  1.2094 +      break;
  1.2095 +
  1.2096 +    default:
  1.2097 +      MOZ_CRASH("Invalid deltaMode value comes");
  1.2098 +  }
  1.2099 +
  1.2100 +  // Send the legacy events in following order:
  1.2101 +  // 1. Vertical scroll
  1.2102 +  // 2. Vertical pixel scroll (even if #1 isn't consumed)
  1.2103 +  // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
  1.2104 +  // 4. Horizontal pixel scroll (even if #3 isn't consumed)
  1.2105 +
  1.2106 +  nsWeakFrame targetFrame(aTargetFrame);
  1.2107 +
  1.2108 +  MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&
  1.2109 +             !aEvent->mFlags.mDefaultPrevented,
  1.2110 +             "If you make legacy events dispatched for default prevented wheel "
  1.2111 +             "event, you need to initialize stateX and stateY");
  1.2112 +  EventState stateX, stateY;
  1.2113 +  if (scrollDeltaY) {
  1.2114 +    SendLineScrollEvent(aTargetFrame, aEvent, stateY,
  1.2115 +                        scrollDeltaY, DELTA_DIRECTION_Y);
  1.2116 +    if (!targetFrame.IsAlive()) {
  1.2117 +      *aStatus = nsEventStatus_eConsumeNoDefault;
  1.2118 +      return;
  1.2119 +    }
  1.2120 +  }
  1.2121 +
  1.2122 +  if (pixelDeltaY) {
  1.2123 +    SendPixelScrollEvent(aTargetFrame, aEvent, stateY,
  1.2124 +                         pixelDeltaY, DELTA_DIRECTION_Y);
  1.2125 +    if (!targetFrame.IsAlive()) {
  1.2126 +      *aStatus = nsEventStatus_eConsumeNoDefault;
  1.2127 +      return;
  1.2128 +    }
  1.2129 +  }
  1.2130 +
  1.2131 +  if (scrollDeltaX) {
  1.2132 +    SendLineScrollEvent(aTargetFrame, aEvent, stateX,
  1.2133 +                        scrollDeltaX, DELTA_DIRECTION_X);
  1.2134 +    if (!targetFrame.IsAlive()) {
  1.2135 +      *aStatus = nsEventStatus_eConsumeNoDefault;
  1.2136 +      return;
  1.2137 +    }
  1.2138 +  }
  1.2139 +
  1.2140 +  if (pixelDeltaX) {
  1.2141 +    SendPixelScrollEvent(aTargetFrame, aEvent, stateX,
  1.2142 +                         pixelDeltaX, DELTA_DIRECTION_X);
  1.2143 +    if (!targetFrame.IsAlive()) {
  1.2144 +      *aStatus = nsEventStatus_eConsumeNoDefault;
  1.2145 +      return;
  1.2146 +    }
  1.2147 +  }
  1.2148 +
  1.2149 +  if (stateY.mDefaultPrevented || stateX.mDefaultPrevented) {
  1.2150 +    *aStatus = nsEventStatus_eConsumeNoDefault;
  1.2151 +    aEvent->mFlags.mDefaultPrevented = true;
  1.2152 +    aEvent->mFlags.mDefaultPreventedByContent |=
  1.2153 +      stateY.mDefaultPreventedByContent || stateX.mDefaultPreventedByContent;
  1.2154 +  }
  1.2155 +}
  1.2156 +
  1.2157 +void
  1.2158 +EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
  1.2159 +                                       WidgetWheelEvent* aEvent,
  1.2160 +                                       EventState& aState,
  1.2161 +                                       int32_t aDelta,
  1.2162 +                                       DeltaDirection aDeltaDirection)
  1.2163 +{
  1.2164 +  nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
  1.2165 +  if (!targetContent)
  1.2166 +    targetContent = GetFocusedContent();
  1.2167 +  if (!targetContent)
  1.2168 +    return;
  1.2169 +
  1.2170 +  while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
  1.2171 +    targetContent = targetContent->GetParent();
  1.2172 +  }
  1.2173 +
  1.2174 +  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_SCROLL,
  1.2175 +                               aEvent->widget);
  1.2176 +  event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
  1.2177 +  event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
  1.2178 +  event.refPoint = aEvent->refPoint;
  1.2179 +  event.widget = aEvent->widget;
  1.2180 +  event.time = aEvent->time;
  1.2181 +  event.modifiers = aEvent->modifiers;
  1.2182 +  event.buttons = aEvent->buttons;
  1.2183 +  event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
  1.2184 +  event.delta = aDelta;
  1.2185 +  event.inputSource = aEvent->inputSource;
  1.2186 +
  1.2187 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.2188 +  EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
  1.2189 +                            &event, nullptr, &status);
  1.2190 +  aState.mDefaultPrevented =
  1.2191 +    event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault;
  1.2192 +  aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
  1.2193 +}
  1.2194 +
  1.2195 +void
  1.2196 +EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
  1.2197 +                                        WidgetWheelEvent* aEvent,
  1.2198 +                                        EventState& aState,
  1.2199 +                                        int32_t aPixelDelta,
  1.2200 +                                        DeltaDirection aDeltaDirection)
  1.2201 +{
  1.2202 +  nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
  1.2203 +  if (!targetContent) {
  1.2204 +    targetContent = GetFocusedContent();
  1.2205 +    if (!targetContent)
  1.2206 +      return;
  1.2207 +  }
  1.2208 +
  1.2209 +  while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
  1.2210 +    targetContent = targetContent->GetParent();
  1.2211 +  }
  1.2212 +
  1.2213 +  WidgetMouseScrollEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_PIXEL_SCROLL,
  1.2214 +                               aEvent->widget);
  1.2215 +  event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
  1.2216 +  event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
  1.2217 +  event.refPoint = aEvent->refPoint;
  1.2218 +  event.widget = aEvent->widget;
  1.2219 +  event.time = aEvent->time;
  1.2220 +  event.modifiers = aEvent->modifiers;
  1.2221 +  event.buttons = aEvent->buttons;
  1.2222 +  event.isHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
  1.2223 +  event.delta = aPixelDelta;
  1.2224 +  event.inputSource = aEvent->inputSource;
  1.2225 +
  1.2226 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.2227 +  EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
  1.2228 +                            &event, nullptr, &status);
  1.2229 +  aState.mDefaultPrevented =
  1.2230 +    event.mFlags.mDefaultPrevented || status == nsEventStatus_eConsumeNoDefault;
  1.2231 +  aState.mDefaultPreventedByContent = event.mFlags.mDefaultPreventedByContent;
  1.2232 +}
  1.2233 +
  1.2234 +nsIScrollableFrame*
  1.2235 +EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
  1.2236 +                                       WidgetWheelEvent* aEvent,
  1.2237 +                                       ComputeScrollTargetOptions aOptions)
  1.2238 +{
  1.2239 +  return ComputeScrollTarget(aTargetFrame, aEvent->deltaX, aEvent->deltaY,
  1.2240 +                             aEvent, aOptions);
  1.2241 +}
  1.2242 +
  1.2243 +// Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
  1.2244 +// for which scrollbarowners to activate when two finger down on trackpad
  1.2245 +// and before any actual motion
  1.2246 +nsIScrollableFrame*
  1.2247 +EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
  1.2248 +                                       double aDirectionX,
  1.2249 +                                       double aDirectionY,
  1.2250 +                                       WidgetWheelEvent* aEvent,
  1.2251 +                                       ComputeScrollTargetOptions aOptions)
  1.2252 +{
  1.2253 +  if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
  1.2254 +    // If the user recently scrolled with the mousewheel, then they probably
  1.2255 +    // want to scroll the same view as before instead of the view under the
  1.2256 +    // cursor.  WheelTransaction tracks the frame currently being
  1.2257 +    // scrolled with the mousewheel. We consider the transaction ended when the
  1.2258 +    // mouse moves more than "mousewheel.transaction.ignoremovedelay"
  1.2259 +    // milliseconds after the last scroll operation, or any time the mouse moves
  1.2260 +    // out of the frame, or when more than "mousewheel.transaction.timeout"
  1.2261 +    // milliseconds have passed after the last operation, even if the mouse
  1.2262 +    // hasn't moved.
  1.2263 +    nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame();
  1.2264 +    if (lastScrollFrame) {
  1.2265 +      nsIScrollableFrame* frameToScroll =
  1.2266 +        lastScrollFrame->GetScrollTargetFrame();
  1.2267 +      if (frameToScroll) {
  1.2268 +        return frameToScroll;
  1.2269 +      }
  1.2270 +    }
  1.2271 +  }
  1.2272 +
  1.2273 +  // If the event doesn't cause scroll actually, we cannot find scroll target
  1.2274 +  // because we check if the event can cause scroll actually on each found
  1.2275 +  // scrollable frame.
  1.2276 +  if (!aDirectionX && !aDirectionY) {
  1.2277 +    return nullptr;
  1.2278 +  }
  1.2279 +
  1.2280 +  bool checkIfScrollableX =
  1.2281 +    aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
  1.2282 +  bool checkIfScrollableY =
  1.2283 +    aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
  1.2284 +
  1.2285 +  nsIScrollableFrame* frameToScroll = nullptr;
  1.2286 +  nsIFrame* scrollFrame =
  1.2287 +    !(aOptions & START_FROM_PARENT) ? aTargetFrame :
  1.2288 +                                      GetParentFrameToScroll(aTargetFrame);
  1.2289 +  for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
  1.2290 +    // Check whether the frame wants to provide us with a scrollable view.
  1.2291 +    frameToScroll = scrollFrame->GetScrollTargetFrame();
  1.2292 +    if (!frameToScroll) {
  1.2293 +      continue;
  1.2294 +    }
  1.2295 +
  1.2296 +    // Don't scroll vertically by mouse-wheel on a single-line text control.
  1.2297 +    if (checkIfScrollableY) {
  1.2298 +      nsIContent* c = scrollFrame->GetContent();
  1.2299 +      nsCOMPtr<nsITextControlElement> ctrl =
  1.2300 +        do_QueryInterface(c->IsInAnonymousSubtree() ? c->GetBindingParent() : c);
  1.2301 +      if (ctrl && ctrl->IsSingleLineTextControl()) {
  1.2302 +        continue;
  1.2303 +      }
  1.2304 +    }
  1.2305 +
  1.2306 +    if (!checkIfScrollableX && !checkIfScrollableY) {
  1.2307 +      return frameToScroll;
  1.2308 +    }
  1.2309 +
  1.2310 +    ScrollbarStyles ss = frameToScroll->GetScrollbarStyles();
  1.2311 +    bool hiddenForV = (NS_STYLE_OVERFLOW_HIDDEN == ss.mVertical);
  1.2312 +    bool hiddenForH = (NS_STYLE_OVERFLOW_HIDDEN == ss.mHorizontal);
  1.2313 +    if ((hiddenForV && hiddenForH) ||
  1.2314 +        (checkIfScrollableY && !checkIfScrollableX && hiddenForV) ||
  1.2315 +        (checkIfScrollableX && !checkIfScrollableY && hiddenForH)) {
  1.2316 +      continue;
  1.2317 +    }
  1.2318 +
  1.2319 +    // For default action, we should climb up the tree if cannot scroll it
  1.2320 +    // by the event actually.
  1.2321 +    bool canScroll =
  1.2322 +      WheelHandlingUtils::CanScrollOn(frameToScroll, aDirectionX, aDirectionY);
  1.2323 +    // Comboboxes need special care.
  1.2324 +    nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
  1.2325 +    if (comboBox) {
  1.2326 +      if (comboBox->IsDroppedDown()) {
  1.2327 +        // Don't propagate to parent when drop down menu is active.
  1.2328 +        return canScroll ? frameToScroll : nullptr;
  1.2329 +      }
  1.2330 +      // Always propagate when not dropped down (even if focused).
  1.2331 +      continue;
  1.2332 +    }
  1.2333 +
  1.2334 +    if (canScroll) {
  1.2335 +      return frameToScroll;
  1.2336 +    }
  1.2337 +  }
  1.2338 +
  1.2339 +  nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
  1.2340 +      aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
  1.2341 +  aOptions =
  1.2342 +    static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
  1.2343 +  return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr;
  1.2344 +}
  1.2345 +
  1.2346 +nsSize
  1.2347 +EventStateManager::GetScrollAmount(nsPresContext* aPresContext,
  1.2348 +                                   WidgetWheelEvent* aEvent,
  1.2349 +                                   nsIScrollableFrame* aScrollableFrame)
  1.2350 +{
  1.2351 +  MOZ_ASSERT(aPresContext);
  1.2352 +  MOZ_ASSERT(aEvent);
  1.2353 +
  1.2354 +  bool isPage = (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
  1.2355 +  if (aScrollableFrame) {
  1.2356 +    return isPage ? aScrollableFrame->GetPageScrollAmount() :
  1.2357 +                    aScrollableFrame->GetLineScrollAmount();
  1.2358 +  }
  1.2359 +
  1.2360 +  // If there is no scrollable frame and page scrolling, use view port size.
  1.2361 +  if (isPage) {
  1.2362 +    return aPresContext->GetVisibleArea().Size();
  1.2363 +  }
  1.2364 +
  1.2365 +  // If there is no scrollable frame, we should use root frame's information.
  1.2366 +  nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
  1.2367 +  if (!rootFrame) {
  1.2368 +    return nsSize(0, 0);
  1.2369 +  }
  1.2370 +  nsRefPtr<nsFontMetrics> fm;
  1.2371 +  nsLayoutUtils::GetFontMetricsForFrame(rootFrame, getter_AddRefs(fm),
  1.2372 +    nsLayoutUtils::FontSizeInflationFor(rootFrame));
  1.2373 +  NS_ENSURE_TRUE(fm, nsSize(0, 0));
  1.2374 +  return nsSize(fm->AveCharWidth(), fm->MaxHeight());
  1.2375 +}
  1.2376 +
  1.2377 +void
  1.2378 +EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
  1.2379 +                                WidgetWheelEvent* aEvent)
  1.2380 +{
  1.2381 +  MOZ_ASSERT(aScrollableFrame);
  1.2382 +  MOZ_ASSERT(aEvent);
  1.2383 +
  1.2384 +  nsIFrame* scrollFrame = do_QueryFrame(aScrollableFrame);
  1.2385 +  MOZ_ASSERT(scrollFrame);
  1.2386 +  nsWeakFrame scrollFrameWeak(scrollFrame);
  1.2387 +
  1.2388 +  nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame();
  1.2389 +  if (!lastScrollFrame) {
  1.2390 +    WheelTransaction::BeginTransaction(scrollFrame, aEvent);
  1.2391 +  } else if (lastScrollFrame != scrollFrame) {
  1.2392 +    WheelTransaction::EndTransaction();
  1.2393 +    WheelTransaction::BeginTransaction(scrollFrame, aEvent);
  1.2394 +  } else {
  1.2395 +    WheelTransaction::UpdateTransaction(aEvent);
  1.2396 +  }
  1.2397 +
  1.2398 +  // When the scroll event will not scroll any views, UpdateTransaction
  1.2399 +  // fired MozMouseScrollFailed event which is for automated testing.
  1.2400 +  // In the event handler, the target frame might be destroyed.  Then,
  1.2401 +  // we should not try scrolling anything.
  1.2402 +  if (!scrollFrameWeak.IsAlive()) {
  1.2403 +    WheelTransaction::EndTransaction();
  1.2404 +    return;
  1.2405 +  }
  1.2406 +
  1.2407 +  // Default action's actual scroll amount should be computed from device
  1.2408 +  // pixels.
  1.2409 +  nsPresContext* pc = scrollFrame->PresContext();
  1.2410 +  nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollableFrame);
  1.2411 +  nsIntSize scrollAmountInDevPixels(
  1.2412 +    pc->AppUnitsToDevPixels(scrollAmount.width),
  1.2413 +    pc->AppUnitsToDevPixels(scrollAmount.height));
  1.2414 +  nsIntPoint actualDevPixelScrollAmount =
  1.2415 +    DeltaAccumulator::GetInstance()->
  1.2416 +      ComputeScrollAmountForDefaultAction(aEvent, scrollAmountInDevPixels);
  1.2417 +
  1.2418 +  // Don't scroll around the axis whose overflow style is hidden.
  1.2419 +  ScrollbarStyles overflowStyle = aScrollableFrame->GetScrollbarStyles();
  1.2420 +  if (overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
  1.2421 +    actualDevPixelScrollAmount.x = 0;
  1.2422 +  }
  1.2423 +  if (overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN) {
  1.2424 +    actualDevPixelScrollAmount.y = 0;
  1.2425 +  }
  1.2426 +
  1.2427 +  nsIAtom* origin = nullptr;
  1.2428 +  switch (aEvent->deltaMode) {
  1.2429 +    case nsIDOMWheelEvent::DOM_DELTA_LINE:
  1.2430 +      origin = nsGkAtoms::mouseWheel;
  1.2431 +      break;
  1.2432 +    case nsIDOMWheelEvent::DOM_DELTA_PAGE:
  1.2433 +      origin = nsGkAtoms::pages;
  1.2434 +      break;
  1.2435 +    case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
  1.2436 +      origin = nsGkAtoms::pixels;
  1.2437 +      break;
  1.2438 +    default:
  1.2439 +      MOZ_CRASH("Invalid deltaMode value comes");
  1.2440 +  }
  1.2441 +
  1.2442 +  // We shouldn't scroll more one page at once except when over one page scroll
  1.2443 +  // is allowed for the event.
  1.2444 +  nsSize pageSize = aScrollableFrame->GetPageScrollAmount();
  1.2445 +  nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
  1.2446 +                             pc->AppUnitsToDevPixels(pageSize.height));
  1.2447 +  if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
  1.2448 +      DeprecatedAbs(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
  1.2449 +    actualDevPixelScrollAmount.x =
  1.2450 +      (actualDevPixelScrollAmount.x >= 0) ? devPixelPageSize.width :
  1.2451 +                                            -devPixelPageSize.width;
  1.2452 +  }
  1.2453 +
  1.2454 +  if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
  1.2455 +      DeprecatedAbs(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
  1.2456 +    actualDevPixelScrollAmount.y =
  1.2457 +      (actualDevPixelScrollAmount.y >= 0) ? devPixelPageSize.height :
  1.2458 +                                            -devPixelPageSize.height;
  1.2459 +  }
  1.2460 +
  1.2461 +  bool isDeltaModePixel =
  1.2462 +    (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL);
  1.2463 +
  1.2464 +  nsIScrollableFrame::ScrollMode mode;
  1.2465 +  switch (aEvent->scrollType) {
  1.2466 +    case WidgetWheelEvent::SCROLL_DEFAULT:
  1.2467 +      if (isDeltaModePixel) {
  1.2468 +        mode = nsIScrollableFrame::NORMAL;
  1.2469 +      } else {
  1.2470 +        mode = nsIScrollableFrame::SMOOTH;
  1.2471 +      }
  1.2472 +      break;
  1.2473 +    case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
  1.2474 +      mode = nsIScrollableFrame::INSTANT;
  1.2475 +      break;
  1.2476 +    case WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY:
  1.2477 +      mode = nsIScrollableFrame::NORMAL;
  1.2478 +      break;
  1.2479 +    case WidgetWheelEvent::SCROLL_SMOOTHLY:
  1.2480 +      mode = nsIScrollableFrame::SMOOTH;
  1.2481 +      break;
  1.2482 +    default:
  1.2483 +      MOZ_CRASH("Invalid scrollType value comes");
  1.2484 +  }
  1.2485 +
  1.2486 +  nsIntPoint overflow;
  1.2487 +  aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
  1.2488 +                             nsIScrollableFrame::DEVICE_PIXELS,
  1.2489 +                             mode, &overflow, origin);
  1.2490 +
  1.2491 +  if (!scrollFrameWeak.IsAlive()) {
  1.2492 +    // If the scroll causes changing the layout, we can think that the event
  1.2493 +    // has been completely consumed by the content.  Then, users probably don't
  1.2494 +    // want additional action.
  1.2495 +    aEvent->overflowDeltaX = aEvent->overflowDeltaY = 0;
  1.2496 +  } else if (isDeltaModePixel) {
  1.2497 +    aEvent->overflowDeltaX = overflow.x;
  1.2498 +    aEvent->overflowDeltaY = overflow.y;
  1.2499 +  } else {
  1.2500 +    aEvent->overflowDeltaX =
  1.2501 +      static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
  1.2502 +    aEvent->overflowDeltaY =
  1.2503 +      static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
  1.2504 +  }
  1.2505 +
  1.2506 +  // If CSS overflow properties caused not to scroll, the overflowDelta* values
  1.2507 +  // should be same as delta* values since they may be used as gesture event by
  1.2508 +  // widget.  However, if there is another scrollable element in the ancestor
  1.2509 +  // along the axis, probably users don't want the operation to cause
  1.2510 +  // additional action such as moving history.  In such case, overflowDelta
  1.2511 +  // values should stay zero.
  1.2512 +  if (scrollFrameWeak.IsAlive()) {
  1.2513 +    if (aEvent->deltaX &&
  1.2514 +        overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
  1.2515 +        !ComputeScrollTarget(scrollFrame, aEvent,
  1.2516 +                             COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS)) {
  1.2517 +      aEvent->overflowDeltaX = aEvent->deltaX;
  1.2518 +    }
  1.2519 +    if (aEvent->deltaY &&
  1.2520 +        overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
  1.2521 +        !ComputeScrollTarget(scrollFrame, aEvent,
  1.2522 +                             COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS)) {
  1.2523 +      aEvent->overflowDeltaY = aEvent->deltaY;
  1.2524 +    }
  1.2525 +  }
  1.2526 +
  1.2527 +  NS_ASSERTION(aEvent->overflowDeltaX == 0 ||
  1.2528 +    (aEvent->overflowDeltaX > 0) == (aEvent->deltaX > 0),
  1.2529 +    "The sign of overflowDeltaX is different from the scroll direction");
  1.2530 +  NS_ASSERTION(aEvent->overflowDeltaY == 0 ||
  1.2531 +    (aEvent->overflowDeltaY > 0) == (aEvent->deltaY > 0),
  1.2532 +    "The sign of overflowDeltaY is different from the scroll direction");
  1.2533 +
  1.2534 +  WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
  1.2535 +}
  1.2536 +
  1.2537 +void
  1.2538 +EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
  1.2539 +                                      nsIFrame* targetFrame)
  1.2540 +{
  1.2541 +
  1.2542 +  NS_ASSERTION(aEvent->message == NS_GESTURENOTIFY_EVENT_START,
  1.2543 +               "DecideGestureEvent called with a non-gesture event");
  1.2544 +
  1.2545 +  /* Check the ancestor tree to decide if any frame is willing* to receive
  1.2546 +   * a MozPixelScroll event. If that's the case, the current touch gesture
  1.2547 +   * will be used as a pan gesture; otherwise it will be a regular
  1.2548 +   * mousedown/mousemove/click event.
  1.2549 +   *
  1.2550 +   * *willing: determine if it makes sense to pan the element using scroll events:
  1.2551 +   *  - For web content: if there are any visible scrollbars on the touch point
  1.2552 +   *  - For XUL: if it's an scrollable element that can currently scroll in some
  1.2553 +    *    direction.
  1.2554 +   *
  1.2555 +   * Note: we'll have to one-off various cases to ensure a good usable behavior
  1.2556 +   */
  1.2557 +  WidgetGestureNotifyEvent::ePanDirection panDirection =
  1.2558 +    WidgetGestureNotifyEvent::ePanNone;
  1.2559 +  bool displayPanFeedback = false;
  1.2560 +  for (nsIFrame* current = targetFrame; current;
  1.2561 +       current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
  1.2562 +
  1.2563 +    nsIAtom* currentFrameType = current->GetType();
  1.2564 +
  1.2565 +    // Scrollbars should always be draggable
  1.2566 +    if (currentFrameType == nsGkAtoms::scrollbarFrame) {
  1.2567 +      panDirection = WidgetGestureNotifyEvent::ePanNone;
  1.2568 +      break;
  1.2569 +    }
  1.2570 +
  1.2571 +#ifdef MOZ_XUL
  1.2572 +    // Special check for trees
  1.2573 +    nsTreeBodyFrame* treeFrame = do_QueryFrame(current);
  1.2574 +    if (treeFrame) {
  1.2575 +      if (treeFrame->GetHorizontalOverflow()) {
  1.2576 +        panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
  1.2577 +      }
  1.2578 +      if (treeFrame->GetVerticalOverflow()) {
  1.2579 +        panDirection = WidgetGestureNotifyEvent::ePanVertical;
  1.2580 +      }
  1.2581 +      break;
  1.2582 +    }
  1.2583 +#endif
  1.2584 +
  1.2585 +    nsIScrollableFrame* scrollableFrame = do_QueryFrame(current);
  1.2586 +    if (scrollableFrame) {
  1.2587 +      if (current->IsFrameOfType(nsIFrame::eXULBox)) {
  1.2588 +        displayPanFeedback = true;
  1.2589 +
  1.2590 +        nsRect scrollRange = scrollableFrame->GetScrollRange();
  1.2591 +        bool canScrollHorizontally = scrollRange.width > 0;
  1.2592 +
  1.2593 +        if (targetFrame->GetType() == nsGkAtoms::menuFrame) {
  1.2594 +          // menu frames report horizontal scroll when they have submenus
  1.2595 +          // and we don't want that
  1.2596 +          canScrollHorizontally = false;
  1.2597 +          displayPanFeedback = false;
  1.2598 +        }
  1.2599 +
  1.2600 +        // Vertical panning has priority over horizontal panning, so
  1.2601 +        // when vertical movement is possible we can just finish the loop.
  1.2602 +        if (scrollRange.height > 0) {
  1.2603 +          panDirection = WidgetGestureNotifyEvent::ePanVertical;
  1.2604 +          break;
  1.2605 +        }
  1.2606 +
  1.2607 +        if (canScrollHorizontally) {
  1.2608 +          panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
  1.2609 +          displayPanFeedback = false;
  1.2610 +        }
  1.2611 +      } else { //Not a XUL box
  1.2612 +        uint32_t scrollbarVisibility = scrollableFrame->GetScrollbarVisibility();
  1.2613 +
  1.2614 +        //Check if we have visible scrollbars
  1.2615 +        if (scrollbarVisibility & nsIScrollableFrame::VERTICAL) {
  1.2616 +          panDirection = WidgetGestureNotifyEvent::ePanVertical;
  1.2617 +          displayPanFeedback = true;
  1.2618 +          break;
  1.2619 +        }
  1.2620 +
  1.2621 +        if (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) {
  1.2622 +          panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
  1.2623 +          displayPanFeedback = true;
  1.2624 +        }
  1.2625 +      }
  1.2626 +    } //scrollableFrame
  1.2627 +  } //ancestor chain
  1.2628 +
  1.2629 +  aEvent->displayPanFeedback = displayPanFeedback;
  1.2630 +  aEvent->panDirection = panDirection;
  1.2631 +}
  1.2632 +
  1.2633 +#ifdef XP_MACOSX
  1.2634 +static bool
  1.2635 +NodeAllowsClickThrough(nsINode* aNode)
  1.2636 +{
  1.2637 +  while (aNode) {
  1.2638 +    if (aNode->IsElement() && aNode->AsElement()->IsXUL()) {
  1.2639 +      mozilla::dom::Element* element = aNode->AsElement();
  1.2640 +      static nsIContent::AttrValuesArray strings[] =
  1.2641 +        {&nsGkAtoms::always, &nsGkAtoms::never, nullptr};
  1.2642 +      switch (element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::clickthrough,
  1.2643 +                                       strings, eCaseMatters)) {
  1.2644 +        case 0:
  1.2645 +          return true;
  1.2646 +        case 1:
  1.2647 +          return false;
  1.2648 +      }
  1.2649 +    }
  1.2650 +    aNode = nsContentUtils::GetCrossDocParentNode(aNode);
  1.2651 +  }
  1.2652 +  return true;
  1.2653 +}
  1.2654 +#endif
  1.2655 +
  1.2656 +nsresult
  1.2657 +EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
  1.2658 +                                   WidgetEvent* aEvent,
  1.2659 +                                   nsIFrame* aTargetFrame,
  1.2660 +                                   nsEventStatus* aStatus)
  1.2661 +{
  1.2662 +  NS_ENSURE_ARG(aPresContext);
  1.2663 +  NS_ENSURE_ARG_POINTER(aStatus);
  1.2664 +
  1.2665 +  bool dispatchedToContentProcess = HandleCrossProcessEvent(aEvent,
  1.2666 +                                                            aTargetFrame,
  1.2667 +                                                            aStatus);
  1.2668 +
  1.2669 +  mCurrentTarget = aTargetFrame;
  1.2670 +  mCurrentTargetContent = nullptr;
  1.2671 +
  1.2672 +  // Most of the events we handle below require a frame.
  1.2673 +  // Add special cases here.
  1.2674 +  if (!mCurrentTarget && aEvent->message != NS_MOUSE_BUTTON_UP &&
  1.2675 +      aEvent->message != NS_MOUSE_BUTTON_DOWN) {
  1.2676 +    return NS_OK;
  1.2677 +  }
  1.2678 +
  1.2679 +  //Keep the prescontext alive, we might need it after event dispatch
  1.2680 +  nsRefPtr<nsPresContext> presContext = aPresContext;
  1.2681 +  nsresult ret = NS_OK;
  1.2682 +
  1.2683 +  switch (aEvent->message) {
  1.2684 +  case NS_MOUSE_BUTTON_DOWN:
  1.2685 +    {
  1.2686 +      WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  1.2687 +      if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
  1.2688 +          !sNormalLMouseEventInProcess) {
  1.2689 +        // We got a mouseup event while a mousedown event was being processed.
  1.2690 +        // Make sure that the capturing content is cleared.
  1.2691 +        nsIPresShell::SetCapturingContent(nullptr, 0);
  1.2692 +        break;
  1.2693 +      }
  1.2694 +
  1.2695 +      nsCOMPtr<nsIContent> activeContent;
  1.2696 +      if (nsEventStatus_eConsumeNoDefault != *aStatus) {
  1.2697 +        nsCOMPtr<nsIContent> newFocus;      
  1.2698 +        bool suppressBlur = false;
  1.2699 +        if (mCurrentTarget) {
  1.2700 +          mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
  1.2701 +          const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface();
  1.2702 +          activeContent = mCurrentTarget->GetContent();
  1.2703 +
  1.2704 +          // In some cases, we do not want to even blur the current focused
  1.2705 +          // element. Those cases are:
  1.2706 +          // 1. -moz-user-focus CSS property is set to 'ignore';
  1.2707 +          // 2. Element with NS_EVENT_STATE_DISABLED
  1.2708 +          //    (aka :disabled pseudo-class for HTML element);
  1.2709 +          // 3. XUL control element has the disabled property set to 'true'.
  1.2710 +          //
  1.2711 +          // We can't use nsIFrame::IsFocusable() because we want to blur when
  1.2712 +          // we click on a visibility: none element.
  1.2713 +          // We can't use nsIContent::IsFocusable() because we want to blur when
  1.2714 +          // we click on a non-focusable element like a <div>.
  1.2715 +          // We have to use |aEvent->target| to not make sure we do not check an
  1.2716 +          // anonymous node of the targeted element.
  1.2717 +          suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE);
  1.2718 +
  1.2719 +          if (!suppressBlur) {
  1.2720 +            nsCOMPtr<Element> element = do_QueryInterface(aEvent->target);
  1.2721 +            suppressBlur = element &&
  1.2722 +                           element->State().HasState(NS_EVENT_STATE_DISABLED);
  1.2723 +          }
  1.2724 +
  1.2725 +          if (!suppressBlur) {
  1.2726 +            nsCOMPtr<nsIDOMXULControlElement> xulControl =
  1.2727 +              do_QueryInterface(aEvent->target);
  1.2728 +            if (xulControl) {
  1.2729 +              bool disabled;
  1.2730 +              xulControl->GetDisabled(&disabled);
  1.2731 +              suppressBlur = disabled;
  1.2732 +            }
  1.2733 +          }
  1.2734 +        }
  1.2735 +
  1.2736 +        if (!suppressBlur) {
  1.2737 +          suppressBlur = nsContentUtils::IsUserFocusIgnored(activeContent);
  1.2738 +        }
  1.2739 +
  1.2740 +        nsIFrame* currFrame = mCurrentTarget;
  1.2741 +
  1.2742 +        // When a root content which isn't editable but has an editable HTML
  1.2743 +        // <body> element is clicked, we should redirect the focus to the
  1.2744 +        // the <body> element.  E.g., when an user click bottom of the editor
  1.2745 +        // where is outside of the <body> element, the <body> should be focused
  1.2746 +        // and the user can edit immediately after that.
  1.2747 +        //
  1.2748 +        // NOTE: The newFocus isn't editable that also means it's not in
  1.2749 +        // designMode.  In designMode, all contents are not focusable.
  1.2750 +        if (newFocus && !newFocus->IsEditable()) {
  1.2751 +          nsIDocument *doc = newFocus->GetCurrentDoc();
  1.2752 +          if (doc && newFocus == doc->GetRootElement()) {
  1.2753 +            nsIContent *bodyContent =
  1.2754 +              nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
  1.2755 +            if (bodyContent) {
  1.2756 +              nsIFrame* bodyFrame = bodyContent->GetPrimaryFrame();
  1.2757 +              if (bodyFrame) {
  1.2758 +                currFrame = bodyFrame;
  1.2759 +                newFocus = bodyContent;
  1.2760 +              }
  1.2761 +            }
  1.2762 +          }
  1.2763 +        }
  1.2764 +
  1.2765 +        // When the mouse is pressed, the default action is to focus the
  1.2766 +        // target. Look for the nearest enclosing focusable frame.
  1.2767 +        while (currFrame) {
  1.2768 +          // If the mousedown happened inside a popup, don't
  1.2769 +          // try to set focus on one of its containing elements
  1.2770 +          const nsStyleDisplay* display = currFrame->StyleDisplay();
  1.2771 +          if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) {
  1.2772 +            newFocus = nullptr;
  1.2773 +            break;
  1.2774 +          }
  1.2775 +
  1.2776 +          int32_t tabIndexUnused;
  1.2777 +          if (currFrame->IsFocusable(&tabIndexUnused, true)) {
  1.2778 +            newFocus = currFrame->GetContent();
  1.2779 +            nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
  1.2780 +            if (domElement)
  1.2781 +              break;
  1.2782 +          }
  1.2783 +          currFrame = currFrame->GetParent();
  1.2784 +        }
  1.2785 +
  1.2786 +        nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.2787 +        if (fm) {
  1.2788 +          // if something was found to focus, focus it. Otherwise, if the
  1.2789 +          // element that was clicked doesn't have -moz-user-focus: ignore,
  1.2790 +          // clear the existing focus. For -moz-user-focus: ignore, the focus
  1.2791 +          // is just left as is.
  1.2792 +          // Another effect of mouse clicking, handled in nsSelection, is that
  1.2793 +          // it should update the caret position to where the mouse was
  1.2794 +          // clicked. Because the focus is cleared when clicking on a
  1.2795 +          // non-focusable node, the next press of the tab key will cause
  1.2796 +          // focus to be shifted from the caret position instead of the root.
  1.2797 +          if (newFocus && currFrame) {
  1.2798 +            // use the mouse flag and the noscroll flag so that the content
  1.2799 +            // doesn't unexpectedly scroll when clicking an element that is
  1.2800 +            // only hald visible
  1.2801 +            nsCOMPtr<nsIDOMElement> newFocusElement = do_QueryInterface(newFocus);
  1.2802 +            fm->SetFocus(newFocusElement, nsIFocusManager::FLAG_BYMOUSE |
  1.2803 +                                          nsIFocusManager::FLAG_NOSCROLL);
  1.2804 +          }
  1.2805 +          else if (!suppressBlur) {
  1.2806 +            // clear the focus within the frame and then set it as the
  1.2807 +            // focused frame
  1.2808 +            EnsureDocument(mPresContext);
  1.2809 +            if (mDocument) {
  1.2810 +#ifdef XP_MACOSX
  1.2811 +              if (!activeContent || !activeContent->IsXUL())
  1.2812 +#endif
  1.2813 +                fm->ClearFocus(mDocument->GetWindow());
  1.2814 +              fm->SetFocusedWindow(mDocument->GetWindow());
  1.2815 +            }
  1.2816 +          }
  1.2817 +        }
  1.2818 +
  1.2819 +        // The rest is left button-specific.
  1.2820 +        if (mouseEvent->button != WidgetMouseEvent::eLeftButton) {
  1.2821 +          break;
  1.2822 +        }
  1.2823 +
  1.2824 +        if (activeContent) {
  1.2825 +          // The nearest enclosing element goes into the
  1.2826 +          // :active state.  If we fail the QI to DOMElement,
  1.2827 +          // then we know we're only a node, and that we need
  1.2828 +          // to obtain our parent element and put it into :active
  1.2829 +          // instead.
  1.2830 +          nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(activeContent));
  1.2831 +          if (!elt) {
  1.2832 +            nsIContent* par = activeContent->GetParent();
  1.2833 +            if (par)
  1.2834 +              activeContent = par;
  1.2835 +          }
  1.2836 +        }
  1.2837 +      }
  1.2838 +      else {
  1.2839 +        // if we're here, the event handler returned false, so stop
  1.2840 +        // any of our own processing of a drag. Workaround for bug 43258.
  1.2841 +        StopTrackingDragGesture();
  1.2842 +
  1.2843 +        // When the event was cancelled, there is currently a chrome document
  1.2844 +        // focused and a mousedown just occurred on a content document, ensure
  1.2845 +        // that the window that was clicked is focused.
  1.2846 +        EnsureDocument(mPresContext);
  1.2847 +        nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.2848 +        if (mDocument && fm) {
  1.2849 +          nsCOMPtr<nsIDOMWindow> currentWindow;
  1.2850 +          fm->GetFocusedWindow(getter_AddRefs(currentWindow));
  1.2851 +          if (currentWindow && mDocument->GetWindow() &&
  1.2852 +              currentWindow != mDocument->GetWindow() &&
  1.2853 +              !nsContentUtils::IsChromeDoc(mDocument)) {
  1.2854 +            nsCOMPtr<nsIDOMWindow> currentTop;
  1.2855 +            nsCOMPtr<nsIDOMWindow> newTop;
  1.2856 +            currentWindow->GetTop(getter_AddRefs(currentTop));
  1.2857 +            mDocument->GetWindow()->GetTop(getter_AddRefs(newTop));
  1.2858 +            nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(currentWindow);
  1.2859 +            nsCOMPtr<nsIDocument> currentDoc = win->GetExtantDoc();
  1.2860 +            if (nsContentUtils::IsChromeDoc(currentDoc) ||
  1.2861 +                (currentTop && newTop && currentTop != newTop)) {
  1.2862 +              fm->SetFocusedWindow(mDocument->GetWindow());
  1.2863 +            }
  1.2864 +          }
  1.2865 +        }
  1.2866 +      }
  1.2867 +      SetActiveManager(this, activeContent);
  1.2868 +    }
  1.2869 +    break;
  1.2870 +  case NS_POINTER_CANCEL:
  1.2871 +  case NS_POINTER_UP: {
  1.2872 +    WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
  1.2873 +    // After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table
  1.2874 +    // Mouse/Pen pointers are valid all the time (not only between down/up)
  1.2875 +    if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
  1.2876 +      mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
  1.2877 +    }
  1.2878 +    if (pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_MOUSE) {
  1.2879 +      GenerateMouseEnterExit(pointerEvent);
  1.2880 +    }
  1.2881 +    break;
  1.2882 +  }
  1.2883 +  case NS_MOUSE_BUTTON_UP:
  1.2884 +    {
  1.2885 +      ClearGlobalActiveContent(this);
  1.2886 +      WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  1.2887 +      if (mouseEvent && mouseEvent->IsReal()) {
  1.2888 +        if (!mCurrentTarget) {
  1.2889 +          GetEventTarget();
  1.2890 +        }
  1.2891 +        // Make sure to dispatch the click even if there is no frame for
  1.2892 +        // the current target element. This is required for Web compatibility.
  1.2893 +        ret = CheckForAndDispatchClick(presContext, mouseEvent, aStatus);
  1.2894 +      }
  1.2895 +
  1.2896 +      nsIPresShell *shell = presContext->GetPresShell();
  1.2897 +      if (shell) {
  1.2898 +        nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
  1.2899 +        frameSelection->SetMouseDownState(false);
  1.2900 +      }
  1.2901 +    }
  1.2902 +    break;
  1.2903 +  case NS_WHEEL_STOP:
  1.2904 +    {
  1.2905 +      MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
  1.2906 +      ScrollbarsForWheel::MayInactivate();
  1.2907 +    }
  1.2908 +    break;
  1.2909 +  case NS_WHEEL_WHEEL:
  1.2910 +  case NS_WHEEL_START:
  1.2911 +    {
  1.2912 +      MOZ_ASSERT(aEvent->mFlags.mIsTrusted);
  1.2913 +
  1.2914 +      if (*aStatus == nsEventStatus_eConsumeNoDefault) {
  1.2915 +        ScrollbarsForWheel::Inactivate();
  1.2916 +        break;
  1.2917 +      }
  1.2918 +
  1.2919 +      WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
  1.2920 +      switch (WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent)) {
  1.2921 +        case WheelPrefs::ACTION_SCROLL: {
  1.2922 +          // For scrolling of default action, we should honor the mouse wheel
  1.2923 +          // transaction.
  1.2924 +
  1.2925 +          ScrollbarsForWheel::PrepareToScrollText(this, aTargetFrame, wheelEvent);
  1.2926 +
  1.2927 +          if (aEvent->message != NS_WHEEL_WHEEL ||
  1.2928 +              (!wheelEvent->deltaX && !wheelEvent->deltaY)) {
  1.2929 +            break;
  1.2930 +          }
  1.2931 +
  1.2932 +          nsIScrollableFrame* scrollTarget =
  1.2933 +            ComputeScrollTarget(aTargetFrame, wheelEvent,
  1.2934 +                                COMPUTE_DEFAULT_ACTION_TARGET);
  1.2935 +
  1.2936 +          ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
  1.2937 +
  1.2938 +          nsIFrame* rootScrollFrame = !aTargetFrame ? nullptr :
  1.2939 +            aTargetFrame->PresContext()->PresShell()->GetRootScrollFrame();
  1.2940 +          nsIScrollableFrame* rootScrollableFrame = nullptr;
  1.2941 +          if (rootScrollFrame) {
  1.2942 +            rootScrollableFrame = do_QueryFrame(rootScrollFrame);
  1.2943 +          }
  1.2944 +          if (!scrollTarget || scrollTarget == rootScrollableFrame) {
  1.2945 +            wheelEvent->mViewPortIsOverscrolled = true;
  1.2946 +          }
  1.2947 +          wheelEvent->overflowDeltaX = wheelEvent->deltaX;
  1.2948 +          wheelEvent->overflowDeltaY = wheelEvent->deltaY;
  1.2949 +          WheelPrefs::GetInstance()->
  1.2950 +            CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
  1.2951 +          if (scrollTarget) {
  1.2952 +            DoScrollText(scrollTarget, wheelEvent);
  1.2953 +          } else {
  1.2954 +            WheelTransaction::EndTransaction();
  1.2955 +            ScrollbarsForWheel::Inactivate();
  1.2956 +          }
  1.2957 +          break;
  1.2958 +        }
  1.2959 +        case WheelPrefs::ACTION_HISTORY: {
  1.2960 +          // If this event doesn't cause NS_MOUSE_SCROLL event or the direction
  1.2961 +          // is oblique, don't perform history back/forward.
  1.2962 +          int32_t intDelta = wheelEvent->GetPreferredIntDelta();
  1.2963 +          if (!intDelta) {
  1.2964 +            break;
  1.2965 +          }
  1.2966 +          DoScrollHistory(intDelta);
  1.2967 +          break;
  1.2968 +        }
  1.2969 +        case WheelPrefs::ACTION_ZOOM: {
  1.2970 +          // If this event doesn't cause NS_MOUSE_SCROLL event or the direction
  1.2971 +          // is oblique, don't perform zoom in/out.
  1.2972 +          int32_t intDelta = wheelEvent->GetPreferredIntDelta();
  1.2973 +          if (!intDelta) {
  1.2974 +            break;
  1.2975 +          }
  1.2976 +          DoScrollZoom(aTargetFrame, intDelta);
  1.2977 +          break;
  1.2978 +        }
  1.2979 +        case WheelPrefs::ACTION_NONE:
  1.2980 +        default:
  1.2981 +          // If we don't handle the wheel event, all of the delta values must
  1.2982 +          // be overflown delta values.
  1.2983 +          wheelEvent->overflowDeltaX = wheelEvent->deltaX;
  1.2984 +          wheelEvent->overflowDeltaY = wheelEvent->deltaY;
  1.2985 +          WheelPrefs::GetInstance()->
  1.2986 +            CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
  1.2987 +          break;
  1.2988 +      }
  1.2989 +      *aStatus = nsEventStatus_eConsumeNoDefault;
  1.2990 +    }
  1.2991 +    break;
  1.2992 +
  1.2993 +  case NS_GESTURENOTIFY_EVENT_START:
  1.2994 +    {
  1.2995 +      if (nsEventStatus_eConsumeNoDefault != *aStatus) {
  1.2996 +        DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
  1.2997 +      }
  1.2998 +    }
  1.2999 +    break;
  1.3000 +
  1.3001 +  case NS_DRAGDROP_ENTER:
  1.3002 +  case NS_DRAGDROP_OVER:
  1.3003 +    {
  1.3004 +      NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "Expected a drag event");
  1.3005 +
  1.3006 +      nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
  1.3007 +      if (!dragSession)
  1.3008 +        break;
  1.3009 +
  1.3010 +      // Reset the flag.
  1.3011 +      dragSession->SetOnlyChromeDrop(false);
  1.3012 +      if (mPresContext) {
  1.3013 +        EnsureDocument(mPresContext);
  1.3014 +      }
  1.3015 +      bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
  1.3016 +
  1.3017 +      // the initial dataTransfer is the one from the dragstart event that
  1.3018 +      // was set on the dragSession when the drag began.
  1.3019 +      nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
  1.3020 +      nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
  1.3021 +      dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
  1.3022 +
  1.3023 +      WidgetDragEvent *dragEvent = aEvent->AsDragEvent();
  1.3024 +
  1.3025 +      // collect any changes to moz cursor settings stored in the event's
  1.3026 +      // data transfer.
  1.3027 +      UpdateDragDataTransfer(dragEvent);
  1.3028 +
  1.3029 +      // cancelling a dragenter or dragover event means that a drop should be
  1.3030 +      // allowed, so update the dropEffect and the canDrop state to indicate
  1.3031 +      // that a drag is allowed. If the event isn't cancelled, a drop won't be
  1.3032 +      // allowed. Essentially, to allow a drop somewhere, specify the effects
  1.3033 +      // using the effectAllowed and dropEffect properties in a dragenter or
  1.3034 +      // dragover event and cancel the event. To not allow a drop somewhere,
  1.3035 +      // don't cancel the event or set the effectAllowed or dropEffect to
  1.3036 +      // "none". This way, if the event is just ignored, no drop will be
  1.3037 +      // allowed.
  1.3038 +      uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
  1.3039 +      if (nsEventStatus_eConsumeNoDefault == *aStatus) {
  1.3040 +        // if the event has a dataTransfer set, use it.
  1.3041 +        if (dragEvent->dataTransfer) {
  1.3042 +          // get the dataTransfer and the dropEffect that was set on it
  1.3043 +          dataTransfer = do_QueryInterface(dragEvent->dataTransfer);
  1.3044 +          dataTransfer->GetDropEffectInt(&dropEffect);
  1.3045 +        }
  1.3046 +        else {
  1.3047 +          // if dragEvent->dataTransfer is null, it means that no attempt was
  1.3048 +          // made to access the dataTransfer during the event, yet the event
  1.3049 +          // was cancelled. Instead, use the initial data transfer available
  1.3050 +          // from the drag session. The drop effect would not have been
  1.3051 +          // initialized (which is done in DragEvent::GetDataTransfer),
  1.3052 +          // so set it from the drag action. We'll still want to filter it
  1.3053 +          // based on the effectAllowed below.
  1.3054 +          dataTransfer = initialDataTransfer;
  1.3055 +
  1.3056 +          uint32_t action;
  1.3057 +          dragSession->GetDragAction(&action);
  1.3058 +
  1.3059 +          // filter the drop effect based on the action. Use UNINITIALIZED as
  1.3060 +          // any effect is allowed.
  1.3061 +          dropEffect = nsContentUtils::FilterDropEffect(action,
  1.3062 +                         nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
  1.3063 +        }
  1.3064 +
  1.3065 +        // At this point, if the dataTransfer is null, it means that the
  1.3066 +        // drag was originally started by directly calling the drag service.
  1.3067 +        // Just assume that all effects are allowed.
  1.3068 +        uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
  1.3069 +        if (dataTransfer)
  1.3070 +          dataTransfer->GetEffectAllowedInt(&effectAllowed);
  1.3071 +
  1.3072 +        // set the drag action based on the drop effect and effect allowed.
  1.3073 +        // The drop effect field on the drag transfer object specifies the
  1.3074 +        // desired current drop effect. However, it cannot be used if the
  1.3075 +        // effectAllowed state doesn't include that type of action. If the
  1.3076 +        // dropEffect is "none", then the action will be 'none' so a drop will
  1.3077 +        // not be allowed.
  1.3078 +        uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
  1.3079 +        if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
  1.3080 +            dropEffect & effectAllowed)
  1.3081 +          action = dropEffect;
  1.3082 +
  1.3083 +        if (action == nsIDragService::DRAGDROP_ACTION_NONE)
  1.3084 +          dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
  1.3085 +
  1.3086 +        // inform the drag session that a drop is allowed on this node.
  1.3087 +        dragSession->SetDragAction(action);
  1.3088 +        dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
  1.3089 +
  1.3090 +        // For now, do this only for dragover.
  1.3091 +        //XXXsmaug dragenter needs some more work.
  1.3092 +        if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
  1.3093 +          // Someone has called preventDefault(), check whether is was on
  1.3094 +          // content or chrome.
  1.3095 +          dragSession->SetOnlyChromeDrop(
  1.3096 +            !dragEvent->mDefaultPreventedOnContent);
  1.3097 +        }
  1.3098 +      } else if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
  1.3099 +        // No one called preventDefault(), so handle drop only in chrome.
  1.3100 +        dragSession->SetOnlyChromeDrop(true);
  1.3101 +      }
  1.3102 +
  1.3103 +      // now set the drop effect in the initial dataTransfer. This ensures
  1.3104 +      // that we can get the desired drop effect in the drop event.
  1.3105 +      if (initialDataTransfer)
  1.3106 +        initialDataTransfer->SetDropEffectInt(dropEffect);
  1.3107 +    }
  1.3108 +    break;
  1.3109 +
  1.3110 +  case NS_DRAGDROP_DROP:
  1.3111 +    {
  1.3112 +      // now fire the dragdrop event, for compatibility with XUL
  1.3113 +      if (mCurrentTarget && nsEventStatus_eConsumeNoDefault != *aStatus) {
  1.3114 +        nsCOMPtr<nsIContent> targetContent;
  1.3115 +        mCurrentTarget->GetContentForEvent(aEvent,
  1.3116 +                                           getter_AddRefs(targetContent));
  1.3117 +
  1.3118 +        nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
  1.3119 +        WidgetDragEvent event(aEvent->mFlags.mIsTrusted,
  1.3120 +                              NS_DRAGDROP_DRAGDROP, widget);
  1.3121 +
  1.3122 +        WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  1.3123 +        event.refPoint = mouseEvent->refPoint;
  1.3124 +        if (mouseEvent->widget) {
  1.3125 +          event.refPoint += LayoutDeviceIntPoint::FromUntyped(mouseEvent->widget->WidgetToScreenOffset());
  1.3126 +        }
  1.3127 +        event.refPoint -= LayoutDeviceIntPoint::FromUntyped(widget->WidgetToScreenOffset());
  1.3128 +        event.modifiers = mouseEvent->modifiers;
  1.3129 +        event.buttons = mouseEvent->buttons;
  1.3130 +        event.inputSource = mouseEvent->inputSource;
  1.3131 +
  1.3132 +        nsEventStatus status = nsEventStatus_eIgnore;
  1.3133 +        nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
  1.3134 +        if (presShell) {
  1.3135 +          presShell->HandleEventWithTarget(&event, mCurrentTarget,
  1.3136 +                                           targetContent, &status);
  1.3137 +        }
  1.3138 +      }
  1.3139 +      sLastDragOverFrame = nullptr;
  1.3140 +      ClearGlobalActiveContent(this);
  1.3141 +      break;
  1.3142 +    }
  1.3143 +  case NS_DRAGDROP_EXIT:
  1.3144 +     // make sure to fire the enter and exit_synth events after the
  1.3145 +     // NS_DRAGDROP_EXIT event, otherwise we'll clean up too early
  1.3146 +    GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
  1.3147 +    break;
  1.3148 +
  1.3149 +  case NS_KEY_UP:
  1.3150 +    break;
  1.3151 +
  1.3152 +  case NS_KEY_PRESS:
  1.3153 +    if (nsEventStatus_eConsumeNoDefault != *aStatus) {
  1.3154 +      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
  1.3155 +      //This is to prevent keyboard scrolling while alt modifier in use.
  1.3156 +      if (!keyEvent->IsAlt()) {
  1.3157 +        switch(keyEvent->keyCode) {
  1.3158 +          case NS_VK_TAB:
  1.3159 +          case NS_VK_F6:
  1.3160 +            // Handling the tab event after it was sent to content is bad,
  1.3161 +            // because to the FocusManager the remote-browser looks like one
  1.3162 +            // element, so we would just move the focus to the next element
  1.3163 +            // in chrome, instead of handling it in content.
  1.3164 +            if (dispatchedToContentProcess)
  1.3165 +              break;
  1.3166 +
  1.3167 +            EnsureDocument(mPresContext);
  1.3168 +            nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.3169 +            if (fm && mDocument) {
  1.3170 +              // Shift focus forward or back depending on shift key
  1.3171 +              bool isDocMove =
  1.3172 +                keyEvent->IsControl() || keyEvent->keyCode == NS_VK_F6;
  1.3173 +              uint32_t dir = keyEvent->IsShift() ?
  1.3174 +                  (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC) :
  1.3175 +                               static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD)) :
  1.3176 +                  (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARDDOC) :
  1.3177 +                               static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD));
  1.3178 +              nsCOMPtr<nsIDOMElement> result;
  1.3179 +              fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
  1.3180 +                            nsIFocusManager::FLAG_BYKEY,
  1.3181 +                            getter_AddRefs(result));
  1.3182 +            }
  1.3183 +            *aStatus = nsEventStatus_eConsumeNoDefault;
  1.3184 +            break;
  1.3185 +        }
  1.3186 +      }
  1.3187 +    }
  1.3188 +    break;
  1.3189 +
  1.3190 +  case NS_MOUSE_ENTER:
  1.3191 +    if (mCurrentTarget) {
  1.3192 +      nsCOMPtr<nsIContent> targetContent;
  1.3193 +      mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
  1.3194 +      SetContentState(targetContent, NS_EVENT_STATE_HOVER);
  1.3195 +    }
  1.3196 +    break;
  1.3197 +
  1.3198 +#ifdef XP_MACOSX
  1.3199 +  case NS_MOUSE_ACTIVATE:
  1.3200 +    if (mCurrentTarget) {
  1.3201 +      nsCOMPtr<nsIContent> targetContent;
  1.3202 +      mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
  1.3203 +      if (!NodeAllowsClickThrough(targetContent)) {
  1.3204 +        *aStatus = nsEventStatus_eConsumeNoDefault;
  1.3205 +      }
  1.3206 +    }
  1.3207 +    break;
  1.3208 +#endif
  1.3209 +  }
  1.3210 +
  1.3211 +  //Reset target frame to null to avoid mistargeting after reentrant event
  1.3212 +  mCurrentTarget = nullptr;
  1.3213 +  mCurrentTargetContent = nullptr;
  1.3214 +
  1.3215 +  return ret;
  1.3216 +}
  1.3217 +
  1.3218 +bool
  1.3219 +EventStateManager::RemoteQueryContentEvent(WidgetEvent* aEvent)
  1.3220 +{
  1.3221 +  WidgetQueryContentEvent* queryEvent = aEvent->AsQueryContentEvent();
  1.3222 +  if (!IsTargetCrossProcess(queryEvent)) {
  1.3223 +    return false;
  1.3224 +  }
  1.3225 +  // Will not be handled locally, remote the event
  1.3226 +  GetCrossProcessTarget()->HandleQueryContentEvent(*queryEvent);
  1.3227 +  return true;
  1.3228 +}
  1.3229 +
  1.3230 +TabParent*
  1.3231 +EventStateManager::GetCrossProcessTarget()
  1.3232 +{
  1.3233 +  return TabParent::GetIMETabParent();
  1.3234 +}
  1.3235 +
  1.3236 +bool
  1.3237 +EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent)
  1.3238 +{
  1.3239 +  // Check to see if there is a focused, editable content in chrome,
  1.3240 +  // in that case, do not forward IME events to content
  1.3241 +  nsIContent *focusedContent = GetFocusedContent();
  1.3242 +  if (focusedContent && focusedContent->IsEditable())
  1.3243 +    return false;
  1.3244 +  return TabParent::GetIMETabParent() != nullptr;
  1.3245 +}
  1.3246 +
  1.3247 +void
  1.3248 +EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
  1.3249 +{
  1.3250 +  IMEStateManager::OnDestroyPresContext(aPresContext);
  1.3251 +  if (mHoverContent) {
  1.3252 +    // Bug 70855: Presentation is going away, possibly for a reframe.
  1.3253 +    // Reset the hover state so that if we're recreating the presentation,
  1.3254 +    // we won't have the old hover state still set in the new presentation,
  1.3255 +    // as if the new presentation is resized, a new element may be hovered. 
  1.3256 +    SetContentState(nullptr, NS_EVENT_STATE_HOVER);
  1.3257 +  }
  1.3258 +  mPointersEnterLeaveHelper.Clear();
  1.3259 +}
  1.3260 +
  1.3261 +void
  1.3262 +EventStateManager::SetPresContext(nsPresContext* aPresContext)
  1.3263 +{
  1.3264 +  mPresContext = aPresContext;
  1.3265 +}
  1.3266 +
  1.3267 +void
  1.3268 +EventStateManager::ClearFrameRefs(nsIFrame* aFrame)
  1.3269 +{
  1.3270 +  if (aFrame && aFrame == mCurrentTarget) {
  1.3271 +    mCurrentTargetContent = aFrame->GetContent();
  1.3272 +  }
  1.3273 +}
  1.3274 +
  1.3275 +void
  1.3276 +EventStateManager::UpdateCursor(nsPresContext* aPresContext,
  1.3277 +                                WidgetEvent* aEvent,
  1.3278 +                                nsIFrame* aTargetFrame,
  1.3279 +                                nsEventStatus* aStatus)
  1.3280 +{
  1.3281 +  if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
  1.3282 +    return;
  1.3283 +  }
  1.3284 +
  1.3285 +  int32_t cursor = NS_STYLE_CURSOR_DEFAULT;
  1.3286 +  imgIContainer* container = nullptr;
  1.3287 +  bool haveHotspot = false;
  1.3288 +  float hotspotX = 0.0f, hotspotY = 0.0f;
  1.3289 +
  1.3290 +  //If cursor is locked just use the locked one
  1.3291 +  if (mLockCursor) {
  1.3292 +    cursor = mLockCursor;
  1.3293 +  }
  1.3294 +  //If not locked, look for correct cursor
  1.3295 +  else if (aTargetFrame) {
  1.3296 +      nsIFrame::Cursor framecursor;
  1.3297 +      nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
  1.3298 +                                                                aTargetFrame);
  1.3299 +      if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor)))
  1.3300 +        return;  // don't update the cursor if we failed to get it from the frame see bug 118877
  1.3301 +      cursor = framecursor.mCursor;
  1.3302 +      container = framecursor.mContainer;
  1.3303 +      haveHotspot = framecursor.mHaveHotspot;
  1.3304 +      hotspotX = framecursor.mHotspotX;
  1.3305 +      hotspotY = framecursor.mHotspotY;
  1.3306 +  }
  1.3307 +
  1.3308 +  if (Preferences::GetBool("ui.use_activity_cursor", false)) {
  1.3309 +    // Check whether or not to show the busy cursor
  1.3310 +    nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell());
  1.3311 +    if (!docShell) return;
  1.3312 +    uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
  1.3313 +    docShell->GetBusyFlags(&busyFlags);
  1.3314 +
  1.3315 +    // Show busy cursor everywhere before page loads
  1.3316 +    // and just replace the arrow cursor after page starts loading
  1.3317 +    if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY &&
  1.3318 +          (cursor == NS_STYLE_CURSOR_AUTO || cursor == NS_STYLE_CURSOR_DEFAULT))
  1.3319 +    {
  1.3320 +      cursor = NS_STYLE_CURSOR_SPINNING;
  1.3321 +      container = nullptr;
  1.3322 +    }
  1.3323 +  }
  1.3324 +
  1.3325 +  if (aTargetFrame) {
  1.3326 +    SetCursor(cursor, container, haveHotspot, hotspotX, hotspotY,
  1.3327 +              aTargetFrame->GetNearestWidget(), false);
  1.3328 +  }
  1.3329 +
  1.3330 +  if (mLockCursor || NS_STYLE_CURSOR_AUTO != cursor) {
  1.3331 +    *aStatus = nsEventStatus_eConsumeDoDefault;
  1.3332 +  }
  1.3333 +}
  1.3334 +
  1.3335 +nsresult
  1.3336 +EventStateManager::SetCursor(int32_t aCursor, imgIContainer* aContainer,
  1.3337 +                             bool aHaveHotspot,
  1.3338 +                             float aHotspotX, float aHotspotY,
  1.3339 +                             nsIWidget* aWidget, bool aLockCursor)
  1.3340 +{
  1.3341 +  EnsureDocument(mPresContext);
  1.3342 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
  1.3343 +  sMouseOverDocument = mDocument.get();
  1.3344 +
  1.3345 +  nsCursor c;
  1.3346 +
  1.3347 +  NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE);
  1.3348 +  if (aLockCursor) {
  1.3349 +    if (NS_STYLE_CURSOR_AUTO != aCursor) {
  1.3350 +      mLockCursor = aCursor;
  1.3351 +    }
  1.3352 +    else {
  1.3353 +      //If cursor style is set to auto we unlock the cursor again.
  1.3354 +      mLockCursor = 0;
  1.3355 +    }
  1.3356 +  }
  1.3357 +  switch (aCursor) {
  1.3358 +  default:
  1.3359 +  case NS_STYLE_CURSOR_AUTO:
  1.3360 +  case NS_STYLE_CURSOR_DEFAULT:
  1.3361 +    c = eCursor_standard;
  1.3362 +    break;
  1.3363 +  case NS_STYLE_CURSOR_POINTER:
  1.3364 +    c = eCursor_hyperlink;
  1.3365 +    break;
  1.3366 +  case NS_STYLE_CURSOR_CROSSHAIR:
  1.3367 +    c = eCursor_crosshair;
  1.3368 +    break;
  1.3369 +  case NS_STYLE_CURSOR_MOVE:
  1.3370 +    c = eCursor_move;
  1.3371 +    break;
  1.3372 +  case NS_STYLE_CURSOR_TEXT:
  1.3373 +    c = eCursor_select;
  1.3374 +    break;
  1.3375 +  case NS_STYLE_CURSOR_WAIT:
  1.3376 +    c = eCursor_wait;
  1.3377 +    break;
  1.3378 +  case NS_STYLE_CURSOR_HELP:
  1.3379 +    c = eCursor_help;
  1.3380 +    break;
  1.3381 +  case NS_STYLE_CURSOR_N_RESIZE:
  1.3382 +    c = eCursor_n_resize;
  1.3383 +    break;
  1.3384 +  case NS_STYLE_CURSOR_S_RESIZE:
  1.3385 +    c = eCursor_s_resize;
  1.3386 +    break;
  1.3387 +  case NS_STYLE_CURSOR_W_RESIZE:
  1.3388 +    c = eCursor_w_resize;
  1.3389 +    break;
  1.3390 +  case NS_STYLE_CURSOR_E_RESIZE:
  1.3391 +    c = eCursor_e_resize;
  1.3392 +    break;
  1.3393 +  case NS_STYLE_CURSOR_NW_RESIZE:
  1.3394 +    c = eCursor_nw_resize;
  1.3395 +    break;
  1.3396 +  case NS_STYLE_CURSOR_SE_RESIZE:
  1.3397 +    c = eCursor_se_resize;
  1.3398 +    break;
  1.3399 +  case NS_STYLE_CURSOR_NE_RESIZE:
  1.3400 +    c = eCursor_ne_resize;
  1.3401 +    break;
  1.3402 +  case NS_STYLE_CURSOR_SW_RESIZE:
  1.3403 +    c = eCursor_sw_resize;
  1.3404 +    break;
  1.3405 +  case NS_STYLE_CURSOR_COPY: // CSS3
  1.3406 +    c = eCursor_copy;
  1.3407 +    break;
  1.3408 +  case NS_STYLE_CURSOR_ALIAS:
  1.3409 +    c = eCursor_alias;
  1.3410 +    break;
  1.3411 +  case NS_STYLE_CURSOR_CONTEXT_MENU:
  1.3412 +    c = eCursor_context_menu;
  1.3413 +    break;
  1.3414 +  case NS_STYLE_CURSOR_CELL:
  1.3415 +    c = eCursor_cell;
  1.3416 +    break;
  1.3417 +  case NS_STYLE_CURSOR_GRAB:
  1.3418 +    c = eCursor_grab;
  1.3419 +    break;
  1.3420 +  case NS_STYLE_CURSOR_GRABBING:
  1.3421 +    c = eCursor_grabbing;
  1.3422 +    break;
  1.3423 +  case NS_STYLE_CURSOR_SPINNING:
  1.3424 +    c = eCursor_spinning;
  1.3425 +    break;
  1.3426 +  case NS_STYLE_CURSOR_ZOOM_IN:
  1.3427 +    c = eCursor_zoom_in;
  1.3428 +    break;
  1.3429 +  case NS_STYLE_CURSOR_ZOOM_OUT:
  1.3430 +    c = eCursor_zoom_out;
  1.3431 +    break;
  1.3432 +  case NS_STYLE_CURSOR_NOT_ALLOWED:
  1.3433 +    c = eCursor_not_allowed;
  1.3434 +    break;
  1.3435 +  case NS_STYLE_CURSOR_COL_RESIZE:
  1.3436 +    c = eCursor_col_resize;
  1.3437 +    break;
  1.3438 +  case NS_STYLE_CURSOR_ROW_RESIZE:
  1.3439 +    c = eCursor_row_resize;
  1.3440 +    break;
  1.3441 +  case NS_STYLE_CURSOR_NO_DROP:
  1.3442 +    c = eCursor_no_drop;
  1.3443 +    break;
  1.3444 +  case NS_STYLE_CURSOR_VERTICAL_TEXT:
  1.3445 +    c = eCursor_vertical_text;
  1.3446 +    break;
  1.3447 +  case NS_STYLE_CURSOR_ALL_SCROLL:
  1.3448 +    c = eCursor_all_scroll;
  1.3449 +    break;
  1.3450 +  case NS_STYLE_CURSOR_NESW_RESIZE:
  1.3451 +    c = eCursor_nesw_resize;
  1.3452 +    break;
  1.3453 +  case NS_STYLE_CURSOR_NWSE_RESIZE:
  1.3454 +    c = eCursor_nwse_resize;
  1.3455 +    break;
  1.3456 +  case NS_STYLE_CURSOR_NS_RESIZE:
  1.3457 +    c = eCursor_ns_resize;
  1.3458 +    break;
  1.3459 +  case NS_STYLE_CURSOR_EW_RESIZE:
  1.3460 +    c = eCursor_ew_resize;
  1.3461 +    break;
  1.3462 +  case NS_STYLE_CURSOR_NONE:
  1.3463 +    c = eCursor_none;
  1.3464 +    break;
  1.3465 +  }
  1.3466 +
  1.3467 +  // First, try the imgIContainer, if non-null
  1.3468 +  nsresult rv = NS_ERROR_FAILURE;
  1.3469 +  if (aContainer) {
  1.3470 +    uint32_t hotspotX, hotspotY;
  1.3471 +
  1.3472 +    // css3-ui says to use the CSS-specified hotspot if present,
  1.3473 +    // otherwise use the intrinsic hotspot, otherwise use the top left
  1.3474 +    // corner.
  1.3475 +    if (aHaveHotspot) {
  1.3476 +      int32_t imgWidth, imgHeight;
  1.3477 +      aContainer->GetWidth(&imgWidth);
  1.3478 +      aContainer->GetHeight(&imgHeight);
  1.3479 +
  1.3480 +      // XXX std::max(NS_lround(x), 0)?
  1.3481 +      hotspotX = aHotspotX > 0.0f
  1.3482 +                   ? uint32_t(aHotspotX + 0.5f) : uint32_t(0);
  1.3483 +      if (hotspotX >= uint32_t(imgWidth))
  1.3484 +        hotspotX = imgWidth - 1;
  1.3485 +      hotspotY = aHotspotY > 0.0f
  1.3486 +                   ? uint32_t(aHotspotY + 0.5f) : uint32_t(0);
  1.3487 +      if (hotspotY >= uint32_t(imgHeight))
  1.3488 +        hotspotY = imgHeight - 1;
  1.3489 +    } else {
  1.3490 +      hotspotX = 0;
  1.3491 +      hotspotY = 0;
  1.3492 +      nsCOMPtr<nsIProperties> props(do_QueryInterface(aContainer));
  1.3493 +      if (props) {
  1.3494 +        nsCOMPtr<nsISupportsPRUint32> hotspotXWrap, hotspotYWrap;
  1.3495 +
  1.3496 +        props->Get("hotspotX", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotXWrap));
  1.3497 +        props->Get("hotspotY", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotYWrap));
  1.3498 +
  1.3499 +        if (hotspotXWrap)
  1.3500 +          hotspotXWrap->GetData(&hotspotX);
  1.3501 +        if (hotspotYWrap)
  1.3502 +          hotspotYWrap->GetData(&hotspotY);
  1.3503 +      }
  1.3504 +    }
  1.3505 +
  1.3506 +    rv = aWidget->SetCursor(aContainer, hotspotX, hotspotY);
  1.3507 +  }
  1.3508 +
  1.3509 +  if (NS_FAILED(rv))
  1.3510 +    aWidget->SetCursor(c);
  1.3511 +
  1.3512 +  return NS_OK;
  1.3513 +}
  1.3514 +
  1.3515 +class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback
  1.3516 +{
  1.3517 +public:
  1.3518 +  ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
  1.3519 +
  1.3520 +  virtual void HandleEvent(EventChainPostVisitor& aVisitor)
  1.3521 +  {
  1.3522 +    if (aVisitor.mPresContext) {
  1.3523 +      nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
  1.3524 +      if (frame) {
  1.3525 +        frame->HandleEvent(aVisitor.mPresContext,
  1.3526 +                           aVisitor.mEvent->AsGUIEvent(),
  1.3527 +                           &aVisitor.mEventStatus);
  1.3528 +      }
  1.3529 +    }
  1.3530 +  }
  1.3531 +
  1.3532 +  nsCOMPtr<nsIContent> mTarget;
  1.3533 +};
  1.3534 +
  1.3535 +/*static*/ bool
  1.3536 +EventStateManager::IsHandlingUserInput()
  1.3537 +{
  1.3538 +  if (sUserInputEventDepth <= 0) {
  1.3539 +    return false;
  1.3540 +  }
  1.3541 +
  1.3542 +  TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout();
  1.3543 +  return timeout <= TimeDuration(0) ||
  1.3544 +         (TimeStamp::Now() - sHandlingInputStart) <= timeout;
  1.3545 +}
  1.3546 +
  1.3547 +nsIFrame*
  1.3548 +EventStateManager::DispatchMouseOrPointerEvent(WidgetMouseEvent* aMouseEvent,
  1.3549 +                                               uint32_t aMessage,
  1.3550 +                                               nsIContent* aTargetContent,
  1.3551 +                                               nsIContent* aRelatedContent)
  1.3552 +{
  1.3553 +  // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
  1.3554 +  // "[When the mouse is locked on an element...e]vents that require the concept
  1.3555 +  // of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
  1.3556 +  if (sIsPointerLocked &&
  1.3557 +      (aMessage == NS_MOUSELEAVE ||
  1.3558 +       aMessage == NS_MOUSEENTER ||
  1.3559 +       aMessage == NS_MOUSE_ENTER_SYNTH ||
  1.3560 +       aMessage == NS_MOUSE_EXIT_SYNTH)) {
  1.3561 +    mCurrentTargetContent = nullptr;
  1.3562 +    nsCOMPtr<Element> pointerLockedElement =
  1.3563 +      do_QueryReferent(EventStateManager::sPointerLockedElement);
  1.3564 +    if (!pointerLockedElement) {
  1.3565 +      NS_WARNING("Should have pointer locked element, but didn't.");
  1.3566 +      return nullptr;
  1.3567 +    }
  1.3568 +    nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
  1.3569 +    return mPresContext->GetPrimaryFrameFor(content);
  1.3570 +  }
  1.3571 +
  1.3572 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.3573 +  nsAutoPtr<WidgetMouseEvent> event;
  1.3574 +  WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
  1.3575 +  if (sourcePointer) {
  1.3576 +    PROFILER_LABEL("Input", "DispatchPointerEvent");
  1.3577 +    nsAutoPtr<WidgetPointerEvent> newPointerEvent;
  1.3578 +    newPointerEvent =
  1.3579 +      new WidgetPointerEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
  1.3580 +                             aMouseEvent->widget);
  1.3581 +    newPointerEvent->isPrimary = sourcePointer->isPrimary;
  1.3582 +    newPointerEvent->pointerId = sourcePointer->pointerId;
  1.3583 +    newPointerEvent->width = sourcePointer->width;
  1.3584 +    newPointerEvent->height = sourcePointer->height;
  1.3585 +    newPointerEvent->inputSource = sourcePointer->inputSource;
  1.3586 +    newPointerEvent->relatedTarget = nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
  1.3587 +                                       ? nullptr
  1.3588 +                                       : aRelatedContent;
  1.3589 +    event = newPointerEvent.forget();
  1.3590 +  } else {
  1.3591 +    PROFILER_LABEL("Input", "DispatchMouseEvent");
  1.3592 +    event =
  1.3593 +      new WidgetMouseEvent(aMouseEvent->mFlags.mIsTrusted, aMessage,
  1.3594 +                           aMouseEvent->widget, WidgetMouseEvent::eReal);
  1.3595 +    event->relatedTarget = aRelatedContent;
  1.3596 +  }
  1.3597 +  event->refPoint = aMouseEvent->refPoint;
  1.3598 +  event->modifiers = aMouseEvent->modifiers;
  1.3599 +  event->button = aMouseEvent->button;
  1.3600 +  event->buttons = aMouseEvent->buttons;
  1.3601 +  event->pressure = aMouseEvent->pressure;
  1.3602 +  event->pluginEvent = aMouseEvent->pluginEvent;
  1.3603 +  event->inputSource = aMouseEvent->inputSource;
  1.3604 +
  1.3605 +  nsWeakFrame previousTarget = mCurrentTarget;
  1.3606 +
  1.3607 +  mCurrentTargetContent = aTargetContent;
  1.3608 +
  1.3609 +  nsIFrame* targetFrame = nullptr;
  1.3610 +  if (aTargetContent) {
  1.3611 +    ESMEventCB callback(aTargetContent);
  1.3612 +    EventDispatcher::Dispatch(aTargetContent, mPresContext, event, nullptr,
  1.3613 +                              &status, &callback);
  1.3614 +
  1.3615 +    // Although the primary frame was checked in event callback, 
  1.3616 +    // it may not be the same object after event dispatching and handling.
  1.3617 +    // So we need to refetch it.
  1.3618 +    if (mPresContext) {
  1.3619 +      targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent);
  1.3620 +    }
  1.3621 +  }
  1.3622 +
  1.3623 +  mCurrentTargetContent = nullptr;
  1.3624 +  mCurrentTarget = previousTarget;
  1.3625 +
  1.3626 +  return targetFrame;
  1.3627 +}
  1.3628 +
  1.3629 +class EnterLeaveDispatcher
  1.3630 +{
  1.3631 +public:
  1.3632 +  EnterLeaveDispatcher(EventStateManager* aESM,
  1.3633 +                       nsIContent* aTarget, nsIContent* aRelatedTarget,
  1.3634 +                       WidgetMouseEvent* aMouseEvent, uint32_t aType)
  1.3635 +    : mESM(aESM)
  1.3636 +    , mMouseEvent(aMouseEvent)
  1.3637 +    , mType(aType)
  1.3638 +  {
  1.3639 +    nsPIDOMWindow* win =
  1.3640 +      aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
  1.3641 +    if (aMouseEvent->AsPointerEvent() ? win && win->HasPointerEnterLeaveEventListeners() :
  1.3642 +                                        win && win->HasMouseEnterLeaveEventListeners()) {
  1.3643 +      mRelatedTarget = aRelatedTarget ?
  1.3644 +        aRelatedTarget->FindFirstNonChromeOnlyAccessContent() : nullptr;
  1.3645 +      nsINode* commonParent = nullptr;
  1.3646 +      if (aTarget && aRelatedTarget) {
  1.3647 +        commonParent =
  1.3648 +          nsContentUtils::GetCommonAncestor(aTarget, aRelatedTarget);
  1.3649 +      }
  1.3650 +      nsIContent* current = aTarget;
  1.3651 +      // Note, it is ok if commonParent is null!
  1.3652 +      while (current && current != commonParent) {
  1.3653 +        if (!current->ChromeOnlyAccess()) {
  1.3654 +          mTargets.AppendObject(current);
  1.3655 +        }
  1.3656 +        // mouseenter/leave is fired only on elements.
  1.3657 +        current = current->GetParent();
  1.3658 +      }
  1.3659 +    }
  1.3660 +  }
  1.3661 +
  1.3662 +  ~EnterLeaveDispatcher()
  1.3663 +  {
  1.3664 +    if (mType == NS_MOUSEENTER ||
  1.3665 +        mType == NS_POINTER_ENTER) {
  1.3666 +      for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
  1.3667 +        mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i],
  1.3668 +                                          mRelatedTarget);
  1.3669 +      }
  1.3670 +    } else {
  1.3671 +      for (int32_t i = 0; i < mTargets.Count(); ++i) {
  1.3672 +        mESM->DispatchMouseOrPointerEvent(mMouseEvent, mType, mTargets[i],
  1.3673 +                                          mRelatedTarget);
  1.3674 +      }
  1.3675 +    }
  1.3676 +  }
  1.3677 +
  1.3678 +  EventStateManager* mESM;
  1.3679 +  nsCOMArray<nsIContent> mTargets;
  1.3680 +  nsCOMPtr<nsIContent> mRelatedTarget;
  1.3681 +  WidgetMouseEvent* mMouseEvent;
  1.3682 +  uint32_t mType;
  1.3683 +};
  1.3684 +
  1.3685 +void
  1.3686 +EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
  1.3687 +                                  nsIContent* aMovingInto)
  1.3688 +{
  1.3689 +  OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
  1.3690 +
  1.3691 +  if (!wrapper->mLastOverElement)
  1.3692 +    return;
  1.3693 +  // Before firing mouseout, check for recursion
  1.3694 +  if (wrapper->mLastOverElement == wrapper->mFirstOutEventElement)
  1.3695 +    return;
  1.3696 +
  1.3697 +  if (wrapper->mLastOverFrame) {
  1.3698 +    // if the frame is associated with a subdocument,
  1.3699 +    // tell the subdocument that we're moving out of it
  1.3700 +    nsSubDocumentFrame* subdocFrame = do_QueryFrame(wrapper->mLastOverFrame.GetFrame());
  1.3701 +    if (subdocFrame) {
  1.3702 +      nsCOMPtr<nsIDocShell> docshell;
  1.3703 +      subdocFrame->GetDocShell(getter_AddRefs(docshell));
  1.3704 +      if (docshell) {
  1.3705 +        nsRefPtr<nsPresContext> presContext;
  1.3706 +        docshell->GetPresContext(getter_AddRefs(presContext));
  1.3707 +
  1.3708 +        if (presContext) {
  1.3709 +          EventStateManager* kidESM = presContext->EventStateManager();
  1.3710 +          // Not moving into any element in this subdocument
  1.3711 +          kidESM->NotifyMouseOut(aMouseEvent, nullptr);
  1.3712 +        }
  1.3713 +      }
  1.3714 +    }
  1.3715 +  }
  1.3716 +  // That could have caused DOM events which could wreak havoc. Reverify
  1.3717 +  // things and be careful.
  1.3718 +  if (!wrapper->mLastOverElement)
  1.3719 +    return;
  1.3720 +
  1.3721 +  // Store the first mouseOut event we fire and don't refire mouseOut
  1.3722 +  // to that element while the first mouseOut is still ongoing.
  1.3723 +  wrapper->mFirstOutEventElement = wrapper->mLastOverElement;
  1.3724 +
  1.3725 +  // Don't touch hover state if aMovingInto is non-null.  Caller will update
  1.3726 +  // hover state itself, and we have optimizations for hover switching between
  1.3727 +  // two nearby elements both deep in the DOM tree that would be defeated by
  1.3728 +  // switching the hover state to null here.
  1.3729 +  bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
  1.3730 +  if (!aMovingInto && !isPointer) {
  1.3731 +    // Unset :hover
  1.3732 +    SetContentState(nullptr, NS_EVENT_STATE_HOVER);
  1.3733 +  }
  1.3734 +
  1.3735 +  EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
  1.3736 +                                       aMovingInto, aMouseEvent,
  1.3737 +                                       isPointer ? NS_POINTER_LEAVE :
  1.3738 +                                                   NS_MOUSELEAVE);
  1.3739 +
  1.3740 +  // Fire mouseout
  1.3741 +  DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_EXIT_SYNTH,
  1.3742 +                              wrapper->mLastOverElement, aMovingInto);
  1.3743 +
  1.3744 +  wrapper->mLastOverFrame = nullptr;
  1.3745 +  wrapper->mLastOverElement = nullptr;
  1.3746 +
  1.3747 +  // Turn recursion protection back off
  1.3748 +  wrapper->mFirstOutEventElement = nullptr;
  1.3749 +}
  1.3750 +
  1.3751 +void
  1.3752 +EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
  1.3753 +                                   nsIContent* aContent)
  1.3754 +{
  1.3755 +  NS_ASSERTION(aContent, "Mouse must be over something");
  1.3756 +
  1.3757 +  OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
  1.3758 +
  1.3759 +  if (wrapper->mLastOverElement == aContent)
  1.3760 +    return;
  1.3761 +
  1.3762 +  // Before firing mouseover, check for recursion
  1.3763 +  if (aContent == wrapper->mFirstOverEventElement)
  1.3764 +    return;
  1.3765 +
  1.3766 +  // Check to see if we're a subdocument and if so update the parent
  1.3767 +  // document's ESM state to indicate that the mouse is over the
  1.3768 +  // content associated with our subdocument.
  1.3769 +  EnsureDocument(mPresContext);
  1.3770 +  nsIDocument *parentDoc = mDocument->GetParentDocument();
  1.3771 +  if (parentDoc) {
  1.3772 +    nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument);
  1.3773 +    if (docContent) {
  1.3774 +      nsIPresShell *parentShell = parentDoc->GetShell();
  1.3775 +      if (parentShell) {
  1.3776 +        EventStateManager* parentESM =
  1.3777 +          parentShell->GetPresContext()->EventStateManager();
  1.3778 +        parentESM->NotifyMouseOver(aMouseEvent, docContent);
  1.3779 +      }
  1.3780 +    }
  1.3781 +  }
  1.3782 +  // Firing the DOM event in the parent document could cause all kinds
  1.3783 +  // of havoc.  Reverify and take care.
  1.3784 +  if (wrapper->mLastOverElement == aContent)
  1.3785 +    return;
  1.3786 +
  1.3787 +  // Remember mLastOverElement as the related content for the
  1.3788 +  // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
  1.3789 +  nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
  1.3790 +
  1.3791 +  bool isPointer = aMouseEvent->eventStructType == NS_POINTER_EVENT;
  1.3792 +  EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
  1.3793 +                                       aMouseEvent,
  1.3794 +                                       isPointer ? NS_POINTER_ENTER :
  1.3795 +                                                   NS_MOUSEENTER);
  1.3796 +
  1.3797 +  NotifyMouseOut(aMouseEvent, aContent);
  1.3798 +
  1.3799 +  // Store the first mouseOver event we fire and don't refire mouseOver
  1.3800 +  // to that element while the first mouseOver is still ongoing.
  1.3801 +  wrapper->mFirstOverEventElement = aContent;
  1.3802 +
  1.3803 +  if (!isPointer) {
  1.3804 +    SetContentState(aContent, NS_EVENT_STATE_HOVER);
  1.3805 +  }
  1.3806 +
  1.3807 +  // Fire mouseover
  1.3808 +  wrapper->mLastOverFrame =
  1.3809 +    DispatchMouseOrPointerEvent(aMouseEvent,
  1.3810 +                                isPointer ? NS_POINTER_OVER :
  1.3811 +                                            NS_MOUSE_ENTER_SYNTH,
  1.3812 +                                aContent, lastOverElement);
  1.3813 +  wrapper->mLastOverElement = aContent;
  1.3814 +
  1.3815 +  // Turn recursion protection back off
  1.3816 +  wrapper->mFirstOverEventElement = nullptr;
  1.3817 +}
  1.3818 +
  1.3819 +// Returns the center point of the window's inner content area.
  1.3820 +// This is in widget coordinates, i.e. relative to the widget's top
  1.3821 +// left corner, not in screen coordinates, the same units that
  1.3822 +// UIEvent::refPoint is in.
  1.3823 +//
  1.3824 +// XXX Hack alert: XXX
  1.3825 +// However, we do the computation in integer CSS pixels, NOT device pix,
  1.3826 +// in order to fudge around the one-pixel error in innerHeight in fullscreen
  1.3827 +// mode (see bug 799523 comment 35, and bug 729011). Using integer CSS pix
  1.3828 +// makes us throw away the fractional error that results, rather than having
  1.3829 +// it manifest as a potential one-device-pix discrepancy.
  1.3830 +static LayoutDeviceIntPoint
  1.3831 +GetWindowInnerRectCenter(nsPIDOMWindow* aWindow,
  1.3832 +                         nsIWidget* aWidget,
  1.3833 +                         nsPresContext* aContext)
  1.3834 +{
  1.3835 +  NS_ENSURE_TRUE(aWindow && aWidget && aContext, LayoutDeviceIntPoint(0, 0));
  1.3836 +
  1.3837 +  float cssInnerX = 0.0;
  1.3838 +  aWindow->GetMozInnerScreenX(&cssInnerX);
  1.3839 +  int32_t innerX = int32_t(NS_round(cssInnerX));
  1.3840 +
  1.3841 +  float cssInnerY = 0.0;
  1.3842 +  aWindow->GetMozInnerScreenY(&cssInnerY);
  1.3843 +  int32_t innerY = int32_t(NS_round(cssInnerY));
  1.3844 + 
  1.3845 +  int32_t innerWidth = 0;
  1.3846 +  aWindow->GetInnerWidth(&innerWidth);
  1.3847 +
  1.3848 +  int32_t innerHeight = 0;
  1.3849 +  aWindow->GetInnerHeight(&innerHeight);
  1.3850 +
  1.3851 +  nsIntRect screen;
  1.3852 +  aWidget->GetScreenBounds(screen);
  1.3853 +
  1.3854 +  int32_t cssScreenX = aContext->DevPixelsToIntCSSPixels(screen.x);
  1.3855 +  int32_t cssScreenY = aContext->DevPixelsToIntCSSPixels(screen.y);
  1.3856 +
  1.3857 +  return LayoutDeviceIntPoint(
  1.3858 +    aContext->CSSPixelsToDevPixels(innerX - cssScreenX + innerWidth / 2),
  1.3859 +    aContext->CSSPixelsToDevPixels(innerY - cssScreenY + innerHeight / 2));
  1.3860 +}
  1.3861 +
  1.3862 +void
  1.3863 +EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
  1.3864 +{
  1.3865 +  EnsureDocument(mPresContext);
  1.3866 +  if (!mDocument)
  1.3867 +    return;
  1.3868 +
  1.3869 +  // Hold onto old target content through the event and reset after.
  1.3870 +  nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
  1.3871 +
  1.3872 +  switch(aMouseEvent->message) {
  1.3873 +  case NS_MOUSE_MOVE:
  1.3874 +    {
  1.3875 +      // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
  1.3876 +      // Movement is calculated in UIEvent::GetMovementPoint() as:
  1.3877 +      //   previous_mousemove_refPoint - current_mousemove_refPoint.
  1.3878 +      if (sIsPointerLocked && aMouseEvent->widget) {
  1.3879 +        // The pointer is locked. If the pointer is not located at the center of
  1.3880 +        // the window, dispatch a synthetic mousemove to return the pointer there.
  1.3881 +        // Doing this between "real" pointer moves gives the impression that the
  1.3882 +        // (locked) pointer can continue moving and won't stop at the screen
  1.3883 +        // boundary. We cancel the synthetic event so that we don't end up
  1.3884 +        // dispatching the centering move event to content.
  1.3885 +        LayoutDeviceIntPoint center =
  1.3886 +          GetWindowInnerRectCenter(mDocument->GetWindow(), aMouseEvent->widget,
  1.3887 +                                   mPresContext);
  1.3888 +        aMouseEvent->lastRefPoint = center;
  1.3889 +        if (aMouseEvent->refPoint != center) {
  1.3890 +          // Mouse move doesn't finish at the center of the window. Dispatch a
  1.3891 +          // synthetic native mouse event to move the pointer back to the center
  1.3892 +          // of the window, to faciliate more movement. But first, record that
  1.3893 +          // we've dispatched a synthetic mouse movement, so we can cancel it
  1.3894 +          // in the other branch here.
  1.3895 +          sSynthCenteringPoint = center;
  1.3896 +          aMouseEvent->widget->SynthesizeNativeMouseMove(
  1.3897 +            LayoutDeviceIntPoint::ToUntyped(center) +
  1.3898 +              aMouseEvent->widget->WidgetToScreenOffset());
  1.3899 +        } else if (aMouseEvent->refPoint == sSynthCenteringPoint) {
  1.3900 +          // This is the "synthetic native" event we dispatched to re-center the
  1.3901 +          // pointer. Cancel it so we don't expose the centering move to content.
  1.3902 +          aMouseEvent->mFlags.mPropagationStopped = true;
  1.3903 +          // Clear sSynthCenteringPoint so we don't cancel other events
  1.3904 +          // targeted at the center.
  1.3905 +          sSynthCenteringPoint = kInvalidRefPoint;
  1.3906 +        }
  1.3907 +      } else if (sLastRefPoint == kInvalidRefPoint) {
  1.3908 +        // We don't have a valid previous mousemove refPoint. This is either
  1.3909 +        // the first move we've encountered, or the mouse has just re-entered
  1.3910 +        // the application window. We should report (0,0) movement for this
  1.3911 +        // case, so make the current and previous refPoints the same.
  1.3912 +        aMouseEvent->lastRefPoint = aMouseEvent->refPoint;
  1.3913 +      } else {
  1.3914 +        aMouseEvent->lastRefPoint = sLastRefPoint;
  1.3915 +      }
  1.3916 +
  1.3917 +      // Update the last known refPoint with the current refPoint.
  1.3918 +      sLastRefPoint = aMouseEvent->refPoint;
  1.3919 +
  1.3920 +    }
  1.3921 +  case NS_POINTER_MOVE:
  1.3922 +  case NS_POINTER_DOWN:
  1.3923 +    {
  1.3924 +      // Get the target content target (mousemove target == mouseover target)
  1.3925 +      nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
  1.3926 +      if (!targetElement) {
  1.3927 +        // We're always over the document root, even if we're only
  1.3928 +        // over dead space in a page (whose frame is not associated with
  1.3929 +        // any content) or in print preview dead space
  1.3930 +        targetElement = mDocument->GetRootElement();
  1.3931 +      }
  1.3932 +      if (targetElement) {
  1.3933 +        NotifyMouseOver(aMouseEvent, targetElement);
  1.3934 +      }
  1.3935 +    }
  1.3936 +    break;
  1.3937 +  case NS_POINTER_UP:
  1.3938 +    {
  1.3939 +      // Get the target content target (mousemove target == mouseover target)
  1.3940 +      nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
  1.3941 +      if (!targetElement) {
  1.3942 +        // We're always over the document root, even if we're only
  1.3943 +        // over dead space in a page (whose frame is not associated with
  1.3944 +        // any content) or in print preview dead space
  1.3945 +        targetElement = mDocument->GetRootElement();
  1.3946 +      }
  1.3947 +      if (targetElement) {
  1.3948 +        OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
  1.3949 +        if (helper) {
  1.3950 +          helper->mLastOverElement = targetElement;
  1.3951 +        }
  1.3952 +        NotifyMouseOut(aMouseEvent, nullptr);
  1.3953 +      }
  1.3954 +    }
  1.3955 +    break;
  1.3956 +  case NS_POINTER_LEAVE:
  1.3957 +  case NS_POINTER_CANCEL:
  1.3958 +  case NS_MOUSE_EXIT:
  1.3959 +    {
  1.3960 +      // This is actually the window mouse exit or pointer leave event. We're not moving
  1.3961 +      // into any new element.
  1.3962 +
  1.3963 +      OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
  1.3964 +      if (helper->mLastOverFrame &&
  1.3965 +          nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
  1.3966 +          nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
  1.3967 +        // the Mouse/PointerOut event widget doesn't have same top widget with
  1.3968 +        // mLastOverFrame, it's a spurious event for mLastOverFrame
  1.3969 +        break;
  1.3970 +      }
  1.3971 +
  1.3972 +      // Reset sLastRefPoint, so that we'll know not to report any
  1.3973 +      // movement the next time we re-enter the window.
  1.3974 +      sLastRefPoint = kInvalidRefPoint;
  1.3975 +
  1.3976 +      NotifyMouseOut(aMouseEvent, nullptr);
  1.3977 +    }
  1.3978 +    break;
  1.3979 +  }
  1.3980 +
  1.3981 +  // reset mCurretTargetContent to what it was
  1.3982 +  mCurrentTargetContent = targetBeforeEvent;
  1.3983 +}
  1.3984 +
  1.3985 +OverOutElementsWrapper*
  1.3986 +EventStateManager::GetWrapperByEventID(WidgetMouseEvent* aEvent)
  1.3987 +{
  1.3988 +  WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
  1.3989 +  if (!pointer) {
  1.3990 +    MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr);
  1.3991 +    if (!mMouseEnterLeaveHelper) {
  1.3992 +      mMouseEnterLeaveHelper = new OverOutElementsWrapper();
  1.3993 +    }
  1.3994 +    return mMouseEnterLeaveHelper;
  1.3995 +  }
  1.3996 +  nsRefPtr<OverOutElementsWrapper> helper;
  1.3997 +  if (!mPointersEnterLeaveHelper.Get(pointer->pointerId, getter_AddRefs(helper))) {
  1.3998 +    helper = new OverOutElementsWrapper();
  1.3999 +    mPointersEnterLeaveHelper.Put(pointer->pointerId, helper);
  1.4000 +  }
  1.4001 +
  1.4002 +  return helper;
  1.4003 +}
  1.4004 +
  1.4005 +void
  1.4006 +EventStateManager::SetPointerLock(nsIWidget* aWidget,
  1.4007 +                                  nsIContent* aElement)
  1.4008 +{
  1.4009 +  // NOTE: aElement will be nullptr when unlocking.
  1.4010 +  sIsPointerLocked = !!aElement;
  1.4011 +
  1.4012 +  if (!aWidget) {
  1.4013 +    return;
  1.4014 +  }
  1.4015 +
  1.4016 +  // Reset mouse wheel transaction
  1.4017 +  WheelTransaction::EndTransaction();
  1.4018 +
  1.4019 +  // Deal with DnD events
  1.4020 +  nsCOMPtr<nsIDragService> dragService =
  1.4021 +    do_GetService("@mozilla.org/widget/dragservice;1");
  1.4022 +
  1.4023 +  if (sIsPointerLocked) {
  1.4024 +    // Store the last known ref point so we can reposition the pointer after unlock.
  1.4025 +    mPreLockPoint = sLastRefPoint;
  1.4026 +
  1.4027 +    // Fire a synthetic mouse move to ensure event state is updated. We first
  1.4028 +    // set the mouse to the center of the window, so that the mouse event
  1.4029 +    // doesn't report any movement.
  1.4030 +    sLastRefPoint = GetWindowInnerRectCenter(aElement->OwnerDoc()->GetWindow(),
  1.4031 +                                             aWidget,
  1.4032 +                                             mPresContext);
  1.4033 +    aWidget->SynthesizeNativeMouseMove(
  1.4034 +      LayoutDeviceIntPoint::ToUntyped(sLastRefPoint) + aWidget->WidgetToScreenOffset());
  1.4035 +
  1.4036 +    // Retarget all events to this element via capture.
  1.4037 +    nsIPresShell::SetCapturingContent(aElement, CAPTURE_POINTERLOCK);
  1.4038 +
  1.4039 +    // Suppress DnD
  1.4040 +    if (dragService) {
  1.4041 +      dragService->Suppress();
  1.4042 +    }
  1.4043 +  } else {
  1.4044 +    // Unlocking, so return pointer to the original position by firing a
  1.4045 +    // synthetic mouse event. We first reset sLastRefPoint to its
  1.4046 +    // pre-pointerlock position, so that the synthetic mouse event reports
  1.4047 +    // no movement.
  1.4048 +    sLastRefPoint = mPreLockPoint;
  1.4049 +    aWidget->SynthesizeNativeMouseMove(
  1.4050 +      LayoutDeviceIntPoint::ToUntyped(mPreLockPoint) + aWidget->WidgetToScreenOffset());
  1.4051 +
  1.4052 +    // Don't retarget events to this element any more.
  1.4053 +    nsIPresShell::SetCapturingContent(nullptr, CAPTURE_POINTERLOCK);
  1.4054 +
  1.4055 +    // Unsuppress DnD
  1.4056 +    if (dragService) {
  1.4057 +      dragService->Unsuppress();
  1.4058 +    }
  1.4059 +  }
  1.4060 +}
  1.4061 +
  1.4062 +void
  1.4063 +EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
  1.4064 +                                             WidgetDragEvent* aDragEvent)
  1.4065 +{
  1.4066 +  //Hold onto old target content through the event and reset after.
  1.4067 +  nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
  1.4068 +
  1.4069 +  switch(aDragEvent->message) {
  1.4070 +  case NS_DRAGDROP_OVER:
  1.4071 +    {
  1.4072 +      // when dragging from one frame to another, events are fired in the
  1.4073 +      // order: dragexit, dragenter, dragleave
  1.4074 +      if (sLastDragOverFrame != mCurrentTarget) {
  1.4075 +        //We'll need the content, too, to check if it changed separately from the frames.
  1.4076 +        nsCOMPtr<nsIContent> lastContent;
  1.4077 +        nsCOMPtr<nsIContent> targetContent;
  1.4078 +        mCurrentTarget->GetContentForEvent(aDragEvent,
  1.4079 +                                           getter_AddRefs(targetContent));
  1.4080 +
  1.4081 +        if (sLastDragOverFrame) {
  1.4082 +          //The frame has changed but the content may not have. Check before dispatching to content
  1.4083 +          sLastDragOverFrame->GetContentForEvent(aDragEvent,
  1.4084 +                                                 getter_AddRefs(lastContent));
  1.4085 +
  1.4086 +          FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
  1.4087 +                              aDragEvent, NS_DRAGDROP_EXIT_SYNTH,
  1.4088 +                              targetContent, lastContent, sLastDragOverFrame);
  1.4089 +        }
  1.4090 +
  1.4091 +        FireDragEnterOrExit(aPresContext, aDragEvent, NS_DRAGDROP_ENTER,
  1.4092 +                            lastContent, targetContent, mCurrentTarget);
  1.4093 +
  1.4094 +        if (sLastDragOverFrame) {
  1.4095 +          FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
  1.4096 +                              aDragEvent, NS_DRAGDROP_LEAVE_SYNTH,
  1.4097 +                              targetContent, lastContent, sLastDragOverFrame);
  1.4098 +        }
  1.4099 +
  1.4100 +        sLastDragOverFrame = mCurrentTarget;
  1.4101 +      }
  1.4102 +    }
  1.4103 +    break;
  1.4104 +
  1.4105 +  case NS_DRAGDROP_EXIT:
  1.4106 +    {
  1.4107 +      //This is actually the window mouse exit event.
  1.4108 +      if (sLastDragOverFrame) {
  1.4109 +        nsCOMPtr<nsIContent> lastContent;
  1.4110 +        sLastDragOverFrame->GetContentForEvent(aDragEvent,
  1.4111 +                                               getter_AddRefs(lastContent));
  1.4112 +
  1.4113 +        nsRefPtr<nsPresContext> lastDragOverFramePresContext = sLastDragOverFrame->PresContext();
  1.4114 +        FireDragEnterOrExit(lastDragOverFramePresContext,
  1.4115 +                            aDragEvent, NS_DRAGDROP_EXIT_SYNTH,
  1.4116 +                            nullptr, lastContent, sLastDragOverFrame);
  1.4117 +        FireDragEnterOrExit(lastDragOverFramePresContext,
  1.4118 +                            aDragEvent, NS_DRAGDROP_LEAVE_SYNTH,
  1.4119 +                            nullptr, lastContent, sLastDragOverFrame);
  1.4120 +
  1.4121 +        sLastDragOverFrame = nullptr;
  1.4122 +      }
  1.4123 +    }
  1.4124 +    break;
  1.4125 +  }
  1.4126 +
  1.4127 +  //reset mCurretTargetContent to what it was
  1.4128 +  mCurrentTargetContent = targetBeforeEvent;
  1.4129 +
  1.4130 +  // Now flush all pending notifications, for better responsiveness.
  1.4131 +  FlushPendingEvents(aPresContext);
  1.4132 +}
  1.4133 +
  1.4134 +void
  1.4135 +EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
  1.4136 +                                       WidgetDragEvent* aDragEvent,
  1.4137 +                                       uint32_t aMsg,
  1.4138 +                                       nsIContent* aRelatedTarget,
  1.4139 +                                       nsIContent* aTargetContent,
  1.4140 +                                       nsWeakFrame& aTargetFrame)
  1.4141 +{
  1.4142 +  nsEventStatus status = nsEventStatus_eIgnore;
  1.4143 +  WidgetDragEvent event(aDragEvent->mFlags.mIsTrusted, aMsg,
  1.4144 +                        aDragEvent->widget);
  1.4145 +  event.refPoint = aDragEvent->refPoint;
  1.4146 +  event.modifiers = aDragEvent->modifiers;
  1.4147 +  event.buttons = aDragEvent->buttons;
  1.4148 +  event.relatedTarget = aRelatedTarget;
  1.4149 +  event.inputSource = aDragEvent->inputSource;
  1.4150 +
  1.4151 +  mCurrentTargetContent = aTargetContent;
  1.4152 +
  1.4153 +  if (aTargetContent != aRelatedTarget) {
  1.4154 +    //XXX This event should still go somewhere!!
  1.4155 +    if (aTargetContent) {
  1.4156 +      EventDispatcher::Dispatch(aTargetContent, aPresContext, &event,
  1.4157 +                                nullptr, &status);
  1.4158 +    }
  1.4159 +
  1.4160 +    // adjust the drag hover if the dragenter event was cancelled or this is a drag exit
  1.4161 +    if (status == nsEventStatus_eConsumeNoDefault || aMsg == NS_DRAGDROP_EXIT)
  1.4162 +      SetContentState((aMsg == NS_DRAGDROP_ENTER) ? aTargetContent : nullptr,
  1.4163 +                      NS_EVENT_STATE_DRAGOVER);
  1.4164 +
  1.4165 +    // collect any changes to moz cursor settings stored in the event's
  1.4166 +    // data transfer.
  1.4167 +    if (aMsg == NS_DRAGDROP_LEAVE_SYNTH || aMsg == NS_DRAGDROP_EXIT_SYNTH ||
  1.4168 +        aMsg == NS_DRAGDROP_ENTER)
  1.4169 +      UpdateDragDataTransfer(&event);
  1.4170 +  }
  1.4171 +
  1.4172 +  // Finally dispatch the event to the frame
  1.4173 +  if (aTargetFrame)
  1.4174 +    aTargetFrame->HandleEvent(aPresContext, &event, &status);
  1.4175 +}
  1.4176 +
  1.4177 +void
  1.4178 +EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent)
  1.4179 +{
  1.4180 +  NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!");
  1.4181 +  if (!dragEvent->dataTransfer)
  1.4182 +    return;
  1.4183 +
  1.4184 +  nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
  1.4185 +
  1.4186 +  if (dragSession) {
  1.4187 +    // the initial dataTransfer is the one from the dragstart event that
  1.4188 +    // was set on the dragSession when the drag began.
  1.4189 +    nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
  1.4190 +    dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
  1.4191 +    if (initialDataTransfer) {
  1.4192 +      // retrieve the current moz cursor setting and save it.
  1.4193 +      nsAutoString mozCursor;
  1.4194 +      dragEvent->dataTransfer->GetMozCursor(mozCursor);
  1.4195 +      initialDataTransfer->SetMozCursor(mozCursor);
  1.4196 +    }
  1.4197 +  }
  1.4198 +}
  1.4199 +
  1.4200 +nsresult
  1.4201 +EventStateManager::SetClickCount(nsPresContext* aPresContext,
  1.4202 +                                 WidgetMouseEvent* aEvent,
  1.4203 +                                 nsEventStatus* aStatus)
  1.4204 +{
  1.4205 +  nsCOMPtr<nsIContent> mouseContent;
  1.4206 +  nsIContent* mouseContentParent = nullptr;
  1.4207 +  mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
  1.4208 +  if (mouseContent) {
  1.4209 +    if (mouseContent->IsNodeOfType(nsINode::eTEXT)) {
  1.4210 +      mouseContent = mouseContent->GetParent();
  1.4211 +    }
  1.4212 +    if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
  1.4213 +      mouseContentParent = mouseContent->GetParent();
  1.4214 +    }
  1.4215 +  }
  1.4216 +
  1.4217 +  switch (aEvent->button) {
  1.4218 +  case WidgetMouseEvent::eLeftButton:
  1.4219 +    if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
  1.4220 +      mLastLeftMouseDownContent = mouseContent;
  1.4221 +      mLastLeftMouseDownContentParent = mouseContentParent;
  1.4222 +    } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
  1.4223 +      if (mLastLeftMouseDownContent == mouseContent ||
  1.4224 +          mLastLeftMouseDownContentParent == mouseContent ||
  1.4225 +          mLastLeftMouseDownContent == mouseContentParent) {
  1.4226 +        aEvent->clickCount = mLClickCount;
  1.4227 +        mLClickCount = 0;
  1.4228 +      } else {
  1.4229 +        aEvent->clickCount = 0;
  1.4230 +      }
  1.4231 +      mLastLeftMouseDownContent = nullptr;
  1.4232 +      mLastLeftMouseDownContentParent = nullptr;
  1.4233 +    }
  1.4234 +    break;
  1.4235 +
  1.4236 +  case WidgetMouseEvent::eMiddleButton:
  1.4237 +    if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
  1.4238 +      mLastMiddleMouseDownContent = mouseContent;
  1.4239 +      mLastMiddleMouseDownContentParent = mouseContentParent;
  1.4240 +    } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
  1.4241 +      if (mLastMiddleMouseDownContent == mouseContent ||
  1.4242 +          mLastMiddleMouseDownContentParent == mouseContent ||
  1.4243 +          mLastMiddleMouseDownContent == mouseContentParent) {
  1.4244 +        aEvent->clickCount = mMClickCount;
  1.4245 +        mMClickCount = 0;
  1.4246 +      } else {
  1.4247 +        aEvent->clickCount = 0;
  1.4248 +      }
  1.4249 +      mLastMiddleMouseDownContent = nullptr;
  1.4250 +      mLastMiddleMouseDownContentParent = nullptr;
  1.4251 +    }
  1.4252 +    break;
  1.4253 +
  1.4254 +  case WidgetMouseEvent::eRightButton:
  1.4255 +    if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
  1.4256 +      mLastRightMouseDownContent = mouseContent;
  1.4257 +      mLastRightMouseDownContentParent = mouseContentParent;
  1.4258 +    } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
  1.4259 +      if (mLastRightMouseDownContent == mouseContent ||
  1.4260 +          mLastRightMouseDownContentParent == mouseContent ||
  1.4261 +          mLastRightMouseDownContent == mouseContentParent) {
  1.4262 +        aEvent->clickCount = mRClickCount;
  1.4263 +        mRClickCount = 0;
  1.4264 +      } else {
  1.4265 +        aEvent->clickCount = 0;
  1.4266 +      }
  1.4267 +      mLastRightMouseDownContent = nullptr;
  1.4268 +      mLastRightMouseDownContentParent = nullptr;
  1.4269 +    }
  1.4270 +    break;
  1.4271 +  }
  1.4272 +
  1.4273 +  return NS_OK;
  1.4274 +}
  1.4275 +
  1.4276 +nsresult
  1.4277 +EventStateManager::CheckForAndDispatchClick(nsPresContext* aPresContext,
  1.4278 +                                            WidgetMouseEvent* aEvent,
  1.4279 +                                            nsEventStatus* aStatus)
  1.4280 +{
  1.4281 +  nsresult ret = NS_OK;
  1.4282 +
  1.4283 +  //If mouse is still over same element, clickcount will be > 1.
  1.4284 +  //If it has moved it will be zero, so no click.
  1.4285 +  if (0 != aEvent->clickCount) {
  1.4286 +    //Check that the window isn't disabled before firing a click
  1.4287 +    //(see bug 366544).
  1.4288 +    if (aEvent->widget && !aEvent->widget->IsEnabled()) {
  1.4289 +      return ret;
  1.4290 +    }
  1.4291 +    //fire click
  1.4292 +    bool notDispatchToContents =
  1.4293 +     (aEvent->button == WidgetMouseEvent::eMiddleButton ||
  1.4294 +      aEvent->button == WidgetMouseEvent::eRightButton);
  1.4295 +
  1.4296 +    WidgetMouseEvent event(aEvent->mFlags.mIsTrusted, NS_MOUSE_CLICK,
  1.4297 +                           aEvent->widget, WidgetMouseEvent::eReal);
  1.4298 +    event.refPoint = aEvent->refPoint;
  1.4299 +    event.clickCount = aEvent->clickCount;
  1.4300 +    event.modifiers = aEvent->modifiers;
  1.4301 +    event.buttons = aEvent->buttons;
  1.4302 +    event.time = aEvent->time;
  1.4303 +    event.mFlags.mNoContentDispatch = notDispatchToContents;
  1.4304 +    event.button = aEvent->button;
  1.4305 +    event.inputSource = aEvent->inputSource;
  1.4306 +
  1.4307 +    nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
  1.4308 +    if (presShell) {
  1.4309 +      nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
  1.4310 +      if (!mouseContent && !mCurrentTarget) {
  1.4311 +        return NS_OK;
  1.4312 +      }
  1.4313 +
  1.4314 +      // HandleEvent clears out mCurrentTarget which we might need again
  1.4315 +      nsWeakFrame currentTarget = mCurrentTarget;
  1.4316 +      ret = presShell->HandleEventWithTarget(&event, currentTarget,
  1.4317 +                                             mouseContent, aStatus);
  1.4318 +      if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) {
  1.4319 +        //fire double click
  1.4320 +        WidgetMouseEvent event2(aEvent->mFlags.mIsTrusted, NS_MOUSE_DOUBLECLICK,
  1.4321 +                                aEvent->widget, WidgetMouseEvent::eReal);
  1.4322 +        event2.refPoint = aEvent->refPoint;
  1.4323 +        event2.clickCount = aEvent->clickCount;
  1.4324 +        event2.modifiers = aEvent->modifiers;
  1.4325 +        event2.buttons = aEvent->buttons;
  1.4326 +        event2.mFlags.mNoContentDispatch = notDispatchToContents;
  1.4327 +        event2.button = aEvent->button;
  1.4328 +        event2.inputSource = aEvent->inputSource;
  1.4329 +
  1.4330 +        ret = presShell->HandleEventWithTarget(&event2, currentTarget,
  1.4331 +                                               mouseContent, aStatus);
  1.4332 +      }
  1.4333 +    }
  1.4334 +  }
  1.4335 +  return ret;
  1.4336 +}
  1.4337 +
  1.4338 +nsIFrame*
  1.4339 +EventStateManager::GetEventTarget()
  1.4340 +{
  1.4341 +  nsIPresShell *shell;
  1.4342 +  if (mCurrentTarget ||
  1.4343 +      !mPresContext ||
  1.4344 +      !(shell = mPresContext->GetPresShell())) {
  1.4345 +    return mCurrentTarget;
  1.4346 +  }
  1.4347 +
  1.4348 +  if (mCurrentTargetContent) {
  1.4349 +    mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
  1.4350 +    if (mCurrentTarget) {
  1.4351 +      return mCurrentTarget;
  1.4352 +    }
  1.4353 +  }
  1.4354 +
  1.4355 +  nsIFrame* frame = shell->GetEventTargetFrame();
  1.4356 +  return (mCurrentTarget = frame);
  1.4357 +}
  1.4358 +
  1.4359 +already_AddRefed<nsIContent>
  1.4360 +EventStateManager::GetEventTargetContent(WidgetEvent* aEvent)
  1.4361 +{
  1.4362 +  if (aEvent &&
  1.4363 +      (aEvent->message == NS_FOCUS_CONTENT ||
  1.4364 +       aEvent->message == NS_BLUR_CONTENT)) {
  1.4365 +    nsCOMPtr<nsIContent> content = GetFocusedContent();
  1.4366 +    return content.forget();
  1.4367 +  }
  1.4368 +
  1.4369 +  if (mCurrentTargetContent) {
  1.4370 +    nsCOMPtr<nsIContent> content = mCurrentTargetContent;
  1.4371 +    return content.forget();
  1.4372 +  }
  1.4373 +
  1.4374 +  nsCOMPtr<nsIContent> content;
  1.4375 +
  1.4376 +  nsIPresShell *presShell = mPresContext->GetPresShell();
  1.4377 +  if (presShell) {
  1.4378 +    content = presShell->GetEventTargetContent(aEvent);
  1.4379 +  }
  1.4380 +
  1.4381 +  // Some events here may set mCurrentTarget but not set the corresponding
  1.4382 +  // event target in the PresShell.
  1.4383 +  if (!content && mCurrentTarget) {
  1.4384 +    mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
  1.4385 +  }
  1.4386 +
  1.4387 +  return content.forget();
  1.4388 +}
  1.4389 +
  1.4390 +static Element*
  1.4391 +GetLabelTarget(nsIContent* aPossibleLabel)
  1.4392 +{
  1.4393 +  mozilla::dom::HTMLLabelElement* label =
  1.4394 +    mozilla::dom::HTMLLabelElement::FromContent(aPossibleLabel);
  1.4395 +  if (!label)
  1.4396 +    return nullptr;
  1.4397 +
  1.4398 +  return label->GetLabeledElement();
  1.4399 +}
  1.4400 +
  1.4401 +static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
  1.4402 +{
  1.4403 +  // Find closest common ancestor
  1.4404 +  if (aNode1 && aNode2) {
  1.4405 +    // Find the nearest common ancestor by counting the distance to the
  1.4406 +    // root and then walking up again, in pairs.
  1.4407 +    int32_t offset = 0;
  1.4408 +    nsIContent *anc1 = aNode1;
  1.4409 +    for (;;) {
  1.4410 +      ++offset;
  1.4411 +      nsIContent* parent = anc1->GetParent();
  1.4412 +      if (!parent)
  1.4413 +        break;
  1.4414 +      anc1 = parent;
  1.4415 +    }
  1.4416 +    nsIContent *anc2 = aNode2;
  1.4417 +    for (;;) {
  1.4418 +      --offset;
  1.4419 +      nsIContent* parent = anc2->GetParent();
  1.4420 +      if (!parent)
  1.4421 +        break;
  1.4422 +      anc2 = parent;
  1.4423 +    }
  1.4424 +    if (anc1 == anc2) {
  1.4425 +      anc1 = aNode1;
  1.4426 +      anc2 = aNode2;
  1.4427 +      while (offset > 0) {
  1.4428 +        anc1 = anc1->GetParent();
  1.4429 +        --offset;
  1.4430 +      }
  1.4431 +      while (offset < 0) {
  1.4432 +        anc2 = anc2->GetParent();
  1.4433 +        ++offset;
  1.4434 +      }
  1.4435 +      while (anc1 != anc2) {
  1.4436 +        anc1 = anc1->GetParent();
  1.4437 +        anc2 = anc2->GetParent();
  1.4438 +      }
  1.4439 +      return anc1;
  1.4440 +    }
  1.4441 +  }
  1.4442 +  return nullptr;
  1.4443 +}
  1.4444 +
  1.4445 +static Element*
  1.4446 +GetParentElement(Element* aElement)
  1.4447 +{
  1.4448 +  nsIContent* p = aElement->GetParent();
  1.4449 +  return (p && p->IsElement()) ? p->AsElement() : nullptr;
  1.4450 +}
  1.4451 +
  1.4452 +/* static */
  1.4453 +void
  1.4454 +EventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
  1.4455 +{
  1.4456 +  DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
  1.4457 +  Element* ancestor = aElement;
  1.4458 +  while ((ancestor = GetParentElement(ancestor))) {
  1.4459 +    DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen);
  1.4460 +  }
  1.4461 +}
  1.4462 +
  1.4463 +/* static */
  1.4464 +inline void
  1.4465 +EventStateManager::DoStateChange(Element* aElement, EventStates aState,
  1.4466 +                                 bool aAddState)
  1.4467 +{
  1.4468 +  if (aAddState) {
  1.4469 +    aElement->AddStates(aState);
  1.4470 +  } else {
  1.4471 +    aElement->RemoveStates(aState);
  1.4472 +  }
  1.4473 +}
  1.4474 +
  1.4475 +/* static */
  1.4476 +inline void
  1.4477 +EventStateManager::DoStateChange(nsIContent* aContent, EventStates aState,
  1.4478 +                                 bool aStateAdded)
  1.4479 +{
  1.4480 +  if (aContent->IsElement()) {
  1.4481 +    DoStateChange(aContent->AsElement(), aState, aStateAdded);
  1.4482 +  }
  1.4483 +}
  1.4484 +
  1.4485 +/* static */
  1.4486 +void
  1.4487 +EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
  1.4488 +                                       nsIContent* aStopBefore,
  1.4489 +                                       EventStates aState,
  1.4490 +                                       bool aAddState)
  1.4491 +{
  1.4492 +  for (; aStartNode && aStartNode != aStopBefore;
  1.4493 +       aStartNode = aStartNode->GetParent()) {
  1.4494 +    // We might be starting with a non-element (e.g. a text node) and
  1.4495 +    // if someone is doing something weird might be ending with a
  1.4496 +    // non-element too (e.g. a document fragment)
  1.4497 +    if (!aStartNode->IsElement()) {
  1.4498 +      continue;
  1.4499 +    }
  1.4500 +    Element* element = aStartNode->AsElement();
  1.4501 +    DoStateChange(element, aState, aAddState);
  1.4502 +    Element* labelTarget = GetLabelTarget(element);
  1.4503 +    if (labelTarget) {
  1.4504 +      DoStateChange(labelTarget, aState, aAddState);
  1.4505 +    }
  1.4506 +  }
  1.4507 +
  1.4508 +  if (aAddState) {
  1.4509 +    // We might be in a situation where a node was in hover both
  1.4510 +    // because it was hovered and because the label for it was
  1.4511 +    // hovered, and while we stopped hovering the node the label is
  1.4512 +    // still hovered.  Or we might have had two nested labels for the
  1.4513 +    // same node, and while one is no longer hovered the other still
  1.4514 +    // is.  In that situation, the label that's still hovered will be
  1.4515 +    // aStopBefore or some ancestor of it, and the call we just made
  1.4516 +    // to UpdateAncestorState with aAddState = false would have
  1.4517 +    // removed the hover state from the node.  But the node should
  1.4518 +    // still be in hover state.  To handle this situation we need to
  1.4519 +    // keep walking up the tree and any time we find a label mark its
  1.4520 +    // corresponding node as still in our state.
  1.4521 +    for ( ; aStartNode; aStartNode = aStartNode->GetParent()) {
  1.4522 +      if (!aStartNode->IsElement()) {
  1.4523 +        continue;
  1.4524 +      }
  1.4525 +
  1.4526 +      Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
  1.4527 +      if (labelTarget && !labelTarget->State().HasState(aState)) {
  1.4528 +        DoStateChange(labelTarget, aState, true);
  1.4529 +      }
  1.4530 +    }
  1.4531 +  }
  1.4532 +}
  1.4533 +
  1.4534 +bool
  1.4535 +EventStateManager::SetContentState(nsIContent* aContent, EventStates aState)
  1.4536 +{
  1.4537 +  // We manage 4 states here: ACTIVE, HOVER, DRAGOVER, URLTARGET
  1.4538 +  // The input must be exactly one of them.
  1.4539 +  NS_PRECONDITION(aState == NS_EVENT_STATE_ACTIVE ||
  1.4540 +                  aState == NS_EVENT_STATE_HOVER ||
  1.4541 +                  aState == NS_EVENT_STATE_DRAGOVER ||
  1.4542 +                  aState == NS_EVENT_STATE_URLTARGET,
  1.4543 +                  "Unexpected state");
  1.4544 +
  1.4545 +  nsCOMPtr<nsIContent> notifyContent1;
  1.4546 +  nsCOMPtr<nsIContent> notifyContent2;
  1.4547 +  bool updateAncestors;
  1.4548 +
  1.4549 +  if (aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE) {
  1.4550 +    // Hover and active are hierarchical
  1.4551 +    updateAncestors = true;
  1.4552 +
  1.4553 +    // check to see that this state is allowed by style. Check dragover too?
  1.4554 +    // XXX Is this even what we want?
  1.4555 +    if (mCurrentTarget)
  1.4556 +    {
  1.4557 +      const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface();
  1.4558 +      if (ui->mUserInput == NS_STYLE_USER_INPUT_NONE)
  1.4559 +        return false;
  1.4560 +    }
  1.4561 +
  1.4562 +    if (aState == NS_EVENT_STATE_ACTIVE) {
  1.4563 +      if (aContent != mActiveContent) {
  1.4564 +        notifyContent1 = aContent;
  1.4565 +        notifyContent2 = mActiveContent;
  1.4566 +        mActiveContent = aContent;
  1.4567 +      }
  1.4568 +    } else {
  1.4569 +      NS_ASSERTION(aState == NS_EVENT_STATE_HOVER, "How did that happen?");
  1.4570 +      nsIContent* newHover;
  1.4571 +      
  1.4572 +      if (mPresContext->IsDynamic()) {
  1.4573 +        newHover = aContent;
  1.4574 +      } else {
  1.4575 +        NS_ASSERTION(!aContent ||
  1.4576 +                     aContent->GetCurrentDoc() == mPresContext->PresShell()->GetDocument(),
  1.4577 +                     "Unexpected document");
  1.4578 +        nsIFrame *frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
  1.4579 +        if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
  1.4580 +          // The scrollbars of viewport should not ignore the hover state.
  1.4581 +          // Because they are *not* the content of the web page.
  1.4582 +          newHover = aContent;
  1.4583 +        } else {
  1.4584 +          // All contents of the web page should ignore the hover state.
  1.4585 +          newHover = nullptr;
  1.4586 +        }
  1.4587 +      }
  1.4588 +
  1.4589 +      if (newHover != mHoverContent) {
  1.4590 +        notifyContent1 = newHover;
  1.4591 +        notifyContent2 = mHoverContent;
  1.4592 +        mHoverContent = newHover;
  1.4593 +      }
  1.4594 +    }
  1.4595 +  } else {
  1.4596 +    updateAncestors = false;
  1.4597 +    if (aState == NS_EVENT_STATE_DRAGOVER) {
  1.4598 +      if (aContent != sDragOverContent) {
  1.4599 +        notifyContent1 = aContent;
  1.4600 +        notifyContent2 = sDragOverContent;
  1.4601 +        sDragOverContent = aContent;
  1.4602 +      }
  1.4603 +    } else if (aState == NS_EVENT_STATE_URLTARGET) {
  1.4604 +      if (aContent != mURLTargetContent) {
  1.4605 +        notifyContent1 = aContent;
  1.4606 +        notifyContent2 = mURLTargetContent;
  1.4607 +        mURLTargetContent = aContent;
  1.4608 +      }
  1.4609 +    }
  1.4610 +  }
  1.4611 +
  1.4612 +  // We need to keep track of which of notifyContent1 and notifyContent2 is
  1.4613 +  // getting the state set and which is getting it unset.  If both are
  1.4614 +  // non-null, then notifyContent1 is having the state set and notifyContent2
  1.4615 +  // is having it unset.  But if one of them is null, we need to keep track of
  1.4616 +  // the right thing for notifyContent1 explicitly.
  1.4617 +  bool content1StateSet = true;
  1.4618 +  if (!notifyContent1) {
  1.4619 +    // This is ok because FindCommonAncestor wouldn't find anything
  1.4620 +    // anyway if notifyContent1 is null.
  1.4621 +    notifyContent1 = notifyContent2;
  1.4622 +    notifyContent2 = nullptr;
  1.4623 +    content1StateSet = false;
  1.4624 +  }
  1.4625 +
  1.4626 +  if (notifyContent1 && mPresContext) {
  1.4627 +    EnsureDocument(mPresContext);
  1.4628 +    if (mDocument) {
  1.4629 +      nsAutoScriptBlocker scriptBlocker;
  1.4630 +
  1.4631 +      if (updateAncestors) {
  1.4632 +        nsCOMPtr<nsIContent> commonAncestor =
  1.4633 +          FindCommonAncestor(notifyContent1, notifyContent2);
  1.4634 +        if (notifyContent2) {
  1.4635 +          // It's very important to first notify the state removal and
  1.4636 +          // then the state addition, because due to labels it's
  1.4637 +          // possible that we're removing state from some element but
  1.4638 +          // then adding it again (say because mHoverContent changed
  1.4639 +          // from a control to its label).
  1.4640 +          UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
  1.4641 +        }
  1.4642 +        UpdateAncestorState(notifyContent1, commonAncestor, aState,
  1.4643 +                            content1StateSet);
  1.4644 +      } else {
  1.4645 +        if (notifyContent2) {
  1.4646 +          DoStateChange(notifyContent2, aState, false);
  1.4647 +        }
  1.4648 +        DoStateChange(notifyContent1, aState, content1StateSet);
  1.4649 +      }
  1.4650 +    }
  1.4651 +  }
  1.4652 +
  1.4653 +  return true;
  1.4654 +}
  1.4655 +
  1.4656 +PLDHashOperator
  1.4657 +EventStateManager::ResetLastOverForContent(
  1.4658 +                     const uint32_t& aIdx,
  1.4659 +                     nsRefPtr<OverOutElementsWrapper>& aElemWrapper,
  1.4660 +                     void* aClosure)
  1.4661 +{
  1.4662 +  nsIContent* content = static_cast<nsIContent*>(aClosure);
  1.4663 +  if (aElemWrapper && aElemWrapper->mLastOverElement &&
  1.4664 +      nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement, content)) {
  1.4665 +    aElemWrapper->mLastOverElement = nullptr;
  1.4666 +  }
  1.4667 +
  1.4668 +  return PL_DHASH_NEXT;
  1.4669 +}
  1.4670 +
  1.4671 +void
  1.4672 +EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
  1.4673 +{
  1.4674 +  /*
  1.4675 +   * Anchor and area elements when focused or hovered might make the UI to show
  1.4676 +   * the current link. We want to make sure that the UI gets informed when they
  1.4677 +   * are actually removed from the DOM.
  1.4678 +   */
  1.4679 +  if (aContent->IsHTML() &&
  1.4680 +      (aContent->Tag() == nsGkAtoms::a || aContent->Tag() == nsGkAtoms::area) &&
  1.4681 +      (aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS |
  1.4682 +                                                            NS_EVENT_STATE_HOVER))) {
  1.4683 +    nsGenericHTMLElement* element = static_cast<nsGenericHTMLElement*>(aContent);
  1.4684 +    element->LeaveLink(element->GetPresContext());
  1.4685 +  }
  1.4686 +
  1.4687 +  IMEStateManager::OnRemoveContent(mPresContext, aContent);
  1.4688 +
  1.4689 +  // inform the focus manager that the content is being removed. If this
  1.4690 +  // content is focused, the focus will be removed without firing events.
  1.4691 +  nsFocusManager* fm = nsFocusManager::GetFocusManager();
  1.4692 +  if (fm)
  1.4693 +    fm->ContentRemoved(aDocument, aContent);
  1.4694 +
  1.4695 +  if (mHoverContent &&
  1.4696 +      nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) {
  1.4697 +    // Since hover is hierarchical, set the current hover to the
  1.4698 +    // content's parent node.
  1.4699 +    SetContentState(aContent->GetParent(), NS_EVENT_STATE_HOVER);
  1.4700 +  }
  1.4701 +
  1.4702 +  if (mActiveContent &&
  1.4703 +      nsContentUtils::ContentIsDescendantOf(mActiveContent, aContent)) {
  1.4704 +    // Active is hierarchical, so set the current active to the
  1.4705 +    // content's parent node.
  1.4706 +    SetContentState(aContent->GetParent(), NS_EVENT_STATE_ACTIVE);
  1.4707 +  }
  1.4708 +
  1.4709 +  if (sDragOverContent &&
  1.4710 +      sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
  1.4711 +      nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) {
  1.4712 +    sDragOverContent = nullptr;
  1.4713 +  }
  1.4714 +
  1.4715 +  // See bug 292146 for why we want to null this out
  1.4716 +  ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
  1.4717 +  mPointersEnterLeaveHelper.Enumerate(
  1.4718 +    &EventStateManager::ResetLastOverForContent, aContent);
  1.4719 +}
  1.4720 +
  1.4721 +bool
  1.4722 +EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent)
  1.4723 +{
  1.4724 +  return !(aEvent->message == NS_MOUSE_BUTTON_DOWN &&
  1.4725 +           aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
  1.4726 +           !sNormalLMouseEventInProcess);
  1.4727 +}
  1.4728 +
  1.4729 +//-------------------------------------------
  1.4730 +// Access Key Registration
  1.4731 +//-------------------------------------------
  1.4732 +void
  1.4733 +EventStateManager::RegisterAccessKey(nsIContent* aContent, uint32_t aKey)
  1.4734 +{
  1.4735 +  if (aContent && mAccessKeys.IndexOf(aContent) == -1)
  1.4736 +    mAccessKeys.AppendObject(aContent);
  1.4737 +}
  1.4738 +
  1.4739 +void
  1.4740 +EventStateManager::UnregisterAccessKey(nsIContent* aContent, uint32_t aKey)
  1.4741 +{
  1.4742 +  if (aContent)
  1.4743 +    mAccessKeys.RemoveObject(aContent);
  1.4744 +}
  1.4745 +
  1.4746 +uint32_t
  1.4747 +EventStateManager::GetRegisteredAccessKey(nsIContent* aContent)
  1.4748 +{
  1.4749 +  MOZ_ASSERT(aContent);
  1.4750 +
  1.4751 +  if (mAccessKeys.IndexOf(aContent) == -1)
  1.4752 +    return 0;
  1.4753 +
  1.4754 +  nsAutoString accessKey;
  1.4755 +  aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
  1.4756 +  return accessKey.First();
  1.4757 +}
  1.4758 +
  1.4759 +void
  1.4760 +EventStateManager::EnsureDocument(nsPresContext* aPresContext)
  1.4761 +{
  1.4762 +  if (!mDocument)
  1.4763 +    mDocument = aPresContext->Document();
  1.4764 +}
  1.4765 +
  1.4766 +void
  1.4767 +EventStateManager::FlushPendingEvents(nsPresContext* aPresContext)
  1.4768 +{
  1.4769 +  NS_PRECONDITION(nullptr != aPresContext, "nullptr ptr");
  1.4770 +  nsIPresShell *shell = aPresContext->GetPresShell();
  1.4771 +  if (shell) {
  1.4772 +    shell->FlushPendingNotifications(Flush_InterruptibleLayout);
  1.4773 +  }
  1.4774 +}
  1.4775 +
  1.4776 +nsIContent*
  1.4777 +EventStateManager::GetFocusedContent()
  1.4778 +{
  1.4779 +  nsIFocusManager* fm = nsFocusManager::GetFocusManager();
  1.4780 +  if (!fm || !mDocument)
  1.4781 +    return nullptr;
  1.4782 +
  1.4783 +  nsCOMPtr<nsPIDOMWindow> focusedWindow;
  1.4784 +  return nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(), false,
  1.4785 +                                              getter_AddRefs(focusedWindow));
  1.4786 +}
  1.4787 +
  1.4788 +//-------------------------------------------------------
  1.4789 +// Return true if the docshell is visible
  1.4790 +
  1.4791 +bool
  1.4792 +EventStateManager::IsShellVisible(nsIDocShell* aShell)
  1.4793 +{
  1.4794 +  NS_ASSERTION(aShell, "docshell is null");
  1.4795 +
  1.4796 +  nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
  1.4797 +  if (!basewin)
  1.4798 +    return true;
  1.4799 +
  1.4800 +  bool isVisible = true;
  1.4801 +  basewin->GetVisibility(&isVisible);
  1.4802 +
  1.4803 +  // We should be doing some additional checks here so that
  1.4804 +  // we don't tab into hidden tabs of tabbrowser.  -bryner
  1.4805 +
  1.4806 +  return isVisible;
  1.4807 +}
  1.4808 +
  1.4809 +nsresult
  1.4810 +EventStateManager::DoContentCommandEvent(WidgetContentCommandEvent* aEvent)
  1.4811 +{
  1.4812 +  EnsureDocument(mPresContext);
  1.4813 +  NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
  1.4814 +  nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow());
  1.4815 +  NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
  1.4816 +
  1.4817 +  nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
  1.4818 +  NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
  1.4819 +  const char* cmd;
  1.4820 +  switch (aEvent->message) {
  1.4821 +    case NS_CONTENT_COMMAND_CUT:
  1.4822 +      cmd = "cmd_cut";
  1.4823 +      break;
  1.4824 +    case NS_CONTENT_COMMAND_COPY:
  1.4825 +      cmd = "cmd_copy";
  1.4826 +      break;
  1.4827 +    case NS_CONTENT_COMMAND_PASTE:
  1.4828 +      cmd = "cmd_paste";
  1.4829 +      break;
  1.4830 +    case NS_CONTENT_COMMAND_DELETE:
  1.4831 +      cmd = "cmd_delete";
  1.4832 +      break;
  1.4833 +    case NS_CONTENT_COMMAND_UNDO:
  1.4834 +      cmd = "cmd_undo";
  1.4835 +      break;
  1.4836 +    case NS_CONTENT_COMMAND_REDO:
  1.4837 +      cmd = "cmd_redo";
  1.4838 +      break;
  1.4839 +    case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE:
  1.4840 +      cmd = "cmd_pasteTransferable";
  1.4841 +      break;
  1.4842 +    default:
  1.4843 +      return NS_ERROR_NOT_IMPLEMENTED;
  1.4844 +  }
  1.4845 +  nsCOMPtr<nsIController> controller;
  1.4846 +  nsresult rv = root->GetControllerForCommand(cmd, getter_AddRefs(controller));
  1.4847 +  NS_ENSURE_SUCCESS(rv, rv);
  1.4848 +  if (!controller) {
  1.4849 +    // When GetControllerForCommand succeeded but there is no controller, the
  1.4850 +    // command isn't supported.
  1.4851 +    aEvent->mIsEnabled = false;
  1.4852 +  } else {
  1.4853 +    bool canDoIt;
  1.4854 +    rv = controller->IsCommandEnabled(cmd, &canDoIt);
  1.4855 +    NS_ENSURE_SUCCESS(rv, rv);
  1.4856 +    aEvent->mIsEnabled = canDoIt;
  1.4857 +    if (canDoIt && !aEvent->mOnlyEnabledCheck) {
  1.4858 +      switch (aEvent->message) {
  1.4859 +        case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: {
  1.4860 +          nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
  1.4861 +          NS_ENSURE_STATE(commandController);
  1.4862 +
  1.4863 +          nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
  1.4864 +          NS_ENSURE_SUCCESS(rv, rv);
  1.4865 +
  1.4866 +          rv = params->SetISupportsValue("transferable", aEvent->mTransferable);
  1.4867 +          NS_ENSURE_SUCCESS(rv, rv);
  1.4868 +
  1.4869 +          rv = commandController->DoCommandWithParams(cmd, params);
  1.4870 +          break;
  1.4871 +        }
  1.4872 +        
  1.4873 +        default:
  1.4874 +          rv = controller->DoCommand(cmd);
  1.4875 +          break;
  1.4876 +      }
  1.4877 +      NS_ENSURE_SUCCESS(rv, rv);
  1.4878 +    }
  1.4879 +  }
  1.4880 +  aEvent->mSucceeded = true;
  1.4881 +  return NS_OK;
  1.4882 +}
  1.4883 +
  1.4884 +nsresult
  1.4885 +EventStateManager::DoContentCommandScrollEvent(
  1.4886 +                     WidgetContentCommandEvent* aEvent)
  1.4887 +{
  1.4888 +  NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
  1.4889 +  nsIPresShell* ps = mPresContext->GetPresShell();
  1.4890 +  NS_ENSURE_TRUE(ps, NS_ERROR_NOT_AVAILABLE);
  1.4891 +  NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG);
  1.4892 +
  1.4893 +  nsIScrollableFrame::ScrollUnit scrollUnit;
  1.4894 +  switch (aEvent->mScroll.mUnit) {
  1.4895 +    case WidgetContentCommandEvent::eCmdScrollUnit_Line:
  1.4896 +      scrollUnit = nsIScrollableFrame::LINES;
  1.4897 +      break;
  1.4898 +    case WidgetContentCommandEvent::eCmdScrollUnit_Page:
  1.4899 +      scrollUnit = nsIScrollableFrame::PAGES;
  1.4900 +      break;
  1.4901 +    case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
  1.4902 +      scrollUnit = nsIScrollableFrame::WHOLE;
  1.4903 +      break;
  1.4904 +    default:
  1.4905 +      return NS_ERROR_INVALID_ARG;
  1.4906 +  }
  1.4907 +
  1.4908 +  aEvent->mSucceeded = true;
  1.4909 +
  1.4910 +  nsIScrollableFrame* sf =
  1.4911 +    ps->GetFrameToScrollAsScrollable(nsIPresShell::eEither);
  1.4912 +  aEvent->mIsEnabled = sf ?
  1.4913 +    (aEvent->mScroll.mIsHorizontal ?
  1.4914 +      WheelHandlingUtils::CanScrollOn(sf, aEvent->mScroll.mAmount, 0) :
  1.4915 +      WheelHandlingUtils::CanScrollOn(sf, 0, aEvent->mScroll.mAmount)) : false;
  1.4916 +
  1.4917 +  if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
  1.4918 +    return NS_OK;
  1.4919 +  }
  1.4920 +
  1.4921 +  nsIntPoint pt(0, 0);
  1.4922 +  if (aEvent->mScroll.mIsHorizontal) {
  1.4923 +    pt.x = aEvent->mScroll.mAmount;
  1.4924 +  } else {
  1.4925 +    pt.y = aEvent->mScroll.mAmount;
  1.4926 +  }
  1.4927 +
  1.4928 +  // The caller may want synchronous scrolling.
  1.4929 +  sf->ScrollBy(pt, scrollUnit, nsIScrollableFrame::INSTANT);
  1.4930 +  return NS_OK;
  1.4931 +}
  1.4932 +
  1.4933 +void
  1.4934 +EventStateManager::DoQuerySelectedText(WidgetQueryContentEvent* aEvent)
  1.4935 +{
  1.4936 +  if (RemoteQueryContentEvent(aEvent)) {
  1.4937 +    return;
  1.4938 +  }
  1.4939 +  ContentEventHandler handler(mPresContext);
  1.4940 +  handler.OnQuerySelectedText(aEvent);
  1.4941 +}
  1.4942 +
  1.4943 +void
  1.4944 +EventStateManager::SetActiveManager(EventStateManager* aNewESM,
  1.4945 +                                    nsIContent* aContent)
  1.4946 +{
  1.4947 +  if (sActiveESM && aNewESM != sActiveESM) {
  1.4948 +    sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
  1.4949 +  }
  1.4950 +  sActiveESM = aNewESM;
  1.4951 +  if (sActiveESM && aContent) {
  1.4952 +    sActiveESM->SetContentState(aContent, NS_EVENT_STATE_ACTIVE);
  1.4953 +  }
  1.4954 +}
  1.4955 +
  1.4956 +void
  1.4957 +EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer)
  1.4958 +{
  1.4959 +  if (aClearer) {
  1.4960 +    aClearer->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
  1.4961 +    if (sDragOverContent) {
  1.4962 +      aClearer->SetContentState(nullptr, NS_EVENT_STATE_DRAGOVER);
  1.4963 +    }
  1.4964 +  }
  1.4965 +  if (sActiveESM && aClearer != sActiveESM) {
  1.4966 +    sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
  1.4967 +  }
  1.4968 +  sActiveESM = nullptr;
  1.4969 +}
  1.4970 +
  1.4971 +/******************************************************************/
  1.4972 +/* mozilla::EventStateManager::DeltaAccumulator                   */
  1.4973 +/******************************************************************/
  1.4974 +
  1.4975 +void
  1.4976 +EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
  1.4977 +                                       nsIFrame* aTargetFrame,
  1.4978 +                                       EventStateManager* aESM,
  1.4979 +                                       WidgetWheelEvent* aEvent)
  1.4980 +{
  1.4981 +  MOZ_ASSERT(aESM);
  1.4982 +  MOZ_ASSERT(aEvent);
  1.4983 +
  1.4984 +  // Reset if the previous wheel event is too old.
  1.4985 +  if (!mLastTime.IsNull()) {
  1.4986 +    TimeDuration duration = TimeStamp::Now() - mLastTime;
  1.4987 +    if (duration.ToMilliseconds() > WheelTransaction::GetTimeoutTime()) {
  1.4988 +      Reset();
  1.4989 +    }
  1.4990 +  }
  1.4991 +  // If we have accumulated delta,  we may need to reset it.
  1.4992 +  if (IsInTransaction()) {
  1.4993 +    // If wheel event type is changed, reset the values.
  1.4994 +    if (mHandlingDeltaMode != aEvent->deltaMode ||
  1.4995 +        mHandlingPixelOnlyDevice != aEvent->isPixelOnlyDevice) {
  1.4996 +      Reset();
  1.4997 +    } else {
  1.4998 +      // If the delta direction is changed, we should reset only the
  1.4999 +      // accumulated values.
  1.5000 +      if (mX && aEvent->deltaX && ((aEvent->deltaX > 0.0) != (mX > 0.0))) {
  1.5001 +        mX = mPendingScrollAmountX = 0.0;
  1.5002 +      }
  1.5003 +      if (mY && aEvent->deltaY && ((aEvent->deltaY > 0.0) != (mY > 0.0))) {
  1.5004 +        mY = mPendingScrollAmountY = 0.0;
  1.5005 +      }
  1.5006 +    }
  1.5007 +  }
  1.5008 +
  1.5009 +  mHandlingDeltaMode = aEvent->deltaMode;
  1.5010 +  mHandlingPixelOnlyDevice = aEvent->isPixelOnlyDevice;
  1.5011 +
  1.5012 +  // If it's handling neither pixel scroll mode for pixel only device nor
  1.5013 +  // delta values multiplied by prefs, we must not modify lineOrPageDelta
  1.5014 +  // values.
  1.5015 +  if (!(mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL &&
  1.5016 +        mHandlingPixelOnlyDevice) &&
  1.5017 +      !EventStateManager::WheelPrefs::GetInstance()->
  1.5018 +        NeedToComputeLineOrPageDelta(aEvent)) {
  1.5019 +    // Set the delta values to mX and mY.  They would be used when above block
  1.5020 +    // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
  1.5021 +    // is changed.
  1.5022 +    // NOTE: We shouldn't accumulate the delta values, it might could cause
  1.5023 +    //       overflow even though it's not a realistic situation.
  1.5024 +    if (aEvent->deltaX) {
  1.5025 +      mX = aEvent->deltaX;
  1.5026 +    }
  1.5027 +    if (aEvent->deltaY) {
  1.5028 +      mY = aEvent->deltaY;
  1.5029 +    }
  1.5030 +    mLastTime = TimeStamp::Now();
  1.5031 +    return;
  1.5032 +  }
  1.5033 +
  1.5034 +  mX += aEvent->deltaX;
  1.5035 +  mY += aEvent->deltaY;
  1.5036 +
  1.5037 +  if (mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
  1.5038 +    // Records pixel delta values and init lineOrPageDeltaX and
  1.5039 +    // lineOrPageDeltaY for wheel events which are caused by pixel only
  1.5040 +    // devices.  Ignore mouse wheel transaction for computing this.  The
  1.5041 +    // lineOrPageDelta values will be used by dispatching legacy
  1.5042 +    // NS_MOUSE_SCROLL_EVENT (DOMMouseScroll) but not be used for scrolling
  1.5043 +    // of default action.  The transaction should be used only for the default
  1.5044 +    // action.
  1.5045 +    nsIScrollableFrame* scrollTarget =
  1.5046 +      aESM->ComputeScrollTarget(aTargetFrame, aEvent,
  1.5047 +                                COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
  1.5048 +    nsIFrame* frame = do_QueryFrame(scrollTarget);
  1.5049 +    nsPresContext* pc =
  1.5050 +      frame ? frame->PresContext() : aTargetFrame->PresContext();
  1.5051 +    nsSize scrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
  1.5052 +    nsIntSize scrollAmountInCSSPixels(
  1.5053 +      nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),
  1.5054 +      nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height));
  1.5055 +
  1.5056 +    aEvent->lineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
  1.5057 +    aEvent->lineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
  1.5058 +
  1.5059 +    mX -= aEvent->lineOrPageDeltaX * scrollAmountInCSSPixels.width;
  1.5060 +    mY -= aEvent->lineOrPageDeltaY * scrollAmountInCSSPixels.height;
  1.5061 +  } else {
  1.5062 +    aEvent->lineOrPageDeltaX = RoundDown(mX);
  1.5063 +    aEvent->lineOrPageDeltaY = RoundDown(mY);
  1.5064 +    mX -= aEvent->lineOrPageDeltaX;
  1.5065 +    mY -= aEvent->lineOrPageDeltaY;
  1.5066 +  }
  1.5067 +
  1.5068 +  mLastTime = TimeStamp::Now();
  1.5069 +}
  1.5070 +
  1.5071 +void
  1.5072 +EventStateManager::DeltaAccumulator::Reset()
  1.5073 +{
  1.5074 +  mX = mY = 0.0;
  1.5075 +  mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
  1.5076 +  mHandlingDeltaMode = UINT32_MAX;
  1.5077 +  mHandlingPixelOnlyDevice = false;
  1.5078 +}
  1.5079 +
  1.5080 +nsIntPoint
  1.5081 +EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
  1.5082 +                     WidgetWheelEvent* aEvent,
  1.5083 +                     const nsIntSize& aScrollAmountInDevPixels)
  1.5084 +{
  1.5085 +  MOZ_ASSERT(aEvent);
  1.5086 +
  1.5087 +  // If the wheel event is line scroll and the delta value is computed from
  1.5088 +  // system settings, allow to override the system speed.
  1.5089 +  bool allowScrollSpeedOverride =
  1.5090 +    (!aEvent->customizedByUserPrefs &&
  1.5091 +     aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE);
  1.5092 +  DeltaValues acceleratedDelta =
  1.5093 +    WheelTransaction::AccelerateWheelDelta(aEvent, allowScrollSpeedOverride);
  1.5094 +
  1.5095 +  nsIntPoint result(0, 0);
  1.5096 +  if (aEvent->deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
  1.5097 +    mPendingScrollAmountX += acceleratedDelta.deltaX;
  1.5098 +    mPendingScrollAmountY += acceleratedDelta.deltaY;
  1.5099 +  } else {
  1.5100 +    mPendingScrollAmountX +=
  1.5101 +      aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
  1.5102 +    mPendingScrollAmountY +=
  1.5103 +      aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
  1.5104 +  }
  1.5105 +  result.x = RoundDown(mPendingScrollAmountX);
  1.5106 +  result.y = RoundDown(mPendingScrollAmountY);
  1.5107 +  mPendingScrollAmountX -= result.x;
  1.5108 +  mPendingScrollAmountY -= result.y;
  1.5109 +
  1.5110 +  return result;
  1.5111 +}
  1.5112 +
  1.5113 +/******************************************************************/
  1.5114 +/* mozilla::EventStateManager::WheelPrefs                         */
  1.5115 +/******************************************************************/
  1.5116 +
  1.5117 +// static
  1.5118 +EventStateManager::WheelPrefs*
  1.5119 +EventStateManager::WheelPrefs::GetInstance()
  1.5120 +{
  1.5121 +  if (!sInstance) {
  1.5122 +    sInstance = new WheelPrefs();
  1.5123 +  }
  1.5124 +  return sInstance;
  1.5125 +}
  1.5126 +
  1.5127 +// static
  1.5128 +void
  1.5129 +EventStateManager::WheelPrefs::Shutdown()
  1.5130 +{
  1.5131 +  delete sInstance;
  1.5132 +  sInstance = nullptr;
  1.5133 +}
  1.5134 +
  1.5135 +// static
  1.5136 +void
  1.5137 +EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
  1.5138 +                                             void* aClosure)
  1.5139 +{
  1.5140 +  // forget all prefs, it's not problem for performance.
  1.5141 +  sInstance->Reset();
  1.5142 +  DeltaAccumulator::GetInstance()->Reset();
  1.5143 +}
  1.5144 +
  1.5145 +EventStateManager::WheelPrefs::WheelPrefs()
  1.5146 +{
  1.5147 +  Reset();
  1.5148 +  Preferences::RegisterCallback(OnPrefChanged, "mousewheel.", nullptr);
  1.5149 +}
  1.5150 +
  1.5151 +EventStateManager::WheelPrefs::~WheelPrefs()
  1.5152 +{
  1.5153 +  Preferences::UnregisterCallback(OnPrefChanged, "mousewheel.", nullptr);
  1.5154 +}
  1.5155 +
  1.5156 +void
  1.5157 +EventStateManager::WheelPrefs::Reset()
  1.5158 +{
  1.5159 +  memset(mInit, 0, sizeof(mInit));
  1.5160 +
  1.5161 +}
  1.5162 +
  1.5163 +EventStateManager::WheelPrefs::Index
  1.5164 +EventStateManager::WheelPrefs::GetIndexFor(WidgetWheelEvent* aEvent)
  1.5165 +{
  1.5166 +  if (!aEvent) {
  1.5167 +    return INDEX_DEFAULT;
  1.5168 +  }
  1.5169 +
  1.5170 +  Modifiers modifiers =
  1.5171 +    (aEvent->modifiers & (MODIFIER_ALT |
  1.5172 +                          MODIFIER_CONTROL |
  1.5173 +                          MODIFIER_META |
  1.5174 +                          MODIFIER_SHIFT |
  1.5175 +                          MODIFIER_OS));
  1.5176 +
  1.5177 +  switch (modifiers) {
  1.5178 +    case MODIFIER_ALT:
  1.5179 +      return INDEX_ALT;
  1.5180 +    case MODIFIER_CONTROL:
  1.5181 +      return INDEX_CONTROL;
  1.5182 +    case MODIFIER_META:
  1.5183 +      return INDEX_META;
  1.5184 +    case MODIFIER_SHIFT:
  1.5185 +      return INDEX_SHIFT;
  1.5186 +    case MODIFIER_OS:
  1.5187 +      return INDEX_OS;
  1.5188 +    default:
  1.5189 +      // If two or more modifier keys are pressed, we should use default
  1.5190 +      // settings.
  1.5191 +      return INDEX_DEFAULT;
  1.5192 +  }
  1.5193 +}
  1.5194 +
  1.5195 +void
  1.5196 +EventStateManager::WheelPrefs::GetBasePrefName(
  1.5197 +                     EventStateManager::WheelPrefs::Index aIndex,
  1.5198 +                     nsACString& aBasePrefName)
  1.5199 +{
  1.5200 +  aBasePrefName.AssignLiteral("mousewheel.");
  1.5201 +  switch (aIndex) {
  1.5202 +    case INDEX_ALT:
  1.5203 +      aBasePrefName.AppendLiteral("with_alt.");
  1.5204 +      break;
  1.5205 +    case INDEX_CONTROL:
  1.5206 +      aBasePrefName.AppendLiteral("with_control.");
  1.5207 +      break;
  1.5208 +    case INDEX_META:
  1.5209 +      aBasePrefName.AppendLiteral("with_meta.");
  1.5210 +      break;
  1.5211 +    case INDEX_SHIFT:
  1.5212 +      aBasePrefName.AppendLiteral("with_shift.");
  1.5213 +      break;
  1.5214 +    case INDEX_OS:
  1.5215 +      aBasePrefName.AppendLiteral("with_win.");
  1.5216 +      break;
  1.5217 +    case INDEX_DEFAULT:
  1.5218 +    default:
  1.5219 +      aBasePrefName.AppendLiteral("default.");
  1.5220 +      break;
  1.5221 +  }
  1.5222 +}
  1.5223 +
  1.5224 +void
  1.5225 +EventStateManager::WheelPrefs::Init(EventStateManager::WheelPrefs::Index aIndex)
  1.5226 +{
  1.5227 +  if (mInit[aIndex]) {
  1.5228 +    return;
  1.5229 +  }
  1.5230 +  mInit[aIndex] = true;
  1.5231 +
  1.5232 +  nsAutoCString basePrefName;
  1.5233 +  GetBasePrefName(aIndex, basePrefName);
  1.5234 +
  1.5235 +  nsAutoCString prefNameX(basePrefName);
  1.5236 +  prefNameX.AppendLiteral("delta_multiplier_x");
  1.5237 +  mMultiplierX[aIndex] =
  1.5238 +    static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
  1.5239 +
  1.5240 +  nsAutoCString prefNameY(basePrefName);
  1.5241 +  prefNameY.AppendLiteral("delta_multiplier_y");
  1.5242 +  mMultiplierY[aIndex] =
  1.5243 +    static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
  1.5244 +
  1.5245 +  nsAutoCString prefNameZ(basePrefName);
  1.5246 +  prefNameZ.AppendLiteral("delta_multiplier_z");
  1.5247 +  mMultiplierZ[aIndex] =
  1.5248 +    static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
  1.5249 +
  1.5250 +  nsAutoCString prefNameAction(basePrefName);
  1.5251 +  prefNameAction.AppendLiteral("action");
  1.5252 +  int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
  1.5253 +  if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
  1.5254 +    NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.");
  1.5255 +    action = ACTION_SCROLL;
  1.5256 +  }
  1.5257 +  mActions[aIndex] = static_cast<Action>(action);
  1.5258 +
  1.5259 +  // Compute action values overridden by .override_x pref.
  1.5260 +  // At present, override is possible only for the x-direction
  1.5261 +  // because this pref is introduced mainly for tilt wheels.
  1.5262 +  prefNameAction.AppendLiteral(".override_x");
  1.5263 +  int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
  1.5264 +  if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST)) {
  1.5265 +    NS_WARNING("Unsupported action override pref value, didn't override.");
  1.5266 +    actionOverrideX = -1;
  1.5267 +  }
  1.5268 +  mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
  1.5269 +                              ? static_cast<Action>(action)
  1.5270 +                              : static_cast<Action>(actionOverrideX);
  1.5271 +}
  1.5272 +
  1.5273 +void
  1.5274 +EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent)
  1.5275 +{
  1.5276 +  Index index = GetIndexFor(aEvent);
  1.5277 +  Init(index);
  1.5278 +
  1.5279 +  aEvent->deltaX *= mMultiplierX[index];
  1.5280 +  aEvent->deltaY *= mMultiplierY[index];
  1.5281 +  aEvent->deltaZ *= mMultiplierZ[index];
  1.5282 +
  1.5283 +  // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
  1.5284 +  // value, we should use lineOrPageDelta values which were set by widget.
  1.5285 +  // Otherwise, we need to compute them from accumulated delta values.
  1.5286 +  if (!NeedToComputeLineOrPageDelta(aEvent)) {
  1.5287 +    aEvent->lineOrPageDeltaX *= static_cast<int32_t>(mMultiplierX[index]);
  1.5288 +    aEvent->lineOrPageDeltaY *= static_cast<int32_t>(mMultiplierY[index]);
  1.5289 +  } else {
  1.5290 +    aEvent->lineOrPageDeltaX = 0;
  1.5291 +    aEvent->lineOrPageDeltaY = 0;
  1.5292 +  }
  1.5293 +
  1.5294 +  aEvent->customizedByUserPrefs =
  1.5295 +    ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
  1.5296 +     (mMultiplierZ[index] != 1.0));
  1.5297 +}
  1.5298 +
  1.5299 +void
  1.5300 +EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
  1.5301 +                                 WidgetWheelEvent* aEvent)
  1.5302 +{
  1.5303 +  Index index = GetIndexFor(aEvent);
  1.5304 +  Init(index);
  1.5305 +
  1.5306 +  // XXX If the multiplier pref value is negative, the scroll direction was
  1.5307 +  //     changed and caused to scroll different direction.  In such case,
  1.5308 +  //     this method reverts the sign of overflowDelta.  Does it make widget
  1.5309 +  //     happy?  Although, widget can know the pref applied delta values by
  1.5310 +  //     referrencing the deltaX and deltaY of the event.
  1.5311 +
  1.5312 +  if (mMultiplierX[index]) {
  1.5313 +    aEvent->overflowDeltaX /= mMultiplierX[index];
  1.5314 +  }
  1.5315 +  if (mMultiplierY[index]) {
  1.5316 +    aEvent->overflowDeltaY /= mMultiplierY[index];
  1.5317 +  }
  1.5318 +}
  1.5319 +
  1.5320 +EventStateManager::WheelPrefs::Action
  1.5321 +EventStateManager::WheelPrefs::ComputeActionFor(WidgetWheelEvent* aEvent)
  1.5322 +{
  1.5323 +  Index index = GetIndexFor(aEvent);
  1.5324 +  Init(index);
  1.5325 +
  1.5326 +  bool deltaXPreferred =
  1.5327 +    (Abs(aEvent->deltaX) > Abs(aEvent->deltaY) &&
  1.5328 +     Abs(aEvent->deltaX) > Abs(aEvent->deltaZ));
  1.5329 +  Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
  1.5330 +  if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL) {
  1.5331 +    return actions[index];
  1.5332 +  }
  1.5333 +
  1.5334 +  // Momentum events shouldn't run special actions.
  1.5335 +  if (aEvent->isMomentum) {
  1.5336 +    // Use the default action.  Note that user might kill the wheel scrolling.
  1.5337 +    Init(INDEX_DEFAULT);
  1.5338 +    return (actions[INDEX_DEFAULT] == ACTION_SCROLL) ? ACTION_SCROLL :
  1.5339 +                                                       ACTION_NONE;
  1.5340 +  }
  1.5341 +
  1.5342 +  return actions[index];
  1.5343 +}
  1.5344 +
  1.5345 +bool
  1.5346 +EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
  1.5347 +                                 WidgetWheelEvent* aEvent)
  1.5348 +{
  1.5349 +  Index index = GetIndexFor(aEvent);
  1.5350 +  Init(index);
  1.5351 +
  1.5352 +  return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
  1.5353 +         (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
  1.5354 +}
  1.5355 +
  1.5356 +bool
  1.5357 +EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
  1.5358 +                                 WidgetWheelEvent* aEvent)
  1.5359 +{
  1.5360 +  Index index = GetIndexFor(aEvent);
  1.5361 +  Init(index);
  1.5362 +  return Abs(mMultiplierX[index]) >=
  1.5363 +           MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
  1.5364 +}
  1.5365 +
  1.5366 +bool
  1.5367 +EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
  1.5368 +                                 WidgetWheelEvent* aEvent)
  1.5369 +{
  1.5370 +  Index index = GetIndexFor(aEvent);
  1.5371 +  Init(index);
  1.5372 +  return Abs(mMultiplierY[index]) >=
  1.5373 +           MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
  1.5374 +}
  1.5375 +
  1.5376 +/******************************************************************/
  1.5377 +/* mozilla::EventStateManager::Prefs                              */
  1.5378 +/******************************************************************/
  1.5379 +
  1.5380 +bool EventStateManager::Prefs::sKeyCausesActivation = true;
  1.5381 +bool EventStateManager::Prefs::sClickHoldContextMenu = false;
  1.5382 +int32_t EventStateManager::Prefs::sGenericAccessModifierKey = -1;
  1.5383 +int32_t EventStateManager::Prefs::sChromeAccessModifierMask = 0;
  1.5384 +int32_t EventStateManager::Prefs::sContentAccessModifierMask = 0;
  1.5385 +
  1.5386 +// static
  1.5387 +void
  1.5388 +EventStateManager::Prefs::Init()
  1.5389 +{
  1.5390 +  DebugOnly<nsresult> rv =
  1.5391 +    Preferences::AddBoolVarCache(&sKeyCausesActivation,
  1.5392 +                                 "accessibility.accesskeycausesactivation",
  1.5393 +                                 sKeyCausesActivation);
  1.5394 +  MOZ_ASSERT(NS_SUCCEEDED(rv),
  1.5395 +             "Failed to observe \"accessibility.accesskeycausesactivation\"");
  1.5396 +  rv = Preferences::AddBoolVarCache(&sClickHoldContextMenu,
  1.5397 +                                    "ui.click_hold_context_menus",
  1.5398 +                                    sClickHoldContextMenu);
  1.5399 +  MOZ_ASSERT(NS_SUCCEEDED(rv),
  1.5400 +             "Failed to observe \"ui.click_hold_context_menus\"");
  1.5401 +  rv = Preferences::AddIntVarCache(&sGenericAccessModifierKey,
  1.5402 +                                   "ui.key.generalAccessKey",
  1.5403 +                                   sGenericAccessModifierKey);
  1.5404 +  MOZ_ASSERT(NS_SUCCEEDED(rv),
  1.5405 +             "Failed to observe \"ui.key.generalAccessKey\"");
  1.5406 +  rv = Preferences::AddIntVarCache(&sChromeAccessModifierMask,
  1.5407 +                                   "ui.key.chromeAccess",
  1.5408 +                                   sChromeAccessModifierMask);
  1.5409 +  MOZ_ASSERT(NS_SUCCEEDED(rv),
  1.5410 +             "Failed to observe \"ui.key.chromeAccess\"");
  1.5411 +  rv = Preferences::AddIntVarCache(&sContentAccessModifierMask,
  1.5412 +                                   "ui.key.contentAccess",
  1.5413 +                                   sContentAccessModifierMask);
  1.5414 +  MOZ_ASSERT(NS_SUCCEEDED(rv),
  1.5415 +             "Failed to observe \"ui.key.contentAccess\"");
  1.5416 +
  1.5417 +  rv = Preferences::RegisterCallback(OnChange, "dom.popup_allowed_events");
  1.5418 +  MOZ_ASSERT(NS_SUCCEEDED(rv),
  1.5419 +             "Failed to observe \"dom.popup_allowed_events\"");
  1.5420 +}
  1.5421 +
  1.5422 +// static
  1.5423 +void
  1.5424 +EventStateManager::Prefs::OnChange(const char* aPrefName, void*)
  1.5425 +{
  1.5426 +  nsDependentCString prefName(aPrefName);
  1.5427 +  if (prefName.EqualsLiteral("dom.popup_allowed_events")) {
  1.5428 +    Event::PopupAllowedEventsChanged();
  1.5429 +  }
  1.5430 +}
  1.5431 +
  1.5432 +// static
  1.5433 +void
  1.5434 +EventStateManager::Prefs::Shutdown()
  1.5435 +{
  1.5436 +  Preferences::UnregisterCallback(OnChange, "dom.popup_allowed_events");
  1.5437 +}
  1.5438 +
  1.5439 +// static
  1.5440 +int32_t
  1.5441 +EventStateManager::Prefs::ChromeAccessModifierMask()
  1.5442 +{
  1.5443 +  return GetAccessModifierMask(nsIDocShellTreeItem::typeChrome);
  1.5444 +}
  1.5445 +
  1.5446 +// static
  1.5447 +int32_t
  1.5448 +EventStateManager::Prefs::ContentAccessModifierMask()
  1.5449 +{
  1.5450 +  return GetAccessModifierMask(nsIDocShellTreeItem::typeContent);
  1.5451 +}
  1.5452 +
  1.5453 +// static
  1.5454 +int32_t
  1.5455 +EventStateManager::Prefs::GetAccessModifierMask(int32_t aItemType)
  1.5456 +{
  1.5457 +  switch (sGenericAccessModifierKey) {
  1.5458 +    case -1:                             break; // use the individual prefs
  1.5459 +    case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
  1.5460 +    case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
  1.5461 +    case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
  1.5462 +    case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
  1.5463 +    case nsIDOMKeyEvent::DOM_VK_WIN:     return NS_MODIFIER_OS;
  1.5464 +    default:                             return 0;
  1.5465 +  }
  1.5466 +
  1.5467 +  switch (aItemType) {
  1.5468 +    case nsIDocShellTreeItem::typeChrome:
  1.5469 +      return sChromeAccessModifierMask;
  1.5470 +    case nsIDocShellTreeItem::typeContent:
  1.5471 +      return sContentAccessModifierMask;
  1.5472 +    default:
  1.5473 +      return 0;
  1.5474 +  }
  1.5475 +}
  1.5476 +
  1.5477 +/******************************************************************/
  1.5478 +/* mozilla::AutoHandlingUserInputStatePusher                      */
  1.5479 +/******************************************************************/
  1.5480 +
  1.5481 +AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
  1.5482 +                                    bool aIsHandlingUserInput,
  1.5483 +                                    WidgetEvent* aEvent,
  1.5484 +                                    nsIDocument* aDocument) :
  1.5485 +  mIsHandlingUserInput(aIsHandlingUserInput),
  1.5486 +  mIsMouseDown(aEvent && aEvent->message == NS_MOUSE_BUTTON_DOWN),
  1.5487 +  mResetFMMouseDownState(false)
  1.5488 +{
  1.5489 +  if (!aIsHandlingUserInput) {
  1.5490 +    return;
  1.5491 +  }
  1.5492 +  EventStateManager::StartHandlingUserInput();
  1.5493 +  if (!mIsMouseDown) {
  1.5494 +    return;
  1.5495 +  }
  1.5496 +  nsIPresShell::SetCapturingContent(nullptr, 0);
  1.5497 +  nsIPresShell::AllowMouseCapture(true);
  1.5498 +  if (!aDocument || !aEvent->mFlags.mIsTrusted) {
  1.5499 +    return;
  1.5500 +  }
  1.5501 +  nsFocusManager* fm = nsFocusManager::GetFocusManager();
  1.5502 +  NS_ENSURE_TRUE_VOID(fm);
  1.5503 +  fm->SetMouseButtonDownHandlingDocument(aDocument);
  1.5504 +  mResetFMMouseDownState = true;
  1.5505 +}
  1.5506 +
  1.5507 +AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher()
  1.5508 +{
  1.5509 +  if (!mIsHandlingUserInput) {
  1.5510 +    return;
  1.5511 +  }
  1.5512 +  EventStateManager::StopHandlingUserInput();
  1.5513 +  if (!mIsMouseDown) {
  1.5514 +    return;
  1.5515 +  }
  1.5516 +  nsIPresShell::AllowMouseCapture(false);
  1.5517 +  if (!mResetFMMouseDownState) {
  1.5518 +    return;
  1.5519 +  }
  1.5520 +  nsFocusManager* fm = nsFocusManager::GetFocusManager();
  1.5521 +  NS_ENSURE_TRUE_VOID(fm);
  1.5522 +  fm->SetMouseButtonDownHandlingDocument(nullptr);
  1.5523 +}
  1.5524 +
  1.5525 +} // namespace mozilla
  1.5526 +

mercurial