LCOV - code coverage report
Current view: top level - dom/events - EventStateManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 529 2730 19.4 %
Date: 2017-07-14 16:53:18 Functions: 62 160 38.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/Attributes.h"
       8             : #include "mozilla/EventDispatcher.h"
       9             : #include "mozilla/EventStateManager.h"
      10             : #include "mozilla/EventStates.h"
      11             : #include "mozilla/IMEStateManager.h"
      12             : #include "mozilla/MiscEvents.h"
      13             : #include "mozilla/MathAlgorithms.h"
      14             : #include "mozilla/MouseEvents.h"
      15             : #include "mozilla/TextComposition.h"
      16             : #include "mozilla/TextEvents.h"
      17             : #include "mozilla/TouchEvents.h"
      18             : #include "mozilla/dom/ContentChild.h"
      19             : #include "mozilla/dom/DragEvent.h"
      20             : #include "mozilla/dom/Event.h"
      21             : #include "mozilla/dom/TabChild.h"
      22             : #include "mozilla/dom/TabParent.h"
      23             : #include "mozilla/dom/UIEvent.h"
      24             : 
      25             : #include "ContentEventHandler.h"
      26             : #include "IMEContentObserver.h"
      27             : #include "WheelHandlingHelper.h"
      28             : 
      29             : #include "nsCOMPtr.h"
      30             : #include "nsFocusManager.h"
      31             : #include "nsIContent.h"
      32             : #include "nsIContentInlines.h"
      33             : #include "nsIDocument.h"
      34             : #include "nsIFrame.h"
      35             : #include "nsIWidget.h"
      36             : #include "nsPresContext.h"
      37             : #include "nsIPresShell.h"
      38             : #include "nsGkAtoms.h"
      39             : #include "nsIFormControl.h"
      40             : #include "nsIComboboxControlFrame.h"
      41             : #include "nsIScrollableFrame.h"
      42             : #include "nsIDOMHTMLElement.h"
      43             : #include "nsIDOMXULControlElement.h"
      44             : #include "nsNameSpaceManager.h"
      45             : #include "nsIBaseWindow.h"
      46             : #include "nsISelection.h"
      47             : #include "nsITextControlElement.h"
      48             : #include "nsFrameSelection.h"
      49             : #include "nsPIDOMWindow.h"
      50             : #include "nsPIWindowRoot.h"
      51             : #include "nsIWebNavigation.h"
      52             : #include "nsIContentViewer.h"
      53             : #include "nsFrameManager.h"
      54             : #include "nsITabChild.h"
      55             : #include "nsPluginFrame.h"
      56             : #include "nsMenuPopupFrame.h"
      57             : 
      58             : #include "nsIDOMXULElement.h"
      59             : #include "nsIDOMKeyEvent.h"
      60             : #include "nsIObserverService.h"
      61             : #include "nsIDocShell.h"
      62             : #include "nsIDOMWheelEvent.h"
      63             : #include "nsIDOMUIEvent.h"
      64             : #include "nsIMozBrowserFrame.h"
      65             : 
      66             : #include "nsSubDocumentFrame.h"
      67             : #include "nsLayoutUtils.h"
      68             : #include "nsIInterfaceRequestorUtils.h"
      69             : #include "nsUnicharUtils.h"
      70             : #include "nsContentUtils.h"
      71             : 
      72             : #include "imgIContainer.h"
      73             : #include "nsIProperties.h"
      74             : #include "nsISupportsPrimitives.h"
      75             : 
      76             : #include "nsServiceManagerUtils.h"
      77             : #include "nsITimer.h"
      78             : #include "nsFontMetrics.h"
      79             : #include "nsIDOMXULDocument.h"
      80             : #include "nsIDragService.h"
      81             : #include "nsIDragSession.h"
      82             : #include "mozilla/dom/DataTransfer.h"
      83             : #include "nsContentAreaDragDrop.h"
      84             : #ifdef MOZ_XUL
      85             : #include "nsTreeBodyFrame.h"
      86             : #endif
      87             : #include "nsIController.h"
      88             : #include "nsICommandParams.h"
      89             : #include "mozilla/Services.h"
      90             : #include "mozilla/dom/ContentParent.h"
      91             : #include "mozilla/dom/HTMLLabelElement.h"
      92             : 
      93             : #include "mozilla/Preferences.h"
      94             : #include "mozilla/LookAndFeel.h"
      95             : #include "GeckoProfiler.h"
      96             : #include "Units.h"
      97             : #include "mozilla/layers/APZCTreeManager.h"
      98             : #include "nsIObjectLoadingContent.h"
      99             : 
     100             : #ifdef XP_MACOSX
     101             : #import <ApplicationServices/ApplicationServices.h>
     102             : #endif
     103             : 
     104             : namespace mozilla {
     105             : 
     106             : using namespace dom;
     107             : 
     108             : //#define DEBUG_DOCSHELL_FOCUS
     109             : 
     110             : #define NS_USER_INTERACTION_INTERVAL 5000 // ms
     111             : 
     112           3 : static const LayoutDeviceIntPoint kInvalidRefPoint = LayoutDeviceIntPoint(-1,-1);
     113             : 
     114             : static uint32_t gMouseOrKeyboardEventCounter = 0;
     115             : static nsITimer* gUserInteractionTimer = nullptr;
     116             : static nsITimerCallback* gUserInteractionTimerCallback = nullptr;
     117             : 
     118             : static const double kCursorLoadingTimeout = 1000; // ms
     119           3 : static AutoWeakFrame gLastCursorSourceFrame;
     120             : static TimeStamp gLastCursorUpdateTime;
     121             : 
     122             : static inline int32_t
     123           0 : RoundDown(double aDouble)
     124             : {
     125           0 :   return (aDouble > 0) ? static_cast<int32_t>(floor(aDouble)) :
     126           0 :                          static_cast<int32_t>(ceil(aDouble));
     127             : }
     128             : 
     129             : #ifdef DEBUG_DOCSHELL_FOCUS
     130             : static void
     131             : PrintDocTree(nsIDocShellTreeItem* aParentItem, int aLevel)
     132             : {
     133             :   for (int32_t i=0;i<aLevel;i++) printf("  ");
     134             : 
     135             :   int32_t childWebshellCount;
     136             :   aParentItem->GetChildCount(&childWebshellCount);
     137             :   nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentItem));
     138             :   int32_t type = aParentItem->ItemType();
     139             :   nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
     140             :   RefPtr<nsPresContext> presContext;
     141             :   parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
     142             :   nsCOMPtr<nsIContentViewer> cv;
     143             :   parentAsDocShell->GetContentViewer(getter_AddRefs(cv));
     144             :   nsCOMPtr<nsIDOMDocument> domDoc;
     145             :   if (cv)
     146             :     cv->GetDOMDocument(getter_AddRefs(domDoc));
     147             :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
     148             :   nsCOMPtr<nsIDOMWindow> domwin = doc ? doc->GetWindow() : nullptr;
     149             :   nsIURI* uri = doc ? doc->GetDocumentURI() : nullptr;
     150             : 
     151             :   printf("DS %p  Type %s  Cnt %d  Doc %p  DW %p  EM %p%c",
     152             :     static_cast<void*>(parentAsDocShell.get()),
     153             :     type==nsIDocShellTreeItem::typeChrome?"Chrome":"Content",
     154             :     childWebshellCount, static_cast<void*>(doc.get()),
     155             :     static_cast<void*>(domwin.get()),
     156             :     static_cast<void*>(presContext ? presContext->EventStateManager() : nullptr),
     157             :     uri ? ' ' : '\n');
     158             :   if (uri) {
     159             :     nsAutoCString spec;
     160             :     uri->GetSpec(spec);
     161             :     printf("\"%s\"\n", spec.get());
     162             :   }
     163             : 
     164             :   if (childWebshellCount > 0) {
     165             :     for (int32_t i = 0; i < childWebshellCount; i++) {
     166             :       nsCOMPtr<nsIDocShellTreeItem> child;
     167             :       aParentItem->GetChildAt(i, getter_AddRefs(child));
     168             :       PrintDocTree(child, aLevel + 1);
     169             :     }
     170             :   }
     171             : }
     172             : 
     173             : static void
     174             : PrintDocTreeAll(nsIDocShellTreeItem* aItem)
     175             : {
     176             :   nsCOMPtr<nsIDocShellTreeItem> item = aItem;
     177             :   for(;;) {
     178             :     nsCOMPtr<nsIDocShellTreeItem> parent;
     179             :     item->GetParent(getter_AddRefs(parent));
     180             :     if (!parent)
     181             :       break;
     182             :     item = parent;
     183             :   }
     184             : 
     185             :   PrintDocTree(item, 0);
     186             : }
     187             : #endif
     188             : 
     189             : // mask values for ui.key.chromeAccess and ui.key.contentAccess
     190             : #define NS_MODIFIER_SHIFT    1
     191             : #define NS_MODIFIER_CONTROL  2
     192             : #define NS_MODIFIER_ALT      4
     193             : #define NS_MODIFIER_META     8
     194             : #define NS_MODIFIER_OS       16
     195             : 
     196             : /******************************************************************/
     197             : /* mozilla::UITimerCallback                                       */
     198             : /******************************************************************/
     199             : 
     200             : class UITimerCallback final :
     201             :     public nsITimerCallback,
     202             :     public nsINamed
     203             : {
     204             : public:
     205           2 :   UITimerCallback() : mPreviousCount(0) {}
     206             :   NS_DECL_ISUPPORTS
     207             :   NS_DECL_NSITIMERCALLBACK
     208             :   NS_DECL_NSINAMED
     209             : private:
     210             :   ~UITimerCallback() = default;
     211             :   uint32_t mPreviousCount;
     212             : };
     213             : 
     214          16 : NS_IMPL_ISUPPORTS(UITimerCallback, nsITimerCallback, nsINamed)
     215             : 
     216             : // If aTimer is nullptr, this method always sends "user-interaction-inactive"
     217             : // notification.
     218             : NS_IMETHODIMP
     219           2 : UITimerCallback::Notify(nsITimer* aTimer)
     220             : {
     221             :   nsCOMPtr<nsIObserverService> obs =
     222           4 :     mozilla::services::GetObserverService();
     223           2 :   if (!obs)
     224           0 :     return NS_ERROR_FAILURE;
     225           2 :   if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
     226           2 :     gMouseOrKeyboardEventCounter = 0;
     227           2 :     obs->NotifyObservers(nullptr, "user-interaction-inactive", nullptr);
     228           4 :     if (gUserInteractionTimer) {
     229           2 :       gUserInteractionTimer->Cancel();
     230           2 :       NS_RELEASE(gUserInteractionTimer);
     231             :     }
     232             :   } else {
     233           0 :     obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
     234           0 :     EventStateManager::UpdateUserActivityTimer();
     235             :   }
     236           2 :   mPreviousCount = gMouseOrKeyboardEventCounter;
     237           2 :   return NS_OK;
     238             : }
     239             : 
     240             : NS_IMETHODIMP
     241           3 : UITimerCallback::GetName(nsACString& aName)
     242             : {
     243           3 :   aName.AssignASCII("UITimerCallback_timer");
     244           3 :   return NS_OK;
     245             : }
     246             : 
     247             : NS_IMETHODIMP
     248           0 : UITimerCallback::SetName(const char* aName)
     249             : {
     250           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     251             : }
     252             : 
     253             : /******************************************************************/
     254             : /* mozilla::OverOutElementsWrapper                                */
     255             : /******************************************************************/
     256             : 
     257           2 : OverOutElementsWrapper::OverOutElementsWrapper()
     258           2 :   : mLastOverFrame(nullptr)
     259             : {
     260           2 : }
     261             : 
     262             : OverOutElementsWrapper::~OverOutElementsWrapper() = default;
     263             : 
     264           0 : NS_IMPL_CYCLE_COLLECTION(OverOutElementsWrapper,
     265             :                          mLastOverElement,
     266             :                          mFirstOverEventElement,
     267             :                          mFirstOutEventElement)
     268           2 : NS_IMPL_CYCLE_COLLECTING_ADDREF(OverOutElementsWrapper)
     269           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(OverOutElementsWrapper)
     270             : 
     271           2 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(OverOutElementsWrapper)
     272           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     273           0 : NS_INTERFACE_MAP_END
     274             : 
     275             : /******************************************************************/
     276             : /* mozilla::EventStateManager                                     */
     277             : /******************************************************************/
     278             : 
     279             : static uint32_t sESMInstanceCount = 0;
     280             : static bool sPointerEventEnabled = false;
     281             : 
     282             : uint64_t EventStateManager::sUserInputCounter = 0;
     283             : int32_t EventStateManager::sUserInputEventDepth = 0;
     284             : bool EventStateManager::sNormalLMouseEventInProcess = false;
     285             : EventStateManager* EventStateManager::sActiveESM = nullptr;
     286             : nsIDocument* EventStateManager::sMouseOverDocument = nullptr;
     287           3 : AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
     288           3 : LayoutDeviceIntPoint EventStateManager::sPreLockPoint = LayoutDeviceIntPoint(0, 0);
     289           3 : LayoutDeviceIntPoint EventStateManager::sLastRefPoint = kInvalidRefPoint;
     290           3 : CSSIntPoint EventStateManager::sLastScreenPoint = CSSIntPoint(0, 0);
     291           3 : LayoutDeviceIntPoint EventStateManager::sSynthCenteringPoint = kInvalidRefPoint;
     292           3 : CSSIntPoint EventStateManager::sLastClientPoint = CSSIntPoint(0, 0);
     293             : bool EventStateManager::sIsPointerLocked = false;
     294             : // Reference to the pointer locked element.
     295           3 : nsWeakPtr EventStateManager::sPointerLockedElement;
     296             : // Reference to the document which requested pointer lock.
     297           3 : nsWeakPtr EventStateManager::sPointerLockedDoc;
     298           3 : nsCOMPtr<nsIContent> EventStateManager::sDragOverContent = nullptr;
     299             : TimeStamp EventStateManager::sLatestUserInputStart;
     300             : TimeStamp EventStateManager::sHandlingInputStart;
     301             : 
     302             : EventStateManager::WheelPrefs*
     303             :   EventStateManager::WheelPrefs::sInstance = nullptr;
     304             : bool EventStateManager::WheelPrefs::sWheelEventsEnabledOnPlugins = true;
     305             : EventStateManager::DeltaAccumulator*
     306             :   EventStateManager::DeltaAccumulator::sInstance = nullptr;
     307             : 
     308          28 : EventStateManager::EventStateManager()
     309             :   : mLockCursor(0)
     310             :   , mLastFrameConsumedSetCursor(false)
     311             :   , mCurrentTarget(nullptr)
     312             :     // init d&d gesture state machine variables
     313             :   , mGestureDownPoint(0,0)
     314             :   , mPresContext(nullptr)
     315             :   , mLClickCount(0)
     316             :   , mMClickCount(0)
     317             :   , mRClickCount(0)
     318             :   , mInTouchDrag(false)
     319          28 :   , m_haveShutdown(false)
     320             : {
     321          28 :   if (sESMInstanceCount == 0) {
     322           2 :     gUserInteractionTimerCallback = new UITimerCallback();
     323           2 :     if (gUserInteractionTimerCallback)
     324           2 :       NS_ADDREF(gUserInteractionTimerCallback);
     325           2 :     UpdateUserActivityTimer();
     326             :   }
     327          28 :   ++sESMInstanceCount;
     328             : 
     329             :   static bool sAddedPointerEventEnabled = false;
     330          28 :   if (!sAddedPointerEventEnabled) {
     331             :     Preferences::AddBoolVarCache(&sPointerEventEnabled,
     332           2 :                                  "dom.w3c_pointer_events.enabled", false);
     333           2 :     sAddedPointerEventEnabled = true;
     334             :   }
     335          28 :   WheelTransaction::InitializeStatics();
     336          28 : }
     337             : 
     338             : nsresult
     339           3 : EventStateManager::UpdateUserActivityTimer()
     340             : {
     341           3 :   if (!gUserInteractionTimerCallback)
     342           0 :     return NS_OK;
     343             : 
     344           3 :   if (!gUserInteractionTimer) {
     345           3 :     CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
     346           3 :     if (gUserInteractionTimer) {
     347           3 :       gUserInteractionTimer->SetTarget(
     348           6 :         SystemGroup::EventTargetFor(TaskCategory::Other));
     349             :     }
     350             :   }
     351             : 
     352           3 :   if (gUserInteractionTimer) {
     353           3 :     gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
     354             :                                             NS_USER_INTERACTION_INTERVAL,
     355           6 :                                             nsITimer::TYPE_ONE_SHOT);
     356             :   }
     357           3 :   return NS_OK;
     358             : }
     359             : 
     360             : nsresult
     361          28 : EventStateManager::Init()
     362             : {
     363             :   nsCOMPtr<nsIObserverService> observerService =
     364          56 :     mozilla::services::GetObserverService();
     365          28 :   if (!observerService)
     366           0 :     return NS_ERROR_FAILURE;
     367             : 
     368          28 :   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
     369             : 
     370          28 :   if (sESMInstanceCount == 1) {
     371           2 :     Prefs::Init();
     372             :   }
     373             : 
     374          28 :   return NS_OK;
     375             : }
     376             : 
     377           0 : EventStateManager::~EventStateManager()
     378             : {
     379           0 :   ReleaseCurrentIMEContentObserver();
     380             : 
     381           0 :   if (sActiveESM == this) {
     382           0 :     sActiveESM = nullptr;
     383             :   }
     384           0 :   if (Prefs::ClickHoldContextMenu())
     385           0 :     KillClickHoldTimer();
     386             : 
     387           0 :   if (mDocument == sMouseOverDocument)
     388           0 :     sMouseOverDocument = nullptr;
     389             : 
     390           0 :   --sESMInstanceCount;
     391           0 :   if(sESMInstanceCount == 0) {
     392           0 :     WheelTransaction::Shutdown();
     393           0 :     if (gUserInteractionTimerCallback) {
     394           0 :       gUserInteractionTimerCallback->Notify(nullptr);
     395           0 :       NS_RELEASE(gUserInteractionTimerCallback);
     396             :     }
     397           0 :     if (gUserInteractionTimer) {
     398           0 :       gUserInteractionTimer->Cancel();
     399           0 :       NS_RELEASE(gUserInteractionTimer);
     400             :     }
     401           0 :     Prefs::Shutdown();
     402           0 :     WheelPrefs::Shutdown();
     403           0 :     DeltaAccumulator::Shutdown();
     404             :   }
     405             : 
     406           0 :   if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
     407           0 :     sDragOverContent = nullptr;
     408             :   }
     409             : 
     410           0 :   if (!m_haveShutdown) {
     411           0 :     Shutdown();
     412             : 
     413             :     // Don't remove from Observer service in Shutdown because Shutdown also
     414             :     // gets called from xpcom shutdown observer.  And we don't want to remove
     415             :     // from the service in that case.
     416             : 
     417             :     nsCOMPtr<nsIObserverService> observerService =
     418           0 :       mozilla::services::GetObserverService();
     419           0 :     if (observerService) {
     420           0 :       observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     421             :     }
     422             :   }
     423             : 
     424           0 : }
     425             : 
     426             : nsresult
     427           0 : EventStateManager::Shutdown()
     428             : {
     429           0 :   m_haveShutdown = true;
     430           0 :   return NS_OK;
     431             : }
     432             : 
     433             : NS_IMETHODIMP
     434           0 : EventStateManager::Observe(nsISupports* aSubject,
     435             :                            const char* aTopic,
     436             :                            const char16_t *someData)
     437             : {
     438           0 :   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
     439           0 :     Shutdown();
     440             :   }
     441             : 
     442           0 :   return NS_OK;
     443             : }
     444             : 
     445          56 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(EventStateManager)
     446          28 :    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
     447          28 :    NS_INTERFACE_MAP_ENTRY(nsIObserver)
     448          28 :    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     449           0 : NS_INTERFACE_MAP_END
     450             : 
     451          68 : NS_IMPL_CYCLE_COLLECTING_ADDREF(EventStateManager)
     452          40 : NS_IMPL_CYCLE_COLLECTING_RELEASE(EventStateManager)
     453             : 
     454           0 : NS_IMPL_CYCLE_COLLECTION(EventStateManager,
     455             :                          mCurrentTargetContent,
     456             :                          mGestureDownContent,
     457             :                          mGestureDownFrameOwner,
     458             :                          mLastLeftMouseDownContent,
     459             :                          mLastLeftMouseDownContentParent,
     460             :                          mLastMiddleMouseDownContent,
     461             :                          mLastMiddleMouseDownContentParent,
     462             :                          mLastRightMouseDownContent,
     463             :                          mLastRightMouseDownContentParent,
     464             :                          mActiveContent,
     465             :                          mHoverContent,
     466             :                          mURLTargetContent,
     467             :                          mMouseEnterLeaveHelper,
     468             :                          mPointersEnterLeaveHelper,
     469             :                          mDocument,
     470             :                          mIMEContentObserver,
     471             :                          mAccessKeys)
     472             : 
     473             : void
     474           0 : EventStateManager::ReleaseCurrentIMEContentObserver()
     475             : {
     476           0 :   if (mIMEContentObserver) {
     477           0 :     mIMEContentObserver->DisconnectFromEventStateManager();
     478             :   }
     479           0 :   mIMEContentObserver = nullptr;
     480           0 : }
     481             : 
     482             : void
     483           0 : EventStateManager::OnStartToObserveContent(
     484             :                      IMEContentObserver* aIMEContentObserver)
     485             : {
     486           0 :   if (mIMEContentObserver == aIMEContentObserver) {
     487           0 :     return;
     488             :   }
     489           0 :   ReleaseCurrentIMEContentObserver();
     490           0 :   mIMEContentObserver = aIMEContentObserver;
     491             : }
     492             : 
     493             : void
     494           0 : EventStateManager::OnStopObservingContent(
     495             :                      IMEContentObserver* aIMEContentObserver)
     496             : {
     497           0 :   aIMEContentObserver->DisconnectFromEventStateManager();
     498           0 :   NS_ENSURE_TRUE_VOID(mIMEContentObserver == aIMEContentObserver);
     499           0 :   mIMEContentObserver = nullptr;
     500             : }
     501             : 
     502             : void
     503          10 : EventStateManager::TryToFlushPendingNotificationsToIME()
     504             : {
     505          10 :   if (mIMEContentObserver) {
     506           0 :     mIMEContentObserver->TryToFlushPendingNotifications();
     507             :   }
     508          10 : }
     509             : 
     510             : static bool
     511          10 : IsMessageMouseUserActivity(EventMessage aMessage)
     512             : {
     513           6 :   return aMessage == eMouseMove ||
     514           6 :          aMessage == eMouseUp ||
     515           6 :          aMessage == eMouseDown ||
     516           6 :          aMessage == eMouseAuxClick ||
     517           6 :          aMessage == eMouseDoubleClick ||
     518           6 :          aMessage == eMouseClick ||
     519          16 :          aMessage == eMouseActivate ||
     520          10 :          aMessage == eMouseLongTap;
     521             : }
     522             : 
     523             : static bool
     524           2 : IsMessageGamepadUserActivity(EventMessage aMessage)
     525             : {
     526           2 :   return aMessage == eGamepadButtonDown ||
     527           4 :          aMessage == eGamepadButtonUp ||
     528           2 :          aMessage == eGamepadAxisMove;
     529             : }
     530             : 
     531             : nsresult
     532          10 : EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
     533             :                                   WidgetEvent* aEvent,
     534             :                                   nsIFrame* aTargetFrame,
     535             :                                   nsIContent* aTargetContent,
     536             :                                   nsEventStatus* aStatus)
     537             : {
     538          10 :   NS_ENSURE_ARG_POINTER(aStatus);
     539          10 :   NS_ENSURE_ARG(aPresContext);
     540          10 :   if (!aEvent) {
     541           0 :     NS_ERROR("aEvent is null.  This should never happen.");
     542           0 :     return NS_ERROR_NULL_POINTER;
     543             :   }
     544             : 
     545          10 :   NS_WARNING_ASSERTION(
     546             :     !aTargetFrame || !aTargetFrame->GetContent() ||
     547             :     aTargetFrame->GetContent() == aTargetContent ||
     548             :     aTargetFrame->GetContent()->GetFlattenedTreeParent() == aTargetContent ||
     549             :     aTargetFrame->IsGeneratedContentFrame(),
     550             :     "aTargetFrame should be related with aTargetContent");
     551             : #if DEBUG
     552          10 :   if (aTargetFrame && aTargetFrame->IsGeneratedContentFrame()) {
     553           0 :     nsCOMPtr<nsIContent> targetContent;
     554           0 :     aTargetFrame->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
     555           0 :     MOZ_ASSERT(aTargetContent == targetContent,
     556             :                "Unexpected target for generated content frame!");
     557             :   }
     558             : #endif
     559             : 
     560          10 :   mCurrentTarget = aTargetFrame;
     561          10 :   mCurrentTargetContent = nullptr;
     562             : 
     563             :   // Do not take account eMouseEnterIntoWidget/ExitFromWidget so that loading
     564             :   // a page when user is not active doesn't change the state to active.
     565          10 :   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
     566          18 :   if (aEvent->IsTrusted() &&
     567          20 :       ((mouseEvent && mouseEvent->IsReal() &&
     568          16 :         IsMessageMouseUserActivity(mouseEvent->mMessage)) ||
     569          12 :        aEvent->mClass == eWheelEventClass ||
     570           8 :        aEvent->mClass == ePointerEventClass ||
     571           4 :        aEvent->mClass == eTouchEventClass ||
     572           4 :        aEvent->mClass == eKeyboardEventClass ||
     573           2 :        IsMessageGamepadUserActivity(aEvent->mMessage))) {
     574           8 :     if (gMouseOrKeyboardEventCounter == 0) {
     575             :       nsCOMPtr<nsIObserverService> obs =
     576           2 :         mozilla::services::GetObserverService();
     577           1 :       if (obs) {
     578           1 :         obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
     579           1 :         UpdateUserActivityTimer();
     580             :       }
     581             :     }
     582           8 :     ++gMouseOrKeyboardEventCounter;
     583             : 
     584          16 :     nsCOMPtr<nsINode> node = do_QueryInterface(aTargetContent);
     585          16 :     if (node &&
     586          24 :         (aEvent->mMessage == eKeyUp || aEvent->mMessage == eMouseUp ||
     587          24 :          aEvent->mMessage == eWheel || aEvent->mMessage == eTouchEnd ||
     588          16 :          aEvent->mMessage == ePointerUp)) {
     589           0 :       nsIDocument* doc = node->OwnerDoc();
     590           0 :       while (doc && !doc->UserHasInteracted()) {
     591           0 :         doc->SetUserHasInteracted(true);
     592           0 :         doc = nsContentUtils::IsChildOfSameType(doc) ?
     593             :           doc->GetParentDocument() : nullptr;
     594             :       }
     595             :     }
     596             :   }
     597             : 
     598          10 :   WheelTransaction::OnEvent(aEvent);
     599             : 
     600             :   // Focus events don't necessarily need a frame.
     601          10 :   if (!mCurrentTarget && !aTargetContent) {
     602           0 :     NS_ERROR("mCurrentTarget and aTargetContent are null");
     603           0 :     return NS_ERROR_NULL_POINTER;
     604             :   }
     605             : #ifdef DEBUG
     606          10 :   if (aEvent->HasDragEventMessage() && sIsPointerLocked) {
     607           0 :     NS_ASSERTION(sIsPointerLocked,
     608             :       "sIsPointerLocked is true. Drag events should be suppressed when "
     609             :       "the pointer is locked.");
     610             :   }
     611             : #endif
     612             :   // Store last known screenPoint and clientPoint so pointer lock
     613             :   // can use these values as constants.
     614          30 :   if (aEvent->IsTrusted() &&
     615          10 :       ((mouseEvent && mouseEvent->IsReal()) ||
     616          20 :        aEvent->mClass == eWheelEventClass) &&
     617          10 :       !sIsPointerLocked) {
     618             :     sLastScreenPoint =
     619          10 :       Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint);
     620             :     sLastClientPoint =
     621             :       Event::GetClientCoords(aPresContext, aEvent, aEvent->mRefPoint,
     622          10 :                              CSSIntPoint(0, 0));
     623             :   }
     624             : 
     625          10 :   *aStatus = nsEventStatus_eIgnore;
     626             : 
     627          10 :   if (aEvent->mClass == eQueryContentEventClass) {
     628           0 :     HandleQueryContentEvent(aEvent->AsQueryContentEvent());
     629           0 :     return NS_OK;
     630             :   }
     631             : 
     632          10 :   WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
     633          10 :   if (touchEvent && mInTouchDrag) {
     634           0 :     if (touchEvent->mMessage == eTouchMove) {
     635           0 :       GenerateDragGesture(aPresContext, touchEvent);
     636             :     } else {
     637           0 :       mInTouchDrag = false;
     638           0 :       StopTrackingDragGesture();
     639             :     }
     640             :   }
     641             : 
     642          10 :   switch (aEvent->mMessage) {
     643             :   case eContextMenu:
     644           0 :     if (sIsPointerLocked) {
     645           0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
     646             :     }
     647           0 :     break;
     648             :   case eMouseTouchDrag:
     649           0 :     mInTouchDrag = true;
     650           0 :     BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
     651           0 :     break;
     652             :   case eMouseDown: {
     653           0 :     switch (mouseEvent->button) {
     654             :     case WidgetMouseEvent::eLeftButton:
     655           0 :       BeginTrackingDragGesture(aPresContext, mouseEvent, aTargetFrame);
     656           0 :       mLClickCount = mouseEvent->mClickCount;
     657           0 :       SetClickCount(mouseEvent, aStatus);
     658           0 :       sNormalLMouseEventInProcess = true;
     659           0 :       break;
     660             :     case WidgetMouseEvent::eMiddleButton:
     661           0 :       mMClickCount = mouseEvent->mClickCount;
     662           0 :       SetClickCount(mouseEvent, aStatus);
     663           0 :       break;
     664             :     case WidgetMouseEvent::eRightButton:
     665           0 :       mRClickCount = mouseEvent->mClickCount;
     666           0 :       SetClickCount(mouseEvent, aStatus);
     667           0 :       break;
     668             :     }
     669           0 :     break;
     670             :   }
     671             :   case eMouseUp: {
     672           0 :     switch (mouseEvent->button) {
     673             :       case WidgetMouseEvent::eLeftButton:
     674           0 :         if (Prefs::ClickHoldContextMenu()) {
     675           0 :           KillClickHoldTimer();
     676             :         }
     677           0 :         StopTrackingDragGesture();
     678           0 :         sNormalLMouseEventInProcess = false;
     679             :         // then fall through...
     680             :         MOZ_FALLTHROUGH;
     681             :       case WidgetMouseEvent::eRightButton:
     682             :       case WidgetMouseEvent::eMiddleButton:
     683           0 :         SetClickCount(mouseEvent, aStatus);
     684           0 :         break;
     685             :     }
     686           0 :     break;
     687             :   }
     688             :   case eMouseEnterIntoWidget:
     689             :     // In some cases on e10s eMouseEnterIntoWidget
     690             :     // event was sent twice into child process of content.
     691             :     // (From specific widget code (sending is not permanent) and
     692             :     // from ESM::DispatchMouseOrPointerEvent (sending is permanent)).
     693             :     // IsCrossProcessForwardingStopped() helps to suppress sending accidental
     694             :     // event from widget code.
     695           1 :     aEvent->StopCrossProcessForwarding();
     696           1 :     break;
     697             :   case eMouseExitFromWidget:
     698             :     // If this is a remote frame, we receive eMouseExitFromWidget from the
     699             :     // parent the mouse exits our content. Since the parent may update the
     700             :     // cursor while the mouse is outside our frame, and since PuppetWidget
     701             :     // caches the current cursor internally, re-entering our content (say from
     702             :     // over a window edge) wont update the cursor if the cached value and the
     703             :     // current cursor match. So when the mouse exits a remote frame, clear the
     704             :     // cached widget cursor so a proper update will occur when the mouse
     705             :     // re-enters.
     706           1 :     if (XRE_IsContentProcess()) {
     707           0 :       ClearCachedWidgetCursor(mCurrentTarget);
     708             :     }
     709             : 
     710             :     // IsCrossProcessForwardingStopped() helps to suppress double event sending
     711             :     // into process of content.
     712             :     // For more information see comment above, at eMouseEnterIntoWidget case.
     713           1 :     aEvent->StopCrossProcessForwarding();
     714             : 
     715             :     // If the event is not a top-level window exit, then it's not
     716             :     // really an exit --- we may have traversed widget boundaries but
     717             :     // we're still in our toplevel window.
     718           1 :     if (mouseEvent->mExitFrom != WidgetMouseEvent::eTopLevel) {
     719             :       // Treat it as a synthetic move so we don't generate spurious
     720             :       // "exit" or "move" events.  Any necessary "out" or "over" events
     721             :       // will be generated by GenerateMouseEnterExit
     722           0 :       mouseEvent->mMessage = eMouseMove;
     723           0 :       mouseEvent->mReason = WidgetMouseEvent::eSynthesized;
     724             :       // then fall through...
     725             :     } else {
     726           1 :       if (sPointerEventEnabled) {
     727             :         // We should synthetize corresponding pointer events
     728           1 :         GeneratePointerEnterExit(ePointerLeave, mouseEvent);
     729             :       }
     730           1 :       GenerateMouseEnterExit(mouseEvent);
     731             :       //This is a window level mouse exit event and should stop here
     732           1 :       aEvent->mMessage = eVoidEvent;
     733           1 :       break;
     734             :     }
     735             :     MOZ_FALLTHROUGH;
     736             :   case eMouseMove:
     737             :   case ePointerDown:
     738             :   case ePointerMove: {
     739             :     // on the Mac, GenerateDragGesture() may not return until the drag
     740             :     // has completed and so |aTargetFrame| may have been deleted (moving
     741             :     // a bookmark, for example).  If this is the case, however, we know
     742             :     // that ClearFrameRefs() has been called and it cleared out
     743             :     // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
     744             :     // into UpdateCursor().
     745           8 :     GenerateDragGesture(aPresContext, mouseEvent);
     746           8 :     UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
     747           8 :     GenerateMouseEnterExit(mouseEvent);
     748             :     // Flush pending layout changes, so that later mouse move events
     749             :     // will go to the right nodes.
     750           8 :     FlushPendingEvents(aPresContext);
     751           8 :     break;
     752             :   }
     753             :   case ePointerGotCapture:
     754           0 :     GenerateMouseEnterExit(mouseEvent);
     755           0 :     break;
     756             :   case eDragStart:
     757           0 :     if (Prefs::ClickHoldContextMenu()) {
     758             :       // an external drag gesture event came in, not generated internally
     759             :       // by Gecko. Make sure we get rid of the click-hold timer.
     760           0 :       KillClickHoldTimer();
     761             :     }
     762           0 :     break;
     763             :   case eDragOver:
     764             :     // Send the enter/exit events before eDrop.
     765           0 :     GenerateDragDropEnterExit(aPresContext, aEvent->AsDragEvent());
     766           0 :     break;
     767             : 
     768             :   case eKeyPress:
     769             :     {
     770           0 :       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
     771             : 
     772           0 :       int32_t modifierMask = 0;
     773           0 :       if (keyEvent->IsShift())
     774           0 :         modifierMask |= NS_MODIFIER_SHIFT;
     775           0 :       if (keyEvent->IsControl())
     776           0 :         modifierMask |= NS_MODIFIER_CONTROL;
     777           0 :       if (keyEvent->IsAlt())
     778           0 :         modifierMask |= NS_MODIFIER_ALT;
     779           0 :       if (keyEvent->IsMeta())
     780           0 :         modifierMask |= NS_MODIFIER_META;
     781           0 :       if (keyEvent->IsOS())
     782           0 :         modifierMask |= NS_MODIFIER_OS;
     783             : 
     784             :       // Prevent keyboard scrolling while an accesskey modifier is in use.
     785           0 :       if (modifierMask) {
     786           0 :         bool matchesContentAccessKey = (modifierMask == Prefs::ContentAccessModifierMask());
     787             : 
     788           0 :         if (modifierMask == Prefs::ChromeAccessModifierMask() ||
     789             :             matchesContentAccessKey) {
     790           0 :           AutoTArray<uint32_t, 10> accessCharCodes;
     791           0 :           keyEvent->GetAccessKeyCandidates(accessCharCodes);
     792             : 
     793           0 :           if (HandleAccessKey(keyEvent, aPresContext, accessCharCodes,
     794             :                               modifierMask, matchesContentAccessKey)) {
     795           0 :             *aStatus = nsEventStatus_eConsumeNoDefault;
     796             :           }
     797             :         }
     798             :       }
     799             :     }
     800             :     // then fall through...
     801             :     MOZ_FALLTHROUGH;
     802             :   case eKeyDown:
     803             :   case eKeyUp:
     804             :     {
     805           0 :       nsIContent* content = GetFocusedContent();
     806           0 :       if (content)
     807           0 :         mCurrentTargetContent = content;
     808             : 
     809             :       // NOTE: Don't refer TextComposition::IsComposing() since UI Events
     810             :       //       defines that KeyboardEvent.isComposing is true when it's
     811             :       //       dispatched after compositionstart and compositionend.
     812             :       //       TextComposition::IsComposing() is false even before
     813             :       //       compositionend if there is no composing string.
     814             :       //       And also don't expose other document's composition state.
     815             :       //       A native IME context is typically shared by multiple documents.
     816             :       //       So, don't use GetTextCompositionFor(nsIWidget*) here.
     817             :       RefPtr<TextComposition> composition =
     818           0 :         IMEStateManager::GetTextCompositionFor(aPresContext);
     819           0 :       aEvent->AsKeyboardEvent()->mIsComposing = !!composition;
     820             :     }
     821           0 :     break;
     822             :   case eWheel:
     823             :   case eWheelOperationStart:
     824             :   case eWheelOperationEnd:
     825             :     {
     826           0 :       NS_ASSERTION(aEvent->IsTrusted(),
     827             :                    "Untrusted wheel event shouldn't be here");
     828             : 
     829           0 :       nsIContent* content = GetFocusedContent();
     830           0 :       if (content) {
     831           0 :         mCurrentTargetContent = content;
     832             :       }
     833             : 
     834           0 :       if (aEvent->mMessage != eWheel) {
     835           0 :         break;
     836             :       }
     837             : 
     838           0 :       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
     839           0 :       WheelPrefs::GetInstance()->ApplyUserPrefsToDelta(wheelEvent);
     840             : 
     841             :       // If we won't dispatch a DOM event for this event, nothing to do anymore.
     842           0 :       if (!wheelEvent->IsAllowedToDispatchDOMEvent()) {
     843           0 :         break;
     844             :       }
     845             : 
     846             :       // Init lineOrPageDelta values for line scroll events for some devices
     847             :       // on some platforms which might dispatch wheel events which don't have
     848             :       // lineOrPageDelta values.  And also, if delta values are customized by
     849             :       // prefs, this recomputes them.
     850             :       DeltaAccumulator::GetInstance()->
     851           0 :         InitLineOrPageDelta(aTargetFrame, this, wheelEvent);
     852             :     }
     853           0 :     break;
     854             :   case eSetSelection:
     855           0 :     IMEStateManager::HandleSelectionEvent(aPresContext, GetFocusedContent(),
     856           0 :                                           aEvent->AsSelectionEvent());
     857           0 :     break;
     858             :   case eContentCommandCut:
     859             :   case eContentCommandCopy:
     860             :   case eContentCommandPaste:
     861             :   case eContentCommandDelete:
     862             :   case eContentCommandUndo:
     863             :   case eContentCommandRedo:
     864             :   case eContentCommandPasteTransferable:
     865             :   case eContentCommandLookUpDictionary:
     866           0 :     DoContentCommandEvent(aEvent->AsContentCommandEvent());
     867           0 :     break;
     868             :   case eContentCommandScroll:
     869           0 :     DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
     870           0 :     break;
     871             :   case eCompositionStart:
     872           0 :     if (aEvent->IsTrusted()) {
     873             :       // If the event is trusted event, set the selected text to data of
     874             :       // composition event.
     875           0 :       WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
     876             :       WidgetQueryContentEvent selectedText(true, eQuerySelectedText,
     877           0 :                                            compositionEvent->mWidget);
     878           0 :       HandleQueryContentEvent(&selectedText);
     879           0 :       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
     880           0 :       compositionEvent->mData = selectedText.mReply.mString;
     881             :     }
     882           0 :     break;
     883             :   default:
     884           0 :     break;
     885             :   }
     886          10 :   return NS_OK;
     887             : }
     888             : 
     889             : void
     890           0 : EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
     891             : {
     892           0 :   switch (aEvent->mMessage) {
     893             :     case eQuerySelectedText:
     894             :     case eQueryTextContent:
     895             :     case eQueryCaretRect:
     896             :     case eQueryTextRect:
     897             :     case eQueryEditorRect:
     898           0 :       if (!IsTargetCrossProcess(aEvent)) {
     899           0 :         break;
     900             :       }
     901             :       // Will not be handled locally, remote the event
     902           0 :       GetCrossProcessTarget()->HandleQueryContentEvent(*aEvent);
     903           0 :       return;
     904             :     // Following events have not been supported in e10s mode yet.
     905             :     case eQueryContentState:
     906             :     case eQuerySelectionAsTransferable:
     907             :     case eQueryCharacterAtPoint:
     908             :     case eQueryDOMWidgetHittest:
     909             :     case eQueryTextRectArray:
     910           0 :       break;
     911             :     default:
     912           0 :       return;
     913             :   }
     914             : 
     915             :   // If there is an IMEContentObserver, we need to handle QueryContentEvent
     916             :   // with it.
     917           0 :   if (mIMEContentObserver) {
     918           0 :     RefPtr<IMEContentObserver> contentObserver = mIMEContentObserver;
     919           0 :     contentObserver->HandleQueryContentEvent(aEvent);
     920           0 :     return;
     921             :   }
     922             : 
     923           0 :   ContentEventHandler handler(mPresContext);
     924           0 :   handler.HandleQueryContentEvent(aEvent);
     925             : }
     926             : 
     927             : // static
     928             : int32_t
     929           0 : EventStateManager::GetAccessModifierMaskFor(nsISupports* aDocShell)
     930             : {
     931           0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
     932           0 :   if (!treeItem)
     933           0 :     return -1; // invalid modifier
     934             : 
     935           0 :   switch (treeItem->ItemType()) {
     936             :   case nsIDocShellTreeItem::typeChrome:
     937           0 :     return Prefs::ChromeAccessModifierMask();
     938             : 
     939             :   case nsIDocShellTreeItem::typeContent:
     940           0 :     return Prefs::ContentAccessModifierMask();
     941             : 
     942             :   default:
     943           0 :     return -1; // invalid modifier
     944             :   }
     945             : }
     946             : 
     947             : static bool
     948           0 : IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsAString& aKey)
     949             : {
     950             :   // Use GetAttr because we want Unicode case=insensitive matching
     951             :   // XXXbz shouldn't this be case-sensitive, per spec?
     952           0 :   nsString contentKey;
     953           0 :   if (!aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, contentKey) ||
     954           0 :       !contentKey.Equals(aKey, nsCaseInsensitiveStringComparator()))
     955           0 :     return false;
     956             : 
     957             :   nsCOMPtr<nsIDOMXULDocument> xulDoc =
     958           0 :     do_QueryInterface(aContent->OwnerDoc());
     959           0 :   if (!xulDoc && !aContent->IsXULElement())
     960           0 :     return true;
     961             : 
     962             :     // For XUL we do visibility checks.
     963           0 :   if (!aFrame)
     964           0 :     return false;
     965             : 
     966           0 :   if (aFrame->IsFocusable())
     967           0 :     return true;
     968             : 
     969           0 :   if (!aFrame->IsVisibleConsideringAncestors())
     970           0 :     return false;
     971             : 
     972             :   // XUL controls can be activated.
     973           0 :   nsCOMPtr<nsIDOMXULControlElement> control(do_QueryInterface(aContent));
     974           0 :   if (control)
     975           0 :     return true;
     976             : 
     977             :   // HTML area, label and legend elements are never focusable, so
     978             :   // we need to check for them explicitly before giving up.
     979           0 :   if (aContent->IsAnyOfHTMLElements(nsGkAtoms::area,
     980             :                                     nsGkAtoms::label,
     981             :                                     nsGkAtoms::legend)) {
     982           0 :     return true;
     983             :   }
     984             : 
     985             :   // XUL label elements are never focusable, so we need to check for them
     986             :   // explicitly before giving up.
     987           0 :   if (aContent->IsXULElement(nsGkAtoms::label)) {
     988           0 :     return true;
     989             :   }
     990             : 
     991           0 :   return false;
     992             : }
     993             : 
     994             : bool
     995           0 : EventStateManager::ExecuteAccessKey(nsTArray<uint32_t>& aAccessCharCodes,
     996             :                                     bool aIsTrustedEvent)
     997             : {
     998           0 :   int32_t count, start = -1;
     999           0 :   nsIContent* focusedContent = GetFocusedContent();
    1000           0 :   if (focusedContent) {
    1001           0 :     start = mAccessKeys.IndexOf(focusedContent);
    1002           0 :     if (start == -1 && focusedContent->GetBindingParent())
    1003           0 :       start = mAccessKeys.IndexOf(focusedContent->GetBindingParent());
    1004             :   }
    1005             :   nsIContent *content;
    1006             :   nsIFrame *frame;
    1007           0 :   int32_t length = mAccessKeys.Count();
    1008           0 :   for (uint32_t i = 0; i < aAccessCharCodes.Length(); ++i) {
    1009           0 :     uint32_t ch = aAccessCharCodes[i];
    1010           0 :     nsAutoString accessKey;
    1011           0 :     AppendUCS4ToUTF16(ch, accessKey);
    1012           0 :     for (count = 1; count <= length; ++count) {
    1013           0 :       content = mAccessKeys[(start + count) % length];
    1014           0 :       frame = content->GetPrimaryFrame();
    1015           0 :       if (IsAccessKeyTarget(content, frame, accessKey)) {
    1016           0 :         bool shouldActivate = Prefs::KeyCausesActivation();
    1017           0 :         while (shouldActivate && ++count <= length) {
    1018           0 :           nsIContent *oc = mAccessKeys[(start + count) % length];
    1019           0 :           nsIFrame *of = oc->GetPrimaryFrame();
    1020           0 :           if (IsAccessKeyTarget(oc, of, accessKey))
    1021           0 :             shouldActivate = false;
    1022             :         }
    1023             : 
    1024           0 :         bool focusChanged = false;
    1025           0 :         if (shouldActivate) {
    1026           0 :           focusChanged = content->PerformAccesskey(shouldActivate, aIsTrustedEvent);
    1027             :         } else {
    1028           0 :           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    1029           0 :           if (fm) {
    1030           0 :             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
    1031           0 :             fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
    1032           0 :             focusChanged = true;
    1033             :           }
    1034             :         }
    1035             : 
    1036           0 :         if (focusChanged && aIsTrustedEvent) {
    1037             :           // If this is a child process, inform the parent that we want the focus, but
    1038             :           // pass false since we don't want to change the window order.
    1039           0 :           nsIDocShell* docShell = mPresContext->GetDocShell();
    1040             :           nsCOMPtr<nsITabChild> child =
    1041           0 :             docShell ? docShell->GetTabChild() : nullptr;
    1042           0 :           if (child) {
    1043           0 :             child->SendRequestFocus(false);
    1044             :           }
    1045             :         }
    1046             : 
    1047           0 :         return true;
    1048             :       }
    1049             :     }
    1050             :   }
    1051           0 :   return false;
    1052             : }
    1053             : 
    1054             : // static
    1055             : void
    1056           0 : EventStateManager::GetAccessKeyLabelPrefix(Element* aElement, nsAString& aPrefix)
    1057             : {
    1058           0 :   aPrefix.Truncate();
    1059           0 :   nsAutoString separator, modifierText;
    1060           0 :   nsContentUtils::GetModifierSeparatorText(separator);
    1061             : 
    1062           0 :   nsCOMPtr<nsISupports> container = aElement->OwnerDoc()->GetDocShell();
    1063           0 :   int32_t modifierMask = GetAccessModifierMaskFor(container);
    1064             : 
    1065           0 :   if (modifierMask == -1) {
    1066           0 :     return;
    1067             :   }
    1068             : 
    1069           0 :   if (modifierMask & NS_MODIFIER_CONTROL) {
    1070           0 :     nsContentUtils::GetControlText(modifierText);
    1071           0 :     aPrefix.Append(modifierText + separator);
    1072             :   }
    1073           0 :   if (modifierMask & NS_MODIFIER_META) {
    1074           0 :     nsContentUtils::GetMetaText(modifierText);
    1075           0 :     aPrefix.Append(modifierText + separator);
    1076             :   }
    1077           0 :   if (modifierMask & NS_MODIFIER_OS) {
    1078           0 :     nsContentUtils::GetOSText(modifierText);
    1079           0 :     aPrefix.Append(modifierText + separator);
    1080             :   }
    1081           0 :   if (modifierMask & NS_MODIFIER_ALT) {
    1082           0 :     nsContentUtils::GetAltText(modifierText);
    1083           0 :     aPrefix.Append(modifierText + separator);
    1084             :   }
    1085           0 :   if (modifierMask & NS_MODIFIER_SHIFT) {
    1086           0 :     nsContentUtils::GetShiftText(modifierText);
    1087           0 :     aPrefix.Append(modifierText + separator);
    1088             :   }
    1089             : }
    1090             : 
    1091             : struct MOZ_STACK_CLASS AccessKeyInfo
    1092             : {
    1093             :   WidgetKeyboardEvent* event;
    1094             :   nsTArray<uint32_t>& charCodes;
    1095             :   int32_t modifierMask;
    1096             : 
    1097           0 :   AccessKeyInfo(WidgetKeyboardEvent* aEvent, nsTArray<uint32_t>& aCharCodes, int32_t aModifierMask)
    1098           0 :     : event(aEvent)
    1099             :     , charCodes(aCharCodes)
    1100           0 :     , modifierMask(aModifierMask)
    1101             :   {
    1102           0 :   }
    1103             : };
    1104             : 
    1105             : static bool
    1106           0 : HandleAccessKeyInRemoteChild(TabParent* aTabParent, void* aArg)
    1107             : {
    1108           0 :   AccessKeyInfo* accessKeyInfo = static_cast<AccessKeyInfo*>(aArg);
    1109             : 
    1110             :   // Only forward accesskeys for the active tab.
    1111             :   bool active;
    1112           0 :   aTabParent->GetDocShellIsActive(&active);
    1113           0 :   if (active) {
    1114           0 :     accessKeyInfo->event->mAccessKeyForwardedToChild = true;
    1115           0 :     aTabParent->HandleAccessKey(*accessKeyInfo->event,
    1116             :                                 accessKeyInfo->charCodes,
    1117           0 :                                 accessKeyInfo->modifierMask);
    1118           0 :     return true;
    1119             :   }
    1120             : 
    1121           0 :   return false;
    1122             : }
    1123             : 
    1124             : bool
    1125           0 : EventStateManager::HandleAccessKey(WidgetKeyboardEvent* aEvent,
    1126             :                                    nsPresContext* aPresContext,
    1127             :                                    nsTArray<uint32_t>& aAccessCharCodes,
    1128             :                                    bool aMatchesContentAccessKey,
    1129             :                                    nsIDocShellTreeItem* aBubbledFrom,
    1130             :                                    ProcessingAccessKeyState aAccessKeyState,
    1131             :                                    int32_t aModifierMask)
    1132             : {
    1133           0 :   EnsureDocument(mPresContext);
    1134           0 :   nsCOMPtr<nsIDocShell> docShell = aPresContext->GetDocShell();
    1135           0 :   if (NS_WARN_IF(!docShell) || NS_WARN_IF(!mDocument)) {
    1136           0 :     return false;
    1137             :   }
    1138             : 
    1139             :   // Alt or other accesskey modifier is down, we may need to do an accesskey.
    1140           0 :   if (mAccessKeys.Count() > 0 &&
    1141           0 :       aModifierMask == GetAccessModifierMaskFor(docShell)) {
    1142             :     // Someone registered an accesskey.  Find and activate it.
    1143           0 :     if (ExecuteAccessKey(aAccessCharCodes, aEvent->IsTrusted())) {
    1144           0 :       return true;
    1145             :     }
    1146             :   }
    1147             : 
    1148             :   int32_t childCount;
    1149           0 :   docShell->GetChildCount(&childCount);
    1150           0 :   for (int32_t counter = 0; counter < childCount; counter++) {
    1151             :     // Not processing the child which bubbles up the handling
    1152           0 :     nsCOMPtr<nsIDocShellTreeItem> subShellItem;
    1153           0 :     docShell->GetChildAt(counter, getter_AddRefs(subShellItem));
    1154           0 :     if (aAccessKeyState == eAccessKeyProcessingUp &&
    1155           0 :         subShellItem == aBubbledFrom) {
    1156           0 :       continue;
    1157             :     }
    1158             : 
    1159           0 :     nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
    1160           0 :     if (subDS && IsShellVisible(subDS)) {
    1161           0 :       nsCOMPtr<nsIPresShell> subPS = subDS->GetPresShell();
    1162             : 
    1163             :       // Docshells need not have a presshell (eg. display:none
    1164             :       // iframes, docshells in transition between documents, etc).
    1165           0 :       if (!subPS) {
    1166             :         // Oh, well.  Just move on to the next child
    1167           0 :         continue;
    1168             :       }
    1169             : 
    1170           0 :       nsPresContext *subPC = subPS->GetPresContext();
    1171             : 
    1172             :       EventStateManager* esm =
    1173           0 :         static_cast<EventStateManager*>(subPC->EventStateManager());
    1174             : 
    1175           0 :       if (esm &&
    1176           0 :           esm->HandleAccessKey(aEvent, subPC, aAccessCharCodes,
    1177             :                                aMatchesContentAccessKey, nullptr,
    1178             :                                eAccessKeyProcessingDown, aModifierMask)) {
    1179           0 :         return true;
    1180             :       }
    1181             :     }
    1182             :   }// if end . checking all sub docshell ends here.
    1183             : 
    1184             :   // bubble up the process to the parent docshell if necessary
    1185           0 :   if (eAccessKeyProcessingDown != aAccessKeyState) {
    1186           0 :     nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
    1187           0 :     docShell->GetParent(getter_AddRefs(parentShellItem));
    1188           0 :     nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
    1189           0 :     if (parentDS) {
    1190           0 :       nsCOMPtr<nsIPresShell> parentPS = parentDS->GetPresShell();
    1191           0 :       NS_ASSERTION(parentPS, "Our PresShell exists but the parent's does not?");
    1192             : 
    1193           0 :       nsPresContext *parentPC = parentPS->GetPresContext();
    1194           0 :       NS_ASSERTION(parentPC, "PresShell without PresContext");
    1195             : 
    1196             :       EventStateManager* esm =
    1197           0 :         static_cast<EventStateManager*>(parentPC->EventStateManager());
    1198           0 :       if (esm &&
    1199           0 :           esm->HandleAccessKey(aEvent, parentPC, aAccessCharCodes,
    1200             :                                aMatchesContentAccessKey, docShell,
    1201           0 :                                eAccessKeyProcessingDown, aModifierMask)) {
    1202           0 :         return true;
    1203             :       }
    1204             :     }
    1205             :   }// if end. bubble up process
    1206             : 
    1207             :   // If the content access key modifier is pressed, try remote children
    1208           0 :   if (aMatchesContentAccessKey && mDocument && mDocument->GetWindow()) {
    1209             :     // If the focus is currently on a node with a TabParent, the key event will
    1210             :     // get forwarded to the child process and HandleAccessKey called from there.
    1211             :     // If focus is somewhere else, then we need to check the remote children.
    1212           0 :     nsFocusManager* fm = nsFocusManager::GetFocusManager();
    1213           0 :     nsIContent* focusedContent = fm ? fm->GetFocusedContent() : nullptr;
    1214           0 :     if (TabParent::GetFrom(focusedContent)) {
    1215             :       // A remote child process is focused. The key event should get sent to
    1216             :       // the child process.
    1217           0 :       aEvent->mAccessKeyForwardedToChild = true;
    1218             :     } else {
    1219           0 :       AccessKeyInfo accessKeyInfo(aEvent, aAccessCharCodes, aModifierMask);
    1220           0 :       nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(),
    1221           0 :                                               HandleAccessKeyInRemoteChild, &accessKeyInfo);
    1222             :     }
    1223             :   }
    1224             : 
    1225           0 :   return false;
    1226             : }// end of HandleAccessKey
    1227             : 
    1228             : void
    1229           6 : EventStateManager::DispatchCrossProcessEvent(WidgetEvent* aEvent,
    1230             :                                              nsFrameLoader* aFrameLoader,
    1231             :                                              nsEventStatus *aStatus)
    1232             : {
    1233           6 :   TabParent* remote = TabParent::GetFrom(aFrameLoader);
    1234           6 :   if (!remote) {
    1235           0 :     return;
    1236             :   }
    1237             : 
    1238           6 :   switch (aEvent->mClass) {
    1239             :   case eMouseEventClass: {
    1240           6 :     remote->SendRealMouseEvent(*aEvent->AsMouseEvent());
    1241           6 :     return;
    1242             :   }
    1243             :   case eKeyboardEventClass: {
    1244           0 :     remote->SendRealKeyEvent(*aEvent->AsKeyboardEvent());
    1245           0 :     return;
    1246             :   }
    1247             :   case eWheelEventClass: {
    1248           0 :     remote->SendMouseWheelEvent(*aEvent->AsWheelEvent());
    1249           0 :     return;
    1250             :   }
    1251             :   case eTouchEventClass: {
    1252             :     // Let the child process synthesize a mouse event if needed, and
    1253             :     // ensure we don't synthesize one in this process.
    1254           0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
    1255           0 :     remote->SendRealTouchEvent(*aEvent->AsTouchEvent());
    1256           0 :     return;
    1257             :   }
    1258             :   case eDragEventClass: {
    1259           0 :     if (remote->Manager()->IsContentParent()) {
    1260           0 :       remote->Manager()->AsContentParent()->MaybeInvokeDragSession(remote);
    1261             :     }
    1262             : 
    1263           0 :     nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    1264           0 :     uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
    1265           0 :     uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
    1266           0 :     if (dragSession) {
    1267           0 :       dragSession->DragEventDispatchedToChildProcess();
    1268           0 :       dragSession->GetDragAction(&action);
    1269           0 :       nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
    1270           0 :       dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
    1271           0 :       if (initialDataTransfer) {
    1272           0 :         initialDataTransfer->GetDropEffectInt(&dropEffect);
    1273             :       }
    1274             :     }
    1275             : 
    1276           0 :     remote->SendRealDragEvent(*aEvent->AsDragEvent(), action, dropEffect);
    1277           0 :     return;
    1278             :   }
    1279             :   case ePluginEventClass: {
    1280           0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
    1281           0 :     remote->SendPluginEvent(*aEvent->AsPluginEvent());
    1282           0 :     return;
    1283             :   }
    1284             :   default: {
    1285           0 :     MOZ_CRASH("Attempt to send non-whitelisted event?");
    1286             :   }
    1287             :   }
    1288             : }
    1289             : 
    1290             : bool
    1291          18 : EventStateManager::IsRemoteTarget(nsIContent* target)
    1292             : {
    1293          18 :   return !!TabParent::GetFrom(target);
    1294             : }
    1295             : 
    1296             : bool
    1297          12 : EventStateManager::HandleCrossProcessEvent(WidgetEvent* aEvent,
    1298             :                                            nsEventStatus *aStatus) {
    1299          24 :   if (*aStatus == nsEventStatus_eConsumeNoDefault ||
    1300          12 :       !aEvent->CanBeSentToRemoteProcess()) {
    1301           6 :     return false;
    1302             :   }
    1303             : 
    1304           6 :   MOZ_ASSERT(!aEvent->HasBeenPostedToRemoteProcess(),
    1305             :     "Why do we need to post same event to remote processes again?");
    1306             : 
    1307             :   // Collect the remote event targets we're going to forward this
    1308             :   // event to.
    1309             :   //
    1310             :   // NB: the elements of |targets| must be unique, for correctness.
    1311          12 :   AutoTArray<nsCOMPtr<nsIContent>, 1> targets;
    1312           6 :   if (aEvent->mClass != eTouchEventClass || aEvent->mMessage == eTouchStart) {
    1313             :     // If this event only has one target, and it's remote, add it to
    1314             :     // the array.
    1315             :     nsIFrame* frame =
    1316           6 :       aEvent->mMessage == eDragExit ? sLastDragOverFrame.GetFrame() : GetEventTarget();
    1317           6 :     nsIContent* target = frame ? frame->GetContent() : nullptr;
    1318           6 :     if (IsRemoteTarget(target)) {
    1319           6 :       targets.AppendElement(target);
    1320           6 :     }
    1321             :   } else {
    1322             :     // This is a touch event with possibly multiple touch points.
    1323             :     // Each touch point may have its own target.  So iterate through
    1324             :     // all of them and collect the unique set of targets for event
    1325             :     // forwarding.
    1326             :     //
    1327             :     // This loop is similar to the one used in
    1328             :     // PresShell::DispatchTouchEvent().
    1329             :     const WidgetTouchEvent::TouchArray& touches =
    1330           0 :       aEvent->AsTouchEvent()->mTouches;
    1331           0 :     for (uint32_t i = 0; i < touches.Length(); ++i) {
    1332           0 :       Touch* touch = touches[i];
    1333             :       // NB: the |mChanged| check is an optimization, subprocesses can
    1334             :       // compute this for themselves.  If the touch hasn't changed, we
    1335             :       // may be able to avoid forwarding the event entirely (which is
    1336             :       // not free).
    1337           0 :       if (!touch || !touch->mChanged) {
    1338           0 :         continue;
    1339             :       }
    1340           0 :       nsCOMPtr<EventTarget> targetPtr = touch->mTarget;
    1341           0 :       if (!targetPtr) {
    1342           0 :         continue;
    1343             :       }
    1344           0 :       nsCOMPtr<nsIContent> target = do_QueryInterface(targetPtr);
    1345           0 :       if (IsRemoteTarget(target) && !targets.Contains(target)) {
    1346           0 :         targets.AppendElement(target);
    1347             :       }
    1348             :     }
    1349             :   }
    1350             : 
    1351           6 :   if (targets.Length() == 0) {
    1352           0 :     return false;
    1353             :   }
    1354             : 
    1355             :   // Look up the frame loader for all the remote targets we found, and
    1356             :   // then dispatch the event to the remote content they represent.
    1357          12 :   for (uint32_t i = 0; i < targets.Length(); ++i) {
    1358           6 :     nsIContent* target = targets[i];
    1359          12 :     nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target);
    1360           6 :     if (!loaderOwner) {
    1361           0 :       continue;
    1362             :     }
    1363             : 
    1364          12 :     RefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
    1365           6 :     if (!frameLoader) {
    1366           0 :       continue;
    1367             :     }
    1368             : 
    1369             :     uint32_t eventMode;
    1370           6 :     frameLoader->GetEventMode(&eventMode);
    1371           6 :     if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) {
    1372           0 :       continue;
    1373             :     }
    1374             : 
    1375           6 :     DispatchCrossProcessEvent(aEvent, frameLoader, aStatus);
    1376             :   }
    1377           6 :   return aEvent->HasBeenPostedToRemoteProcess();
    1378             : }
    1379             : 
    1380             : //
    1381             : // CreateClickHoldTimer
    1382             : //
    1383             : // Fire off a timer for determining if the user wants click-hold. This timer
    1384             : // is a one-shot that will be cancelled when the user moves enough to fire
    1385             : // a drag.
    1386             : //
    1387             : void
    1388           0 : EventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
    1389             :                                         nsIFrame* inDownFrame,
    1390             :                                         WidgetGUIEvent* inMouseDownEvent)
    1391             : {
    1392           0 :   if (!inMouseDownEvent->IsTrusted() ||
    1393           0 :       IsRemoteTarget(mGestureDownContent) ||
    1394             :       sIsPointerLocked) {
    1395           0 :     return;
    1396             :   }
    1397             : 
    1398             :   // just to be anal (er, safe)
    1399           0 :   if (mClickHoldTimer) {
    1400           0 :     mClickHoldTimer->Cancel();
    1401           0 :     mClickHoldTimer = nullptr;
    1402             :   }
    1403             : 
    1404             :   // if content clicked on has a popup, don't even start the timer
    1405             :   // since we'll end up conflicting and both will show.
    1406           0 :   if (mGestureDownContent) {
    1407             :     // check for the |popup| attribute
    1408           0 :     if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
    1409           0 :                                         nsGkAtoms::popup))
    1410           0 :       return;
    1411             : 
    1412             :     // check for a <menubutton> like bookmarks
    1413           0 :     if (mGestureDownContent->IsXULElement(nsGkAtoms::menubutton))
    1414           0 :       return;
    1415             :   }
    1416             : 
    1417           0 :   mClickHoldTimer = do_CreateInstance("@mozilla.org/timer;1");
    1418           0 :   if (mClickHoldTimer) {
    1419             :     int32_t clickHoldDelay =
    1420           0 :       Preferences::GetInt("ui.click_hold_context_menus.delay", 500);
    1421           0 :     mClickHoldTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::Other));
    1422           0 :     mClickHoldTimer->InitWithNamedFuncCallback(
    1423             :       sClickHoldCallback,
    1424             :       this,
    1425             :       clickHoldDelay,
    1426             :       nsITimer::TYPE_ONE_SHOT,
    1427           0 :       "EventStateManager::CreateClickHoldTimer");
    1428             :   }
    1429             : } // CreateClickHoldTimer
    1430             : 
    1431             : //
    1432             : // KillClickHoldTimer
    1433             : //
    1434             : // Stop the timer that would show the context menu dead in its tracks
    1435             : //
    1436             : void
    1437           0 : EventStateManager::KillClickHoldTimer()
    1438             : {
    1439           0 :   if (mClickHoldTimer) {
    1440           0 :     mClickHoldTimer->Cancel();
    1441           0 :     mClickHoldTimer = nullptr;
    1442             :   }
    1443           0 : }
    1444             : 
    1445             : //
    1446             : // sClickHoldCallback
    1447             : //
    1448             : // This fires after the mouse has been down for a certain length of time.
    1449             : //
    1450             : void
    1451           0 : EventStateManager::sClickHoldCallback(nsITimer* aTimer, void* aESM)
    1452             : {
    1453           0 :   RefPtr<EventStateManager> self = static_cast<EventStateManager*>(aESM);
    1454           0 :   if (self) {
    1455           0 :     self->FireContextClick();
    1456             :   }
    1457             : 
    1458             :   // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
    1459             : 
    1460           0 : } // sAutoHideCallback
    1461             : 
    1462             : //
    1463             : // FireContextClick
    1464             : //
    1465             : // If we're this far, our timer has fired, which means the mouse has been down
    1466             : // for a certain period of time and has not moved enough to generate a dragGesture.
    1467             : // We can be certain the user wants a context-click at this stage, so generate
    1468             : // a dom event and fire it in.
    1469             : //
    1470             : // After the event fires, check if PreventDefault() has been set on the event which
    1471             : // means that someone either ate the event or put up a context menu. This is our cue
    1472             : // to stop tracking the drag gesture. If we always did this, draggable items w/out
    1473             : // a context menu wouldn't be draggable after a certain length of time, which is
    1474             : // _not_ what we want.
    1475             : //
    1476             : void
    1477           0 : EventStateManager::FireContextClick()
    1478             : {
    1479           0 :   if (!mGestureDownContent || !mPresContext || sIsPointerLocked) {
    1480           0 :     return;
    1481             :   }
    1482             : 
    1483             : #ifdef XP_MACOSX
    1484             :   // Hack to ensure that we don't show a context menu when the user
    1485             :   // let go of the mouse after a long cpu-hogging operation prevented
    1486             :   // us from handling any OS events. See bug 117589.
    1487             :   if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft))
    1488             :     return;
    1489             : #endif
    1490             : 
    1491           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    1492             : 
    1493             :   // Dispatch to the DOM. We have to fake out the ESM and tell it that the
    1494             :   // current target frame is actually where the mouseDown occurred, otherwise it
    1495             :   // will use the frame the mouse is currently over which may or may not be
    1496             :   // the same. (Note: saari and I have decided that we don't have to reset |mCurrentTarget|
    1497             :   // when we're through because no one else is doing anything more with this
    1498             :   // event and it will get reset on the very next event to the correct frame).
    1499           0 :   mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
    1500             :   // make sure the widget sticks around
    1501           0 :   nsCOMPtr<nsIWidget> targetWidget;
    1502           0 :   if (mCurrentTarget && (targetWidget = mCurrentTarget->GetNearestWidget())) {
    1503           0 :     NS_ASSERTION(mPresContext == mCurrentTarget->PresContext(),
    1504             :                  "a prescontext returned a primary frame that didn't belong to it?");
    1505             : 
    1506             :     // before dispatching, check that we're not on something that
    1507             :     // doesn't get a context menu
    1508           0 :     bool allowedToDispatch = true;
    1509             : 
    1510           0 :     if (mGestureDownContent->IsAnyOfXULElements(nsGkAtoms::scrollbar,
    1511             :                                                 nsGkAtoms::scrollbarbutton,
    1512             :                                                 nsGkAtoms::button)) {
    1513           0 :       allowedToDispatch = false;
    1514           0 :     } else if (mGestureDownContent->IsXULElement(nsGkAtoms::toolbarbutton)) {
    1515             :       // a <toolbarbutton> that has the container attribute set
    1516             :       // will already have its own dropdown.
    1517           0 :       if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent,
    1518           0 :               kNameSpaceID_None, nsGkAtoms::container)) {
    1519           0 :         allowedToDispatch = false;
    1520             :       } else {
    1521             :         // If the toolbar button has an open menu, don't attempt to open
    1522             :           // a second menu
    1523           0 :         if (mGestureDownContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1524             :                                              nsGkAtoms::_true, eCaseMatters)) {
    1525           0 :           allowedToDispatch = false;
    1526             :         }
    1527             :       }
    1528             :     }
    1529           0 :     else if (mGestureDownContent->IsHTMLElement()) {
    1530           0 :       nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent));
    1531             : 
    1532           0 :       if (formCtrl) {
    1533           0 :         allowedToDispatch = formCtrl->IsTextOrNumberControl(/*aExcludePassword*/ false) ||
    1534           0 :                             formCtrl->ControlType() == NS_FORM_INPUT_FILE;
    1535             :       }
    1536           0 :       else if (mGestureDownContent->IsAnyOfHTMLElements(nsGkAtoms::applet,
    1537             :                                                         nsGkAtoms::embed,
    1538             :                                                         nsGkAtoms::object,
    1539             :                                                         nsGkAtoms::label)) {
    1540           0 :         allowedToDispatch = false;
    1541             :       }
    1542             :     }
    1543             : 
    1544           0 :     if (allowedToDispatch) {
    1545             :       // init the event while mCurrentTarget is still good
    1546             :       WidgetMouseEvent event(true, eContextMenu, targetWidget,
    1547           0 :                              WidgetMouseEvent::eReal);
    1548           0 :       event.mClickCount = 1;
    1549           0 :       FillInEventFromGestureDown(&event);
    1550             : 
    1551             :       // stop selection tracking, we're in control now
    1552           0 :       if (mCurrentTarget)
    1553             :       {
    1554             :         RefPtr<nsFrameSelection> frameSel =
    1555           0 :           mCurrentTarget->GetFrameSelection();
    1556             : 
    1557           0 :         if (frameSel && frameSel->GetDragState()) {
    1558             :           // note that this can cause selection changed events to fire if we're in
    1559             :           // a text field, which will null out mCurrentTarget
    1560           0 :           frameSel->SetDragState(false);
    1561             :         }
    1562             :       }
    1563             : 
    1564           0 :       nsIDocument* doc = mGestureDownContent->GetComposedDoc();
    1565           0 :       AutoHandlingUserInputStatePusher userInpStatePusher(true, &event, doc);
    1566             : 
    1567             :       // dispatch to DOM
    1568           0 :       EventDispatcher::Dispatch(mGestureDownContent, mPresContext, &event,
    1569           0 :                                 nullptr, &status);
    1570             : 
    1571             :       // We don't need to dispatch to frame handling because no frames
    1572             :       // watch eContextMenu except for nsMenuFrame and that's only for
    1573             :       // dismissal. That's just as well since we don't really know
    1574             :       // which frame to send it to.
    1575             :     }
    1576             :   }
    1577             : 
    1578             :   // now check if the event has been handled. If so, stop tracking a drag
    1579           0 :   if (status == nsEventStatus_eConsumeNoDefault) {
    1580           0 :     StopTrackingDragGesture();
    1581             :   }
    1582             : 
    1583           0 :   KillClickHoldTimer();
    1584             : 
    1585             : } // FireContextClick
    1586             : 
    1587             : //
    1588             : // BeginTrackingDragGesture
    1589             : //
    1590             : // Record that the mouse has gone down and that we should move to TRACKING state
    1591             : // of d&d gesture tracker.
    1592             : //
    1593             : // We also use this to track click-hold context menus. When the mouse goes down,
    1594             : // fire off a short timer. If the timer goes off and we have yet to fire the
    1595             : // drag gesture (ie, the mouse hasn't moved a certain distance), then we can
    1596             : // assume the user wants a click-hold, so fire a context-click event. We only
    1597             : // want to cancel the drag gesture if the context-click event is handled.
    1598             : //
    1599             : void
    1600           0 : EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
    1601             :                                             WidgetMouseEvent* inDownEvent,
    1602             :                                             nsIFrame* inDownFrame)
    1603             : {
    1604           0 :   if (!inDownEvent->mWidget) {
    1605           0 :     return;
    1606             :   }
    1607             : 
    1608             :   // Note that |inDownEvent| could be either a mouse down event or a
    1609             :   // synthesized mouse move event.
    1610             :   mGestureDownPoint =
    1611           0 :     inDownEvent->mRefPoint + inDownEvent->mWidget->WidgetToScreenOffset();
    1612             : 
    1613           0 :   if (inDownFrame) {
    1614           0 :     inDownFrame->GetContentForEvent(inDownEvent,
    1615           0 :                                     getter_AddRefs(mGestureDownContent));
    1616             : 
    1617           0 :     mGestureDownFrameOwner = inDownFrame->GetContent();
    1618           0 :     if (!mGestureDownFrameOwner) {
    1619           0 :       mGestureDownFrameOwner = mGestureDownContent;
    1620             :     }
    1621             :   }
    1622           0 :   mGestureModifiers = inDownEvent->mModifiers;
    1623           0 :   mGestureDownButtons = inDownEvent->buttons;
    1624             : 
    1625           0 :   if (inDownEvent->mMessage != eMouseTouchDrag && Prefs::ClickHoldContextMenu()) {
    1626             :     // fire off a timer to track click-hold
    1627           0 :     CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
    1628             :   }
    1629             : }
    1630             : 
    1631             : void
    1632           0 : EventStateManager::BeginTrackingRemoteDragGesture(nsIContent* aContent)
    1633             : {
    1634           0 :   mGestureDownContent = aContent;
    1635           0 :   mGestureDownFrameOwner = aContent;
    1636           0 : }
    1637             : 
    1638             : //
    1639             : // StopTrackingDragGesture
    1640             : //
    1641             : // Record that the mouse has gone back up so that we should leave the TRACKING
    1642             : // state of d&d gesture tracker and return to the START state.
    1643             : //
    1644             : void
    1645           0 : EventStateManager::StopTrackingDragGesture()
    1646             : {
    1647           0 :   mGestureDownContent = nullptr;
    1648           0 :   mGestureDownFrameOwner = nullptr;
    1649           0 : }
    1650             : 
    1651             : void
    1652           0 : EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent)
    1653             : {
    1654           0 :   NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),
    1655             :                "Incorrect widget in event");
    1656             : 
    1657             :   // Set the coordinates in the new event to the coordinates of
    1658             :   // the old event, adjusted for the fact that the widget might be
    1659             :   // different
    1660             :   aEvent->mRefPoint =
    1661           0 :     mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
    1662           0 :   aEvent->mModifiers = mGestureModifiers;
    1663           0 :   aEvent->buttons = mGestureDownButtons;
    1664           0 : }
    1665             : 
    1666             : //
    1667             : // GenerateDragGesture
    1668             : //
    1669             : // If we're in the TRACKING state of the d&d gesture tracker, check the current position
    1670             : // of the mouse in relation to the old one. If we've moved a sufficient amount from
    1671             : // the mouse down, then fire off a drag gesture event.
    1672             : void
    1673           8 : EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
    1674             :                                        WidgetInputEvent* aEvent)
    1675             : {
    1676           8 :   NS_ASSERTION(aPresContext, "This shouldn't happen.");
    1677           8 :   if (IsTrackingDragGesture()) {
    1678           0 :     mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
    1679             : 
    1680           0 :     if (!mCurrentTarget || !mCurrentTarget->GetNearestWidget()) {
    1681           0 :       StopTrackingDragGesture();
    1682           0 :       return;
    1683             :     }
    1684             : 
    1685             :     // Check if selection is tracking drag gestures, if so
    1686             :     // don't interfere!
    1687           0 :     if (mCurrentTarget)
    1688             :     {
    1689           0 :       RefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
    1690           0 :       if (frameSel && frameSel->GetDragState()) {
    1691           0 :         StopTrackingDragGesture();
    1692           0 :         return;
    1693             :       }
    1694             :     }
    1695             : 
    1696             :     // If non-native code is capturing the mouse don't start a drag.
    1697           0 :     if (nsIPresShell::IsMouseCapturePreventingDrag()) {
    1698           0 :       StopTrackingDragGesture();
    1699           0 :       return;
    1700             :     }
    1701             : 
    1702             :     static int32_t pixelThresholdX = 0;
    1703             :     static int32_t pixelThresholdY = 0;
    1704             : 
    1705           0 :     if (!pixelThresholdX) {
    1706           0 :       pixelThresholdX =
    1707           0 :         LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 0);
    1708           0 :       pixelThresholdY =
    1709           0 :         LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0);
    1710           0 :       if (!pixelThresholdX)
    1711           0 :         pixelThresholdX = 5;
    1712           0 :       if (!pixelThresholdY)
    1713           0 :         pixelThresholdY = 5;
    1714             :     }
    1715             : 
    1716             :     // fire drag gesture if mouse has moved enough
    1717           0 :     LayoutDeviceIntPoint pt = aEvent->mWidget->WidgetToScreenOffset() +
    1718           0 :       (aEvent->AsTouchEvent() ? aEvent->AsTouchEvent()->mTouches[0]->mRefPoint
    1719           0 :                               : aEvent->mRefPoint);
    1720           0 :     LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
    1721           0 :     if (Abs(distance.x) > AssertedCast<uint32_t>(pixelThresholdX) ||
    1722           0 :         Abs(distance.y) > AssertedCast<uint32_t>(pixelThresholdY)) {
    1723           0 :       if (Prefs::ClickHoldContextMenu()) {
    1724             :         // stop the click-hold before we fire off the drag gesture, in case
    1725             :         // it takes a long time
    1726           0 :         KillClickHoldTimer();
    1727             :       }
    1728             : 
    1729           0 :       nsCOMPtr<nsIDocShell> docshell = aPresContext->GetDocShell();
    1730           0 :       if (!docshell) {
    1731           0 :         return;
    1732             :       }
    1733             : 
    1734           0 :       nsCOMPtr<nsPIDOMWindowOuter> window = docshell->GetWindow();
    1735           0 :       if (!window)
    1736           0 :         return;
    1737             : 
    1738             :       RefPtr<DataTransfer> dataTransfer =
    1739           0 :         new DataTransfer(window, eDragStart, false, -1);
    1740             : 
    1741           0 :       nsCOMPtr<nsISelection> selection;
    1742           0 :       nsCOMPtr<nsIContent> eventContent, targetContent;
    1743           0 :       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
    1744           0 :       if (eventContent)
    1745           0 :         DetermineDragTargetAndDefaultData(window, eventContent, dataTransfer,
    1746           0 :                                           getter_AddRefs(selection),
    1747           0 :                                           getter_AddRefs(targetContent));
    1748             : 
    1749             :       // Stop tracking the drag gesture now. This should stop us from
    1750             :       // reentering GenerateDragGesture inside DOM event processing.
    1751           0 :       StopTrackingDragGesture();
    1752             : 
    1753           0 :       if (!targetContent)
    1754           0 :         return;
    1755             : 
    1756             :       // Use our targetContent, now that we've determined it, as the
    1757             :       // parent object of the DataTransfer.
    1758           0 :       dataTransfer->SetParentObject(targetContent);
    1759             : 
    1760           0 :       sLastDragOverFrame = nullptr;
    1761           0 :       nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
    1762             : 
    1763             :       // get the widget from the target frame
    1764           0 :       WidgetDragEvent startEvent(aEvent->IsTrusted(), eDragStart, widget);
    1765           0 :       FillInEventFromGestureDown(&startEvent);
    1766             : 
    1767           0 :       startEvent.mDataTransfer = dataTransfer;
    1768           0 :       if (aEvent->AsMouseEvent()) {
    1769           0 :         startEvent.inputSource = aEvent->AsMouseEvent()->inputSource;
    1770           0 :       } else if (aEvent->AsTouchEvent()) {
    1771           0 :         startEvent.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
    1772             :       } else {
    1773           0 :         MOZ_ASSERT(false);
    1774             :       }
    1775             : 
    1776             :       // Dispatch to the DOM. By setting mCurrentTarget we are faking
    1777             :       // out the ESM and telling it that the current target frame is
    1778             :       // actually where the mouseDown occurred, otherwise it will use
    1779             :       // the frame the mouse is currently over which may or may not be
    1780             :       // the same. (Note: saari and I have decided that we don't have
    1781             :       // to reset |mCurrentTarget| when we're through because no one
    1782             :       // else is doing anything more with this event and it will get
    1783             :       // reset on the very next event to the correct frame).
    1784             : 
    1785             :       // Hold onto old target content through the event and reset after.
    1786           0 :       nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
    1787             : 
    1788             :       // Set the current target to the content for the mouse down
    1789           0 :       mCurrentTargetContent = targetContent;
    1790             : 
    1791             :       // Dispatch the dragstart event to the DOM.
    1792           0 :       nsEventStatus status = nsEventStatus_eIgnore;
    1793             :       EventDispatcher::Dispatch(targetContent, aPresContext, &startEvent,
    1794           0 :                                 nullptr, &status);
    1795             : 
    1796           0 :       WidgetDragEvent* event = &startEvent;
    1797             : 
    1798             :       nsCOMPtr<nsIObserverService> observerService =
    1799           0 :         mozilla::services::GetObserverService();
    1800             :       // Emit observer event to allow addons to modify the DataTransfer object.
    1801           0 :       if (observerService) {
    1802           0 :         observerService->NotifyObservers(dataTransfer,
    1803             :                                          "on-datatransfer-available",
    1804           0 :                                          nullptr);
    1805             :       }
    1806             : 
    1807             :       // now that the dataTransfer has been updated in the dragstart and
    1808             :       // draggesture events, make it read only so that the data doesn't
    1809             :       // change during the drag.
    1810           0 :       dataTransfer->SetReadOnly();
    1811             : 
    1812           0 :       if (status != nsEventStatus_eConsumeNoDefault) {
    1813           0 :         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
    1814           0 :                                               targetContent, selection);
    1815           0 :         if (dragStarted) {
    1816           0 :           sActiveESM = nullptr;
    1817           0 :           aEvent->StopPropagation();
    1818             :         }
    1819             :       }
    1820             : 
    1821             :       // Reset mCurretTargetContent to what it was
    1822           0 :       mCurrentTargetContent = targetBeforeEvent;
    1823             :     }
    1824             : 
    1825             :     // Now flush all pending notifications, for better responsiveness
    1826             :     // while dragging.
    1827           0 :     FlushPendingEvents(aPresContext);
    1828             :   }
    1829             : } // GenerateDragGesture
    1830             : 
    1831             : void
    1832           0 : EventStateManager::DetermineDragTargetAndDefaultData(nsPIDOMWindowOuter* aWindow,
    1833             :                                                      nsIContent* aSelectionTarget,
    1834             :                                                      DataTransfer* aDataTransfer,
    1835             :                                                      nsISelection** aSelection,
    1836             :                                                      nsIContent** aTargetNode)
    1837             : {
    1838           0 :   *aTargetNode = nullptr;
    1839             : 
    1840             :   // GetDragData determines if a selection, link or image in the content
    1841             :   // should be dragged, and places the data associated with the drag in the
    1842             :   // data transfer.
    1843             :   // mGestureDownContent is the node where the mousedown event for the drag
    1844             :   // occurred, and aSelectionTarget is the node to use when a selection is used
    1845             :   bool canDrag;
    1846           0 :   nsCOMPtr<nsIContent> dragDataNode;
    1847           0 :   bool wasAlt = (mGestureModifiers & MODIFIER_ALT) != 0;
    1848           0 :   nsresult rv = nsContentAreaDragDrop::GetDragData(aWindow, mGestureDownContent,
    1849             :                                                    aSelectionTarget, wasAlt,
    1850             :                                                    aDataTransfer, &canDrag, aSelection,
    1851           0 :                                                    getter_AddRefs(dragDataNode));
    1852           0 :   if (NS_FAILED(rv) || !canDrag)
    1853           0 :     return;
    1854             : 
    1855             :   // if GetDragData returned a node, use that as the node being dragged.
    1856             :   // Otherwise, if a selection is being dragged, use the node within the
    1857             :   // selection that was dragged. Otherwise, just use the mousedown target.
    1858           0 :   nsIContent* dragContent = mGestureDownContent;
    1859           0 :   if (dragDataNode)
    1860           0 :     dragContent = dragDataNode;
    1861           0 :   else if (*aSelection)
    1862           0 :     dragContent = aSelectionTarget;
    1863             : 
    1864           0 :   nsIContent* originalDragContent = dragContent;
    1865             : 
    1866             :   // If a selection isn't being dragged, look for an ancestor with the
    1867             :   // draggable property set. If one is found, use that as the target of the
    1868             :   // drag instead of the node that was clicked on. If a draggable node wasn't
    1869             :   // found, just use the clicked node.
    1870           0 :   if (!*aSelection) {
    1871           0 :     while (dragContent) {
    1872           0 :       nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(dragContent);
    1873           0 :       if (htmlElement) {
    1874           0 :         bool draggable = false;
    1875           0 :         htmlElement->GetDraggable(&draggable);
    1876           0 :         if (draggable)
    1877           0 :           break;
    1878             :       }
    1879             :       else {
    1880           0 :         nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(dragContent);
    1881           0 :         if (xulElement) {
    1882             :           // All XUL elements are draggable, so if a XUL element is
    1883             :           // encountered, stop looking for draggable nodes and just use the
    1884             :           // original clicked node instead.
    1885             :           // XXXndeakin
    1886             :           // In the future, we will want to improve this so that XUL has a
    1887             :           // better way to specify whether something is draggable than just
    1888             :           // on/off.
    1889           0 :           dragContent = mGestureDownContent;
    1890           0 :           break;
    1891             :         }
    1892             :         // otherwise, it's not an HTML or XUL element, so just keep looking
    1893             :       }
    1894           0 :       dragContent = dragContent->GetParent();
    1895             :     }
    1896             :   }
    1897             : 
    1898             :   // if no node in the hierarchy was found to drag, but the GetDragData method
    1899             :   // returned a node, use that returned node. Otherwise, nothing is draggable.
    1900           0 :   if (!dragContent && dragDataNode)
    1901           0 :     dragContent = dragDataNode;
    1902             : 
    1903           0 :   if (dragContent) {
    1904             :     // if an ancestor node was used instead, clear the drag data
    1905             :     // XXXndeakin rework this a bit. Find a way to just not call GetDragData if we don't need to.
    1906           0 :     if (dragContent != originalDragContent)
    1907           0 :       aDataTransfer->ClearAll();
    1908           0 :     *aTargetNode = dragContent;
    1909           0 :     NS_ADDREF(*aTargetNode);
    1910             :   }
    1911             : }
    1912             : 
    1913             : bool
    1914           0 : EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
    1915             :                                       WidgetDragEvent* aDragEvent,
    1916             :                                       DataTransfer* aDataTransfer,
    1917             :                                       nsIContent* aDragTarget,
    1918             :                                       nsISelection* aSelection)
    1919             : {
    1920             :   nsCOMPtr<nsIDragService> dragService =
    1921           0 :     do_GetService("@mozilla.org/widget/dragservice;1");
    1922           0 :   if (!dragService)
    1923           0 :     return false;
    1924             : 
    1925             :   // Default handling for the dragstart event.
    1926             :   //
    1927             :   // First, check if a drag session already exists. This means that the drag
    1928             :   // service was called directly within a draggesture handler. In this case,
    1929             :   // don't do anything more, as it is assumed that the handler is managing
    1930             :   // drag and drop manually. Make sure to return true to indicate that a drag
    1931             :   // began.
    1932           0 :   nsCOMPtr<nsIDragSession> dragSession;
    1933           0 :   dragService->GetCurrentSession(getter_AddRefs(dragSession));
    1934           0 :   if (dragSession)
    1935           0 :     return true;
    1936             : 
    1937             :   // No drag session is currently active, so check if a handler added
    1938             :   // any items to be dragged. If not, there isn't anything to drag.
    1939           0 :   uint32_t count = 0;
    1940           0 :   if (aDataTransfer)
    1941           0 :     aDataTransfer->GetMozItemCount(&count);
    1942           0 :   if (!count)
    1943           0 :     return false;
    1944             : 
    1945             :   // Get the target being dragged, which may not be the same as the
    1946             :   // target of the mouse event. If one wasn't set in the
    1947             :   // aDataTransfer during the event handler, just use the original
    1948             :   // target instead.
    1949           0 :   nsCOMPtr<nsIContent> dragTarget = aDataTransfer->GetDragTarget();
    1950           0 :   if (!dragTarget) {
    1951           0 :     dragTarget = aDragTarget;
    1952           0 :     if (!dragTarget)
    1953           0 :       return false;
    1954             :   }
    1955             : 
    1956             :   // check which drag effect should initially be used. If the effect was not
    1957             :   // set, just use all actions, otherwise Windows won't allow a drop.
    1958             :   uint32_t action;
    1959           0 :   aDataTransfer->GetEffectAllowedInt(&action);
    1960           0 :   if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
    1961           0 :     action = nsIDragService::DRAGDROP_ACTION_COPY |
    1962             :              nsIDragService::DRAGDROP_ACTION_MOVE |
    1963             :              nsIDragService::DRAGDROP_ACTION_LINK;
    1964             : 
    1965             :   // get any custom drag image that was set
    1966             :   int32_t imageX, imageY;
    1967           0 :   Element* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
    1968             : 
    1969             :   nsCOMPtr<nsIArray> transArray =
    1970           0 :     aDataTransfer->GetTransferables(dragTarget->AsDOMNode());
    1971           0 :   if (!transArray)
    1972           0 :     return false;
    1973             : 
    1974             :   // XXXndeakin don't really want to create a new drag DOM event
    1975             :   // here, but we need something to pass to the InvokeDragSession
    1976             :   // methods.
    1977             :   RefPtr<DragEvent> event =
    1978           0 :     NS_NewDOMDragEvent(dragTarget, aPresContext, aDragEvent);
    1979             : 
    1980             :   // Use InvokeDragSessionWithSelection if a selection is being dragged,
    1981             :   // such that the image can be generated from the selected text. However,
    1982             :   // use InvokeDragSessionWithImage if a custom image was set or something
    1983             :   // other than a selection is being dragged.
    1984           0 :   if (!dragImage && aSelection) {
    1985           0 :     dragService->InvokeDragSessionWithSelection(aSelection, transArray,
    1986           0 :                                                 action, event, aDataTransfer);
    1987             :   }
    1988             :   else {
    1989             :     // if dragging within a XUL tree and no custom drag image was
    1990             :     // set, the region argument to InvokeDragSessionWithImage needs
    1991             :     // to be set to the area encompassing the selected rows of the
    1992             :     // tree to ensure that the drag feedback gets clipped to those
    1993             :     // rows. For other content, region should be null.
    1994           0 :     nsCOMPtr<nsIScriptableRegion> region;
    1995             : #ifdef MOZ_XUL
    1996           0 :     if (dragTarget && !dragImage) {
    1997           0 :       if (dragTarget->NodeInfo()->Equals(nsGkAtoms::treechildren,
    1998             :                                          kNameSpaceID_XUL)) {
    1999             :         nsTreeBodyFrame* treeBody =
    2000           0 :           do_QueryFrame(dragTarget->GetPrimaryFrame());
    2001           0 :         if (treeBody) {
    2002           0 :           treeBody->GetSelectionRegion(getter_AddRefs(region));
    2003             :         }
    2004             :       }
    2005             :     }
    2006             : #endif
    2007             : 
    2008           0 :     dragService->InvokeDragSessionWithImage(dragTarget->AsDOMNode(), transArray,
    2009             :                                             region, action,
    2010           0 :                                             dragImage ? dragImage->AsDOMNode() :
    2011             :                                                         nullptr,
    2012             :                                             imageX, imageY, event,
    2013           0 :                                             aDataTransfer);
    2014             :   }
    2015             : 
    2016           0 :   return true;
    2017             : }
    2018             : 
    2019             : nsresult
    2020           0 : EventStateManager::GetContentViewer(nsIContentViewer** aCv)
    2021             : {
    2022           0 :   *aCv = nullptr;
    2023             : 
    2024           0 :   nsPIDOMWindowOuter* window = mDocument->GetWindow();
    2025           0 :   if (!window) return NS_ERROR_FAILURE;
    2026           0 :   nsCOMPtr<nsPIDOMWindowOuter> rootWindow = window->GetPrivateRoot();
    2027           0 :   if (!rootWindow) return NS_ERROR_FAILURE;
    2028             : 
    2029           0 :   TabChild* tabChild = TabChild::GetFrom(rootWindow);
    2030           0 :   if (!tabChild) {
    2031           0 :     nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    2032           0 :     if (!fm) return NS_ERROR_FAILURE;
    2033             : 
    2034           0 :     nsCOMPtr<mozIDOMWindowProxy> activeWindow;
    2035           0 :     fm->GetActiveWindow(getter_AddRefs(activeWindow));
    2036           0 :     if (rootWindow != activeWindow) return NS_OK;
    2037             :   } else {
    2038           0 :     if (!tabChild->ParentIsActive()) return NS_OK;
    2039             :   }
    2040             : 
    2041           0 :   nsCOMPtr<nsPIDOMWindowOuter> contentWindow = nsGlobalWindow::Cast(rootWindow)->GetContent();
    2042           0 :   if (!contentWindow) return NS_ERROR_FAILURE;
    2043             : 
    2044           0 :   nsIDocument *doc = contentWindow->GetDoc();
    2045           0 :   if (!doc) return NS_ERROR_FAILURE;
    2046             : 
    2047           0 :   nsCOMPtr<nsISupports> container = doc->GetContainer();
    2048           0 :   if (!container) return NS_ERROR_FAILURE;
    2049             : 
    2050           0 :   nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(container);
    2051           0 :   docshell->GetContentViewer(aCv);
    2052           0 :   if (!*aCv) return NS_ERROR_FAILURE;
    2053             : 
    2054           0 :   return NS_OK;
    2055             : }
    2056             : 
    2057             : nsresult
    2058           0 : EventStateManager::ChangeTextSize(int32_t change)
    2059             : {
    2060           0 :   nsCOMPtr<nsIContentViewer> cv;
    2061           0 :   nsresult rv = GetContentViewer(getter_AddRefs(cv));
    2062           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2063             : 
    2064           0 :   if (cv) {
    2065             :     float textzoom;
    2066           0 :     float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100;
    2067           0 :     float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100;
    2068           0 :     cv->GetTextZoom(&textzoom);
    2069           0 :     textzoom += ((float)change) / 10;
    2070           0 :     if (textzoom < zoomMin)
    2071           0 :       textzoom = zoomMin;
    2072           0 :     else if (textzoom > zoomMax)
    2073           0 :       textzoom = zoomMax;
    2074           0 :     cv->SetTextZoom(textzoom);
    2075             :   }
    2076             : 
    2077           0 :   return NS_OK;
    2078             : }
    2079             : 
    2080             : nsresult
    2081           0 : EventStateManager::ChangeFullZoom(int32_t change)
    2082             : {
    2083           0 :   nsCOMPtr<nsIContentViewer> cv;
    2084           0 :   nsresult rv = GetContentViewer(getter_AddRefs(cv));
    2085           0 :   NS_ENSURE_SUCCESS(rv, rv);
    2086             : 
    2087           0 :   if (cv) {
    2088             :     float fullzoom;
    2089           0 :     float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100;
    2090           0 :     float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100;
    2091           0 :     cv->GetFullZoom(&fullzoom);
    2092           0 :     fullzoom += ((float)change) / 10;
    2093           0 :     if (fullzoom < zoomMin)
    2094           0 :       fullzoom = zoomMin;
    2095           0 :     else if (fullzoom > zoomMax)
    2096           0 :       fullzoom = zoomMax;
    2097           0 :     cv->SetFullZoom(fullzoom);
    2098             :   }
    2099             : 
    2100           0 :   return NS_OK;
    2101             : }
    2102             : 
    2103             : void
    2104           0 : EventStateManager::DoScrollHistory(int32_t direction)
    2105             : {
    2106           0 :   nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainerWeak());
    2107           0 :   if (pcContainer) {
    2108           0 :     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
    2109           0 :     if (webNav) {
    2110             :       // positive direction to go back one step, nonpositive to go forward
    2111           0 :       if (direction > 0)
    2112           0 :         webNav->GoBack();
    2113             :       else
    2114           0 :         webNav->GoForward();
    2115             :     }
    2116             :   }
    2117           0 : }
    2118             : 
    2119             : void
    2120           0 : EventStateManager::DoScrollZoom(nsIFrame* aTargetFrame,
    2121             :                                 int32_t adjustment)
    2122             : {
    2123             :   // Exclude form controls and content in chrome docshells.
    2124           0 :   nsIContent *content = aTargetFrame->GetContent();
    2125           0 :   if (content &&
    2126           0 :       !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
    2127           0 :       !nsContentUtils::IsInChromeDocshell(content->OwnerDoc()))
    2128             :     {
    2129             :       // positive adjustment to decrease zoom, negative to increase
    2130           0 :       int32_t change = (adjustment > 0) ? -1 : 1;
    2131             : 
    2132           0 :       EnsureDocument(mPresContext);
    2133           0 :       if (Preferences::GetBool("browser.zoom.full") || content->OwnerDoc()->IsSyntheticDocument()) {
    2134           0 :         ChangeFullZoom(change);
    2135             :       } else {
    2136           0 :         ChangeTextSize(change);
    2137             :       }
    2138           0 :       nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
    2139           0 :                                           NS_LITERAL_STRING("ZoomChangeUsingMouseWheel"),
    2140           0 :                                           true, true);
    2141             :     }
    2142           0 : }
    2143             : 
    2144             : static nsIFrame*
    2145           0 : GetParentFrameToScroll(nsIFrame* aFrame)
    2146             : {
    2147           0 :   if (!aFrame)
    2148           0 :     return nullptr;
    2149             : 
    2150           0 :   if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
    2151           0 :       nsLayoutUtils::IsReallyFixedPos(aFrame))
    2152           0 :     return aFrame->PresContext()->GetPresShell()->GetRootScrollFrame();
    2153             : 
    2154           0 :   return aFrame->GetParent();
    2155             : }
    2156             : 
    2157             : /*static*/ bool
    2158           3 : EventStateManager::CanVerticallyScrollFrameWithWheel(nsIFrame* aFrame)
    2159             : {
    2160           3 :   nsIContent* c = aFrame->GetContent();
    2161           3 :   if (!c) {
    2162           3 :     return true;
    2163             :   }
    2164             :   nsCOMPtr<nsITextControlElement> ctrl =
    2165           0 :     do_QueryInterface(c->IsInAnonymousSubtree() ? c->GetBindingParent() : c);
    2166           0 :   if (ctrl && ctrl->IsSingleLineTextControl()) {
    2167           0 :     return false;
    2168             :   }
    2169           0 :   return true;
    2170             : }
    2171             : 
    2172             : void
    2173           0 : EventStateManager::DispatchLegacyMouseScrollEvents(nsIFrame* aTargetFrame,
    2174             :                                                    WidgetWheelEvent* aEvent,
    2175             :                                                    nsEventStatus* aStatus)
    2176             : {
    2177           0 :   MOZ_ASSERT(aEvent);
    2178           0 :   MOZ_ASSERT(aStatus);
    2179             : 
    2180           0 :   if (!aTargetFrame || *aStatus == nsEventStatus_eConsumeNoDefault) {
    2181           0 :     return;
    2182             :   }
    2183             : 
    2184             :   // Ignore mouse wheel transaction for computing legacy mouse wheel
    2185             :   // events' delta value.
    2186             :   nsIFrame* scrollFrame =
    2187             :     ComputeScrollTarget(aTargetFrame, aEvent,
    2188           0 :                         COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
    2189             : 
    2190           0 :   nsIScrollableFrame* scrollTarget = do_QueryFrame(scrollFrame);
    2191             :   nsPresContext* pc =
    2192           0 :     scrollFrame ? scrollFrame->PresContext() : aTargetFrame->PresContext();
    2193             : 
    2194             :   // DOM event's delta vales are computed from CSS pixels.
    2195           0 :   nsSize scrollAmount = GetScrollAmount(pc, aEvent, scrollTarget);
    2196             :   nsIntSize scrollAmountInCSSPixels(
    2197             :     nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),
    2198           0 :     nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height));
    2199             : 
    2200             :   // XXX We don't deal with fractional amount in legacy event, though the
    2201             :   //     default action handler (DoScrollText()) deals with it.
    2202             :   //     If we implemented such strict computation, we would need additional
    2203             :   //     accumulated delta values. It would made the code more complicated.
    2204             :   //     And also it would computes different delta values from older version.
    2205             :   //     It doesn't make sense to implement such code for legacy events and
    2206             :   //     rare cases.
    2207             :   int32_t scrollDeltaX, scrollDeltaY, pixelDeltaX, pixelDeltaY;
    2208           0 :   switch (aEvent->mDeltaMode) {
    2209             :     case nsIDOMWheelEvent::DOM_DELTA_PAGE:
    2210           0 :       scrollDeltaX =
    2211           0 :         !aEvent->mLineOrPageDeltaX ? 0 :
    2212           0 :           (aEvent->mLineOrPageDeltaX > 0  ? nsIDOMUIEvent::SCROLL_PAGE_DOWN :
    2213             :                                             nsIDOMUIEvent::SCROLL_PAGE_UP);
    2214           0 :       scrollDeltaY =
    2215           0 :         !aEvent->mLineOrPageDeltaY ? 0 :
    2216           0 :           (aEvent->mLineOrPageDeltaY > 0  ? nsIDOMUIEvent::SCROLL_PAGE_DOWN :
    2217             :                                             nsIDOMUIEvent::SCROLL_PAGE_UP);
    2218           0 :       pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
    2219           0 :       pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
    2220           0 :       break;
    2221             : 
    2222             :     case nsIDOMWheelEvent::DOM_DELTA_LINE:
    2223           0 :       scrollDeltaX = aEvent->mLineOrPageDeltaX;
    2224           0 :       scrollDeltaY = aEvent->mLineOrPageDeltaY;
    2225           0 :       pixelDeltaX = RoundDown(aEvent->mDeltaX * scrollAmountInCSSPixels.width);
    2226           0 :       pixelDeltaY = RoundDown(aEvent->mDeltaY * scrollAmountInCSSPixels.height);
    2227           0 :       break;
    2228             : 
    2229             :     case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
    2230           0 :       scrollDeltaX = aEvent->mLineOrPageDeltaX;
    2231           0 :       scrollDeltaY = aEvent->mLineOrPageDeltaY;
    2232           0 :       pixelDeltaX = RoundDown(aEvent->mDeltaX);
    2233           0 :       pixelDeltaY = RoundDown(aEvent->mDeltaY);
    2234           0 :       break;
    2235             : 
    2236             :     default:
    2237           0 :       MOZ_CRASH("Invalid deltaMode value comes");
    2238             :   }
    2239             : 
    2240             :   // Send the legacy events in following order:
    2241             :   // 1. Vertical scroll
    2242             :   // 2. Vertical pixel scroll (even if #1 isn't consumed)
    2243             :   // 3. Horizontal scroll (even if #1 and/or #2 are consumed)
    2244             :   // 4. Horizontal pixel scroll (even if #3 isn't consumed)
    2245             : 
    2246           0 :   AutoWeakFrame targetFrame(aTargetFrame);
    2247             : 
    2248           0 :   MOZ_ASSERT(*aStatus != nsEventStatus_eConsumeNoDefault &&
    2249             :              !aEvent->DefaultPrevented(),
    2250             :              "If you make legacy events dispatched for default prevented wheel "
    2251             :              "event, you need to initialize stateX and stateY");
    2252           0 :   EventState stateX, stateY;
    2253           0 :   if (scrollDeltaY) {
    2254             :     SendLineScrollEvent(aTargetFrame, aEvent, stateY,
    2255           0 :                         scrollDeltaY, DELTA_DIRECTION_Y);
    2256           0 :     if (!targetFrame.IsAlive()) {
    2257           0 :       *aStatus = nsEventStatus_eConsumeNoDefault;
    2258           0 :       return;
    2259             :     }
    2260             :   }
    2261             : 
    2262           0 :   if (pixelDeltaY) {
    2263             :     SendPixelScrollEvent(aTargetFrame, aEvent, stateY,
    2264           0 :                          pixelDeltaY, DELTA_DIRECTION_Y);
    2265           0 :     if (!targetFrame.IsAlive()) {
    2266           0 :       *aStatus = nsEventStatus_eConsumeNoDefault;
    2267           0 :       return;
    2268             :     }
    2269             :   }
    2270             : 
    2271           0 :   if (scrollDeltaX) {
    2272             :     SendLineScrollEvent(aTargetFrame, aEvent, stateX,
    2273           0 :                         scrollDeltaX, DELTA_DIRECTION_X);
    2274           0 :     if (!targetFrame.IsAlive()) {
    2275           0 :       *aStatus = nsEventStatus_eConsumeNoDefault;
    2276           0 :       return;
    2277             :     }
    2278             :   }
    2279             : 
    2280           0 :   if (pixelDeltaX) {
    2281             :     SendPixelScrollEvent(aTargetFrame, aEvent, stateX,
    2282           0 :                          pixelDeltaX, DELTA_DIRECTION_X);
    2283           0 :     if (!targetFrame.IsAlive()) {
    2284           0 :       *aStatus = nsEventStatus_eConsumeNoDefault;
    2285           0 :       return;
    2286             :     }
    2287             :   }
    2288             : 
    2289           0 :   if (stateY.mDefaultPrevented) {
    2290           0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
    2291           0 :     aEvent->PreventDefault(!stateY.mDefaultPreventedByContent);
    2292             :   }
    2293             : 
    2294           0 :   if (stateX.mDefaultPrevented) {
    2295           0 :     *aStatus = nsEventStatus_eConsumeNoDefault;
    2296           0 :     aEvent->PreventDefault(!stateX.mDefaultPreventedByContent);
    2297             :   }
    2298             : }
    2299             : 
    2300             : void
    2301           0 : EventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
    2302             :                                        WidgetWheelEvent* aEvent,
    2303             :                                        EventState& aState,
    2304             :                                        int32_t aDelta,
    2305             :                                        DeltaDirection aDeltaDirection)
    2306             : {
    2307           0 :   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
    2308           0 :   if (!targetContent)
    2309           0 :     targetContent = GetFocusedContent();
    2310           0 :   if (!targetContent)
    2311           0 :     return;
    2312             : 
    2313           0 :   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
    2314           0 :     targetContent = targetContent->GetParent();
    2315             :   }
    2316             : 
    2317           0 :   WidgetMouseScrollEvent event(aEvent->IsTrusted(),
    2318           0 :                                eLegacyMouseLineOrPageScroll, aEvent->mWidget);
    2319           0 :   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
    2320           0 :   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
    2321           0 :   event.mRefPoint = aEvent->mRefPoint;
    2322           0 :   event.mTime = aEvent->mTime;
    2323           0 :   event.mTimeStamp = aEvent->mTimeStamp;
    2324           0 :   event.mModifiers = aEvent->mModifiers;
    2325           0 :   event.buttons = aEvent->buttons;
    2326           0 :   event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
    2327           0 :   event.mDelta = aDelta;
    2328           0 :   event.inputSource = aEvent->inputSource;
    2329             : 
    2330           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    2331           0 :   EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
    2332           0 :                             &event, nullptr, &status);
    2333           0 :   aState.mDefaultPrevented =
    2334           0 :     event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
    2335           0 :   aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
    2336             : }
    2337             : 
    2338             : void
    2339           0 : EventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
    2340             :                                         WidgetWheelEvent* aEvent,
    2341             :                                         EventState& aState,
    2342             :                                         int32_t aPixelDelta,
    2343             :                                         DeltaDirection aDeltaDirection)
    2344             : {
    2345           0 :   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
    2346           0 :   if (!targetContent) {
    2347           0 :     targetContent = GetFocusedContent();
    2348           0 :     if (!targetContent)
    2349           0 :       return;
    2350             :   }
    2351             : 
    2352           0 :   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
    2353           0 :     targetContent = targetContent->GetParent();
    2354             :   }
    2355             : 
    2356           0 :   WidgetMouseScrollEvent event(aEvent->IsTrusted(),
    2357           0 :                                eLegacyMousePixelScroll, aEvent->mWidget);
    2358           0 :   event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
    2359           0 :   event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
    2360           0 :   event.mRefPoint = aEvent->mRefPoint;
    2361           0 :   event.mTime = aEvent->mTime;
    2362           0 :   event.mTimeStamp = aEvent->mTimeStamp;
    2363           0 :   event.mModifiers = aEvent->mModifiers;
    2364           0 :   event.buttons = aEvent->buttons;
    2365           0 :   event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
    2366           0 :   event.mDelta = aPixelDelta;
    2367           0 :   event.inputSource = aEvent->inputSource;
    2368             : 
    2369           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    2370           0 :   EventDispatcher::Dispatch(targetContent, aTargetFrame->PresContext(),
    2371           0 :                             &event, nullptr, &status);
    2372           0 :   aState.mDefaultPrevented =
    2373           0 :     event.DefaultPrevented() || status == nsEventStatus_eConsumeNoDefault;
    2374           0 :   aState.mDefaultPreventedByContent = event.DefaultPreventedByContent();
    2375             : }
    2376             : 
    2377             : nsIFrame*
    2378           0 : EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
    2379             :                                        WidgetWheelEvent* aEvent,
    2380             :                                        ComputeScrollTargetOptions aOptions)
    2381             : {
    2382           0 :   return ComputeScrollTarget(aTargetFrame, aEvent->mDeltaX, aEvent->mDeltaY,
    2383           0 :                              aEvent, aOptions);
    2384             : }
    2385             : 
    2386             : // Overload ComputeScrollTarget method to allow passing "test" dx and dy when looking
    2387             : // for which scrollbarmediators to activate when two finger down on trackpad
    2388             : // and before any actual motion
    2389             : nsIFrame*
    2390           0 : EventStateManager::ComputeScrollTarget(nsIFrame* aTargetFrame,
    2391             :                                        double aDirectionX,
    2392             :                                        double aDirectionY,
    2393             :                                        WidgetWheelEvent* aEvent,
    2394             :                                        ComputeScrollTargetOptions aOptions)
    2395             : {
    2396           0 :   if ((aOptions & INCLUDE_PLUGIN_AS_TARGET) &&
    2397           0 :       !WheelPrefs::WheelEventsEnabledOnPlugins()) {
    2398           0 :     aOptions = RemovePluginFromTarget(aOptions);
    2399             :   }
    2400             : 
    2401           0 :   if (aOptions & PREFER_MOUSE_WHEEL_TRANSACTION) {
    2402             :     // If the user recently scrolled with the mousewheel, then they probably
    2403             :     // want to scroll the same view as before instead of the view under the
    2404             :     // cursor.  WheelTransaction tracks the frame currently being
    2405             :     // scrolled with the mousewheel. We consider the transaction ended when the
    2406             :     // mouse moves more than "mousewheel.transaction.ignoremovedelay"
    2407             :     // milliseconds after the last scroll operation, or any time the mouse moves
    2408             :     // out of the frame, or when more than "mousewheel.transaction.timeout"
    2409             :     // milliseconds have passed after the last operation, even if the mouse
    2410             :     // hasn't moved.
    2411           0 :     nsIFrame* lastScrollFrame = WheelTransaction::GetTargetFrame();
    2412           0 :     if (lastScrollFrame) {
    2413           0 :       if (aOptions & INCLUDE_PLUGIN_AS_TARGET) {
    2414           0 :         nsPluginFrame* pluginFrame = do_QueryFrame(lastScrollFrame);
    2415           0 :         if (pluginFrame &&
    2416           0 :             pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
    2417           0 :           return lastScrollFrame;
    2418             :         }
    2419             :       }
    2420             :       nsIScrollableFrame* scrollableFrame =
    2421           0 :         lastScrollFrame->GetScrollTargetFrame();
    2422           0 :       if (scrollableFrame) {
    2423           0 :         nsIFrame* frameToScroll = do_QueryFrame(scrollableFrame);
    2424           0 :         MOZ_ASSERT(frameToScroll);
    2425           0 :         return frameToScroll;
    2426             :       }
    2427             :     }
    2428             :   }
    2429             : 
    2430             :   // If the event doesn't cause scroll actually, we cannot find scroll target
    2431             :   // because we check if the event can cause scroll actually on each found
    2432             :   // scrollable frame.
    2433           0 :   if (!aDirectionX && !aDirectionY) {
    2434           0 :     return nullptr;
    2435             :   }
    2436             : 
    2437             :   bool checkIfScrollableX =
    2438           0 :     aDirectionX && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_X_AXIS);
    2439             :   bool checkIfScrollableY =
    2440           0 :     aDirectionY && (aOptions & PREFER_ACTUAL_SCROLLABLE_TARGET_ALONG_Y_AXIS);
    2441             : 
    2442             :   nsIFrame* scrollFrame =
    2443           0 :     !(aOptions & START_FROM_PARENT) ? aTargetFrame :
    2444           0 :                                       GetParentFrameToScroll(aTargetFrame);
    2445           0 :   for (; scrollFrame; scrollFrame = GetParentFrameToScroll(scrollFrame)) {
    2446             :     // Check whether the frame wants to provide us with a scrollable view.
    2447           0 :     nsIScrollableFrame* scrollableFrame = scrollFrame->GetScrollTargetFrame();
    2448           0 :     if (!scrollableFrame) {
    2449             :       // If the frame is a plugin frame, then, the plugin content may handle
    2450             :       // wheel events.  Only when the caller computes the scroll target for
    2451             :       // default action handling, we should assume the plugin frame as
    2452             :       // scrollable if the plugin wants to handle wheel events as default
    2453             :       // action.
    2454           0 :       if (aOptions & INCLUDE_PLUGIN_AS_TARGET) {
    2455           0 :         nsPluginFrame* pluginFrame = do_QueryFrame(scrollFrame);
    2456           0 :         if (pluginFrame &&
    2457           0 :             pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
    2458           0 :           return scrollFrame;
    2459             :         }
    2460             :       }
    2461           0 :       nsMenuPopupFrame* menuPopupFrame = do_QueryFrame(scrollFrame);
    2462           0 :       if (menuPopupFrame) {
    2463           0 :         return nullptr;
    2464             :       }
    2465           0 :       continue;
    2466             :     }
    2467             : 
    2468           0 :     nsIFrame* frameToScroll = do_QueryFrame(scrollableFrame);
    2469           0 :     MOZ_ASSERT(frameToScroll);
    2470             : 
    2471             :     // Don't scroll vertically by mouse-wheel on a single-line text control.
    2472           0 :     if (checkIfScrollableY) {
    2473           0 :       if (!CanVerticallyScrollFrameWithWheel(scrollFrame)) {
    2474           0 :         continue;
    2475             :       }
    2476             :     }
    2477             : 
    2478           0 :     if (!checkIfScrollableX && !checkIfScrollableY) {
    2479           0 :       return frameToScroll;
    2480             :     }
    2481             : 
    2482           0 :     ScrollbarStyles ss = scrollableFrame->GetScrollbarStyles();
    2483           0 :     bool hiddenForV = (NS_STYLE_OVERFLOW_HIDDEN == ss.mVertical);
    2484           0 :     bool hiddenForH = (NS_STYLE_OVERFLOW_HIDDEN == ss.mHorizontal);
    2485           0 :     if ((hiddenForV && hiddenForH) ||
    2486           0 :         (checkIfScrollableY && !checkIfScrollableX && hiddenForV) ||
    2487           0 :         (checkIfScrollableX && !checkIfScrollableY && hiddenForH)) {
    2488           0 :       continue;
    2489             :     }
    2490             : 
    2491             :     // For default action, we should climb up the tree if cannot scroll it
    2492             :     // by the event actually.
    2493             :     bool canScroll = WheelHandlingUtils::CanScrollOn(scrollableFrame,
    2494           0 :                                                      aDirectionX, aDirectionY);
    2495             :     // Comboboxes need special care.
    2496           0 :     nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
    2497           0 :     if (comboBox) {
    2498           0 :       if (comboBox->IsDroppedDown()) {
    2499             :         // Don't propagate to parent when drop down menu is active.
    2500           0 :         return canScroll ? frameToScroll : nullptr;
    2501             :       }
    2502             :       // Always propagate when not dropped down (even if focused).
    2503           0 :       continue;
    2504             :     }
    2505             : 
    2506           0 :     if (canScroll) {
    2507           0 :       return frameToScroll;
    2508             :     }
    2509             :   }
    2510             : 
    2511             :   nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
    2512           0 :       aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
    2513           0 :   aOptions =
    2514           0 :     static_cast<ComputeScrollTargetOptions>(aOptions & ~START_FROM_PARENT);
    2515           0 :   return newFrame ? ComputeScrollTarget(newFrame, aEvent, aOptions) : nullptr;
    2516             : }
    2517             : 
    2518             : nsSize
    2519           0 : EventStateManager::GetScrollAmount(nsPresContext* aPresContext,
    2520             :                                    WidgetWheelEvent* aEvent,
    2521             :                                    nsIScrollableFrame* aScrollableFrame)
    2522             : {
    2523           0 :   MOZ_ASSERT(aPresContext);
    2524           0 :   MOZ_ASSERT(aEvent);
    2525             : 
    2526           0 :   bool isPage = (aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PAGE);
    2527           0 :   if (aScrollableFrame) {
    2528           0 :     return isPage ? aScrollableFrame->GetPageScrollAmount() :
    2529           0 :                     aScrollableFrame->GetLineScrollAmount();
    2530             :   }
    2531             : 
    2532             :   // If there is no scrollable frame and page scrolling, use view port size.
    2533           0 :   if (isPage) {
    2534           0 :     return aPresContext->GetVisibleArea().Size();
    2535             :   }
    2536             : 
    2537             :   // If there is no scrollable frame, we should use root frame's information.
    2538           0 :   nsIFrame* rootFrame = aPresContext->PresShell()->GetRootFrame();
    2539           0 :   if (!rootFrame) {
    2540           0 :     return nsSize(0, 0);
    2541             :   }
    2542             :   RefPtr<nsFontMetrics> fm =
    2543           0 :     nsLayoutUtils::GetInflatedFontMetricsForFrame(rootFrame);
    2544           0 :   NS_ENSURE_TRUE(fm, nsSize(0, 0));
    2545           0 :   return nsSize(fm->AveCharWidth(), fm->MaxHeight());
    2546             : }
    2547             : 
    2548             : void
    2549           0 : EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
    2550             :                                 WidgetWheelEvent* aEvent)
    2551             : {
    2552           0 :   MOZ_ASSERT(aScrollableFrame);
    2553           0 :   MOZ_ASSERT(aEvent);
    2554             : 
    2555           0 :   nsIFrame* scrollFrame = do_QueryFrame(aScrollableFrame);
    2556           0 :   MOZ_ASSERT(scrollFrame);
    2557             : 
    2558           0 :   AutoWeakFrame scrollFrameWeak(scrollFrame);
    2559           0 :   if (!WheelTransaction::WillHandleDefaultAction(aEvent, scrollFrameWeak)) {
    2560           0 :     return;
    2561             :   }
    2562             : 
    2563             :   // Default action's actual scroll amount should be computed from device
    2564             :   // pixels.
    2565           0 :   nsPresContext* pc = scrollFrame->PresContext();
    2566           0 :   nsSize scrollAmount = GetScrollAmount(pc, aEvent, aScrollableFrame);
    2567             :   nsIntSize scrollAmountInDevPixels(
    2568             :     pc->AppUnitsToDevPixels(scrollAmount.width),
    2569           0 :     pc->AppUnitsToDevPixels(scrollAmount.height));
    2570             :   nsIntPoint actualDevPixelScrollAmount =
    2571             :     DeltaAccumulator::GetInstance()->
    2572           0 :       ComputeScrollAmountForDefaultAction(aEvent, scrollAmountInDevPixels);
    2573             : 
    2574             :   // Don't scroll around the axis whose overflow style is hidden.
    2575           0 :   ScrollbarStyles overflowStyle = aScrollableFrame->GetScrollbarStyles();
    2576           0 :   if (overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
    2577           0 :     actualDevPixelScrollAmount.x = 0;
    2578             :   }
    2579           0 :   if (overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN) {
    2580           0 :     actualDevPixelScrollAmount.y = 0;
    2581             :   }
    2582             : 
    2583           0 :   nsIScrollbarMediator::ScrollSnapMode snapMode = nsIScrollbarMediator::DISABLE_SNAP;
    2584           0 :   nsIAtom* origin = nullptr;
    2585           0 :   switch (aEvent->mDeltaMode) {
    2586             :     case nsIDOMWheelEvent::DOM_DELTA_LINE:
    2587           0 :       origin = nsGkAtoms::mouseWheel;
    2588           0 :       snapMode = nsIScrollableFrame::ENABLE_SNAP;
    2589           0 :       break;
    2590             :     case nsIDOMWheelEvent::DOM_DELTA_PAGE:
    2591           0 :       origin = nsGkAtoms::pages;
    2592           0 :       snapMode = nsIScrollableFrame::ENABLE_SNAP;
    2593           0 :       break;
    2594             :     case nsIDOMWheelEvent::DOM_DELTA_PIXEL:
    2595           0 :       origin = nsGkAtoms::pixels;
    2596           0 :       break;
    2597             :     default:
    2598           0 :       MOZ_CRASH("Invalid deltaMode value comes");
    2599             :   }
    2600             : 
    2601             :   // We shouldn't scroll more one page at once except when over one page scroll
    2602             :   // is allowed for the event.
    2603           0 :   nsSize pageSize = aScrollableFrame->GetPageScrollAmount();
    2604             :   nsIntSize devPixelPageSize(pc->AppUnitsToDevPixels(pageSize.width),
    2605           0 :                              pc->AppUnitsToDevPixels(pageSize.height));
    2606           0 :   if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedX(aEvent) &&
    2607           0 :       DeprecatedAbs(actualDevPixelScrollAmount.x) > devPixelPageSize.width) {
    2608           0 :     actualDevPixelScrollAmount.x =
    2609           0 :       (actualDevPixelScrollAmount.x >= 0) ? devPixelPageSize.width :
    2610           0 :                                             -devPixelPageSize.width;
    2611             :   }
    2612             : 
    2613           0 :   if (!WheelPrefs::GetInstance()->IsOverOnePageScrollAllowedY(aEvent) &&
    2614           0 :       DeprecatedAbs(actualDevPixelScrollAmount.y) > devPixelPageSize.height) {
    2615           0 :     actualDevPixelScrollAmount.y =
    2616           0 :       (actualDevPixelScrollAmount.y >= 0) ? devPixelPageSize.height :
    2617           0 :                                             -devPixelPageSize.height;
    2618             :   }
    2619             : 
    2620             :   bool isDeltaModePixel =
    2621           0 :     (aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL);
    2622             : 
    2623             :   nsIScrollableFrame::ScrollMode mode;
    2624           0 :   switch (aEvent->mScrollType) {
    2625             :     case WidgetWheelEvent::SCROLL_DEFAULT:
    2626           0 :       if (isDeltaModePixel) {
    2627           0 :         mode = nsIScrollableFrame::NORMAL;
    2628           0 :       } else if (aEvent->mFlags.mHandledByAPZ) {
    2629           0 :         mode = nsIScrollableFrame::SMOOTH_MSD;
    2630             :       } else {
    2631           0 :         mode = nsIScrollableFrame::SMOOTH;
    2632             :       }
    2633           0 :       break;
    2634             :     case WidgetWheelEvent::SCROLL_SYNCHRONOUSLY:
    2635           0 :       mode = nsIScrollableFrame::INSTANT;
    2636           0 :       break;
    2637             :     case WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY:
    2638           0 :       mode = nsIScrollableFrame::NORMAL;
    2639           0 :       break;
    2640             :     case WidgetWheelEvent::SCROLL_SMOOTHLY:
    2641           0 :       mode = nsIScrollableFrame::SMOOTH;
    2642           0 :       break;
    2643             :     default:
    2644           0 :       MOZ_CRASH("Invalid mScrollType value comes");
    2645             :   }
    2646             : 
    2647             :   nsIScrollableFrame::ScrollMomentum momentum =
    2648           0 :     aEvent->mIsMomentum ? nsIScrollableFrame::SYNTHESIZED_MOMENTUM_EVENT
    2649           0 :                         : nsIScrollableFrame::NOT_MOMENTUM;
    2650             : 
    2651           0 :   nsIntPoint overflow;
    2652             :   aScrollableFrame->ScrollBy(actualDevPixelScrollAmount,
    2653             :                              nsIScrollableFrame::DEVICE_PIXELS,
    2654           0 :                              mode, &overflow, origin, momentum, snapMode);
    2655             : 
    2656           0 :   if (!scrollFrameWeak.IsAlive()) {
    2657             :     // If the scroll causes changing the layout, we can think that the event
    2658             :     // has been completely consumed by the content.  Then, users probably don't
    2659             :     // want additional action.
    2660           0 :     aEvent->mOverflowDeltaX = aEvent->mOverflowDeltaY = 0;
    2661           0 :   } else if (isDeltaModePixel) {
    2662           0 :     aEvent->mOverflowDeltaX = overflow.x;
    2663           0 :     aEvent->mOverflowDeltaY = overflow.y;
    2664             :   } else {
    2665           0 :     aEvent->mOverflowDeltaX =
    2666           0 :       static_cast<double>(overflow.x) / scrollAmountInDevPixels.width;
    2667           0 :     aEvent->mOverflowDeltaY =
    2668           0 :       static_cast<double>(overflow.y) / scrollAmountInDevPixels.height;
    2669             :   }
    2670             : 
    2671             :   // If CSS overflow properties caused not to scroll, the overflowDelta* values
    2672             :   // should be same as delta* values since they may be used as gesture event by
    2673             :   // widget.  However, if there is another scrollable element in the ancestor
    2674             :   // along the axis, probably users don't want the operation to cause
    2675             :   // additional action such as moving history.  In such case, overflowDelta
    2676             :   // values should stay zero.
    2677           0 :   if (scrollFrameWeak.IsAlive()) {
    2678           0 :     if (aEvent->mDeltaX &&
    2679           0 :         overflowStyle.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
    2680           0 :         !ComputeScrollTarget(scrollFrame, aEvent,
    2681             :                              COMPUTE_SCROLLABLE_ANCESTOR_ALONG_X_AXIS)) {
    2682           0 :       aEvent->mOverflowDeltaX = aEvent->mDeltaX;
    2683             :     }
    2684           0 :     if (aEvent->mDeltaY &&
    2685           0 :         overflowStyle.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
    2686           0 :         !ComputeScrollTarget(scrollFrame, aEvent,
    2687             :                              COMPUTE_SCROLLABLE_ANCESTOR_ALONG_Y_AXIS)) {
    2688           0 :       aEvent->mOverflowDeltaY = aEvent->mDeltaY;
    2689             :     }
    2690             :   }
    2691             : 
    2692           0 :   NS_ASSERTION(aEvent->mOverflowDeltaX == 0 ||
    2693             :     (aEvent->mOverflowDeltaX > 0) == (aEvent->mDeltaX > 0),
    2694             :     "The sign of mOverflowDeltaX is different from the scroll direction");
    2695           0 :   NS_ASSERTION(aEvent->mOverflowDeltaY == 0 ||
    2696             :     (aEvent->mOverflowDeltaY > 0) == (aEvent->mDeltaY > 0),
    2697             :     "The sign of mOverflowDeltaY is different from the scroll direction");
    2698             : 
    2699           0 :   WheelPrefs::GetInstance()->CancelApplyingUserPrefsFromOverflowDelta(aEvent);
    2700             : }
    2701             : 
    2702             : void
    2703           0 : EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
    2704             :                                       nsIFrame* targetFrame)
    2705             : {
    2706             : 
    2707           0 :   NS_ASSERTION(aEvent->mMessage == eGestureNotify,
    2708             :                "DecideGestureEvent called with a non-gesture event");
    2709             : 
    2710             :   /* Check the ancestor tree to decide if any frame is willing* to receive
    2711             :    * a MozPixelScroll event. If that's the case, the current touch gesture
    2712             :    * will be used as a pan gesture; otherwise it will be a regular
    2713             :    * mousedown/mousemove/click event.
    2714             :    *
    2715             :    * *willing: determine if it makes sense to pan the element using scroll events:
    2716             :    *  - For web content: if there are any visible scrollbars on the touch point
    2717             :    *  - For XUL: if it's an scrollable element that can currently scroll in some
    2718             :     *    direction.
    2719             :    *
    2720             :    * Note: we'll have to one-off various cases to ensure a good usable behavior
    2721             :    */
    2722             :   WidgetGestureNotifyEvent::PanDirection panDirection =
    2723           0 :     WidgetGestureNotifyEvent::ePanNone;
    2724           0 :   bool displayPanFeedback = false;
    2725           0 :   for (nsIFrame* current = targetFrame; current;
    2726             :        current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
    2727             : 
    2728             :     // e10s - mark remote content as pannable. This is a work around since
    2729             :     // we don't have access to remote frame scroll info here. Apz data may
    2730             :     // assist is solving this.
    2731           0 :     if (current && IsRemoteTarget(current->GetContent())) {
    2732           0 :       panDirection = WidgetGestureNotifyEvent::ePanBoth;
    2733             :       // We don't know when we reach bounds, so just disable feedback for now.
    2734           0 :       displayPanFeedback = false;
    2735           0 :       break;
    2736             :     }
    2737             : 
    2738           0 :     LayoutFrameType currentFrameType = current->Type();
    2739             : 
    2740             :     // Scrollbars should always be draggable
    2741           0 :     if (currentFrameType == LayoutFrameType::Scrollbar) {
    2742           0 :       panDirection = WidgetGestureNotifyEvent::ePanNone;
    2743           0 :       break;
    2744             :     }
    2745             : 
    2746             : #ifdef MOZ_XUL
    2747             :     // Special check for trees
    2748           0 :     nsTreeBodyFrame* treeFrame = do_QueryFrame(current);
    2749           0 :     if (treeFrame) {
    2750           0 :       if (treeFrame->GetHorizontalOverflow()) {
    2751           0 :         panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
    2752             :       }
    2753           0 :       if (treeFrame->GetVerticalOverflow()) {
    2754           0 :         panDirection = WidgetGestureNotifyEvent::ePanVertical;
    2755             :       }
    2756           0 :       break;
    2757             :     }
    2758             : #endif
    2759             : 
    2760           0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(current);
    2761           0 :     if (scrollableFrame) {
    2762           0 :       if (current->IsFrameOfType(nsIFrame::eXULBox)) {
    2763           0 :         displayPanFeedback = true;
    2764             : 
    2765           0 :         nsRect scrollRange = scrollableFrame->GetScrollRange();
    2766           0 :         bool canScrollHorizontally = scrollRange.width > 0;
    2767             : 
    2768           0 :         if (targetFrame->IsMenuFrame()) {
    2769             :           // menu frames report horizontal scroll when they have submenus
    2770             :           // and we don't want that
    2771           0 :           canScrollHorizontally = false;
    2772           0 :           displayPanFeedback = false;
    2773             :         }
    2774             : 
    2775             :         // Vertical panning has priority over horizontal panning, so
    2776             :         // when vertical movement is possible we can just finish the loop.
    2777           0 :         if (scrollRange.height > 0) {
    2778           0 :           panDirection = WidgetGestureNotifyEvent::ePanVertical;
    2779           0 :           break;
    2780             :         }
    2781             : 
    2782           0 :         if (canScrollHorizontally) {
    2783           0 :           panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
    2784           0 :           displayPanFeedback = false;
    2785             :         }
    2786             :       } else { //Not a XUL box
    2787           0 :         uint32_t scrollbarVisibility = scrollableFrame->GetScrollbarVisibility();
    2788             : 
    2789             :         //Check if we have visible scrollbars
    2790           0 :         if (scrollbarVisibility & nsIScrollableFrame::VERTICAL) {
    2791           0 :           panDirection = WidgetGestureNotifyEvent::ePanVertical;
    2792           0 :           displayPanFeedback = true;
    2793           0 :           break;
    2794             :         }
    2795             : 
    2796           0 :         if (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) {
    2797           0 :           panDirection = WidgetGestureNotifyEvent::ePanHorizontal;
    2798           0 :           displayPanFeedback = true;
    2799             :         }
    2800             :       }
    2801             :     } //scrollableFrame
    2802             :   } //ancestor chain
    2803           0 :   aEvent->mDisplayPanFeedback = displayPanFeedback;
    2804           0 :   aEvent->mPanDirection = panDirection;
    2805           0 : }
    2806             : 
    2807             : #ifdef XP_MACOSX
    2808             : static bool
    2809             : NodeAllowsClickThrough(nsINode* aNode)
    2810             : {
    2811             :   while (aNode) {
    2812             :     if (aNode->IsXULElement()) {
    2813             :       mozilla::dom::Element* element = aNode->AsElement();
    2814             :       static nsIContent::AttrValuesArray strings[] =
    2815             :         {&nsGkAtoms::always, &nsGkAtoms::never, nullptr};
    2816             :       switch (element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::clickthrough,
    2817             :                                        strings, eCaseMatters)) {
    2818             :         case 0:
    2819             :           return true;
    2820             :         case 1:
    2821             :           return false;
    2822             :       }
    2823             :     }
    2824             :     aNode = nsContentUtils::GetCrossDocParentNode(aNode);
    2825             :   }
    2826             :   return true;
    2827             : }
    2828             : #endif
    2829             : 
    2830             : void
    2831           0 : EventStateManager::PostHandleKeyboardEvent(WidgetKeyboardEvent* aKeyboardEvent,
    2832             :                                            nsEventStatus& aStatus)
    2833             : {
    2834           0 :   if (aStatus == nsEventStatus_eConsumeNoDefault) {
    2835           0 :     return;
    2836             :   }
    2837             : 
    2838           0 :   if (!aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
    2839             :     // The widget expects a reply for every keyboard event. If the event wasn't
    2840             :     // dispatched to a content process (non-e10s or no content process
    2841             :     // running), we need to short-circuit here. Otherwise, we need to wait for
    2842             :     // the content process to handle the event.
    2843           0 :     aKeyboardEvent->mWidget->PostHandleKeyEvent(aKeyboardEvent);
    2844           0 :     if (aKeyboardEvent->DefaultPrevented()) {
    2845           0 :       aStatus = nsEventStatus_eConsumeNoDefault;
    2846           0 :       return;
    2847             :     }
    2848             :   }
    2849             : 
    2850             :   // XXX Currently, our automated tests don't support mKeyNameIndex.
    2851             :   //     Therefore, we still need to handle this with keyCode.
    2852           0 :   switch(aKeyboardEvent->mKeyCode) {
    2853             :     case NS_VK_TAB:
    2854             :     case NS_VK_F6:
    2855             :       // This is to prevent keyboard scrolling while alt modifier in use.
    2856           0 :       if (!aKeyboardEvent->IsAlt()) {
    2857           0 :         aStatus = nsEventStatus_eConsumeNoDefault;
    2858             : 
    2859             :         // Handling the tab event after it was sent to content is bad,
    2860             :         // because to the FocusManager the remote-browser looks like one
    2861             :         // element, so we would just move the focus to the next element
    2862             :         // in chrome, instead of handling it in content.
    2863           0 :         if (aKeyboardEvent->HasBeenPostedToRemoteProcess()) {
    2864           0 :           break;
    2865             :         }
    2866             : 
    2867           0 :         EnsureDocument(mPresContext);
    2868           0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    2869           0 :         if (fm && mDocument) {
    2870             :           // Shift focus forward or back depending on shift key
    2871             :           bool isDocMove =
    2872           0 :             aKeyboardEvent->IsControl() || aKeyboardEvent->mKeyCode == NS_VK_F6;
    2873           0 :           uint32_t dir = aKeyboardEvent->IsShift() ?
    2874           0 :             (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC) :
    2875             :                          static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_BACKWARD)) :
    2876           0 :             (isDocMove ? static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARDDOC) :
    2877           0 :                          static_cast<uint32_t>(nsIFocusManager::MOVEFOCUS_FORWARD));
    2878           0 :           nsCOMPtr<nsIDOMElement> result;
    2879           0 :           fm->MoveFocus(mDocument->GetWindow(), nullptr, dir,
    2880             :                         nsIFocusManager::FLAG_BYKEY,
    2881           0 :                         getter_AddRefs(result));
    2882             :         }
    2883             :       }
    2884           0 :       return;
    2885             :     case 0:
    2886             :       // We handle keys with no specific keycode value below.
    2887           0 :       break;
    2888             :     default:
    2889           0 :       return;
    2890             :   }
    2891             : 
    2892           0 :   switch(aKeyboardEvent->mKeyNameIndex) {
    2893             :     case KEY_NAME_INDEX_ZoomIn:
    2894             :     case KEY_NAME_INDEX_ZoomOut:
    2895           0 :       ChangeFullZoom(
    2896           0 :         aKeyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_ZoomIn ? 1 : -1);
    2897           0 :       aStatus = nsEventStatus_eConsumeNoDefault;
    2898           0 :       break;
    2899             :     default:
    2900           0 :       break;
    2901             :   }
    2902             : }
    2903             : 
    2904             : nsresult
    2905          10 : EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
    2906             :                                    WidgetEvent* aEvent,
    2907             :                                    nsIFrame* aTargetFrame,
    2908             :                                    nsEventStatus* aStatus)
    2909             : {
    2910          10 :   NS_ENSURE_ARG(aPresContext);
    2911          10 :   NS_ENSURE_ARG_POINTER(aStatus);
    2912             : 
    2913          10 :   mCurrentTarget = aTargetFrame;
    2914          10 :   mCurrentTargetContent = nullptr;
    2915             : 
    2916          10 :   HandleCrossProcessEvent(aEvent, aStatus);
    2917             :   // NOTE: the above call may have destroyed aTargetFrame, please use
    2918             :   // mCurrentTarget henceforth.  This is to avoid using it accidentally:
    2919          10 :   aTargetFrame = nullptr;
    2920             : 
    2921             :   // Most of the events we handle below require a frame.
    2922             :   // Add special cases here.
    2923          10 :   if (!mCurrentTarget && aEvent->mMessage != eMouseUp &&
    2924           0 :       aEvent->mMessage != eMouseDown) {
    2925           0 :     return NS_OK;
    2926             :   }
    2927             : 
    2928             :   //Keep the prescontext alive, we might need it after event dispatch
    2929          20 :   RefPtr<nsPresContext> presContext = aPresContext;
    2930          10 :   nsresult ret = NS_OK;
    2931             : 
    2932          10 :   switch (aEvent->mMessage) {
    2933             :   case eMouseDown:
    2934             :     {
    2935           0 :       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    2936           0 :       if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
    2937           0 :           !sNormalLMouseEventInProcess) {
    2938             :         // We got a mouseup event while a mousedown event was being processed.
    2939             :         // Make sure that the capturing content is cleared.
    2940           0 :         nsIPresShell::SetCapturingContent(nullptr, 0);
    2941           0 :         break;
    2942             :       }
    2943             : 
    2944             :       // For remote content, capture the event in the parent process at the
    2945             :       // <xul:browser remote> element. This will ensure that subsequent mousemove/mouseup
    2946             :       // events will continue to be dispatched to this element and therefore forwarded
    2947             :       // to the child.
    2948           0 :       if (aEvent->HasBeenPostedToRemoteProcess() &&
    2949           0 :           !nsIPresShell::GetCapturingContent()) {
    2950           0 :         nsIContent* content = mCurrentTarget ? mCurrentTarget->GetContent() : nullptr;
    2951           0 :         nsIPresShell::SetCapturingContent(content, 0);
    2952             :       }
    2953             : 
    2954           0 :       nsCOMPtr<nsIContent> activeContent;
    2955             :       // When content calls PreventDefault on pointerdown, we also call
    2956             :       // PreventDefault on the subsequent mouse events to suppress default
    2957             :       // behaviors. Normally, aStatus should be nsEventStatus_eConsumeNoDefault
    2958             :       // when the event is DefaultPrevented but it's reset to
    2959             :       // nsEventStatus_eIgnore in EventStateManager::PreHandleEvent. So we also
    2960             :       // check if the event is DefaultPrevented.
    2961           0 :       if (nsEventStatus_eConsumeNoDefault != *aStatus &&
    2962           0 :           !aEvent->DefaultPrevented()) {
    2963           0 :         nsCOMPtr<nsIContent> newFocus;
    2964           0 :         bool suppressBlur = false;
    2965           0 :         if (mCurrentTarget) {
    2966           0 :           mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
    2967           0 :           const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface();
    2968           0 :           activeContent = mCurrentTarget->GetContent();
    2969             : 
    2970             :           // In some cases, we do not want to even blur the current focused
    2971             :           // element. Those cases are:
    2972             :           // 1. -moz-user-focus CSS property is set to 'ignore';
    2973             :           // 2. Element with NS_EVENT_STATE_DISABLED
    2974             :           //    (aka :disabled pseudo-class for HTML element);
    2975             :           // 3. XUL control element has the disabled property set to 'true'.
    2976             :           //
    2977             :           // We can't use nsIFrame::IsFocusable() because we want to blur when
    2978             :           // we click on a visibility: none element.
    2979             :           // We can't use nsIContent::IsFocusable() because we want to blur when
    2980             :           // we click on a non-focusable element like a <div>.
    2981             :           // We have to use |aEvent->mTarget| to not make sure we do not check
    2982             :           // an anonymous node of the targeted element.
    2983           0 :           suppressBlur = (ui->mUserFocus == StyleUserFocus::Ignore);
    2984             : 
    2985           0 :           if (!suppressBlur) {
    2986           0 :             nsCOMPtr<Element> element = do_QueryInterface(aEvent->mTarget);
    2987           0 :             suppressBlur = element &&
    2988           0 :                            element->State().HasState(NS_EVENT_STATE_DISABLED);
    2989             :           }
    2990             : 
    2991           0 :           if (!suppressBlur) {
    2992             :             nsCOMPtr<nsIDOMXULControlElement> xulControl =
    2993           0 :               do_QueryInterface(aEvent->mTarget);
    2994           0 :             if (xulControl) {
    2995             :               bool disabled;
    2996           0 :               xulControl->GetDisabled(&disabled);
    2997           0 :               suppressBlur = disabled;
    2998             :             }
    2999             :           }
    3000             :         }
    3001             : 
    3002           0 :         if (!suppressBlur) {
    3003           0 :           suppressBlur = nsContentUtils::IsUserFocusIgnored(activeContent);
    3004             :         }
    3005             : 
    3006           0 :         nsIFrame* currFrame = mCurrentTarget;
    3007             : 
    3008             :         // When a root content which isn't editable but has an editable HTML
    3009             :         // <body> element is clicked, we should redirect the focus to the
    3010             :         // the <body> element.  E.g., when an user click bottom of the editor
    3011             :         // where is outside of the <body> element, the <body> should be focused
    3012             :         // and the user can edit immediately after that.
    3013             :         //
    3014             :         // NOTE: The newFocus isn't editable that also means it's not in
    3015             :         // designMode.  In designMode, all contents are not focusable.
    3016           0 :         if (newFocus && !newFocus->IsEditable()) {
    3017           0 :           nsIDocument *doc = newFocus->GetComposedDoc();
    3018           0 :           if (doc && newFocus == doc->GetRootElement()) {
    3019             :             nsIContent *bodyContent =
    3020           0 :               nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
    3021           0 :             if (bodyContent) {
    3022           0 :               nsIFrame* bodyFrame = bodyContent->GetPrimaryFrame();
    3023           0 :               if (bodyFrame) {
    3024           0 :                 currFrame = bodyFrame;
    3025           0 :                 newFocus = bodyContent;
    3026             :               }
    3027             :             }
    3028             :           }
    3029             :         }
    3030             : 
    3031             :         // When the mouse is pressed, the default action is to focus the
    3032             :         // target. Look for the nearest enclosing focusable frame.
    3033           0 :         while (currFrame) {
    3034             :           // If the mousedown happened inside a popup, don't
    3035             :           // try to set focus on one of its containing elements
    3036           0 :           const nsStyleDisplay* display = currFrame->StyleDisplay();
    3037           0 :           if (display->mDisplay == StyleDisplay::MozPopup) {
    3038           0 :             newFocus = nullptr;
    3039           0 :             break;
    3040             :           }
    3041             : 
    3042             :           int32_t tabIndexUnused;
    3043           0 :           if (currFrame->IsFocusable(&tabIndexUnused, true)) {
    3044           0 :             newFocus = currFrame->GetContent();
    3045           0 :             nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
    3046           0 :             if (domElement)
    3047           0 :               break;
    3048             :           }
    3049           0 :           currFrame = currFrame->GetParent();
    3050             :         }
    3051             : 
    3052           0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3053           0 :         if (fm) {
    3054             :           // if something was found to focus, focus it. Otherwise, if the
    3055             :           // element that was clicked doesn't have -moz-user-focus: ignore,
    3056             :           // clear the existing focus. For -moz-user-focus: ignore, the focus
    3057             :           // is just left as is.
    3058             :           // Another effect of mouse clicking, handled in nsSelection, is that
    3059             :           // it should update the caret position to where the mouse was
    3060             :           // clicked. Because the focus is cleared when clicking on a
    3061             :           // non-focusable node, the next press of the tab key will cause
    3062             :           // focus to be shifted from the caret position instead of the root.
    3063           0 :           if (newFocus && currFrame) {
    3064             :             // use the mouse flag and the noscroll flag so that the content
    3065             :             // doesn't unexpectedly scroll when clicking an element that is
    3066             :             // only half visible
    3067             :             uint32_t flags = nsIFocusManager::FLAG_BYMOUSE |
    3068           0 :                              nsIFocusManager::FLAG_NOSCROLL;
    3069             :             // If this was a touch-generated event, pass that information:
    3070           0 :             if (mouseEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
    3071           0 :               flags |= nsIFocusManager::FLAG_BYTOUCH;
    3072             :             }
    3073           0 :             nsCOMPtr<nsIDOMElement> newFocusElement = do_QueryInterface(newFocus);
    3074           0 :             fm->SetFocus(newFocusElement, flags);
    3075             :           }
    3076           0 :           else if (!suppressBlur) {
    3077             :             // clear the focus within the frame and then set it as the
    3078             :             // focused frame
    3079           0 :             EnsureDocument(mPresContext);
    3080           0 :             if (mDocument) {
    3081             : #ifdef XP_MACOSX
    3082             :               if (!activeContent || !activeContent->IsXULElement())
    3083             : #endif
    3084           0 :                 fm->ClearFocus(mDocument->GetWindow());
    3085           0 :               fm->SetFocusedWindow(mDocument->GetWindow());
    3086             :             }
    3087             :           }
    3088             :         }
    3089             : 
    3090             :         // The rest is left button-specific.
    3091           0 :         if (mouseEvent->button != WidgetMouseEvent::eLeftButton) {
    3092           0 :           break;
    3093             :         }
    3094             : 
    3095           0 :         if (activeContent) {
    3096             :           // The nearest enclosing element goes into the
    3097             :           // :active state.  If we fail the QI to DOMElement,
    3098             :           // then we know we're only a node, and that we need
    3099             :           // to obtain our parent element and put it into :active
    3100             :           // instead.
    3101           0 :           nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(activeContent));
    3102           0 :           if (!elt) {
    3103           0 :             nsIContent* par = activeContent->GetParent();
    3104           0 :             if (par)
    3105           0 :               activeContent = par;
    3106             :           }
    3107             :         }
    3108             :       }
    3109             :       else {
    3110             :         // if we're here, the event handler returned false, so stop
    3111             :         // any of our own processing of a drag. Workaround for bug 43258.
    3112           0 :         StopTrackingDragGesture();
    3113             : 
    3114             :         // When the event was cancelled, there is currently a chrome document
    3115             :         // focused and a mousedown just occurred on a content document, ensure
    3116             :         // that the window that was clicked is focused.
    3117           0 :         EnsureDocument(mPresContext);
    3118           0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3119           0 :         if (mDocument && fm) {
    3120           0 :           nsCOMPtr<mozIDOMWindowProxy> window;
    3121           0 :           fm->GetFocusedWindow(getter_AddRefs(window));
    3122           0 :           auto* currentWindow = nsPIDOMWindowOuter::From(window);
    3123           0 :           if (currentWindow && mDocument->GetWindow() &&
    3124           0 :               currentWindow != mDocument->GetWindow() &&
    3125           0 :               !nsContentUtils::IsChromeDoc(mDocument)) {
    3126           0 :             nsCOMPtr<nsPIDOMWindowOuter> currentTop;
    3127           0 :             nsCOMPtr<nsPIDOMWindowOuter> newTop;
    3128           0 :             currentTop = currentWindow->GetTop();
    3129           0 :             newTop = mDocument->GetWindow()->GetTop();
    3130           0 :             nsCOMPtr<nsIDocument> currentDoc = currentWindow->GetExtantDoc();
    3131           0 :             if (nsContentUtils::IsChromeDoc(currentDoc) ||
    3132           0 :                 (currentTop && newTop && currentTop != newTop)) {
    3133           0 :               fm->SetFocusedWindow(mDocument->GetWindow());
    3134             :             }
    3135             :           }
    3136             :         }
    3137             :       }
    3138           0 :       SetActiveManager(this, activeContent);
    3139             :     }
    3140           0 :     break;
    3141             :   case ePointerCancel: {
    3142           0 :     if(WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
    3143           0 :       GenerateMouseEnterExit(mouseEvent);
    3144             :     }
    3145             :     // After firing the pointercancel event, a user agent must also fire a
    3146             :     // pointerout event followed by a pointerleave event.
    3147             :     MOZ_FALLTHROUGH;
    3148             :   }
    3149             :   case ePointerUp: {
    3150           0 :     WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent();
    3151             :     // After UP/Cancel Touch pointers become invalid so we can remove relevant helper from Table
    3152             :     // Mouse/Pen pointers are valid all the time (not only between down/up)
    3153           0 :     if (pointerEvent->inputSource == nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
    3154           0 :       mPointersEnterLeaveHelper.Remove(pointerEvent->pointerId);
    3155           0 :       GenerateMouseEnterExit(pointerEvent);
    3156             :     }
    3157           0 :     break;
    3158             :   }
    3159             :   case eMouseUp:
    3160             :     {
    3161           0 :       ClearGlobalActiveContent(this);
    3162           0 :       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
    3163           0 :       if (mouseEvent && mouseEvent->IsReal()) {
    3164           0 :         if (!mCurrentTarget) {
    3165           0 :           GetEventTarget();
    3166             :         }
    3167             :         // Make sure to dispatch the click even if there is no frame for
    3168             :         // the current target element. This is required for Web compatibility.
    3169           0 :         ret = CheckForAndDispatchClick(mouseEvent, aStatus);
    3170             :       }
    3171             : 
    3172           0 :       nsIPresShell *shell = presContext->GetPresShell();
    3173           0 :       if (shell) {
    3174           0 :         RefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
    3175           0 :         frameSelection->SetDragState(false);
    3176             :       }
    3177             :     }
    3178           0 :     break;
    3179             :   case eWheelOperationEnd:
    3180             :     {
    3181           0 :       MOZ_ASSERT(aEvent->IsTrusted());
    3182           0 :       ScrollbarsForWheel::MayInactivate();
    3183           0 :       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
    3184             :       nsIScrollableFrame* scrollTarget =
    3185           0 :         do_QueryFrame(ComputeScrollTarget(mCurrentTarget, wheelEvent,
    3186           0 :                                           COMPUTE_DEFAULT_ACTION_TARGET));
    3187           0 :       if (scrollTarget) {
    3188           0 :         scrollTarget->ScrollSnap();
    3189             :       }
    3190             :     }
    3191           0 :     break;
    3192             :   case eWheel:
    3193             :   case eWheelOperationStart:
    3194             :     {
    3195           0 :       MOZ_ASSERT(aEvent->IsTrusted());
    3196             : 
    3197           0 :       if (*aStatus == nsEventStatus_eConsumeNoDefault) {
    3198           0 :         ScrollbarsForWheel::Inactivate();
    3199           0 :         break;
    3200             :       }
    3201             : 
    3202           0 :       WidgetWheelEvent* wheelEvent = aEvent->AsWheelEvent();
    3203             : 
    3204             :       // Check if the frame to scroll before checking the default action
    3205             :       // because if the scroll target is a plugin, the default action should be
    3206             :       // chosen by the plugin rather than by our prefs.
    3207             :       nsIFrame* frameToScroll =
    3208           0 :         ComputeScrollTarget(mCurrentTarget, wheelEvent,
    3209           0 :                             COMPUTE_DEFAULT_ACTION_TARGET);
    3210           0 :       nsPluginFrame* pluginFrame = do_QueryFrame(frameToScroll);
    3211             : 
    3212             :       // When APZ is enabled, the actual scroll animation might be handled by
    3213             :       // the compositor.
    3214             :       WheelPrefs::Action action;
    3215           0 :       if (pluginFrame) {
    3216           0 :         MOZ_ASSERT(pluginFrame->WantsToHandleWheelEventAsDefaultAction());
    3217           0 :         action = WheelPrefs::ACTION_SEND_TO_PLUGIN;
    3218           0 :       } else if (wheelEvent->mFlags.mHandledByAPZ) {
    3219           0 :         action = WheelPrefs::ACTION_NONE;
    3220             :       } else {
    3221           0 :         action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
    3222             :       }
    3223           0 :       switch (action) {
    3224             :         case WheelPrefs::ACTION_SCROLL: {
    3225             :           // For scrolling of default action, we should honor the mouse wheel
    3226             :           // transaction.
    3227             : 
    3228           0 :           ScrollbarsForWheel::PrepareToScrollText(this, mCurrentTarget, wheelEvent);
    3229             : 
    3230           0 :           if (aEvent->mMessage != eWheel ||
    3231           0 :               (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
    3232             :             break;
    3233             :           }
    3234             : 
    3235           0 :           nsIScrollableFrame* scrollTarget = do_QueryFrame(frameToScroll);
    3236           0 :           ScrollbarsForWheel::SetActiveScrollTarget(scrollTarget);
    3237             : 
    3238           0 :           nsIFrame* rootScrollFrame = !mCurrentTarget ? nullptr :
    3239           0 :             mCurrentTarget->PresContext()->PresShell()->GetRootScrollFrame();
    3240           0 :           nsIScrollableFrame* rootScrollableFrame = nullptr;
    3241           0 :           if (rootScrollFrame) {
    3242           0 :             rootScrollableFrame = do_QueryFrame(rootScrollFrame);
    3243             :           }
    3244           0 :           if (!scrollTarget || scrollTarget == rootScrollableFrame) {
    3245           0 :             wheelEvent->mViewPortIsOverscrolled = true;
    3246             :           }
    3247           0 :           wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
    3248           0 :           wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
    3249             :           WheelPrefs::GetInstance()->
    3250           0 :             CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
    3251           0 :           if (scrollTarget) {
    3252           0 :             DoScrollText(scrollTarget, wheelEvent);
    3253             :           } else {
    3254           0 :             WheelTransaction::EndTransaction();
    3255           0 :             ScrollbarsForWheel::Inactivate();
    3256             :           }
    3257           0 :           break;
    3258             :         }
    3259             :         case WheelPrefs::ACTION_HISTORY: {
    3260             :           // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
    3261             :           // the direction is oblique, don't perform history back/forward.
    3262           0 :           int32_t intDelta = wheelEvent->GetPreferredIntDelta();
    3263           0 :           if (!intDelta) {
    3264           0 :             break;
    3265             :           }
    3266           0 :           DoScrollHistory(intDelta);
    3267           0 :           break;
    3268             :         }
    3269             :         case WheelPrefs::ACTION_ZOOM: {
    3270             :           // If this event doesn't cause eLegacyMouseLineOrPageScroll event or
    3271             :           // the direction is oblique, don't perform zoom in/out.
    3272           0 :           int32_t intDelta = wheelEvent->GetPreferredIntDelta();
    3273           0 :           if (!intDelta) {
    3274           0 :             break;
    3275             :           }
    3276           0 :           DoScrollZoom(mCurrentTarget, intDelta);
    3277           0 :           break;
    3278             :         }
    3279             :         case WheelPrefs::ACTION_SEND_TO_PLUGIN:
    3280           0 :           MOZ_ASSERT(pluginFrame);
    3281             : 
    3282           0 :           if (wheelEvent->mMessage != eWheel ||
    3283           0 :               (!wheelEvent->mDeltaX && !wheelEvent->mDeltaY)) {
    3284             :             break;
    3285             :           }
    3286             : 
    3287           0 :           MOZ_ASSERT(static_cast<void*>(frameToScroll) ==
    3288             :                        static_cast<void*>(pluginFrame));
    3289           0 :           if (!WheelTransaction::WillHandleDefaultAction(wheelEvent,
    3290             :                                                          frameToScroll)) {
    3291           0 :             break;
    3292             :           }
    3293             : 
    3294           0 :           pluginFrame->HandleWheelEventAsDefaultAction(wheelEvent);
    3295           0 :           break;
    3296             :         case WheelPrefs::ACTION_NONE:
    3297             :         default:
    3298           0 :           bool allDeltaOverflown = false;
    3299           0 :           if (wheelEvent->mFlags.mHandledByAPZ) {
    3300           0 :             if (wheelEvent->mCanTriggerSwipe) {
    3301             :               // For events that can trigger swipes, APZ needs to know whether
    3302             :               // scrolling is possible in the requested direction. It does this
    3303             :               // by looking at the scroll overflow values on mCanTriggerSwipe
    3304             :               // events after they have been processed.
    3305           0 :               allDeltaOverflown =
    3306           0 :                 !ComputeScrollTarget(mCurrentTarget, wheelEvent,
    3307             :                                      COMPUTE_DEFAULT_ACTION_TARGET);
    3308             :             }
    3309             :           } else {
    3310             :             // The event was processed neither by APZ nor by us, so all of the
    3311             :             // delta values must be overflown delta values.
    3312           0 :             allDeltaOverflown = true;
    3313             :           }
    3314             : 
    3315           0 :           if (!allDeltaOverflown) {
    3316           0 :             break;
    3317             :           }
    3318           0 :           wheelEvent->mOverflowDeltaX = wheelEvent->mDeltaX;
    3319           0 :           wheelEvent->mOverflowDeltaY = wheelEvent->mDeltaY;
    3320             :           WheelPrefs::GetInstance()->
    3321           0 :             CancelApplyingUserPrefsFromOverflowDelta(wheelEvent);
    3322           0 :           wheelEvent->mViewPortIsOverscrolled = true;
    3323           0 :           break;
    3324             :       }
    3325           0 :       *aStatus = nsEventStatus_eConsumeNoDefault;
    3326             :     }
    3327           0 :     break;
    3328             : 
    3329             :   case eGestureNotify:
    3330             :     {
    3331           0 :       if (nsEventStatus_eConsumeNoDefault != *aStatus) {
    3332           0 :         DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);
    3333             :       }
    3334             :     }
    3335           0 :     break;
    3336             : 
    3337             :   case eDragEnter:
    3338             :   case eDragOver:
    3339             :     {
    3340           0 :       NS_ASSERTION(aEvent->mClass == eDragEventClass, "Expected a drag event");
    3341             : 
    3342             :       // Check if the drag is occurring inside a scrollable area. If so, scroll
    3343             :       // the area when the mouse is near the edges.
    3344           0 :       if (mCurrentTarget && aEvent->mMessage == eDragOver) {
    3345           0 :         nsIFrame* checkFrame = mCurrentTarget;
    3346           0 :         while (checkFrame) {
    3347           0 :           nsIScrollableFrame* scrollFrame = do_QueryFrame(checkFrame);
    3348             :           // Break out so only the innermost scrollframe is scrolled.
    3349           0 :           if (scrollFrame && scrollFrame->DragScroll(aEvent)) {
    3350           0 :             break;
    3351             :           }
    3352           0 :           checkFrame = checkFrame->GetParent();
    3353             :         }
    3354             :       }
    3355             : 
    3356           0 :       nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    3357           0 :       if (!dragSession)
    3358           0 :         break;
    3359             : 
    3360             :       // Reset the flag.
    3361           0 :       dragSession->SetOnlyChromeDrop(false);
    3362           0 :       if (mPresContext) {
    3363           0 :         EnsureDocument(mPresContext);
    3364             :       }
    3365           0 :       bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
    3366             : 
    3367             :       // the initial dataTransfer is the one from the dragstart event that
    3368             :       // was set on the dragSession when the drag began.
    3369           0 :       nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
    3370           0 :       nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
    3371           0 :       dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
    3372             : 
    3373           0 :       WidgetDragEvent *dragEvent = aEvent->AsDragEvent();
    3374             : 
    3375             :       // collect any changes to moz cursor settings stored in the event's
    3376             :       // data transfer.
    3377           0 :       UpdateDragDataTransfer(dragEvent);
    3378             : 
    3379             :       // cancelling a dragenter or dragover event means that a drop should be
    3380             :       // allowed, so update the dropEffect and the canDrop state to indicate
    3381             :       // that a drag is allowed. If the event isn't cancelled, a drop won't be
    3382             :       // allowed. Essentially, to allow a drop somewhere, specify the effects
    3383             :       // using the effectAllowed and dropEffect properties in a dragenter or
    3384             :       // dragover event and cancel the event. To not allow a drop somewhere,
    3385             :       // don't cancel the event or set the effectAllowed or dropEffect to
    3386             :       // "none". This way, if the event is just ignored, no drop will be
    3387             :       // allowed.
    3388           0 :       uint32_t dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
    3389           0 :       uint32_t action = nsIDragService::DRAGDROP_ACTION_NONE;
    3390           0 :       if (nsEventStatus_eConsumeNoDefault == *aStatus) {
    3391             :         // if the event has a dataTransfer set, use it.
    3392           0 :         if (dragEvent->mDataTransfer) {
    3393             :           // get the dataTransfer and the dropEffect that was set on it
    3394           0 :           dataTransfer = do_QueryInterface(dragEvent->mDataTransfer);
    3395           0 :           dataTransfer->GetDropEffectInt(&dropEffect);
    3396             :         }
    3397             :         else {
    3398             :           // if dragEvent->mDataTransfer is null, it means that no attempt was
    3399             :           // made to access the dataTransfer during the event, yet the event
    3400             :           // was cancelled. Instead, use the initial data transfer available
    3401             :           // from the drag session. The drop effect would not have been
    3402             :           // initialized (which is done in DragEvent::GetDataTransfer),
    3403             :           // so set it from the drag action. We'll still want to filter it
    3404             :           // based on the effectAllowed below.
    3405           0 :           dataTransfer = initialDataTransfer;
    3406             : 
    3407           0 :           dragSession->GetDragAction(&action);
    3408             : 
    3409             :           // filter the drop effect based on the action. Use UNINITIALIZED as
    3410             :           // any effect is allowed.
    3411           0 :           dropEffect = nsContentUtils::FilterDropEffect(action,
    3412             :                          nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
    3413             :         }
    3414             : 
    3415             :         // At this point, if the dataTransfer is null, it means that the
    3416             :         // drag was originally started by directly calling the drag service.
    3417             :         // Just assume that all effects are allowed.
    3418           0 :         uint32_t effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
    3419           0 :         if (dataTransfer)
    3420           0 :           dataTransfer->GetEffectAllowedInt(&effectAllowed);
    3421             : 
    3422             :         // set the drag action based on the drop effect and effect allowed.
    3423             :         // The drop effect field on the drag transfer object specifies the
    3424             :         // desired current drop effect. However, it cannot be used if the
    3425             :         // effectAllowed state doesn't include that type of action. If the
    3426             :         // dropEffect is "none", then the action will be 'none' so a drop will
    3427             :         // not be allowed.
    3428           0 :         if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
    3429           0 :             dropEffect & effectAllowed)
    3430           0 :           action = dropEffect;
    3431             : 
    3432           0 :         if (action == nsIDragService::DRAGDROP_ACTION_NONE)
    3433           0 :           dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
    3434             : 
    3435             :         // inform the drag session that a drop is allowed on this node.
    3436           0 :         dragSession->SetDragAction(action);
    3437           0 :         dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
    3438             : 
    3439             :         // For now, do this only for dragover.
    3440             :         //XXXsmaug dragenter needs some more work.
    3441           0 :         if (aEvent->mMessage == eDragOver && !isChromeDoc) {
    3442             :           // Someone has called preventDefault(), check whether is was on
    3443             :           // content or chrome.
    3444           0 :           dragSession->SetOnlyChromeDrop(
    3445           0 :             !dragEvent->mDefaultPreventedOnContent);
    3446             :         }
    3447           0 :       } else if (aEvent->mMessage == eDragOver && !isChromeDoc) {
    3448             :         // No one called preventDefault(), so handle drop only in chrome.
    3449           0 :         dragSession->SetOnlyChromeDrop(true);
    3450             :       }
    3451           0 :       if (ContentChild* child = ContentChild::GetSingleton()) {
    3452           0 :         child->SendUpdateDropEffect(action, dropEffect);
    3453             :       }
    3454           0 :       if (aEvent->HasBeenPostedToRemoteProcess()) {
    3455           0 :         dragSession->SetCanDrop(true);
    3456           0 :       } else if (initialDataTransfer) {
    3457             :         // Now set the drop effect in the initial dataTransfer. This ensures
    3458             :         // that we can get the desired drop effect in the drop event. For events
    3459             :         // dispatched to content, the content process will take care of setting
    3460             :         // this.
    3461           0 :         initialDataTransfer->SetDropEffectInt(dropEffect);
    3462             :       }
    3463             :     }
    3464           0 :     break;
    3465             : 
    3466             :   case eDrop:
    3467             :     {
    3468           0 :       sLastDragOverFrame = nullptr;
    3469           0 :       ClearGlobalActiveContent(this);
    3470           0 :       break;
    3471             :     }
    3472             :   case eDragExit:
    3473             :      // make sure to fire the enter and exit_synth events after the
    3474             :      // eDragExit event, otherwise we'll clean up too early
    3475           0 :     GenerateDragDropEnterExit(presContext, aEvent->AsDragEvent());
    3476           0 :     if (ContentChild* child = ContentChild::GetSingleton()) {
    3477             :       // SendUpdateDropEffect to prevent nsIDragService from waiting for
    3478             :       // response of forwarded dragexit event.
    3479           0 :       child->SendUpdateDropEffect(nsIDragService::DRAGDROP_ACTION_NONE,
    3480           0 :                                   nsIDragService::DRAGDROP_ACTION_NONE);
    3481             :     }
    3482           0 :     break;
    3483             : 
    3484             :   case eKeyUp:
    3485           0 :     break;
    3486             : 
    3487             :   case eKeyPress:
    3488             :     {
    3489           0 :       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
    3490           0 :       PostHandleKeyboardEvent(keyEvent, *aStatus);
    3491             :     }
    3492           0 :     break;
    3493             : 
    3494             :   case eMouseEnterIntoWidget:
    3495           1 :     if (mCurrentTarget) {
    3496           2 :       nsCOMPtr<nsIContent> targetContent;
    3497           1 :       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    3498           1 :       SetContentState(targetContent, NS_EVENT_STATE_HOVER);
    3499             :     }
    3500           1 :     break;
    3501             : 
    3502             : #ifdef XP_MACOSX
    3503             :   case eMouseActivate:
    3504             :     if (mCurrentTarget) {
    3505             :       nsCOMPtr<nsIContent> targetContent;
    3506             :       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    3507             :       if (!NodeAllowsClickThrough(targetContent)) {
    3508             :         *aStatus = nsEventStatus_eConsumeNoDefault;
    3509             :       }
    3510             :     }
    3511             :     break;
    3512             : #endif
    3513             : 
    3514             :   default:
    3515           9 :     break;
    3516             :   }
    3517             : 
    3518             :   //Reset target frame to null to avoid mistargeting after reentrant event
    3519          10 :   mCurrentTarget = nullptr;
    3520          10 :   mCurrentTargetContent = nullptr;
    3521             : 
    3522          10 :   return ret;
    3523             : }
    3524             : 
    3525             : TabParent*
    3526           0 : EventStateManager::GetCrossProcessTarget()
    3527             : {
    3528           0 :   return IMEStateManager::GetActiveTabParent();
    3529             : }
    3530             : 
    3531             : bool
    3532           0 : EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent)
    3533             : {
    3534             :   // Check to see if there is a focused, editable content in chrome,
    3535             :   // in that case, do not forward IME events to content
    3536           0 :   nsIContent *focusedContent = GetFocusedContent();
    3537           0 :   if (focusedContent && focusedContent->IsEditable())
    3538           0 :     return false;
    3539           0 :   return IMEStateManager::GetActiveTabParent() != nullptr;
    3540             : }
    3541             : 
    3542             : void
    3543           4 : EventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
    3544             : {
    3545           4 :   IMEStateManager::OnDestroyPresContext(aPresContext);
    3546           4 :   if (mHoverContent) {
    3547             :     // Bug 70855: Presentation is going away, possibly for a reframe.
    3548             :     // Reset the hover state so that if we're recreating the presentation,
    3549             :     // we won't have the old hover state still set in the new presentation,
    3550             :     // as if the new presentation is resized, a new element may be hovered.
    3551           0 :     SetContentState(nullptr, NS_EVENT_STATE_HOVER);
    3552             :   }
    3553           4 :   mPointersEnterLeaveHelper.Clear();
    3554           4 : }
    3555             : 
    3556             : void
    3557          28 : EventStateManager::SetPresContext(nsPresContext* aPresContext)
    3558             : {
    3559          28 :   mPresContext = aPresContext;
    3560          28 : }
    3561             : 
    3562             : void
    3563           5 : EventStateManager::ClearFrameRefs(nsIFrame* aFrame)
    3564             : {
    3565           5 :   if (aFrame && aFrame == mCurrentTarget) {
    3566           0 :     mCurrentTargetContent = aFrame->GetContent();
    3567             :   }
    3568           5 : }
    3569             : 
    3570             : void
    3571           8 : EventStateManager::UpdateCursor(nsPresContext* aPresContext,
    3572             :                                 WidgetEvent* aEvent,
    3573             :                                 nsIFrame* aTargetFrame,
    3574             :                                 nsEventStatus* aStatus)
    3575             : {
    3576           8 :   if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
    3577           8 :     return;
    3578             :   }
    3579             : 
    3580           0 :   int32_t cursor = NS_STYLE_CURSOR_DEFAULT;
    3581           0 :   imgIContainer* container = nullptr;
    3582           0 :   bool haveHotspot = false;
    3583           0 :   float hotspotX = 0.0f, hotspotY = 0.0f;
    3584             : 
    3585             :   //If cursor is locked just use the locked one
    3586           0 :   if (mLockCursor) {
    3587           0 :     cursor = mLockCursor;
    3588             :   }
    3589             :   //If not locked, look for correct cursor
    3590           0 :   else if (aTargetFrame) {
    3591           0 :     nsIFrame::Cursor framecursor;
    3592             :     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
    3593           0 :                                                               aTargetFrame);
    3594             :     // Avoid setting cursor when the mouse is over a windowless pluign.
    3595           0 :     if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor))) {
    3596           0 :       if (XRE_IsContentProcess()) {
    3597           0 :         mLastFrameConsumedSetCursor = true;
    3598             :       }
    3599           0 :       return;
    3600             :     }
    3601             :     // Make sure cursors get reset after the mouse leaves a
    3602             :     // windowless plugin frame.
    3603           0 :     if (mLastFrameConsumedSetCursor) {
    3604           0 :       ClearCachedWidgetCursor(aTargetFrame);
    3605           0 :       mLastFrameConsumedSetCursor = false;
    3606             :     }
    3607             :     // If the current cursor is from the same frame, and it is now
    3608             :     // loading some new image for the cursor, we should wait for a
    3609             :     // while rather than taking its fallback cursor directly.
    3610           0 :     if (framecursor.mLoading &&
    3611           0 :         gLastCursorSourceFrame == aTargetFrame &&
    3612           0 :         TimeStamp::NowLoRes() - gLastCursorUpdateTime <
    3613           0 :           TimeDuration::FromMilliseconds(kCursorLoadingTimeout)) {
    3614           0 :       return;
    3615             :     }
    3616           0 :     cursor = framecursor.mCursor;
    3617           0 :     container = framecursor.mContainer;
    3618           0 :     haveHotspot = framecursor.mHaveHotspot;
    3619           0 :     hotspotX = framecursor.mHotspotX;
    3620           0 :     hotspotY = framecursor.mHotspotY;
    3621             :   }
    3622             : 
    3623           0 :   if (nsContentUtils::UseActivityCursor()) {
    3624             :     // Check whether or not to show the busy cursor
    3625           0 :     nsCOMPtr<nsIDocShell> docShell(aPresContext->GetDocShell());
    3626           0 :     if (!docShell) return;
    3627           0 :     uint32_t busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
    3628           0 :     docShell->GetBusyFlags(&busyFlags);
    3629             : 
    3630             :     // Show busy cursor everywhere before page loads
    3631             :     // and just replace the arrow cursor after page starts loading
    3632           0 :     if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY &&
    3633           0 :           (cursor == NS_STYLE_CURSOR_AUTO || cursor == NS_STYLE_CURSOR_DEFAULT))
    3634             :     {
    3635           0 :       cursor = NS_STYLE_CURSOR_SPINNING;
    3636           0 :       container = nullptr;
    3637             :     }
    3638             :   }
    3639             : 
    3640           0 :   if (aTargetFrame) {
    3641           0 :     SetCursor(cursor, container, haveHotspot, hotspotX, hotspotY,
    3642           0 :               aTargetFrame->GetNearestWidget(), false);
    3643           0 :     gLastCursorSourceFrame = aTargetFrame;
    3644           0 :     gLastCursorUpdateTime = TimeStamp::NowLoRes();
    3645             :   }
    3646             : 
    3647           0 :   if (mLockCursor || NS_STYLE_CURSOR_AUTO != cursor) {
    3648           0 :     *aStatus = nsEventStatus_eConsumeDoDefault;
    3649             :   }
    3650             : }
    3651             : 
    3652             : void
    3653           0 : EventStateManager::ClearCachedWidgetCursor(nsIFrame* aTargetFrame)
    3654             : {
    3655           0 :   if (!aTargetFrame) {
    3656           0 :     return;
    3657             :   }
    3658           0 :   nsIWidget* aWidget = aTargetFrame->GetNearestWidget();
    3659           0 :   if (!aWidget) {
    3660           0 :     return;
    3661             :   }
    3662           0 :   aWidget->ClearCachedCursor();
    3663             : }
    3664             : 
    3665             : nsresult
    3666           0 : EventStateManager::SetCursor(int32_t aCursor, imgIContainer* aContainer,
    3667             :                              bool aHaveHotspot,
    3668             :                              float aHotspotX, float aHotspotY,
    3669             :                              nsIWidget* aWidget, bool aLockCursor)
    3670             : {
    3671           0 :   EnsureDocument(mPresContext);
    3672           0 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
    3673           0 :   sMouseOverDocument = mDocument.get();
    3674             : 
    3675             :   nsCursor c;
    3676             : 
    3677           0 :   NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE);
    3678           0 :   if (aLockCursor) {
    3679           0 :     if (NS_STYLE_CURSOR_AUTO != aCursor) {
    3680           0 :       mLockCursor = aCursor;
    3681             :     }
    3682             :     else {
    3683             :       //If cursor style is set to auto we unlock the cursor again.
    3684           0 :       mLockCursor = 0;
    3685             :     }
    3686             :   }
    3687           0 :   switch (aCursor) {
    3688             :   default:
    3689             :   case NS_STYLE_CURSOR_AUTO:
    3690             :   case NS_STYLE_CURSOR_DEFAULT:
    3691           0 :     c = eCursor_standard;
    3692           0 :     break;
    3693             :   case NS_STYLE_CURSOR_POINTER:
    3694           0 :     c = eCursor_hyperlink;
    3695           0 :     break;
    3696             :   case NS_STYLE_CURSOR_CROSSHAIR:
    3697           0 :     c = eCursor_crosshair;
    3698           0 :     break;
    3699             :   case NS_STYLE_CURSOR_MOVE:
    3700           0 :     c = eCursor_move;
    3701           0 :     break;
    3702             :   case NS_STYLE_CURSOR_TEXT:
    3703           0 :     c = eCursor_select;
    3704           0 :     break;
    3705             :   case NS_STYLE_CURSOR_WAIT:
    3706           0 :     c = eCursor_wait;
    3707           0 :     break;
    3708             :   case NS_STYLE_CURSOR_HELP:
    3709           0 :     c = eCursor_help;
    3710           0 :     break;
    3711             :   case NS_STYLE_CURSOR_N_RESIZE:
    3712           0 :     c = eCursor_n_resize;
    3713           0 :     break;
    3714             :   case NS_STYLE_CURSOR_S_RESIZE:
    3715           0 :     c = eCursor_s_resize;
    3716           0 :     break;
    3717             :   case NS_STYLE_CURSOR_W_RESIZE:
    3718           0 :     c = eCursor_w_resize;
    3719           0 :     break;
    3720             :   case NS_STYLE_CURSOR_E_RESIZE:
    3721           0 :     c = eCursor_e_resize;
    3722           0 :     break;
    3723             :   case NS_STYLE_CURSOR_NW_RESIZE:
    3724           0 :     c = eCursor_nw_resize;
    3725           0 :     break;
    3726             :   case NS_STYLE_CURSOR_SE_RESIZE:
    3727           0 :     c = eCursor_se_resize;
    3728           0 :     break;
    3729             :   case NS_STYLE_CURSOR_NE_RESIZE:
    3730           0 :     c = eCursor_ne_resize;
    3731           0 :     break;
    3732             :   case NS_STYLE_CURSOR_SW_RESIZE:
    3733           0 :     c = eCursor_sw_resize;
    3734           0 :     break;
    3735             :   case NS_STYLE_CURSOR_COPY: // CSS3
    3736           0 :     c = eCursor_copy;
    3737           0 :     break;
    3738             :   case NS_STYLE_CURSOR_ALIAS:
    3739           0 :     c = eCursor_alias;
    3740           0 :     break;
    3741             :   case NS_STYLE_CURSOR_CONTEXT_MENU:
    3742           0 :     c = eCursor_context_menu;
    3743           0 :     break;
    3744             :   case NS_STYLE_CURSOR_CELL:
    3745           0 :     c = eCursor_cell;
    3746           0 :     break;
    3747             :   case NS_STYLE_CURSOR_GRAB:
    3748           0 :     c = eCursor_grab;
    3749           0 :     break;
    3750             :   case NS_STYLE_CURSOR_GRABBING:
    3751           0 :     c = eCursor_grabbing;
    3752           0 :     break;
    3753             :   case NS_STYLE_CURSOR_SPINNING:
    3754           0 :     c = eCursor_spinning;
    3755           0 :     break;
    3756             :   case NS_STYLE_CURSOR_ZOOM_IN:
    3757           0 :     c = eCursor_zoom_in;
    3758           0 :     break;
    3759             :   case NS_STYLE_CURSOR_ZOOM_OUT:
    3760           0 :     c = eCursor_zoom_out;
    3761           0 :     break;
    3762             :   case NS_STYLE_CURSOR_NOT_ALLOWED:
    3763           0 :     c = eCursor_not_allowed;
    3764           0 :     break;
    3765             :   case NS_STYLE_CURSOR_COL_RESIZE:
    3766           0 :     c = eCursor_col_resize;
    3767           0 :     break;
    3768             :   case NS_STYLE_CURSOR_ROW_RESIZE:
    3769           0 :     c = eCursor_row_resize;
    3770           0 :     break;
    3771             :   case NS_STYLE_CURSOR_NO_DROP:
    3772           0 :     c = eCursor_no_drop;
    3773           0 :     break;
    3774             :   case NS_STYLE_CURSOR_VERTICAL_TEXT:
    3775           0 :     c = eCursor_vertical_text;
    3776           0 :     break;
    3777             :   case NS_STYLE_CURSOR_ALL_SCROLL:
    3778           0 :     c = eCursor_all_scroll;
    3779           0 :     break;
    3780             :   case NS_STYLE_CURSOR_NESW_RESIZE:
    3781           0 :     c = eCursor_nesw_resize;
    3782           0 :     break;
    3783             :   case NS_STYLE_CURSOR_NWSE_RESIZE:
    3784           0 :     c = eCursor_nwse_resize;
    3785           0 :     break;
    3786             :   case NS_STYLE_CURSOR_NS_RESIZE:
    3787           0 :     c = eCursor_ns_resize;
    3788           0 :     break;
    3789             :   case NS_STYLE_CURSOR_EW_RESIZE:
    3790           0 :     c = eCursor_ew_resize;
    3791           0 :     break;
    3792             :   case NS_STYLE_CURSOR_NONE:
    3793           0 :     c = eCursor_none;
    3794           0 :     break;
    3795             :   }
    3796             : 
    3797             :   // First, try the imgIContainer, if non-null
    3798           0 :   nsresult rv = NS_ERROR_FAILURE;
    3799           0 :   if (aContainer) {
    3800             :     uint32_t hotspotX, hotspotY;
    3801             : 
    3802             :     // css3-ui says to use the CSS-specified hotspot if present,
    3803             :     // otherwise use the intrinsic hotspot, otherwise use the top left
    3804             :     // corner.
    3805           0 :     if (aHaveHotspot) {
    3806             :       int32_t imgWidth, imgHeight;
    3807           0 :       aContainer->GetWidth(&imgWidth);
    3808           0 :       aContainer->GetHeight(&imgHeight);
    3809             : 
    3810             :       // XXX std::max(NS_lround(x), 0)?
    3811           0 :       hotspotX = aHotspotX > 0.0f
    3812           0 :                    ? uint32_t(aHotspotX + 0.5f) : uint32_t(0);
    3813           0 :       if (hotspotX >= uint32_t(imgWidth))
    3814           0 :         hotspotX = imgWidth - 1;
    3815           0 :       hotspotY = aHotspotY > 0.0f
    3816           0 :                    ? uint32_t(aHotspotY + 0.5f) : uint32_t(0);
    3817           0 :       if (hotspotY >= uint32_t(imgHeight))
    3818           0 :         hotspotY = imgHeight - 1;
    3819             :     } else {
    3820           0 :       hotspotX = 0;
    3821           0 :       hotspotY = 0;
    3822           0 :       nsCOMPtr<nsIProperties> props(do_QueryInterface(aContainer));
    3823           0 :       if (props) {
    3824           0 :         nsCOMPtr<nsISupportsPRUint32> hotspotXWrap, hotspotYWrap;
    3825             : 
    3826           0 :         props->Get("hotspotX", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotXWrap));
    3827           0 :         props->Get("hotspotY", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotYWrap));
    3828             : 
    3829           0 :         if (hotspotXWrap)
    3830           0 :           hotspotXWrap->GetData(&hotspotX);
    3831           0 :         if (hotspotYWrap)
    3832           0 :           hotspotYWrap->GetData(&hotspotY);
    3833             :       }
    3834             :     }
    3835             : 
    3836           0 :     rv = aWidget->SetCursor(aContainer, hotspotX, hotspotY);
    3837             :   }
    3838             : 
    3839           0 :   if (NS_FAILED(rv))
    3840           0 :     aWidget->SetCursor(c);
    3841             : 
    3842           0 :   return NS_OK;
    3843             : }
    3844             : 
    3845           4 : class MOZ_STACK_CLASS ESMEventCB : public EventDispatchingCallback
    3846             : {
    3847             : public:
    3848           4 :   explicit ESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
    3849             : 
    3850           2 :   void HandleEvent(EventChainPostVisitor& aVisitor) override
    3851             :   {
    3852           2 :     if (aVisitor.mPresContext) {
    3853           2 :       nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
    3854           2 :       if (frame) {
    3855           4 :         frame->HandleEvent(aVisitor.mPresContext,
    3856           2 :                            aVisitor.mEvent->AsGUIEvent(),
    3857           4 :                            &aVisitor.mEventStatus);
    3858             :       }
    3859             :     }
    3860           2 :   }
    3861             : 
    3862             :   nsCOMPtr<nsIContent> mTarget;
    3863             : };
    3864             : 
    3865             : /*static*/ bool
    3866         586 : EventStateManager::IsHandlingUserInput()
    3867             : {
    3868         586 :   return sUserInputEventDepth > 0;
    3869             : }
    3870             : 
    3871             : static void
    3872           6 : CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
    3873             :                                 EventMessage aMessage,
    3874             :                                 nsIContent* aRelatedContent,
    3875             :                                 nsAutoPtr<WidgetMouseEvent>& aNewEvent)
    3876             : {
    3877           6 :   WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
    3878           6 :   if (sourcePointer) {
    3879           4 :     AUTO_PROFILER_LABEL("CreateMouseOrPointerWidgetEvent", EVENTS);
    3880             : 
    3881           4 :     nsAutoPtr<WidgetPointerEvent> newPointerEvent;
    3882             :     newPointerEvent =
    3883           2 :       new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
    3884           4 :                              aMouseEvent->mWidget);
    3885           2 :     newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
    3886           2 :     newPointerEvent->mWidth = sourcePointer->mWidth;
    3887           2 :     newPointerEvent->mHeight = sourcePointer->mHeight;
    3888           2 :     newPointerEvent->inputSource = sourcePointer->inputSource;
    3889           2 :     newPointerEvent->relatedTarget = aRelatedContent;
    3890           2 :     aNewEvent = newPointerEvent.forget();
    3891             :   } else {
    3892             :     aNewEvent =
    3893           4 :       new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
    3894           8 :                            aMouseEvent->mWidget, WidgetMouseEvent::eReal);
    3895           4 :     aNewEvent->relatedTarget = aRelatedContent;
    3896             :   }
    3897           6 :   aNewEvent->mRefPoint = aMouseEvent->mRefPoint;
    3898           6 :   aNewEvent->mModifiers = aMouseEvent->mModifiers;
    3899           6 :   aNewEvent->button = aMouseEvent->button;
    3900           6 :   aNewEvent->buttons = aMouseEvent->buttons;
    3901           6 :   aNewEvent->pressure = aMouseEvent->pressure;
    3902           6 :   aNewEvent->mPluginEvent = aMouseEvent->mPluginEvent;
    3903           6 :   aNewEvent->inputSource = aMouseEvent->inputSource;
    3904           6 :   aNewEvent->pointerId = aMouseEvent->pointerId;
    3905           6 : }
    3906             : 
    3907             : nsIFrame*
    3908           4 : EventStateManager::DispatchMouseOrPointerEvent(WidgetMouseEvent* aMouseEvent,
    3909             :                                                EventMessage aMessage,
    3910             :                                                nsIContent* aTargetContent,
    3911             :                                                nsIContent* aRelatedContent)
    3912             : {
    3913             :   // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
    3914             :   // "[When the mouse is locked on an element...e]vents that require the concept
    3915             :   // of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
    3916           4 :   if (sIsPointerLocked &&
    3917           0 :       (aMessage == eMouseLeave ||
    3918           0 :        aMessage == eMouseEnter ||
    3919           0 :        aMessage == eMouseOver ||
    3920             :        aMessage == eMouseOut)) {
    3921           0 :     mCurrentTargetContent = nullptr;
    3922             :     nsCOMPtr<Element> pointerLockedElement =
    3923           0 :       do_QueryReferent(EventStateManager::sPointerLockedElement);
    3924           0 :     if (!pointerLockedElement) {
    3925           0 :       NS_WARNING("Should have pointer locked element, but didn't.");
    3926           0 :       return nullptr;
    3927             :     }
    3928           0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
    3929           0 :     return mPresContext->GetPrimaryFrameFor(content);
    3930             :   }
    3931             : 
    3932           4 :   mCurrentTargetContent = nullptr;
    3933             : 
    3934           4 :   if (!aTargetContent) {
    3935           0 :     return nullptr;
    3936             :   }
    3937             : 
    3938           8 :   nsAutoPtr<WidgetMouseEvent> dispatchEvent;
    3939           4 :   CreateMouseOrPointerWidgetEvent(aMouseEvent, aMessage,
    3940           4 :                                   aRelatedContent, dispatchEvent);
    3941             : 
    3942           8 :   AutoWeakFrame previousTarget = mCurrentTarget;
    3943           4 :   mCurrentTargetContent = aTargetContent;
    3944             : 
    3945           4 :   nsIFrame* targetFrame = nullptr;
    3946             : 
    3947           4 :   nsEventStatus status = nsEventStatus_eIgnore;
    3948           8 :   ESMEventCB callback(aTargetContent);
    3949           4 :   EventDispatcher::Dispatch(aTargetContent, mPresContext, dispatchEvent, nullptr,
    3950           8 :                             &status, &callback);
    3951             : 
    3952           4 :   if (mPresContext) {
    3953             :     // Although the primary frame was checked in event callback, it may not be
    3954             :     // the same object after event dispatch and handling, so refetch it.
    3955           4 :     targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent);
    3956             : 
    3957             :     // If we are entering/leaving remote content, dispatch a mouse enter/exit
    3958             :     // event to the remote frame.
    3959           4 :     if (IsRemoteTarget(aTargetContent)) {
    3960           4 :       if (aMessage == eMouseOut) {
    3961             :         // For remote content, send a "top-level" widget mouse exit event.
    3962           2 :         nsAutoPtr<WidgetMouseEvent> remoteEvent;
    3963             :         CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseExitFromWidget,
    3964           1 :                                         aRelatedContent, remoteEvent);
    3965           1 :         remoteEvent->mExitFrom = WidgetMouseEvent::eTopLevel;
    3966             : 
    3967             :         // mCurrentTarget is set to the new target, so we must reset it to the
    3968             :         // old target and then dispatch a cross-process event. (mCurrentTarget
    3969             :         // will be set back below.) HandleCrossProcessEvent will query for the
    3970             :         // proper target via GetEventTarget which will return mCurrentTarget.
    3971           1 :         mCurrentTarget = targetFrame;
    3972           1 :         HandleCrossProcessEvent(remoteEvent, &status);
    3973           3 :       } else if (aMessage == eMouseOver) {
    3974           2 :         nsAutoPtr<WidgetMouseEvent> remoteEvent;
    3975             :         CreateMouseOrPointerWidgetEvent(aMouseEvent, eMouseEnterIntoWidget,
    3976           1 :                                         aRelatedContent, remoteEvent);
    3977           1 :         HandleCrossProcessEvent(remoteEvent, &status);
    3978             :       }
    3979             :     }
    3980             :   }
    3981             : 
    3982           4 :   mCurrentTargetContent = nullptr;
    3983           4 :   mCurrentTarget = previousTarget;
    3984             : 
    3985           4 :   return targetFrame;
    3986             : }
    3987             : 
    3988           4 : class EnterLeaveDispatcher
    3989             : {
    3990             : public:
    3991           4 :   EnterLeaveDispatcher(EventStateManager* aESM,
    3992             :                        nsIContent* aTarget, nsIContent* aRelatedTarget,
    3993             :                        WidgetMouseEvent* aMouseEvent,
    3994             :                        EventMessage aEventMessage)
    3995           4 :     : mESM(aESM)
    3996             :     , mMouseEvent(aMouseEvent)
    3997           4 :     , mEventMessage(aEventMessage)
    3998             :   {
    3999             :     nsPIDOMWindowInner* win =
    4000           4 :       aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nullptr;
    4001           6 :     if (aMouseEvent->AsPointerEvent() ? win && win->HasPointerEnterLeaveEventListeners() :
    4002           2 :                                         win && win->HasMouseEnterLeaveEventListeners()) {
    4003             :       mRelatedTarget = aRelatedTarget ?
    4004           0 :         aRelatedTarget->FindFirstNonChromeOnlyAccessContent() : nullptr;
    4005           0 :       nsINode* commonParent = nullptr;
    4006           0 :       if (aTarget && aRelatedTarget) {
    4007             :         commonParent =
    4008           0 :           nsContentUtils::GetCommonAncestor(aTarget, aRelatedTarget);
    4009             :       }
    4010           0 :       nsIContent* current = aTarget;
    4011             :       // Note, it is ok if commonParent is null!
    4012           0 :       while (current && current != commonParent) {
    4013           0 :         if (!current->ChromeOnlyAccess()) {
    4014           0 :           mTargets.AppendObject(current);
    4015             :         }
    4016             :         // mouseenter/leave is fired only on elements.
    4017           0 :         current = current->GetParent();
    4018             :       }
    4019             :     }
    4020           4 :   }
    4021             : 
    4022           4 :   void Dispatch()
    4023             :   {
    4024           4 :     if (mEventMessage == eMouseEnter || mEventMessage == ePointerEnter) {
    4025           2 :       for (int32_t i = mTargets.Count() - 1; i >= 0; --i) {
    4026           0 :         mESM->DispatchMouseOrPointerEvent(mMouseEvent, mEventMessage,
    4027           0 :                                           mTargets[i], mRelatedTarget);
    4028           2 :       }
    4029             :     } else {
    4030           2 :       for (int32_t i = 0; i < mTargets.Count(); ++i) {
    4031           0 :         mESM->DispatchMouseOrPointerEvent(mMouseEvent, mEventMessage,
    4032           0 :                                           mTargets[i], mRelatedTarget);
    4033             :       }
    4034             :     }
    4035           4 :   }
    4036             : 
    4037             :   EventStateManager* mESM;
    4038             :   nsCOMArray<nsIContent> mTargets;
    4039             :   nsCOMPtr<nsIContent> mRelatedTarget;
    4040             :   WidgetMouseEvent* mMouseEvent;
    4041             :   EventMessage mEventMessage;
    4042             : };
    4043             : 
    4044             : void
    4045           4 : EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
    4046             :                                   nsIContent* aMovingInto)
    4047             : {
    4048           4 :   OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
    4049             : 
    4050           4 :   if (!wrapper->mLastOverElement)
    4051           4 :     return;
    4052             :   // Before firing mouseout, check for recursion
    4053           2 :   if (wrapper->mLastOverElement == wrapper->mFirstOutEventElement)
    4054           0 :     return;
    4055             : 
    4056           2 :   if (wrapper->mLastOverFrame) {
    4057             :     // if the frame is associated with a subdocument,
    4058             :     // tell the subdocument that we're moving out of it
    4059           2 :     nsSubDocumentFrame* subdocFrame = do_QueryFrame(wrapper->mLastOverFrame.GetFrame());
    4060           2 :     if (subdocFrame) {
    4061           4 :       nsCOMPtr<nsIDocShell> docshell;
    4062           2 :       subdocFrame->GetDocShell(getter_AddRefs(docshell));
    4063           2 :       if (docshell) {
    4064           0 :         RefPtr<nsPresContext> presContext;
    4065           0 :         docshell->GetPresContext(getter_AddRefs(presContext));
    4066             : 
    4067           0 :         if (presContext) {
    4068           0 :           EventStateManager* kidESM = presContext->EventStateManager();
    4069             :           // Not moving into any element in this subdocument
    4070           0 :           kidESM->NotifyMouseOut(aMouseEvent, nullptr);
    4071             :         }
    4072             :       }
    4073             :     }
    4074             :   }
    4075             :   // That could have caused DOM events which could wreak havoc. Reverify
    4076             :   // things and be careful.
    4077           2 :   if (!wrapper->mLastOverElement)
    4078           0 :     return;
    4079             : 
    4080             :   // Store the first mouseOut event we fire and don't refire mouseOut
    4081             :   // to that element while the first mouseOut is still ongoing.
    4082           2 :   wrapper->mFirstOutEventElement = wrapper->mLastOverElement;
    4083             : 
    4084             :   // Don't touch hover state if aMovingInto is non-null.  Caller will update
    4085             :   // hover state itself, and we have optimizations for hover switching between
    4086             :   // two nearby elements both deep in the DOM tree that would be defeated by
    4087             :   // switching the hover state to null here.
    4088           2 :   bool isPointer = aMouseEvent->mClass == ePointerEventClass;
    4089           2 :   if (!aMovingInto && !isPointer) {
    4090             :     // Unset :hover
    4091           1 :     SetContentState(nullptr, NS_EVENT_STATE_HOVER);
    4092             :   }
    4093             : 
    4094             :   EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
    4095             :                                        aMovingInto, aMouseEvent,
    4096           4 :                                        isPointer ? ePointerLeave : eMouseLeave);
    4097             : 
    4098             :   // Fire mouseout
    4099           2 :   DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? ePointerOut : eMouseOut,
    4100           2 :                               wrapper->mLastOverElement, aMovingInto);
    4101           2 :   leaveDispatcher.Dispatch();
    4102             : 
    4103           2 :   wrapper->mLastOverFrame = nullptr;
    4104           2 :   wrapper->mLastOverElement = nullptr;
    4105             : 
    4106             :   // Turn recursion protection back off
    4107           2 :   wrapper->mFirstOutEventElement = nullptr;
    4108             : }
    4109             : 
    4110             : void
    4111           8 : EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
    4112             :                                    nsIContent* aContent)
    4113             : {
    4114           8 :   NS_ASSERTION(aContent, "Mouse must be over something");
    4115             : 
    4116           8 :   OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
    4117             : 
    4118           8 :   if (wrapper->mLastOverElement == aContent)
    4119          12 :     return;
    4120             : 
    4121             :   // Before firing mouseover, check for recursion
    4122           2 :   if (aContent == wrapper->mFirstOverEventElement)
    4123           0 :     return;
    4124             : 
    4125             :   // Check to see if we're a subdocument and if so update the parent
    4126             :   // document's ESM state to indicate that the mouse is over the
    4127             :   // content associated with our subdocument.
    4128           2 :   EnsureDocument(mPresContext);
    4129           2 :   if (nsIDocument *parentDoc = mDocument->GetParentDocument()) {
    4130           0 :     if (nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument)) {
    4131           0 :       if (nsIPresShell *parentShell = parentDoc->GetShell()) {
    4132             :         EventStateManager* parentESM =
    4133           0 :           parentShell->GetPresContext()->EventStateManager();
    4134           0 :         parentESM->NotifyMouseOver(aMouseEvent, docContent);
    4135             :       }
    4136             :     }
    4137             :   }
    4138             :   // Firing the DOM event in the parent document could cause all kinds
    4139             :   // of havoc.  Reverify and take care.
    4140           2 :   if (wrapper->mLastOverElement == aContent)
    4141           0 :     return;
    4142             : 
    4143             :   // Remember mLastOverElement as the related content for the
    4144             :   // DispatchMouseOrPointerEvent() call below, since NotifyMouseOut() resets it, bug 298477.
    4145           4 :   nsCOMPtr<nsIContent> lastOverElement = wrapper->mLastOverElement;
    4146             : 
    4147           2 :   bool isPointer = aMouseEvent->mClass == ePointerEventClass;
    4148             : 
    4149             :   EnterLeaveDispatcher enterDispatcher(this, aContent, lastOverElement,
    4150             :                                        aMouseEvent,
    4151           4 :                                        isPointer ? ePointerEnter : eMouseEnter);
    4152             : 
    4153           2 :   NotifyMouseOut(aMouseEvent, aContent);
    4154             : 
    4155             :   // Store the first mouseOver event we fire and don't refire mouseOver
    4156             :   // to that element while the first mouseOver is still ongoing.
    4157           2 :   wrapper->mFirstOverEventElement = aContent;
    4158             : 
    4159           2 :   if (!isPointer) {
    4160           1 :     SetContentState(aContent, NS_EVENT_STATE_HOVER);
    4161             :   }
    4162             : 
    4163             :   // Fire mouseover
    4164             :   wrapper->mLastOverFrame =
    4165             :     DispatchMouseOrPointerEvent(aMouseEvent,
    4166             :                                 isPointer ? ePointerOver : eMouseOver,
    4167           2 :                                 aContent, lastOverElement);
    4168           2 :   enterDispatcher.Dispatch();
    4169           2 :   wrapper->mLastOverElement = aContent;
    4170             : 
    4171             :   // Turn recursion protection back off
    4172           2 :   wrapper->mFirstOverEventElement = nullptr;
    4173             : }
    4174             : 
    4175             : // Returns the center point of the window's client area. This is
    4176             : // in widget coordinates, i.e. relative to the widget's top-left
    4177             : // corner, not in screen coordinates, the same units that UIEvent::
    4178             : // refpoint is in. It may not be the exact center of the window if
    4179             : // the platform requires rounding the coordinate.
    4180             : static LayoutDeviceIntPoint
    4181           0 : GetWindowClientRectCenter(nsIWidget* aWidget)
    4182             : {
    4183           0 :   NS_ENSURE_TRUE(aWidget, LayoutDeviceIntPoint(0, 0));
    4184             : 
    4185           0 :   LayoutDeviceIntRect rect = aWidget->GetClientBounds();
    4186           0 :   LayoutDeviceIntPoint point(rect.x + rect.width / 2,
    4187           0 :                              rect.y + rect.height / 2);
    4188           0 :   int32_t round = aWidget->RoundsWidgetCoordinatesTo();
    4189           0 :   point.x = point.x / round * round;
    4190           0 :   point.y = point.y / round * round;
    4191           0 :   return point - aWidget->WidgetToScreenOffset();
    4192             : }
    4193             : 
    4194             : void
    4195           1 : EventStateManager::GeneratePointerEnterExit(EventMessage aMessage,
    4196             :                                             WidgetMouseEvent* aEvent)
    4197             : {
    4198           2 :   WidgetPointerEvent pointerEvent(*aEvent);
    4199           1 :   pointerEvent.mMessage = aMessage;
    4200           1 :   GenerateMouseEnterExit(&pointerEvent);
    4201           1 : }
    4202             : 
    4203             : void
    4204          10 : EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
    4205             : {
    4206          10 :   EnsureDocument(mPresContext);
    4207          10 :   if (!mDocument)
    4208           0 :     return;
    4209             : 
    4210             :   // Hold onto old target content through the event and reset after.
    4211          20 :   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
    4212             : 
    4213          10 :   switch(aMouseEvent->mMessage) {
    4214             :   case eMouseMove:
    4215             :     {
    4216             :       // Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
    4217             :       // Movement is calculated in UIEvent::GetMovementPoint() as:
    4218             :       //   previous_mousemove_mRefPoint - current_mousemove_mRefPoint.
    4219           4 :       if (sIsPointerLocked && aMouseEvent->mWidget) {
    4220             :         // The pointer is locked. If the pointer is not located at the center of
    4221             :         // the window, dispatch a synthetic mousemove to return the pointer there.
    4222             :         // Doing this between "real" pointer moves gives the impression that the
    4223             :         // (locked) pointer can continue moving and won't stop at the screen
    4224             :         // boundary. We cancel the synthetic event so that we don't end up
    4225             :         // dispatching the centering move event to content.
    4226             :         LayoutDeviceIntPoint center =
    4227           0 :           GetWindowClientRectCenter(aMouseEvent->mWidget);
    4228           0 :         aMouseEvent->mLastRefPoint = center;
    4229           0 :         if (aMouseEvent->mRefPoint != center) {
    4230             :           // Mouse move doesn't finish at the center of the window. Dispatch a
    4231             :           // synthetic native mouse event to move the pointer back to the center
    4232             :           // of the window, to faciliate more movement. But first, record that
    4233             :           // we've dispatched a synthetic mouse movement, so we can cancel it
    4234             :           // in the other branch here.
    4235           0 :           sSynthCenteringPoint = center;
    4236           0 :           aMouseEvent->mWidget->SynthesizeNativeMouseMove(
    4237           0 :             center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
    4238           0 :         } else if (aMouseEvent->mRefPoint == sSynthCenteringPoint) {
    4239             :           // This is the "synthetic native" event we dispatched to re-center the
    4240             :           // pointer. Cancel it so we don't expose the centering move to content.
    4241           0 :           aMouseEvent->StopPropagation();
    4242             :           // Clear sSynthCenteringPoint so we don't cancel other events
    4243             :           // targeted at the center.
    4244           0 :           sSynthCenteringPoint = kInvalidRefPoint;
    4245             :         }
    4246           4 :       } else if (sLastRefPoint == kInvalidRefPoint) {
    4247             :         // We don't have a valid previous mousemove mRefPoint. This is either
    4248             :         // the first move we've encountered, or the mouse has just re-entered
    4249             :         // the application window. We should report (0,0) movement for this
    4250             :         // case, so make the current and previous mRefPoints the same.
    4251           1 :         aMouseEvent->mLastRefPoint = aMouseEvent->mRefPoint;
    4252             :       } else {
    4253           3 :         aMouseEvent->mLastRefPoint = sLastRefPoint;
    4254             :       }
    4255             : 
    4256             :       // Update the last known mRefPoint with the current mRefPoint.
    4257           4 :       sLastRefPoint = aMouseEvent->mRefPoint;
    4258             :     }
    4259             :     MOZ_FALLTHROUGH;
    4260             :   case ePointerMove:
    4261             :   case ePointerDown:
    4262             :   case ePointerGotCapture:
    4263             :     {
    4264             :       // Get the target content target (mousemove target == mouseover target)
    4265          16 :       nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
    4266           8 :       if (!targetElement) {
    4267             :         // We're always over the document root, even if we're only
    4268             :         // over dead space in a page (whose frame is not associated with
    4269             :         // any content) or in print preview dead space
    4270           0 :         targetElement = mDocument->GetRootElement();
    4271             :       }
    4272           8 :       if (targetElement) {
    4273           8 :         NotifyMouseOver(aMouseEvent, targetElement);
    4274             :       }
    4275             :     }
    4276           8 :     break;
    4277             :   case ePointerUp:
    4278             :     {
    4279             :       // Get the target content target (mousemove target == mouseover target)
    4280           0 :       nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aMouseEvent);
    4281           0 :       if (!targetElement) {
    4282             :         // We're always over the document root, even if we're only
    4283             :         // over dead space in a page (whose frame is not associated with
    4284             :         // any content) or in print preview dead space
    4285           0 :         targetElement = mDocument->GetRootElement();
    4286             :       }
    4287           0 :       if (targetElement) {
    4288           0 :         OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
    4289           0 :         if (helper) {
    4290           0 :           helper->mLastOverElement = targetElement;
    4291             :         }
    4292           0 :         NotifyMouseOut(aMouseEvent, nullptr);
    4293             :       }
    4294             :     }
    4295           0 :     break;
    4296             :   case ePointerLeave:
    4297             :   case ePointerCancel:
    4298             :   case eMouseExitFromWidget:
    4299             :     {
    4300             :       // This is actually the window mouse exit or pointer leave event. We're not moving
    4301             :       // into any new element.
    4302             : 
    4303           2 :       OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
    4304           4 :       if (helper->mLastOverFrame &&
    4305           2 :           nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
    4306           4 :           nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
    4307             :         // the Mouse/PointerOut event widget doesn't have same top widget with
    4308             :         // mLastOverFrame, it's a spurious event for mLastOverFrame
    4309           0 :         break;
    4310             :       }
    4311             : 
    4312             :       // Reset sLastRefPoint, so that we'll know not to report any
    4313             :       // movement the next time we re-enter the window.
    4314           2 :       sLastRefPoint = kInvalidRefPoint;
    4315             : 
    4316           2 :       NotifyMouseOut(aMouseEvent, nullptr);
    4317             :     }
    4318           2 :     break;
    4319             :   default:
    4320           0 :     break;
    4321             :   }
    4322             : 
    4323             :   // reset mCurretTargetContent to what it was
    4324          10 :   mCurrentTargetContent = targetBeforeEvent;
    4325             : }
    4326             : 
    4327             : OverOutElementsWrapper*
    4328          14 : EventStateManager::GetWrapperByEventID(WidgetMouseEvent* aEvent)
    4329             : {
    4330          14 :   WidgetPointerEvent* pointer = aEvent->AsPointerEvent();
    4331          14 :   if (!pointer) {
    4332           7 :     MOZ_ASSERT(aEvent->AsMouseEvent() != nullptr);
    4333           7 :     if (!mMouseEnterLeaveHelper) {
    4334           1 :       mMouseEnterLeaveHelper = new OverOutElementsWrapper();
    4335             :     }
    4336           7 :     return mMouseEnterLeaveHelper;
    4337             :   }
    4338          14 :   return mPointersEnterLeaveHelper.LookupForAdd(pointer->pointerId).OrInsert(
    4339           9 :            [] () { return new OverOutElementsWrapper(); });
    4340             : }
    4341             : 
    4342             : /* static */ void
    4343           0 : EventStateManager::SetPointerLock(nsIWidget* aWidget,
    4344             :                                   nsIContent* aElement)
    4345             : {
    4346             :   // NOTE: aElement will be nullptr when unlocking.
    4347           0 :   sIsPointerLocked = !!aElement;
    4348             : 
    4349             :   // Reset mouse wheel transaction
    4350           0 :   WheelTransaction::EndTransaction();
    4351             : 
    4352             :   // Deal with DnD events
    4353             :   nsCOMPtr<nsIDragService> dragService =
    4354           0 :     do_GetService("@mozilla.org/widget/dragservice;1");
    4355             : 
    4356           0 :   if (sIsPointerLocked) {
    4357           0 :     MOZ_ASSERT(aWidget, "Locking pointer requires a widget");
    4358             : 
    4359             :     // Store the last known ref point so we can reposition the pointer after unlock.
    4360           0 :     sPreLockPoint = sLastRefPoint;
    4361             : 
    4362             :     // Fire a synthetic mouse move to ensure event state is updated. We first
    4363             :     // set the mouse to the center of the window, so that the mouse event
    4364             :     // doesn't report any movement.
    4365           0 :     sLastRefPoint = GetWindowClientRectCenter(aWidget);
    4366           0 :     aWidget->SynthesizeNativeMouseMove(
    4367           0 :       sLastRefPoint + aWidget->WidgetToScreenOffset(), nullptr);
    4368             : 
    4369             :     // Suppress DnD
    4370           0 :     if (dragService) {
    4371           0 :       dragService->Suppress();
    4372             :     }
    4373             :   } else {
    4374             :     // Unlocking, so return pointer to the original position by firing a
    4375             :     // synthetic mouse event. We first reset sLastRefPoint to its
    4376             :     // pre-pointerlock position, so that the synthetic mouse event reports
    4377             :     // no movement.
    4378           0 :     sLastRefPoint = sPreLockPoint;
    4379             :     // Reset SynthCenteringPoint to invalid so that next time we start
    4380             :     // locking pointer, it has its initial value.
    4381           0 :     sSynthCenteringPoint = kInvalidRefPoint;
    4382           0 :     if (aWidget) {
    4383           0 :       aWidget->SynthesizeNativeMouseMove(
    4384           0 :         sPreLockPoint + aWidget->WidgetToScreenOffset(), nullptr);
    4385             :     }
    4386             : 
    4387             :     // Unsuppress DnD
    4388           0 :     if (dragService) {
    4389           0 :       dragService->Unsuppress();
    4390             :     }
    4391             :   }
    4392           0 : }
    4393             : 
    4394             : void
    4395           0 : EventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
    4396             :                                              WidgetDragEvent* aDragEvent)
    4397             : {
    4398             :   //Hold onto old target content through the event and reset after.
    4399           0 :   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
    4400             : 
    4401           0 :   switch(aDragEvent->mMessage) {
    4402             :   case eDragOver:
    4403             :     {
    4404             :       // when dragging from one frame to another, events are fired in the
    4405             :       // order: dragexit, dragenter, dragleave
    4406           0 :       if (sLastDragOverFrame != mCurrentTarget) {
    4407             :         //We'll need the content, too, to check if it changed separately from the frames.
    4408           0 :         nsCOMPtr<nsIContent> lastContent;
    4409           0 :         nsCOMPtr<nsIContent> targetContent;
    4410           0 :         mCurrentTarget->GetContentForEvent(aDragEvent,
    4411           0 :                                            getter_AddRefs(targetContent));
    4412             : 
    4413           0 :         if (sLastDragOverFrame) {
    4414             :           //The frame has changed but the content may not have. Check before dispatching to content
    4415           0 :           sLastDragOverFrame->GetContentForEvent(aDragEvent,
    4416           0 :                                                  getter_AddRefs(lastContent));
    4417             : 
    4418           0 :           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
    4419             :                               aDragEvent, eDragExit,
    4420           0 :                               targetContent, lastContent, sLastDragOverFrame);
    4421           0 :           nsIContent* target = sLastDragOverFrame ? sLastDragOverFrame.GetFrame()->GetContent() : nullptr;
    4422           0 :           if (IsRemoteTarget(target)) {
    4423             :             // Dragging something and moving from web content to chrome only
    4424             :             // fires dragexit and dragleave to xul:browser. We have to forward
    4425             :             // dragexit to sLastDragOverFrame when its content is a remote
    4426             :             // target. We don't forward dragleave since it's generated from
    4427             :             // dragexit.
    4428           0 :             WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), eDragExit,
    4429           0 :                                         aDragEvent->mWidget);
    4430           0 :             remoteEvent.AssignDragEventData(*aDragEvent, true);
    4431           0 :             nsEventStatus remoteStatus = nsEventStatus_eIgnore;
    4432           0 :             HandleCrossProcessEvent(&remoteEvent, &remoteStatus);
    4433             :           }
    4434             :         }
    4435             : 
    4436           0 :         AutoWeakFrame currentTraget = mCurrentTarget;
    4437           0 :         FireDragEnterOrExit(aPresContext, aDragEvent, eDragEnter,
    4438           0 :                             lastContent, targetContent, currentTraget);
    4439             : 
    4440           0 :         if (sLastDragOverFrame) {
    4441           0 :           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
    4442             :                               aDragEvent, eDragLeave,
    4443           0 :                               targetContent, lastContent, sLastDragOverFrame);
    4444             :         }
    4445             : 
    4446           0 :         sLastDragOverFrame = mCurrentTarget;
    4447             :       }
    4448             :     }
    4449           0 :     break;
    4450             : 
    4451             :   case eDragExit:
    4452             :     {
    4453             :       //This is actually the window mouse exit event.
    4454           0 :       if (sLastDragOverFrame) {
    4455           0 :         nsCOMPtr<nsIContent> lastContent;
    4456           0 :         sLastDragOverFrame->GetContentForEvent(aDragEvent,
    4457           0 :                                                getter_AddRefs(lastContent));
    4458             : 
    4459           0 :         RefPtr<nsPresContext> lastDragOverFramePresContext = sLastDragOverFrame->PresContext();
    4460           0 :         FireDragEnterOrExit(lastDragOverFramePresContext,
    4461             :                             aDragEvent, eDragExit,
    4462           0 :                             nullptr, lastContent, sLastDragOverFrame);
    4463           0 :         FireDragEnterOrExit(lastDragOverFramePresContext,
    4464             :                             aDragEvent, eDragLeave,
    4465           0 :                             nullptr, lastContent, sLastDragOverFrame);
    4466             : 
    4467           0 :         sLastDragOverFrame = nullptr;
    4468             :       }
    4469             :     }
    4470           0 :     break;
    4471             : 
    4472             :   default:
    4473           0 :     break;
    4474             :   }
    4475             : 
    4476             :   //reset mCurretTargetContent to what it was
    4477           0 :   mCurrentTargetContent = targetBeforeEvent;
    4478             : 
    4479             :   // Now flush all pending notifications, for better responsiveness.
    4480           0 :   FlushPendingEvents(aPresContext);
    4481           0 : }
    4482             : 
    4483             : void
    4484           0 : EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
    4485             :                                        WidgetDragEvent* aDragEvent,
    4486             :                                        EventMessage aMessage,
    4487             :                                        nsIContent* aRelatedTarget,
    4488             :                                        nsIContent* aTargetContent,
    4489             :                                        AutoWeakFrame& aTargetFrame)
    4490             : {
    4491           0 :   MOZ_ASSERT(aMessage == eDragLeave || aMessage == eDragExit ||
    4492             :              aMessage == eDragEnter);
    4493           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    4494           0 :   WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
    4495           0 :   event.AssignDragEventData(*aDragEvent, true);
    4496           0 :   mCurrentTargetContent = aTargetContent;
    4497             : 
    4498           0 :   if (aTargetContent != aRelatedTarget) {
    4499             :     //XXX This event should still go somewhere!!
    4500           0 :     if (aTargetContent) {
    4501             :       EventDispatcher::Dispatch(aTargetContent, aPresContext, &event,
    4502           0 :                                 nullptr, &status);
    4503             :     }
    4504             : 
    4505             :     // adjust the drag hover if the dragenter event was cancelled or this is a drag exit
    4506           0 :     if (status == nsEventStatus_eConsumeNoDefault || aMessage == eDragExit) {
    4507           0 :       SetContentState((aMessage == eDragEnter) ? aTargetContent : nullptr,
    4508           0 :                       NS_EVENT_STATE_DRAGOVER);
    4509             :     }
    4510             : 
    4511             :     // collect any changes to moz cursor settings stored in the event's
    4512             :     // data transfer.
    4513           0 :     UpdateDragDataTransfer(&event);
    4514             :   }
    4515             : 
    4516             :   // Finally dispatch the event to the frame
    4517           0 :   if (aTargetFrame)
    4518           0 :     aTargetFrame->HandleEvent(aPresContext, &event, &status);
    4519           0 : }
    4520             : 
    4521             : void
    4522           0 : EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent)
    4523             : {
    4524           0 :   NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!");
    4525           0 :   if (!dragEvent->mDataTransfer) {
    4526           0 :     return;
    4527             :   }
    4528             : 
    4529           0 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    4530             : 
    4531           0 :   if (dragSession) {
    4532             :     // the initial dataTransfer is the one from the dragstart event that
    4533             :     // was set on the dragSession when the drag began.
    4534           0 :     nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
    4535           0 :     dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
    4536           0 :     if (initialDataTransfer) {
    4537             :       // retrieve the current moz cursor setting and save it.
    4538           0 :       nsAutoString mozCursor;
    4539           0 :       dragEvent->mDataTransfer->GetMozCursor(mozCursor);
    4540           0 :       initialDataTransfer->SetMozCursor(mozCursor);
    4541             :     }
    4542             :   }
    4543             : }
    4544             : 
    4545             : nsresult
    4546           0 : EventStateManager::SetClickCount(WidgetMouseEvent* aEvent,
    4547             :                                  nsEventStatus* aStatus)
    4548             : {
    4549           0 :   nsCOMPtr<nsIContent> mouseContent;
    4550           0 :   nsIContent* mouseContentParent = nullptr;
    4551           0 :   if (mCurrentTarget) {
    4552           0 :     mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
    4553             :   }
    4554           0 :   if (mouseContent) {
    4555           0 :     if (mouseContent->IsNodeOfType(nsINode::eTEXT)) {
    4556           0 :       mouseContent = mouseContent->GetParent();
    4557             :     }
    4558           0 :     if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
    4559           0 :       mouseContentParent = mouseContent->GetParent();
    4560             :     }
    4561             :   }
    4562             : 
    4563           0 :   switch (aEvent->button) {
    4564             :   case WidgetMouseEvent::eLeftButton:
    4565           0 :     if (aEvent->mMessage == eMouseDown) {
    4566           0 :       mLastLeftMouseDownContent = mouseContent;
    4567           0 :       mLastLeftMouseDownContentParent = mouseContentParent;
    4568           0 :     } else if (aEvent->mMessage == eMouseUp) {
    4569           0 :       if (mLastLeftMouseDownContent == mouseContent ||
    4570           0 :           mLastLeftMouseDownContentParent == mouseContent ||
    4571           0 :           mLastLeftMouseDownContent == mouseContentParent) {
    4572           0 :         aEvent->mClickCount = mLClickCount;
    4573           0 :         mLClickCount = 0;
    4574             :       } else {
    4575           0 :         aEvent->mClickCount = 0;
    4576             :       }
    4577           0 :       mLastLeftMouseDownContent = nullptr;
    4578           0 :       mLastLeftMouseDownContentParent = nullptr;
    4579             :     }
    4580           0 :     break;
    4581             : 
    4582             :   case WidgetMouseEvent::eMiddleButton:
    4583           0 :     if (aEvent->mMessage == eMouseDown) {
    4584           0 :       mLastMiddleMouseDownContent = mouseContent;
    4585           0 :       mLastMiddleMouseDownContentParent = mouseContentParent;
    4586           0 :     } else if (aEvent->mMessage == eMouseUp) {
    4587           0 :       if (mLastMiddleMouseDownContent == mouseContent ||
    4588           0 :           mLastMiddleMouseDownContentParent == mouseContent ||
    4589           0 :           mLastMiddleMouseDownContent == mouseContentParent) {
    4590           0 :         aEvent->mClickCount = mMClickCount;
    4591           0 :         mMClickCount = 0;
    4592             :       } else {
    4593           0 :         aEvent->mClickCount = 0;
    4594             :       }
    4595           0 :       mLastMiddleMouseDownContent = nullptr;
    4596           0 :       mLastMiddleMouseDownContentParent = nullptr;
    4597             :     }
    4598           0 :     break;
    4599             : 
    4600             :   case WidgetMouseEvent::eRightButton:
    4601           0 :     if (aEvent->mMessage == eMouseDown) {
    4602           0 :       mLastRightMouseDownContent = mouseContent;
    4603           0 :       mLastRightMouseDownContentParent = mouseContentParent;
    4604           0 :     } else if (aEvent->mMessage == eMouseUp) {
    4605           0 :       if (mLastRightMouseDownContent == mouseContent ||
    4606           0 :           mLastRightMouseDownContentParent == mouseContent ||
    4607           0 :           mLastRightMouseDownContent == mouseContentParent) {
    4608           0 :         aEvent->mClickCount = mRClickCount;
    4609           0 :         mRClickCount = 0;
    4610             :       } else {
    4611           0 :         aEvent->mClickCount = 0;
    4612             :       }
    4613           0 :       mLastRightMouseDownContent = nullptr;
    4614           0 :       mLastRightMouseDownContentParent = nullptr;
    4615             :     }
    4616           0 :     break;
    4617             :   }
    4618             : 
    4619           0 :   return NS_OK;
    4620             : }
    4621             : 
    4622             : nsresult
    4623           0 : EventStateManager::InitAndDispatchClickEvent(WidgetMouseEvent* aEvent,
    4624             :                                              nsEventStatus* aStatus,
    4625             :                                              EventMessage aMessage,
    4626             :                                              nsIPresShell* aPresShell,
    4627             :                                              nsIContent* aMouseTarget,
    4628             :                                              AutoWeakFrame aCurrentTarget,
    4629             :                                              bool aNoContentDispatch)
    4630             : {
    4631           0 :   WidgetMouseEvent event(aEvent->IsTrusted(), aMessage,
    4632           0 :                          aEvent->mWidget, WidgetMouseEvent::eReal);
    4633             : 
    4634           0 :   event.mRefPoint = aEvent->mRefPoint;
    4635           0 :   event.mClickCount = aEvent->mClickCount;
    4636           0 :   event.mModifiers = aEvent->mModifiers;
    4637           0 :   event.buttons = aEvent->buttons;
    4638           0 :   event.mTime = aEvent->mTime;
    4639           0 :   event.mTimeStamp = aEvent->mTimeStamp;
    4640           0 :   event.mFlags.mNoContentDispatch = aNoContentDispatch;
    4641           0 :   event.button = aEvent->button;
    4642           0 :   event.pointerId = aEvent->pointerId;
    4643           0 :   event.inputSource = aEvent->inputSource;
    4644             : 
    4645           0 :   return aPresShell->HandleEventWithTarget(&event, aCurrentTarget,
    4646           0 :                                            aMouseTarget, aStatus);
    4647             : }
    4648             : 
    4649             : nsresult
    4650           0 : EventStateManager::CheckForAndDispatchClick(WidgetMouseEvent* aEvent,
    4651             :                                             nsEventStatus* aStatus)
    4652             : {
    4653           0 :   nsresult ret = NS_OK;
    4654             : 
    4655             :   //If mouse is still over same element, clickcount will be > 1.
    4656             :   //If it has moved it will be zero, so no click.
    4657           0 :   if (aEvent->mClickCount) {
    4658             :     //Check that the window isn't disabled before firing a click
    4659             :     //(see bug 366544).
    4660           0 :     if (aEvent->mWidget && !aEvent->mWidget->IsEnabled()) {
    4661           0 :       return ret;
    4662             :     }
    4663             :     //fire click
    4664             :     bool notDispatchToContents =
    4665           0 :      (aEvent->button == WidgetMouseEvent::eMiddleButton ||
    4666           0 :       aEvent->button == WidgetMouseEvent::eRightButton);
    4667             : 
    4668           0 :     bool fireAuxClick = notDispatchToContents;
    4669             : 
    4670           0 :     nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
    4671           0 :     if (presShell) {
    4672           0 :       nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
    4673             :       // Click events apply to *elements* not nodes. At this point the target
    4674             :       // content may have been reset to some non-element content, and so we need
    4675             :       // to walk up the closest ancestor element, just like we do in
    4676             :       // nsPresShell::HandlePositionedEvent.
    4677           0 :       while (mouseContent && !mouseContent->IsElement()) {
    4678           0 :         mouseContent = mouseContent->GetParent();
    4679             :       }
    4680             : 
    4681           0 :       if (!mouseContent && !mCurrentTarget) {
    4682           0 :         return NS_OK;
    4683             :       }
    4684             : 
    4685             :       // HandleEvent clears out mCurrentTarget which we might need again
    4686           0 :       AutoWeakFrame currentTarget = mCurrentTarget;
    4687           0 :       ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseClick,
    4688             :                                       presShell, mouseContent, currentTarget,
    4689           0 :                                       notDispatchToContents);
    4690             : 
    4691           0 :       if (NS_SUCCEEDED(ret) && aEvent->mClickCount == 2 &&
    4692           0 :           mouseContent && mouseContent->IsInComposedDoc()) {
    4693             :         //fire double click
    4694           0 :         ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseDoubleClick,
    4695             :                                         presShell, mouseContent, currentTarget,
    4696           0 :                                         notDispatchToContents);
    4697             :       }
    4698           0 :       if (NS_SUCCEEDED(ret) && mouseContent && fireAuxClick &&
    4699           0 :           mouseContent->IsInComposedDoc()) {
    4700           0 :         ret = InitAndDispatchClickEvent(aEvent, aStatus, eMouseAuxClick,
    4701             :                                         presShell, mouseContent, currentTarget,
    4702           0 :                                         false);
    4703             :       }
    4704             :     }
    4705             :   }
    4706           0 :   return ret;
    4707             : }
    4708             : 
    4709             : nsIFrame*
    4710         193 : EventStateManager::GetEventTarget()
    4711             : {
    4712             :   nsIPresShell *shell;
    4713         371 :   if (mCurrentTarget ||
    4714         371 :       !mPresContext ||
    4715         178 :       !(shell = mPresContext->GetPresShell())) {
    4716          15 :     return mCurrentTarget;
    4717             :   }
    4718             : 
    4719         178 :   if (mCurrentTargetContent) {
    4720           0 :     mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
    4721           0 :     if (mCurrentTarget) {
    4722           0 :       return mCurrentTarget;
    4723             :     }
    4724             :   }
    4725             : 
    4726         178 :   nsIFrame* frame = shell->GetEventTargetFrame();
    4727         178 :   return (mCurrentTarget = frame);
    4728             : }
    4729             : 
    4730             : already_AddRefed<nsIContent>
    4731           8 : EventStateManager::GetEventTargetContent(WidgetEvent* aEvent)
    4732             : {
    4733          16 :   if (aEvent &&
    4734          16 :       (aEvent->mMessage == eFocus || aEvent->mMessage == eBlur)) {
    4735           0 :     nsCOMPtr<nsIContent> content = GetFocusedContent();
    4736           0 :     return content.forget();
    4737             :   }
    4738             : 
    4739           8 :   if (mCurrentTargetContent) {
    4740           0 :     nsCOMPtr<nsIContent> content = mCurrentTargetContent;
    4741           0 :     return content.forget();
    4742             :   }
    4743             : 
    4744          16 :   nsCOMPtr<nsIContent> content;
    4745             : 
    4746           8 :   nsIPresShell *presShell = mPresContext->GetPresShell();
    4747           8 :   if (presShell) {
    4748           8 :     content = presShell->GetEventTargetContent(aEvent);
    4749             :   }
    4750             : 
    4751             :   // Some events here may set mCurrentTarget but not set the corresponding
    4752             :   // event target in the PresShell.
    4753           8 :   if (!content && mCurrentTarget) {
    4754           0 :     mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(content));
    4755             :   }
    4756             : 
    4757           8 :   return content.forget();
    4758             : }
    4759             : 
    4760             : static Element*
    4761          28 : GetLabelTarget(nsIContent* aPossibleLabel)
    4762             : {
    4763             :   mozilla::dom::HTMLLabelElement* label =
    4764          28 :     mozilla::dom::HTMLLabelElement::FromContent(aPossibleLabel);
    4765          28 :   if (!label)
    4766          28 :     return nullptr;
    4767             : 
    4768           0 :   return label->GetLabeledElement();
    4769             : }
    4770             : 
    4771             : static nsIContent*
    4772           2 : FindCommonAncestor(nsIContent* aNode1, nsIContent* aNode2)
    4773             : {
    4774           2 :   if (!aNode1 || !aNode2) {
    4775           2 :     return nullptr;
    4776             :   }
    4777           0 :   return nsContentUtils::GetCommonFlattenedTreeAncestor(aNode1, aNode2);
    4778             : }
    4779             : 
    4780             : /* static */
    4781             : void
    4782           0 : EventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
    4783             : {
    4784           0 :   DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
    4785           0 : }
    4786             : 
    4787             : /* static */
    4788             : inline void
    4789          30 : EventStateManager::DoStateChange(Element* aElement, EventStates aState,
    4790             :                                  bool aAddState)
    4791             : {
    4792          30 :   if (aAddState) {
    4793          16 :     aElement->AddStates(aState);
    4794             :   } else {
    4795          14 :     aElement->RemoveStates(aState);
    4796             :   }
    4797          30 : }
    4798             : 
    4799             : /* static */
    4800             : inline void
    4801           2 : EventStateManager::DoStateChange(nsIContent* aContent, EventStates aState,
    4802             :                                  bool aStateAdded)
    4803             : {
    4804           2 :   if (aContent->IsElement()) {
    4805           2 :     DoStateChange(aContent->AsElement(), aState, aStateAdded);
    4806             :   }
    4807           2 : }
    4808             : 
    4809             : /* static */
    4810             : void
    4811          30 : EventStateManager::UpdateAncestorState(nsIContent* aStartNode,
    4812             :                                        nsIContent* aStopBefore,
    4813             :                                        EventStates aState,
    4814             :                                        bool aAddState)
    4815             : {
    4816          58 :   for (; aStartNode && aStartNode != aStopBefore;
    4817             :        aStartNode = aStartNode->GetFlattenedTreeParent()) {
    4818             :     // We might be starting with a non-element (e.g. a text node) and
    4819             :     // if someone is doing something weird might be ending with a
    4820             :     // non-element too (e.g. a document fragment)
    4821          28 :     if (!aStartNode->IsElement()) {
    4822           0 :       continue;
    4823             :     }
    4824          28 :     Element* element = aStartNode->AsElement();
    4825          28 :     DoStateChange(element, aState, aAddState);
    4826          28 :     Element* labelTarget = GetLabelTarget(element);
    4827          28 :     if (labelTarget) {
    4828           0 :       DoStateChange(labelTarget, aState, aAddState);
    4829             :     }
    4830             :   }
    4831             : 
    4832           2 :   if (aAddState) {
    4833             :     // We might be in a situation where a node was in hover both
    4834             :     // because it was hovered and because the label for it was
    4835             :     // hovered, and while we stopped hovering the node the label is
    4836             :     // still hovered.  Or we might have had two nested labels for the
    4837             :     // same node, and while one is no longer hovered the other still
    4838             :     // is.  In that situation, the label that's still hovered will be
    4839             :     // aStopBefore or some ancestor of it, and the call we just made
    4840             :     // to UpdateAncestorState with aAddState = false would have
    4841             :     // removed the hover state from the node.  But the node should
    4842             :     // still be in hover state.  To handle this situation we need to
    4843             :     // keep walking up the tree and any time we find a label mark its
    4844             :     // corresponding node as still in our state.
    4845           1 :     for ( ; aStartNode; aStartNode = aStartNode->GetFlattenedTreeParent()) {
    4846           0 :       if (!aStartNode->IsElement()) {
    4847           0 :         continue;
    4848             :       }
    4849             : 
    4850           0 :       Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
    4851           0 :       if (labelTarget && !labelTarget->State().HasState(aState)) {
    4852           0 :         DoStateChange(labelTarget, aState, true);
    4853             :       }
    4854             :     }
    4855             :   }
    4856           2 : }
    4857             : 
    4858             : bool
    4859           5 : EventStateManager::SetContentState(nsIContent* aContent, EventStates aState)
    4860             : {
    4861             :   // We manage 4 states here: ACTIVE, HOVER, DRAGOVER, URLTARGET
    4862             :   // The input must be exactly one of them.
    4863           5 :   NS_PRECONDITION(aState == NS_EVENT_STATE_ACTIVE ||
    4864             :                   aState == NS_EVENT_STATE_HOVER ||
    4865             :                   aState == NS_EVENT_STATE_DRAGOVER ||
    4866             :                   aState == NS_EVENT_STATE_URLTARGET,
    4867             :                   "Unexpected state");
    4868             : 
    4869          10 :   nsCOMPtr<nsIContent> notifyContent1;
    4870          10 :   nsCOMPtr<nsIContent> notifyContent2;
    4871             :   bool updateAncestors;
    4872             : 
    4873           5 :   if (aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE) {
    4874             :     // Hover and active are hierarchical
    4875           3 :     updateAncestors = true;
    4876             : 
    4877             :     // check to see that this state is allowed by style. Check dragover too?
    4878             :     // XXX Is this even what we want?
    4879           3 :     if (mCurrentTarget)
    4880             :     {
    4881           3 :       const nsStyleUserInterface* ui = mCurrentTarget->StyleUserInterface();
    4882           3 :       if (ui->mUserInput == StyleUserInput::None) {
    4883           0 :         return false;
    4884             :       }
    4885             :     }
    4886             : 
    4887           3 :     if (aState == NS_EVENT_STATE_ACTIVE) {
    4888             :       // Editable content can never become active since their default actions
    4889             :       // are disabled.  Watch out for editable content in native anonymous
    4890             :       // subtrees though, as they belong to text controls.
    4891           0 :       if (aContent && aContent->IsEditable() &&
    4892           0 :           !aContent->IsInNativeAnonymousSubtree()) {
    4893           0 :         aContent = nullptr;
    4894             :       }
    4895           0 :       if (aContent != mActiveContent) {
    4896           0 :         notifyContent1 = aContent;
    4897           0 :         notifyContent2 = mActiveContent;
    4898           0 :         mActiveContent = aContent;
    4899             :       }
    4900             :     } else {
    4901           3 :       NS_ASSERTION(aState == NS_EVENT_STATE_HOVER, "How did that happen?");
    4902             :       nsIContent* newHover;
    4903             : 
    4904           3 :       if (mPresContext->IsDynamic()) {
    4905           3 :         newHover = aContent;
    4906             :       } else {
    4907           0 :         NS_ASSERTION(!aContent ||
    4908             :                      aContent->GetComposedDoc() ==
    4909             :                        mPresContext->PresShell()->GetDocument(),
    4910             :                      "Unexpected document");
    4911           0 :         nsIFrame *frame = aContent ? aContent->GetPrimaryFrame() : nullptr;
    4912           0 :         if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
    4913             :           // The scrollbars of viewport should not ignore the hover state.
    4914             :           // Because they are *not* the content of the web page.
    4915           0 :           newHover = aContent;
    4916             :         } else {
    4917             :           // All contents of the web page should ignore the hover state.
    4918           0 :           newHover = nullptr;
    4919             :         }
    4920             :       }
    4921             : 
    4922           3 :       if (newHover != mHoverContent) {
    4923           2 :         notifyContent1 = newHover;
    4924           2 :         notifyContent2 = mHoverContent;
    4925           2 :         mHoverContent = newHover;
    4926             :       }
    4927             :     }
    4928             :   } else {
    4929           2 :     updateAncestors = false;
    4930           2 :     if (aState == NS_EVENT_STATE_DRAGOVER) {
    4931           0 :       if (aContent != sDragOverContent) {
    4932           0 :         notifyContent1 = aContent;
    4933           0 :         notifyContent2 = sDragOverContent;
    4934           0 :         sDragOverContent = aContent;
    4935             :       }
    4936           2 :     } else if (aState == NS_EVENT_STATE_URLTARGET) {
    4937           2 :       if (aContent != mURLTargetContent) {
    4938           2 :         notifyContent1 = aContent;
    4939           2 :         notifyContent2 = mURLTargetContent;
    4940           2 :         mURLTargetContent = aContent;
    4941             :       }
    4942             :     }
    4943             :   }
    4944             : 
    4945             :   // We need to keep track of which of notifyContent1 and notifyContent2 is
    4946             :   // getting the state set and which is getting it unset.  If both are
    4947             :   // non-null, then notifyContent1 is having the state set and notifyContent2
    4948             :   // is having it unset.  But if one of them is null, we need to keep track of
    4949             :   // the right thing for notifyContent1 explicitly.
    4950           5 :   bool content1StateSet = true;
    4951           5 :   if (!notifyContent1) {
    4952             :     // This is ok because FindCommonAncestor wouldn't find anything
    4953             :     // anyway if notifyContent1 is null.
    4954           2 :     notifyContent1 = notifyContent2;
    4955           2 :     notifyContent2 = nullptr;
    4956           2 :     content1StateSet = false;
    4957             :   }
    4958             : 
    4959           5 :   if (notifyContent1 && mPresContext) {
    4960           4 :     EnsureDocument(mPresContext);
    4961           4 :     if (mDocument) {
    4962           8 :       nsAutoScriptBlocker scriptBlocker;
    4963             : 
    4964           4 :       if (updateAncestors) {
    4965             :         nsCOMPtr<nsIContent> commonAncestor =
    4966           4 :           FindCommonAncestor(notifyContent1, notifyContent2);
    4967           2 :         if (notifyContent2) {
    4968             :           // It's very important to first notify the state removal and
    4969             :           // then the state addition, because due to labels it's
    4970             :           // possible that we're removing state from some element but
    4971             :           // then adding it again (say because mHoverContent changed
    4972             :           // from a control to its label).
    4973           0 :           UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
    4974             :         }
    4975           2 :         UpdateAncestorState(notifyContent1, commonAncestor, aState,
    4976           2 :                             content1StateSet);
    4977             :       } else {
    4978           2 :         if (notifyContent2) {
    4979           0 :           DoStateChange(notifyContent2, aState, false);
    4980             :         }
    4981           2 :         DoStateChange(notifyContent1, aState, content1StateSet);
    4982             :       }
    4983             :     }
    4984             :   }
    4985             : 
    4986           5 :   return true;
    4987             : }
    4988             : 
    4989             : void
    4990          13 : EventStateManager::ResetLastOverForContent(
    4991             :                      const uint32_t& aIdx,
    4992             :                      RefPtr<OverOutElementsWrapper>& aElemWrapper,
    4993             :                      nsIContent* aContent)
    4994             : {
    4995          13 :   if (aElemWrapper && aElemWrapper->mLastOverElement &&
    4996           0 :       nsContentUtils::ContentIsDescendantOf(aElemWrapper->mLastOverElement,
    4997           0 :                                             aContent)) {
    4998           0 :     aElemWrapper->mLastOverElement = nullptr;
    4999             :   }
    5000          13 : }
    5001             : 
    5002             : void
    5003          11 : EventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
    5004             : {
    5005             :   /*
    5006             :    * Anchor and area elements when focused or hovered might make the UI to show
    5007             :    * the current link. We want to make sure that the UI gets informed when they
    5008             :    * are actually removed from the DOM.
    5009             :    */
    5010          33 :   if (aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area) &&
    5011          11 :       (aContent->AsElement()->State().HasAtLeastOneOfStates(NS_EVENT_STATE_FOCUS |
    5012          11 :                                                             NS_EVENT_STATE_HOVER))) {
    5013           0 :     nsGenericHTMLElement* element = static_cast<nsGenericHTMLElement*>(aContent);
    5014           0 :     element->LeaveLink(
    5015           0 :       element->GetPresContext(nsGenericHTMLElement::eForComposedDoc));
    5016             :   }
    5017             : 
    5018          11 :   IMEStateManager::OnRemoveContent(mPresContext, aContent);
    5019             : 
    5020             :   // inform the focus manager that the content is being removed. If this
    5021             :   // content is focused, the focus will be removed without firing events.
    5022          11 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5023          11 :   if (fm)
    5024          11 :     fm->ContentRemoved(aDocument, aContent);
    5025             : 
    5026          11 :   if (mHoverContent &&
    5027          11 :       nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) {
    5028             :     // Since hover is hierarchical, set the current hover to the
    5029             :     // content's parent node.
    5030           0 :     SetContentState(aContent->GetParent(), NS_EVENT_STATE_HOVER);
    5031             :   }
    5032             : 
    5033          11 :   if (mActiveContent &&
    5034          11 :       nsContentUtils::ContentIsDescendantOf(mActiveContent, aContent)) {
    5035             :     // Active is hierarchical, so set the current active to the
    5036             :     // content's parent node.
    5037           0 :     SetContentState(aContent->GetParent(), NS_EVENT_STATE_ACTIVE);
    5038             :   }
    5039             : 
    5040          11 :   if (sDragOverContent &&
    5041          11 :       sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
    5042           0 :       nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) {
    5043           0 :     sDragOverContent = nullptr;
    5044             :   }
    5045             : 
    5046             :   // See bug 292146 for why we want to null this out
    5047          11 :   ResetLastOverForContent(0, mMouseEnterLeaveHelper, aContent);
    5048          26 :   for (auto iter = mPointersEnterLeaveHelper.Iter();
    5049          13 :        !iter.Done();
    5050           2 :        iter.Next()) {
    5051           2 :     ResetLastOverForContent(iter.Key(), iter.Data(), aContent);
    5052             :   }
    5053          11 : }
    5054             : 
    5055             : bool
    5056           0 : EventStateManager::EventStatusOK(WidgetGUIEvent* aEvent)
    5057             : {
    5058           0 :   return !(aEvent->mMessage == eMouseDown &&
    5059           0 :            aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
    5060           0 :            !sNormalLMouseEventInProcess);
    5061             : }
    5062             : 
    5063             : //-------------------------------------------
    5064             : // Access Key Registration
    5065             : //-------------------------------------------
    5066             : void
    5067           0 : EventStateManager::RegisterAccessKey(nsIContent* aContent, uint32_t aKey)
    5068             : {
    5069           0 :   if (aContent && mAccessKeys.IndexOf(aContent) == -1)
    5070           0 :     mAccessKeys.AppendObject(aContent);
    5071           0 : }
    5072             : 
    5073             : void
    5074          15 : EventStateManager::UnregisterAccessKey(nsIContent* aContent, uint32_t aKey)
    5075             : {
    5076          15 :   if (aContent)
    5077          15 :     mAccessKeys.RemoveObject(aContent);
    5078          15 : }
    5079             : 
    5080             : uint32_t
    5081           0 : EventStateManager::GetRegisteredAccessKey(nsIContent* aContent)
    5082             : {
    5083           0 :   MOZ_ASSERT(aContent);
    5084             : 
    5085           0 :   if (mAccessKeys.IndexOf(aContent) == -1)
    5086           0 :     return 0;
    5087             : 
    5088           0 :   nsAutoString accessKey;
    5089           0 :   aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
    5090           0 :   return accessKey.First();
    5091             : }
    5092             : 
    5093             : void
    5094          16 : EventStateManager::EnsureDocument(nsPresContext* aPresContext)
    5095             : {
    5096          16 :   if (!mDocument)
    5097           3 :     mDocument = aPresContext->Document();
    5098          16 : }
    5099             : 
    5100             : void
    5101           8 : EventStateManager::FlushPendingEvents(nsPresContext* aPresContext)
    5102             : {
    5103           8 :   NS_PRECONDITION(nullptr != aPresContext, "nullptr ptr");
    5104           8 :   nsIPresShell *shell = aPresContext->GetPresShell();
    5105           8 :   if (shell) {
    5106           8 :     shell->FlushPendingNotifications(FlushType::InterruptibleLayout);
    5107             :   }
    5108           8 : }
    5109             : 
    5110             : nsIContent*
    5111           0 : EventStateManager::GetFocusedContent()
    5112             : {
    5113           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    5114           0 :   EnsureDocument(mPresContext);
    5115           0 :   if (!fm || !mDocument)
    5116           0 :     return nullptr;
    5117             : 
    5118           0 :   nsCOMPtr<nsPIDOMWindowOuter> focusedWindow;
    5119           0 :   return nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(), false,
    5120           0 :                                               getter_AddRefs(focusedWindow));
    5121             : }
    5122             : 
    5123             : //-------------------------------------------------------
    5124             : // Return true if the docshell is visible
    5125             : 
    5126             : bool
    5127           0 : EventStateManager::IsShellVisible(nsIDocShell* aShell)
    5128             : {
    5129           0 :   NS_ASSERTION(aShell, "docshell is null");
    5130             : 
    5131           0 :   nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
    5132           0 :   if (!basewin)
    5133           0 :     return true;
    5134             : 
    5135           0 :   bool isVisible = true;
    5136           0 :   basewin->GetVisibility(&isVisible);
    5137             : 
    5138             :   // We should be doing some additional checks here so that
    5139             :   // we don't tab into hidden tabs of tabbrowser.  -bryner
    5140             : 
    5141           0 :   return isVisible;
    5142             : }
    5143             : 
    5144             : nsresult
    5145           0 : EventStateManager::DoContentCommandEvent(WidgetContentCommandEvent* aEvent)
    5146             : {
    5147           0 :   EnsureDocument(mPresContext);
    5148           0 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
    5149           0 :   nsCOMPtr<nsPIDOMWindowOuter> window(mDocument->GetWindow());
    5150           0 :   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
    5151             : 
    5152           0 :   nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
    5153           0 :   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
    5154             :   const char* cmd;
    5155           0 :   switch (aEvent->mMessage) {
    5156             :     case eContentCommandCut:
    5157           0 :       cmd = "cmd_cut";
    5158           0 :       break;
    5159             :     case eContentCommandCopy:
    5160           0 :       cmd = "cmd_copy";
    5161           0 :       break;
    5162             :     case eContentCommandPaste:
    5163           0 :       cmd = "cmd_paste";
    5164           0 :       break;
    5165             :     case eContentCommandDelete:
    5166           0 :       cmd = "cmd_delete";
    5167           0 :       break;
    5168             :     case eContentCommandUndo:
    5169           0 :       cmd = "cmd_undo";
    5170           0 :       break;
    5171             :     case eContentCommandRedo:
    5172           0 :       cmd = "cmd_redo";
    5173           0 :       break;
    5174             :     case eContentCommandPasteTransferable:
    5175           0 :       cmd = "cmd_pasteTransferable";
    5176           0 :       break;
    5177             :     case eContentCommandLookUpDictionary:
    5178           0 :       cmd = "cmd_lookUpDictionary";
    5179           0 :       break;
    5180             :     default:
    5181           0 :       return NS_ERROR_NOT_IMPLEMENTED;
    5182             :   }
    5183           0 :   nsCOMPtr<nsIController> controller;
    5184           0 :   nsresult rv = root->GetControllerForCommand(cmd, getter_AddRefs(controller));
    5185           0 :   NS_ENSURE_SUCCESS(rv, rv);
    5186           0 :   if (!controller) {
    5187             :     // When GetControllerForCommand succeeded but there is no controller, the
    5188             :     // command isn't supported.
    5189           0 :     aEvent->mIsEnabled = false;
    5190             :   } else {
    5191             :     bool canDoIt;
    5192           0 :     rv = controller->IsCommandEnabled(cmd, &canDoIt);
    5193           0 :     NS_ENSURE_SUCCESS(rv, rv);
    5194           0 :     aEvent->mIsEnabled = canDoIt;
    5195           0 :     if (canDoIt && !aEvent->mOnlyEnabledCheck) {
    5196           0 :       switch (aEvent->mMessage) {
    5197             :         case eContentCommandPasteTransferable: {
    5198           0 :           nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5199           0 :           nsIContent* focusedContent = fm ? fm->GetFocusedContent() : nullptr;
    5200           0 :           RefPtr<TabParent> remote = TabParent::GetFrom(focusedContent);
    5201           0 :           if (remote) {
    5202           0 :             NS_ENSURE_TRUE(remote->Manager()->IsContentParent(), NS_ERROR_FAILURE);
    5203             : 
    5204           0 :             nsCOMPtr<nsITransferable> transferable = aEvent->mTransferable;
    5205           0 :             IPCDataTransfer ipcDataTransfer;
    5206           0 :             ContentParent* cp = remote->Manager()->AsContentParent();
    5207           0 :             nsContentUtils::TransferableToIPCTransferable(transferable,
    5208             :                                                           &ipcDataTransfer,
    5209             :                                                           false, nullptr,
    5210           0 :                                                           cp);
    5211           0 :             bool isPrivateData = false;
    5212           0 :             transferable->GetIsPrivateData(&isPrivateData);
    5213           0 :             nsCOMPtr<nsIPrincipal> requestingPrincipal;
    5214           0 :             transferable->GetRequestingPrincipal(getter_AddRefs(requestingPrincipal));
    5215           0 :             remote->SendPasteTransferable(ipcDataTransfer, isPrivateData,
    5216           0 :                                           IPC::Principal(requestingPrincipal));
    5217           0 :             rv = NS_OK;
    5218             :           } else {
    5219           0 :             nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
    5220           0 :             NS_ENSURE_STATE(commandController);
    5221             : 
    5222           0 :             nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
    5223           0 :             NS_ENSURE_SUCCESS(rv, rv);
    5224             : 
    5225           0 :             rv = params->SetISupportsValue("transferable", aEvent->mTransferable);
    5226           0 :             NS_ENSURE_SUCCESS(rv, rv);
    5227             : 
    5228           0 :             rv = commandController->DoCommandWithParams(cmd, params);
    5229             :           }
    5230           0 :           break;
    5231             :         }
    5232             : 
    5233             :         case eContentCommandLookUpDictionary: {
    5234             :           nsCOMPtr<nsICommandController> commandController =
    5235           0 :             do_QueryInterface(controller);
    5236           0 :           if (NS_WARN_IF(!commandController)) {
    5237           0 :             return NS_ERROR_FAILURE;
    5238             :           }
    5239             : 
    5240             :           nsCOMPtr<nsICommandParams> params =
    5241           0 :             do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
    5242           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
    5243           0 :             return rv;
    5244             :           }
    5245             : 
    5246           0 :           rv = params->SetLongValue("x", aEvent->mRefPoint.x);
    5247           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
    5248           0 :             return rv;
    5249             :           }
    5250             : 
    5251           0 :           rv = params->SetLongValue("y", aEvent->mRefPoint.y);
    5252           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
    5253           0 :             return rv;
    5254             :           }
    5255             : 
    5256           0 :           rv = commandController->DoCommandWithParams(cmd, params);
    5257           0 :           break;
    5258             :         }
    5259             : 
    5260             :         default:
    5261           0 :           rv = controller->DoCommand(cmd);
    5262           0 :           break;
    5263             :       }
    5264           0 :       NS_ENSURE_SUCCESS(rv, rv);
    5265             :     }
    5266             :   }
    5267           0 :   aEvent->mSucceeded = true;
    5268           0 :   return NS_OK;
    5269             : }
    5270             : 
    5271             : nsresult
    5272           0 : EventStateManager::DoContentCommandScrollEvent(
    5273             :                      WidgetContentCommandEvent* aEvent)
    5274             : {
    5275           0 :   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
    5276           0 :   nsIPresShell* ps = mPresContext->GetPresShell();
    5277           0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_AVAILABLE);
    5278           0 :   NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG);
    5279             : 
    5280             :   nsIScrollableFrame::ScrollUnit scrollUnit;
    5281           0 :   switch (aEvent->mScroll.mUnit) {
    5282             :     case WidgetContentCommandEvent::eCmdScrollUnit_Line:
    5283           0 :       scrollUnit = nsIScrollableFrame::LINES;
    5284           0 :       break;
    5285             :     case WidgetContentCommandEvent::eCmdScrollUnit_Page:
    5286           0 :       scrollUnit = nsIScrollableFrame::PAGES;
    5287           0 :       break;
    5288             :     case WidgetContentCommandEvent::eCmdScrollUnit_Whole:
    5289           0 :       scrollUnit = nsIScrollableFrame::WHOLE;
    5290           0 :       break;
    5291             :     default:
    5292           0 :       return NS_ERROR_INVALID_ARG;
    5293             :   }
    5294             : 
    5295           0 :   aEvent->mSucceeded = true;
    5296             : 
    5297             :   nsIScrollableFrame* sf =
    5298           0 :     ps->GetScrollableFrameToScroll(nsIPresShell::eEither);
    5299           0 :   aEvent->mIsEnabled = sf ?
    5300           0 :     (aEvent->mScroll.mIsHorizontal ?
    5301           0 :       WheelHandlingUtils::CanScrollOn(sf, aEvent->mScroll.mAmount, 0) :
    5302           0 :       WheelHandlingUtils::CanScrollOn(sf, 0, aEvent->mScroll.mAmount)) : false;
    5303             : 
    5304           0 :   if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
    5305           0 :     return NS_OK;
    5306             :   }
    5307             : 
    5308           0 :   nsIntPoint pt(0, 0);
    5309           0 :   if (aEvent->mScroll.mIsHorizontal) {
    5310           0 :     pt.x = aEvent->mScroll.mAmount;
    5311             :   } else {
    5312           0 :     pt.y = aEvent->mScroll.mAmount;
    5313             :   }
    5314             : 
    5315             :   // The caller may want synchronous scrolling.
    5316           0 :   sf->ScrollBy(pt, scrollUnit, nsIScrollableFrame::INSTANT);
    5317           0 :   return NS_OK;
    5318             : }
    5319             : 
    5320             : void
    5321           0 : EventStateManager::SetActiveManager(EventStateManager* aNewESM,
    5322             :                                     nsIContent* aContent)
    5323             : {
    5324           0 :   if (sActiveESM && aNewESM != sActiveESM) {
    5325           0 :     sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
    5326             :   }
    5327           0 :   sActiveESM = aNewESM;
    5328           0 :   if (sActiveESM && aContent) {
    5329           0 :     sActiveESM->SetContentState(aContent, NS_EVENT_STATE_ACTIVE);
    5330             :   }
    5331           0 : }
    5332             : 
    5333             : void
    5334           0 : EventStateManager::ClearGlobalActiveContent(EventStateManager* aClearer)
    5335             : {
    5336           0 :   if (aClearer) {
    5337           0 :     aClearer->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
    5338           0 :     if (sDragOverContent) {
    5339           0 :       aClearer->SetContentState(nullptr, NS_EVENT_STATE_DRAGOVER);
    5340             :     }
    5341             :   }
    5342           0 :   if (sActiveESM && aClearer != sActiveESM) {
    5343           0 :     sActiveESM->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
    5344             :   }
    5345           0 :   sActiveESM = nullptr;
    5346           0 : }
    5347             : 
    5348             : /******************************************************************/
    5349             : /* mozilla::EventStateManager::DeltaAccumulator                   */
    5350             : /******************************************************************/
    5351             : 
    5352             : void
    5353           0 : EventStateManager::DeltaAccumulator::InitLineOrPageDelta(
    5354             :                                        nsIFrame* aTargetFrame,
    5355             :                                        EventStateManager* aESM,
    5356             :                                        WidgetWheelEvent* aEvent)
    5357             : {
    5358           0 :   MOZ_ASSERT(aESM);
    5359           0 :   MOZ_ASSERT(aEvent);
    5360             : 
    5361             :   // Reset if the previous wheel event is too old.
    5362           0 :   if (!mLastTime.IsNull()) {
    5363           0 :     TimeDuration duration = TimeStamp::Now() - mLastTime;
    5364           0 :     if (duration.ToMilliseconds() > WheelTransaction::GetTimeoutTime()) {
    5365           0 :       Reset();
    5366             :     }
    5367             :   }
    5368             :   // If we have accumulated delta,  we may need to reset it.
    5369           0 :   if (IsInTransaction()) {
    5370             :     // If wheel event type is changed, reset the values.
    5371           0 :     if (mHandlingDeltaMode != aEvent->mDeltaMode ||
    5372           0 :         mIsNoLineOrPageDeltaDevice != aEvent->mIsNoLineOrPageDelta) {
    5373           0 :       Reset();
    5374             :     } else {
    5375             :       // If the delta direction is changed, we should reset only the
    5376             :       // accumulated values.
    5377           0 :       if (mX && aEvent->mDeltaX && ((aEvent->mDeltaX > 0.0) != (mX > 0.0))) {
    5378           0 :         mX = mPendingScrollAmountX = 0.0;
    5379             :       }
    5380           0 :       if (mY && aEvent->mDeltaY && ((aEvent->mDeltaY > 0.0) != (mY > 0.0))) {
    5381           0 :         mY = mPendingScrollAmountY = 0.0;
    5382             :       }
    5383             :     }
    5384             :   }
    5385             : 
    5386           0 :   mHandlingDeltaMode = aEvent->mDeltaMode;
    5387           0 :   mIsNoLineOrPageDeltaDevice = aEvent->mIsNoLineOrPageDelta;
    5388             : 
    5389             :   // If it's handling neither a device that does not provide line or page deltas
    5390             :   // nor delta values multiplied by prefs, we must not modify lineOrPageDelta
    5391             :   // values.
    5392           0 :   if (!mIsNoLineOrPageDeltaDevice &&
    5393           0 :       !EventStateManager::WheelPrefs::GetInstance()->
    5394           0 :         NeedToComputeLineOrPageDelta(aEvent)) {
    5395             :     // Set the delta values to mX and mY.  They would be used when above block
    5396             :     // resets mX/mY/mPendingScrollAmountX/mPendingScrollAmountY if the direction
    5397             :     // is changed.
    5398             :     // NOTE: We shouldn't accumulate the delta values, it might could cause
    5399             :     //       overflow even though it's not a realistic situation.
    5400           0 :     if (aEvent->mDeltaX) {
    5401           0 :       mX = aEvent->mDeltaX;
    5402             :     }
    5403           0 :     if (aEvent->mDeltaY) {
    5404           0 :       mY = aEvent->mDeltaY;
    5405             :     }
    5406           0 :     mLastTime = TimeStamp::Now();
    5407           0 :     return;
    5408             :   }
    5409             : 
    5410           0 :   mX += aEvent->mDeltaX;
    5411           0 :   mY += aEvent->mDeltaY;
    5412             : 
    5413           0 :   if (mHandlingDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
    5414             :     // Records pixel delta values and init mLineOrPageDeltaX and
    5415             :     // mLineOrPageDeltaY for wheel events which are caused by pixel only
    5416             :     // devices.  Ignore mouse wheel transaction for computing this.  The
    5417             :     // lineOrPageDelta values will be used by dispatching legacy
    5418             :     // eMouseScrollEventClass (DOMMouseScroll) but not be used for scrolling
    5419             :     // of default action.  The transaction should be used only for the default
    5420             :     // action.
    5421             :     nsIFrame* frame =
    5422             :       aESM->ComputeScrollTarget(aTargetFrame, aEvent,
    5423           0 :                                 COMPUTE_LEGACY_MOUSE_SCROLL_EVENT_TARGET);
    5424             :     nsPresContext* pc =
    5425           0 :       frame ? frame->PresContext() : aTargetFrame->PresContext();
    5426           0 :     nsIScrollableFrame* scrollTarget = do_QueryFrame(frame);
    5427           0 :     nsSize scrollAmount = aESM->GetScrollAmount(pc, aEvent, scrollTarget);
    5428             :     nsIntSize scrollAmountInCSSPixels(
    5429             :       nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.width),
    5430           0 :       nsPresContext::AppUnitsToIntCSSPixels(scrollAmount.height));
    5431             : 
    5432           0 :     aEvent->mLineOrPageDeltaX = RoundDown(mX) / scrollAmountInCSSPixels.width;
    5433           0 :     aEvent->mLineOrPageDeltaY = RoundDown(mY) / scrollAmountInCSSPixels.height;
    5434             : 
    5435           0 :     mX -= aEvent->mLineOrPageDeltaX * scrollAmountInCSSPixels.width;
    5436           0 :     mY -= aEvent->mLineOrPageDeltaY * scrollAmountInCSSPixels.height;
    5437             :   } else {
    5438           0 :     aEvent->mLineOrPageDeltaX = RoundDown(mX);
    5439           0 :     aEvent->mLineOrPageDeltaY = RoundDown(mY);
    5440           0 :     mX -= aEvent->mLineOrPageDeltaX;
    5441           0 :     mY -= aEvent->mLineOrPageDeltaY;
    5442             :   }
    5443             : 
    5444           0 :   mLastTime = TimeStamp::Now();
    5445             : }
    5446             : 
    5447             : void
    5448           0 : EventStateManager::DeltaAccumulator::Reset()
    5449             : {
    5450           0 :   mX = mY = 0.0;
    5451           0 :   mPendingScrollAmountX = mPendingScrollAmountY = 0.0;
    5452           0 :   mHandlingDeltaMode = UINT32_MAX;
    5453           0 :   mIsNoLineOrPageDeltaDevice = false;
    5454           0 : }
    5455             : 
    5456             : nsIntPoint
    5457           0 : EventStateManager::DeltaAccumulator::ComputeScrollAmountForDefaultAction(
    5458             :                      WidgetWheelEvent* aEvent,
    5459             :                      const nsIntSize& aScrollAmountInDevPixels)
    5460             : {
    5461           0 :   MOZ_ASSERT(aEvent);
    5462             : 
    5463             :   // If the wheel event is line scroll and the delta value is computed from
    5464             :   // system settings, allow to override the system speed.
    5465             :   bool allowScrollSpeedOverride =
    5466           0 :     (!aEvent->mCustomizedByUserPrefs &&
    5467           0 :      aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_LINE);
    5468             :   DeltaValues acceleratedDelta =
    5469           0 :     WheelTransaction::AccelerateWheelDelta(aEvent, allowScrollSpeedOverride);
    5470             : 
    5471           0 :   nsIntPoint result(0, 0);
    5472           0 :   if (aEvent->mDeltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
    5473           0 :     mPendingScrollAmountX += acceleratedDelta.deltaX;
    5474           0 :     mPendingScrollAmountY += acceleratedDelta.deltaY;
    5475             :   } else {
    5476           0 :     mPendingScrollAmountX +=
    5477           0 :       aScrollAmountInDevPixels.width * acceleratedDelta.deltaX;
    5478           0 :     mPendingScrollAmountY +=
    5479           0 :       aScrollAmountInDevPixels.height * acceleratedDelta.deltaY;
    5480             :   }
    5481           0 :   result.x = RoundDown(mPendingScrollAmountX);
    5482           0 :   result.y = RoundDown(mPendingScrollAmountY);
    5483           0 :   mPendingScrollAmountX -= result.x;
    5484           0 :   mPendingScrollAmountY -= result.y;
    5485             : 
    5486           0 :   return result;
    5487             : }
    5488             : 
    5489             : /******************************************************************/
    5490             : /* mozilla::EventStateManager::WheelPrefs                         */
    5491             : /******************************************************************/
    5492             : 
    5493             : // static
    5494             : EventStateManager::WheelPrefs*
    5495           0 : EventStateManager::WheelPrefs::GetInstance()
    5496             : {
    5497           0 :   if (!sInstance) {
    5498           0 :     sInstance = new WheelPrefs();
    5499             :   }
    5500           0 :   return sInstance;
    5501             : }
    5502             : 
    5503             : // static
    5504             : void
    5505           0 : EventStateManager::WheelPrefs::Shutdown()
    5506             : {
    5507           0 :   delete sInstance;
    5508           0 :   sInstance = nullptr;
    5509           0 : }
    5510             : 
    5511             : // static
    5512             : void
    5513           0 : EventStateManager::WheelPrefs::OnPrefChanged(const char* aPrefName,
    5514             :                                              void* aClosure)
    5515             : {
    5516             :   // forget all prefs, it's not problem for performance.
    5517           0 :   sInstance->Reset();
    5518           0 :   DeltaAccumulator::GetInstance()->Reset();
    5519           0 : }
    5520             : 
    5521           0 : EventStateManager::WheelPrefs::WheelPrefs()
    5522             : {
    5523           0 :   Reset();
    5524           0 :   Preferences::RegisterPrefixCallback(OnPrefChanged, "mousewheel.");
    5525             :   Preferences::AddBoolVarCache(&sWheelEventsEnabledOnPlugins,
    5526             :                                "plugin.mousewheel.enabled",
    5527           0 :                                true);
    5528           0 : }
    5529             : 
    5530           0 : EventStateManager::WheelPrefs::~WheelPrefs()
    5531             : {
    5532           0 :   Preferences::UnregisterPrefixCallback(OnPrefChanged, "mousewheel.");
    5533           0 : }
    5534             : 
    5535             : void
    5536           0 : EventStateManager::WheelPrefs::Reset()
    5537             : {
    5538           0 :   memset(mInit, 0, sizeof(mInit));
    5539             : 
    5540           0 : }
    5541             : 
    5542             : EventStateManager::WheelPrefs::Index
    5543           0 : EventStateManager::WheelPrefs::GetIndexFor(WidgetWheelEvent* aEvent)
    5544             : {
    5545           0 :   if (!aEvent) {
    5546           0 :     return INDEX_DEFAULT;
    5547             :   }
    5548             : 
    5549             :   Modifiers modifiers =
    5550           0 :     (aEvent->mModifiers & (MODIFIER_ALT |
    5551             :                            MODIFIER_CONTROL |
    5552             :                            MODIFIER_META |
    5553             :                            MODIFIER_SHIFT |
    5554           0 :                            MODIFIER_OS));
    5555             : 
    5556           0 :   switch (modifiers) {
    5557             :     case MODIFIER_ALT:
    5558           0 :       return INDEX_ALT;
    5559             :     case MODIFIER_CONTROL:
    5560           0 :       return INDEX_CONTROL;
    5561             :     case MODIFIER_META:
    5562           0 :       return INDEX_META;
    5563             :     case MODIFIER_SHIFT:
    5564           0 :       return INDEX_SHIFT;
    5565             :     case MODIFIER_OS:
    5566           0 :       return INDEX_OS;
    5567             :     default:
    5568             :       // If two or more modifier keys are pressed, we should use default
    5569             :       // settings.
    5570           0 :       return INDEX_DEFAULT;
    5571             :   }
    5572             : }
    5573             : 
    5574             : void
    5575           0 : EventStateManager::WheelPrefs::GetBasePrefName(
    5576             :                      EventStateManager::WheelPrefs::Index aIndex,
    5577             :                      nsACString& aBasePrefName)
    5578             : {
    5579           0 :   aBasePrefName.AssignLiteral("mousewheel.");
    5580           0 :   switch (aIndex) {
    5581             :     case INDEX_ALT:
    5582           0 :       aBasePrefName.AppendLiteral("with_alt.");
    5583           0 :       break;
    5584             :     case INDEX_CONTROL:
    5585           0 :       aBasePrefName.AppendLiteral("with_control.");
    5586           0 :       break;
    5587             :     case INDEX_META:
    5588           0 :       aBasePrefName.AppendLiteral("with_meta.");
    5589           0 :       break;
    5590             :     case INDEX_SHIFT:
    5591           0 :       aBasePrefName.AppendLiteral("with_shift.");
    5592           0 :       break;
    5593             :     case INDEX_OS:
    5594           0 :       aBasePrefName.AppendLiteral("with_win.");
    5595           0 :       break;
    5596             :     case INDEX_DEFAULT:
    5597             :     default:
    5598           0 :       aBasePrefName.AppendLiteral("default.");
    5599           0 :       break;
    5600             :   }
    5601           0 : }
    5602             : 
    5603             : void
    5604           0 : EventStateManager::WheelPrefs::Init(EventStateManager::WheelPrefs::Index aIndex)
    5605             : {
    5606           0 :   if (mInit[aIndex]) {
    5607           0 :     return;
    5608             :   }
    5609           0 :   mInit[aIndex] = true;
    5610             : 
    5611           0 :   nsAutoCString basePrefName;
    5612           0 :   GetBasePrefName(aIndex, basePrefName);
    5613             : 
    5614           0 :   nsAutoCString prefNameX(basePrefName);
    5615           0 :   prefNameX.AppendLiteral("delta_multiplier_x");
    5616           0 :   mMultiplierX[aIndex] =
    5617           0 :     static_cast<double>(Preferences::GetInt(prefNameX.get(), 100)) / 100;
    5618             : 
    5619           0 :   nsAutoCString prefNameY(basePrefName);
    5620           0 :   prefNameY.AppendLiteral("delta_multiplier_y");
    5621           0 :   mMultiplierY[aIndex] =
    5622           0 :     static_cast<double>(Preferences::GetInt(prefNameY.get(), 100)) / 100;
    5623             : 
    5624           0 :   nsAutoCString prefNameZ(basePrefName);
    5625           0 :   prefNameZ.AppendLiteral("delta_multiplier_z");
    5626           0 :   mMultiplierZ[aIndex] =
    5627           0 :     static_cast<double>(Preferences::GetInt(prefNameZ.get(), 100)) / 100;
    5628             : 
    5629           0 :   nsAutoCString prefNameAction(basePrefName);
    5630           0 :   prefNameAction.AppendLiteral("action");
    5631           0 :   int32_t action = Preferences::GetInt(prefNameAction.get(), ACTION_SCROLL);
    5632           0 :   if (action < int32_t(ACTION_NONE) || action > int32_t(ACTION_LAST)) {
    5633           0 :     NS_WARNING("Unsupported action pref value, replaced with 'Scroll'.");
    5634           0 :     action = ACTION_SCROLL;
    5635             :   }
    5636           0 :   mActions[aIndex] = static_cast<Action>(action);
    5637             : 
    5638             :   // Compute action values overridden by .override_x pref.
    5639             :   // At present, override is possible only for the x-direction
    5640             :   // because this pref is introduced mainly for tilt wheels.
    5641           0 :   prefNameAction.AppendLiteral(".override_x");
    5642           0 :   int32_t actionOverrideX = Preferences::GetInt(prefNameAction.get(), -1);
    5643           0 :   if (actionOverrideX < -1 || actionOverrideX > int32_t(ACTION_LAST)) {
    5644           0 :     NS_WARNING("Unsupported action override pref value, didn't override.");
    5645           0 :     actionOverrideX = -1;
    5646             :   }
    5647           0 :   mOverriddenActionsX[aIndex] = (actionOverrideX == -1)
    5648           0 :                               ? static_cast<Action>(action)
    5649             :                               : static_cast<Action>(actionOverrideX);
    5650             : }
    5651             : 
    5652             : void
    5653           0 : EventStateManager::WheelPrefs::ApplyUserPrefsToDelta(WidgetWheelEvent* aEvent)
    5654             : {
    5655           0 :   if (aEvent->mCustomizedByUserPrefs) {
    5656           0 :     return;
    5657             :   }
    5658             : 
    5659           0 :   Index index = GetIndexFor(aEvent);
    5660           0 :   Init(index);
    5661             : 
    5662           0 :   aEvent->mDeltaX *= mMultiplierX[index];
    5663           0 :   aEvent->mDeltaY *= mMultiplierY[index];
    5664           0 :   aEvent->mDeltaZ *= mMultiplierZ[index];
    5665             : 
    5666             :   // If the multiplier is 1.0 or -1.0, i.e., it doesn't change the absolute
    5667             :   // value, we should use lineOrPageDelta values which were set by widget.
    5668             :   // Otherwise, we need to compute them from accumulated delta values.
    5669           0 :   if (!NeedToComputeLineOrPageDelta(aEvent)) {
    5670           0 :     aEvent->mLineOrPageDeltaX *= static_cast<int32_t>(mMultiplierX[index]);
    5671           0 :     aEvent->mLineOrPageDeltaY *= static_cast<int32_t>(mMultiplierY[index]);
    5672             :   } else {
    5673           0 :     aEvent->mLineOrPageDeltaX = 0;
    5674           0 :     aEvent->mLineOrPageDeltaY = 0;
    5675             :   }
    5676             : 
    5677           0 :   aEvent->mCustomizedByUserPrefs =
    5678           0 :     ((mMultiplierX[index] != 1.0) || (mMultiplierY[index] != 1.0) ||
    5679           0 :      (mMultiplierZ[index] != 1.0));
    5680             : }
    5681             : 
    5682             : void
    5683           0 : EventStateManager::WheelPrefs::CancelApplyingUserPrefsFromOverflowDelta(
    5684             :                                  WidgetWheelEvent* aEvent)
    5685             : {
    5686           0 :   Index index = GetIndexFor(aEvent);
    5687           0 :   Init(index);
    5688             : 
    5689             :   // XXX If the multiplier pref value is negative, the scroll direction was
    5690             :   //     changed and caused to scroll different direction.  In such case,
    5691             :   //     this method reverts the sign of overflowDelta.  Does it make widget
    5692             :   //     happy?  Although, widget can know the pref applied delta values by
    5693             :   //     referrencing the deltaX and deltaY of the event.
    5694             : 
    5695           0 :   if (mMultiplierX[index]) {
    5696           0 :     aEvent->mOverflowDeltaX /= mMultiplierX[index];
    5697             :   }
    5698           0 :   if (mMultiplierY[index]) {
    5699           0 :     aEvent->mOverflowDeltaY /= mMultiplierY[index];
    5700             :   }
    5701           0 : }
    5702             : 
    5703             : EventStateManager::WheelPrefs::Action
    5704           0 : EventStateManager::WheelPrefs::ComputeActionFor(WidgetWheelEvent* aEvent)
    5705             : {
    5706           0 :   Index index = GetIndexFor(aEvent);
    5707           0 :   Init(index);
    5708             : 
    5709             :   bool deltaXPreferred =
    5710           0 :     (Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaY) &&
    5711           0 :      Abs(aEvent->mDeltaX) > Abs(aEvent->mDeltaZ));
    5712           0 :   Action* actions = deltaXPreferred ? mOverriddenActionsX : mActions;
    5713           0 :   if (actions[index] == ACTION_NONE || actions[index] == ACTION_SCROLL) {
    5714           0 :     return actions[index];
    5715             :   }
    5716             : 
    5717             :   // Momentum events shouldn't run special actions.
    5718           0 :   if (aEvent->mIsMomentum) {
    5719             :     // Use the default action.  Note that user might kill the wheel scrolling.
    5720           0 :     Init(INDEX_DEFAULT);
    5721           0 :     return (actions[INDEX_DEFAULT] == ACTION_SCROLL) ? ACTION_SCROLL :
    5722           0 :                                                        ACTION_NONE;
    5723             :   }
    5724             : 
    5725           0 :   return actions[index];
    5726             : }
    5727             : 
    5728             : bool
    5729           0 : EventStateManager::WheelPrefs::NeedToComputeLineOrPageDelta(
    5730             :                                  WidgetWheelEvent* aEvent)
    5731             : {
    5732           0 :   Index index = GetIndexFor(aEvent);
    5733           0 :   Init(index);
    5734             : 
    5735           0 :   return (mMultiplierX[index] != 1.0 && mMultiplierX[index] != -1.0) ||
    5736           0 :          (mMultiplierY[index] != 1.0 && mMultiplierY[index] != -1.0);
    5737             : }
    5738             : 
    5739             : void
    5740           0 : EventStateManager::WheelPrefs::GetUserPrefsForEvent(WidgetWheelEvent* aEvent,
    5741             :                                                     double* aOutMultiplierX,
    5742             :                                                     double* aOutMultiplierY)
    5743             : {
    5744           0 :   Index index = GetIndexFor(aEvent);
    5745           0 :   Init(index);
    5746             : 
    5747           0 :   *aOutMultiplierX = mMultiplierX[index];
    5748           0 :   *aOutMultiplierY = mMultiplierY[index];
    5749           0 : }
    5750             : 
    5751             : // static
    5752             : bool
    5753           0 : EventStateManager::WheelPrefs::WheelEventsEnabledOnPlugins()
    5754             : {
    5755           0 :   if (!sInstance) {
    5756           0 :     GetInstance(); // initializing sWheelEventsEnabledOnPlugins
    5757             :   }
    5758           0 :   return sWheelEventsEnabledOnPlugins;
    5759             : }
    5760             : 
    5761             : bool
    5762           0 : EventStateManager::WheelEventIsScrollAction(WidgetWheelEvent* aEvent)
    5763             : {
    5764           0 :   return aEvent->mMessage == eWheel &&
    5765           0 :          WheelPrefs::GetInstance()->ComputeActionFor(aEvent) == WheelPrefs::ACTION_SCROLL;
    5766             : }
    5767             : 
    5768             : void
    5769           0 : EventStateManager::GetUserPrefsForWheelEvent(WidgetWheelEvent* aEvent,
    5770             :                                              double* aOutMultiplierX,
    5771             :                                              double* aOutMultiplierY)
    5772             : {
    5773           0 :   WheelPrefs::GetInstance()->GetUserPrefsForEvent(
    5774           0 :     aEvent, aOutMultiplierX, aOutMultiplierY);
    5775           0 : }
    5776             : 
    5777             : bool
    5778           0 : EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedX(
    5779             :                                  WidgetWheelEvent* aEvent)
    5780             : {
    5781           0 :   Index index = GetIndexFor(aEvent);
    5782           0 :   Init(index);
    5783           0 :   return Abs(mMultiplierX[index]) >=
    5784           0 :            MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
    5785             : }
    5786             : 
    5787             : bool
    5788           0 : EventStateManager::WheelPrefs::IsOverOnePageScrollAllowedY(
    5789             :                                  WidgetWheelEvent* aEvent)
    5790             : {
    5791           0 :   Index index = GetIndexFor(aEvent);
    5792           0 :   Init(index);
    5793           0 :   return Abs(mMultiplierY[index]) >=
    5794           0 :            MIN_MULTIPLIER_VALUE_ALLOWING_OVER_ONE_PAGE_SCROLL;
    5795             : }
    5796             : 
    5797             : /******************************************************************/
    5798             : /* mozilla::EventStateManager::Prefs                              */
    5799             : /******************************************************************/
    5800             : 
    5801             : bool EventStateManager::Prefs::sKeyCausesActivation = true;
    5802             : bool EventStateManager::Prefs::sClickHoldContextMenu = false;
    5803             : int32_t EventStateManager::Prefs::sGenericAccessModifierKey = -1;
    5804             : int32_t EventStateManager::Prefs::sChromeAccessModifierMask = 0;
    5805             : int32_t EventStateManager::Prefs::sContentAccessModifierMask = 0;
    5806             : 
    5807             : // static
    5808             : void
    5809           2 : EventStateManager::Prefs::Init()
    5810             : {
    5811           4 :   DebugOnly<nsresult> rv = Preferences::RegisterCallback(OnChange, "dom.popup_allowed_events");
    5812           2 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    5813             :              "Failed to observe \"dom.popup_allowed_events\"");
    5814             : 
    5815             :   static bool sPrefsAlreadyCached = false;
    5816           2 :   if (sPrefsAlreadyCached) {
    5817           0 :     return;
    5818             :   }
    5819             : 
    5820           4 :   rv = Preferences::AddBoolVarCache(&sKeyCausesActivation,
    5821             :                                     "accessibility.accesskeycausesactivation",
    5822           2 :                                     sKeyCausesActivation);
    5823           2 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    5824             :              "Failed to observe \"accessibility.accesskeycausesactivation\"");
    5825           4 :   rv = Preferences::AddBoolVarCache(&sClickHoldContextMenu,
    5826             :                                     "ui.click_hold_context_menus",
    5827           2 :                                     sClickHoldContextMenu);
    5828           2 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    5829             :              "Failed to observe \"ui.click_hold_context_menus\"");
    5830           4 :   rv = Preferences::AddIntVarCache(&sGenericAccessModifierKey,
    5831             :                                    "ui.key.generalAccessKey",
    5832           2 :                                    sGenericAccessModifierKey);
    5833           2 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    5834             :              "Failed to observe \"ui.key.generalAccessKey\"");
    5835           4 :   rv = Preferences::AddIntVarCache(&sChromeAccessModifierMask,
    5836             :                                    "ui.key.chromeAccess",
    5837           2 :                                    sChromeAccessModifierMask);
    5838           2 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    5839             :              "Failed to observe \"ui.key.chromeAccess\"");
    5840           4 :   rv = Preferences::AddIntVarCache(&sContentAccessModifierMask,
    5841             :                                    "ui.key.contentAccess",
    5842           2 :                                    sContentAccessModifierMask);
    5843           2 :   MOZ_ASSERT(NS_SUCCEEDED(rv),
    5844             :              "Failed to observe \"ui.key.contentAccess\"");
    5845           2 :   sPrefsAlreadyCached = true;
    5846             : }
    5847             : 
    5848             : // static
    5849             : void
    5850           0 : EventStateManager::Prefs::OnChange(const char* aPrefName, void*)
    5851             : {
    5852           0 :   nsDependentCString prefName(aPrefName);
    5853           0 :   if (prefName.EqualsLiteral("dom.popup_allowed_events")) {
    5854           0 :     Event::PopupAllowedEventsChanged();
    5855             :   }
    5856           0 : }
    5857             : 
    5858             : // static
    5859             : void
    5860           0 : EventStateManager::Prefs::Shutdown()
    5861             : {
    5862           0 :   Preferences::UnregisterCallback(OnChange, "dom.popup_allowed_events");
    5863           0 : }
    5864             : 
    5865             : // static
    5866             : int32_t
    5867           0 : EventStateManager::Prefs::ChromeAccessModifierMask()
    5868             : {
    5869           0 :   return GetAccessModifierMask(nsIDocShellTreeItem::typeChrome);
    5870             : }
    5871             : 
    5872             : // static
    5873             : int32_t
    5874           0 : EventStateManager::Prefs::ContentAccessModifierMask()
    5875             : {
    5876           0 :   return GetAccessModifierMask(nsIDocShellTreeItem::typeContent);
    5877             : }
    5878             : 
    5879             : // static
    5880             : int32_t
    5881           0 : EventStateManager::Prefs::GetAccessModifierMask(int32_t aItemType)
    5882             : {
    5883           0 :   switch (sGenericAccessModifierKey) {
    5884           0 :     case -1:                             break; // use the individual prefs
    5885           0 :     case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
    5886           0 :     case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
    5887           0 :     case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
    5888           0 :     case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
    5889           0 :     case nsIDOMKeyEvent::DOM_VK_WIN:     return NS_MODIFIER_OS;
    5890           0 :     default:                             return 0;
    5891             :   }
    5892             : 
    5893           0 :   switch (aItemType) {
    5894             :     case nsIDocShellTreeItem::typeChrome:
    5895           0 :       return sChromeAccessModifierMask;
    5896             :     case nsIDocShellTreeItem::typeContent:
    5897           0 :       return sContentAccessModifierMask;
    5898             :     default:
    5899           0 :       return 0;
    5900             :   }
    5901             : }
    5902             : 
    5903             : /******************************************************************/
    5904             : /* mozilla::AutoHandlingUserInputStatePusher                      */
    5905             : /******************************************************************/
    5906             : 
    5907          10 : AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
    5908             :                                     bool aIsHandlingUserInput,
    5909             :                                     WidgetEvent* aEvent,
    5910          10 :                                     nsIDocument* aDocument) :
    5911             :   mIsHandlingUserInput(aIsHandlingUserInput),
    5912          10 :   mIsMouseDown(aEvent && aEvent->mMessage == eMouseDown),
    5913          20 :   mResetFMMouseButtonHandlingState(false)
    5914             : {
    5915          10 :   if (!aIsHandlingUserInput) {
    5916          10 :     return;
    5917             :   }
    5918           0 :   EventStateManager::StartHandlingUserInput();
    5919           0 :   if (mIsMouseDown) {
    5920           0 :     nsIPresShell::SetCapturingContent(nullptr, 0);
    5921           0 :     nsIPresShell::AllowMouseCapture(true);
    5922             :   }
    5923           0 :   if (!aDocument || !aEvent || !aEvent->IsTrusted()) {
    5924           0 :     return;
    5925             :   }
    5926           0 :   mResetFMMouseButtonHandlingState =
    5927           0 :     (aEvent->mMessage == eMouseDown || aEvent->mMessage == eMouseUp);
    5928           0 :   if (mResetFMMouseButtonHandlingState) {
    5929           0 :     nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5930           0 :     NS_ENSURE_TRUE_VOID(fm);
    5931             :     // If it's in modal state, mouse button event handling may be nested.
    5932             :     // E.g., a modal dialog is opened at mousedown or mouseup event handler
    5933             :     // and the dialog is clicked.  Therefore, we should store current
    5934             :     // mouse button event handling document if nsFocusManager already has it.
    5935             :     mMouseButtonEventHandlingDocument =
    5936           0 :       fm->SetMouseButtonHandlingDocument(aDocument);
    5937             :   }
    5938             : }
    5939             : 
    5940          20 : AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher()
    5941             : {
    5942          10 :   if (!mIsHandlingUserInput) {
    5943          10 :     return;
    5944             :   }
    5945           0 :   EventStateManager::StopHandlingUserInput();
    5946           0 :   if (mIsMouseDown) {
    5947           0 :     nsIPresShell::AllowMouseCapture(false);
    5948             :   }
    5949           0 :   if (mResetFMMouseButtonHandlingState) {
    5950           0 :     nsFocusManager* fm = nsFocusManager::GetFocusManager();
    5951           0 :     NS_ENSURE_TRUE_VOID(fm);
    5952             :     nsCOMPtr<nsIDocument> handlingDocument =
    5953           0 :       fm->SetMouseButtonHandlingDocument(mMouseButtonEventHandlingDocument);
    5954             :   }
    5955          10 : }
    5956             : 
    5957           9 : } // namespace mozilla

Generated by: LCOV version 1.13