LCOV - code coverage report
Current view: directory - content/events/src - nsEventStateManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 2177 6 0.3 %
Date: 2012-06-02 Functions: 129 2 1.6 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 sw=2 et tw=80: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is mozilla.org code.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications Corporation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Makoto Kato  <m_kato@ga2.so-net.ne.jp>
      25                 :  *   Dean Tessman <dean_tessman@hotmail.com>
      26                 :  *   Mats Palmgren <mats.palmgren@bredband.net>
      27                 :  *   Masayuki Nakano <masayuki@d-toybox.com>
      28                 :  *   Ginn Chen <ginn.chen@sun.com>
      29                 :  *   Simon Bünzli <zeniko@gmail.com>
      30                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      31                 :  *   Ningjie Chen <chenn@email.uc.edu>
      32                 :  *
      33                 :  * Alternatively, the contents of this file may be used under the terms of
      34                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      35                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      36                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      37                 :  * of those above. If you wish to allow use of your version of this file only
      38                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      39                 :  * use your version of this file under the terms of the MPL, indicate your
      40                 :  * decision by deleting the provisions above and replace them with the notice
      41                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      42                 :  * the provisions above, a recipient may use your version of this file under
      43                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      44                 :  *
      45                 :  * ***** END LICENSE BLOCK ***** */
      46                 : 
      47                 : #include "mozilla/dom/TabParent.h"
      48                 : 
      49                 : #include "nsCOMPtr.h"
      50                 : #include "nsEventStateManager.h"
      51                 : #include "nsEventListenerManager.h"
      52                 : #include "nsIMEStateManager.h"
      53                 : #include "nsContentEventHandler.h"
      54                 : #include "nsIContent.h"
      55                 : #include "nsINodeInfo.h"
      56                 : #include "nsIDocument.h"
      57                 : #include "nsIFrame.h"
      58                 : #include "nsIWidget.h"
      59                 : #include "nsPresContext.h"
      60                 : #include "nsIPresShell.h"
      61                 : #include "nsDOMEvent.h"
      62                 : #include "nsGkAtoms.h"
      63                 : #include "nsIEditorDocShell.h"
      64                 : #include "nsIFormControl.h"
      65                 : #include "nsIComboboxControlFrame.h"
      66                 : #include "nsIScrollableFrame.h"
      67                 : #include "nsIDOMHTMLElement.h"
      68                 : #include "nsIDOMXULControlElement.h"
      69                 : #include "nsINameSpaceManager.h"
      70                 : #include "nsIBaseWindow.h"
      71                 : #include "nsISelection.h"
      72                 : #include "nsFrameSelection.h"
      73                 : #include "nsIPrivateDOMEvent.h"
      74                 : #include "nsPIDOMWindow.h"
      75                 : #include "nsPIWindowRoot.h"
      76                 : #include "nsIEnumerator.h"
      77                 : #include "nsIDocShellTreeItem.h"
      78                 : #include "nsIDocShellTreeNode.h"
      79                 : #include "nsIWebNavigation.h"
      80                 : #include "nsIContentViewer.h"
      81                 : #ifdef MOZ_XUL
      82                 : #include "nsXULPopupManager.h"
      83                 : #endif
      84                 : #include "nsFrameManager.h"
      85                 : 
      86                 : #include "nsIServiceManager.h"
      87                 : #include "nsIScriptSecurityManager.h"
      88                 : 
      89                 : #include "nsFocusManager.h"
      90                 : 
      91                 : #include "nsIDOMXULElement.h"
      92                 : #include "nsIDOMDocument.h"
      93                 : #include "nsIDOMKeyEvent.h"
      94                 : #include "nsIObserverService.h"
      95                 : #include "nsIDocShell.h"
      96                 : #include "nsIMarkupDocumentViewer.h"
      97                 : #include "nsIDOMMouseScrollEvent.h"
      98                 : #include "nsIDOMDragEvent.h"
      99                 : #include "nsIDOMEventTarget.h"
     100                 : #include "nsIDOMUIEvent.h"
     101                 : #include "nsDOMDragEvent.h"
     102                 : #include "nsIDOMNSEditableElement.h"
     103                 : 
     104                 : #include "nsCaret.h"
     105                 : 
     106                 : #include "nsSubDocumentFrame.h"
     107                 : #include "nsIFrameTraversal.h"
     108                 : #include "nsLayoutCID.h"
     109                 : #include "nsLayoutUtils.h"
     110                 : #include "nsIInterfaceRequestorUtils.h"
     111                 : #include "nsUnicharUtils.h"
     112                 : #include "nsContentUtils.h"
     113                 : 
     114                 : #include "imgIContainer.h"
     115                 : #include "nsIProperties.h"
     116                 : #include "nsISupportsPrimitives.h"
     117                 : #include "nsEventDispatcher.h"
     118                 : 
     119                 : #include "nsServiceManagerUtils.h"
     120                 : #include "nsITimer.h"
     121                 : #include "nsFontMetrics.h"
     122                 : #include "nsIDOMXULDocument.h"
     123                 : #include "nsIDragService.h"
     124                 : #include "nsIDragSession.h"
     125                 : #include "nsDOMDataTransfer.h"
     126                 : #include "nsContentAreaDragDrop.h"
     127                 : #ifdef MOZ_XUL
     128                 : #include "nsTreeBodyFrame.h"
     129                 : #endif
     130                 : #include "nsIController.h"
     131                 : #include "nsICommandParams.h"
     132                 : #include "mozilla/Services.h"
     133                 : #include "mozAutoDocUpdate.h"
     134                 : #include "nsHTMLLabelElement.h"
     135                 : 
     136                 : #include "mozilla/Preferences.h"
     137                 : #include "mozilla/LookAndFeel.h"
     138                 : #include "sampler.h"
     139                 : 
     140                 : #ifdef XP_MACOSX
     141                 : #import <ApplicationServices/ApplicationServices.h>
     142                 : #endif
     143                 : 
     144                 : using namespace mozilla;
     145                 : using namespace mozilla::dom;
     146                 : 
     147                 : //#define DEBUG_DOCSHELL_FOCUS
     148                 : 
     149                 : #define NS_USER_INTERACTION_INTERVAL 5000 // ms
     150                 : 
     151                 : static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
     152                 : 
     153                 : static bool sLeftClickOnly = true;
     154                 : static bool sKeyCausesActivation = true;
     155                 : static PRUint32 sESMInstanceCount = 0;
     156                 : static PRInt32 sChromeAccessModifier = 0, sContentAccessModifier = 0;
     157                 : PRInt32 nsEventStateManager::sUserInputEventDepth = 0;
     158                 : bool nsEventStateManager::sNormalLMouseEventInProcess = false;
     159                 : nsEventStateManager* nsEventStateManager::sActiveESM = nsnull;
     160                 : nsIDocument* nsEventStateManager::sMouseOverDocument = nsnull;
     161            1464 : nsWeakFrame nsEventStateManager::sLastDragOverFrame = nsnull;
     162            1464 : nsCOMPtr<nsIContent> nsEventStateManager::sDragOverContent = nsnull;
     163                 : 
     164                 : static PRUint32 gMouseOrKeyboardEventCounter = 0;
     165                 : static nsITimer* gUserInteractionTimer = nsnull;
     166                 : static nsITimerCallback* gUserInteractionTimerCallback = nsnull;
     167                 : 
     168                 : // Pixel scroll accumulation for synthetic line scrolls
     169                 : static nscoord gPixelScrollDeltaX = 0;
     170                 : static nscoord gPixelScrollDeltaY = 0;
     171                 : static PRUint32 gPixelScrollDeltaTimeout = 0;
     172                 : 
     173                 : static nscoord
     174                 : GetScrollableLineHeight(nsIFrame* aTargetFrame);
     175                 : 
     176            1464 : TimeStamp nsEventStateManager::sHandlingInputStart;
     177                 : 
     178                 : static inline bool
     179               0 : IsMouseEventReal(nsEvent* aEvent)
     180                 : {
     181               0 :   NS_ABORT_IF_FALSE(NS_IS_MOUSE_EVENT_STRUCT(aEvent), "Not a mouse event");
     182                 :   // Return true if not synthesized.
     183               0 :   return static_cast<nsMouseEvent*>(aEvent)->reason == nsMouseEvent::eReal;
     184                 : }
     185                 : 
     186                 : #ifdef DEBUG_DOCSHELL_FOCUS
     187                 : static void
     188                 : PrintDocTree(nsIDocShellTreeItem* aParentItem, int aLevel)
     189                 : {
     190                 :   for (PRInt32 i=0;i<aLevel;i++) printf("  ");
     191                 : 
     192                 :   PRInt32 childWebshellCount;
     193                 :   aParentItem->GetChildCount(&childWebshellCount);
     194                 :   nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentItem));
     195                 :   PRInt32 type;
     196                 :   aParentItem->GetItemType(&type);
     197                 :   nsCOMPtr<nsIPresShell> presShell;
     198                 :   parentAsDocShell->GetPresShell(getter_AddRefs(presShell));
     199                 :   nsRefPtr<nsPresContext> presContext;
     200                 :   parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
     201                 :   nsCOMPtr<nsIContentViewer> cv;
     202                 :   parentAsDocShell->GetContentViewer(getter_AddRefs(cv));
     203                 :   nsCOMPtr<nsIDOMDocument> domDoc;
     204                 :   if (cv)
     205                 :     cv->GetDOMDocument(getter_AddRefs(domDoc));
     206                 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
     207                 :   nsCOMPtr<nsIDOMWindow> domwin = doc ? doc->GetWindow() : nsnull;
     208                 :   nsIURI* uri = doc ? doc->GetDocumentURI() : nsnull;
     209                 : 
     210                 :   printf("DS %p  Type %s  Cnt %d  Doc %p  DW %p  EM %p%c",
     211                 :     static_cast<void*>(parentAsDocShell.get()),
     212                 :     type==nsIDocShellTreeItem::typeChrome?"Chrome":"Content",
     213                 :     childWebshellCount, static_cast<void*>(doc.get()),
     214                 :     static_cast<void*>(domwin.get()),
     215                 :     static_cast<void*>(presContext ? presContext->EventStateManager() : nsnull),
     216                 :     uri ? ' ' : '\n');
     217                 :   if (uri) {
     218                 :     nsCAutoString spec;
     219                 :     uri->GetSpec(spec);
     220                 :     printf("\"%s\"\n", spec.get());
     221                 :   }
     222                 : 
     223                 :   if (childWebshellCount > 0) {
     224                 :     for (PRInt32 i = 0; i < childWebshellCount; i++) {
     225                 :       nsCOMPtr<nsIDocShellTreeItem> child;
     226                 :       aParentItem->GetChildAt(i, getter_AddRefs(child));
     227                 :       PrintDocTree(child, aLevel + 1);
     228                 :     }
     229                 :   }
     230                 : }
     231                 : 
     232                 : static void
     233                 : PrintDocTreeAll(nsIDocShellTreeItem* aItem)
     234                 : {
     235                 :   nsCOMPtr<nsIDocShellTreeItem> item = aItem;
     236                 :   for(;;) {
     237                 :     nsCOMPtr<nsIDocShellTreeItem> parent;
     238                 :     item->GetParent(getter_AddRefs(parent));
     239                 :     if (!parent)
     240                 :       break;
     241                 :     item = parent;
     242                 :   }
     243                 : 
     244                 :   PrintDocTree(item, 0);
     245                 : }
     246                 : #endif
     247                 : 
     248                 : class nsUITimerCallback : public nsITimerCallback
     249                 : {
     250                 : public:
     251               0 :   nsUITimerCallback() : mPreviousCount(0) {}
     252                 :   NS_DECL_ISUPPORTS
     253                 :   NS_DECL_NSITIMERCALLBACK
     254                 : private:
     255                 :   PRUint32 mPreviousCount;
     256                 : };
     257                 : 
     258               0 : NS_IMPL_ISUPPORTS1(nsUITimerCallback, nsITimerCallback)
     259                 : 
     260                 : // If aTimer is nsnull, this method always sends "user-interaction-inactive"
     261                 : // notification.
     262                 : NS_IMETHODIMP
     263               0 : nsUITimerCallback::Notify(nsITimer* aTimer)
     264                 : {
     265                 :   nsCOMPtr<nsIObserverService> obs =
     266               0 :     mozilla::services::GetObserverService();
     267               0 :   if (!obs)
     268               0 :     return NS_ERROR_FAILURE;
     269               0 :   if ((gMouseOrKeyboardEventCounter == mPreviousCount) || !aTimer) {
     270               0 :     gMouseOrKeyboardEventCounter = 0;
     271               0 :     obs->NotifyObservers(nsnull, "user-interaction-inactive", nsnull);
     272               0 :     if (gUserInteractionTimer) {
     273               0 :       gUserInteractionTimer->Cancel();
     274               0 :       NS_RELEASE(gUserInteractionTimer);
     275                 :     }
     276                 :   } else {
     277               0 :     obs->NotifyObservers(nsnull, "user-interaction-active", nsnull);
     278               0 :     nsEventStateManager::UpdateUserActivityTimer();
     279                 :   }
     280               0 :   mPreviousCount = gMouseOrKeyboardEventCounter;
     281               0 :   return NS_OK;
     282                 : }
     283                 : 
     284                 : enum {
     285                 :  MOUSE_SCROLL_N_LINES,
     286                 :  MOUSE_SCROLL_PAGE,
     287                 :  MOUSE_SCROLL_HISTORY,
     288                 :  MOUSE_SCROLL_ZOOM,
     289                 :  MOUSE_SCROLL_PIXELS
     290                 : };
     291                 : 
     292                 : // mask values for ui.key.chromeAccess and ui.key.contentAccess
     293                 : #define NS_MODIFIER_SHIFT    1
     294                 : #define NS_MODIFIER_CONTROL  2
     295                 : #define NS_MODIFIER_ALT      4
     296                 : #define NS_MODIFIER_META     8
     297                 : 
     298                 : static nsIDocument *
     299               0 : GetDocumentFromWindow(nsIDOMWindow *aWindow)
     300                 : {
     301               0 :   nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aWindow);
     302               0 :   nsCOMPtr<nsIDocument> doc;
     303                 : 
     304               0 :   if (win) {
     305               0 :     doc = do_QueryInterface(win->GetExtantDocument());
     306                 :   }
     307                 : 
     308               0 :   return doc;
     309                 : }
     310                 : 
     311                 : static PRInt32
     312               0 : GetAccessModifierMaskFromPref(PRInt32 aItemType)
     313                 : {
     314               0 :   PRInt32 accessKey = Preferences::GetInt("ui.key.generalAccessKey", -1);
     315               0 :   switch (accessKey) {
     316                 :     case -1:                             break; // use the individual prefs
     317               0 :     case nsIDOMKeyEvent::DOM_VK_SHIFT:   return NS_MODIFIER_SHIFT;
     318               0 :     case nsIDOMKeyEvent::DOM_VK_CONTROL: return NS_MODIFIER_CONTROL;
     319               0 :     case nsIDOMKeyEvent::DOM_VK_ALT:     return NS_MODIFIER_ALT;
     320               0 :     case nsIDOMKeyEvent::DOM_VK_META:    return NS_MODIFIER_META;
     321               0 :     default:                             return 0;
     322                 :   }
     323                 : 
     324               0 :   switch (aItemType) {
     325                 :   case nsIDocShellTreeItem::typeChrome:
     326               0 :     return Preferences::GetInt("ui.key.chromeAccess", 0);
     327                 :   case nsIDocShellTreeItem::typeContent:
     328               0 :     return Preferences::GetInt("ui.key.contentAccess", 0);
     329                 :   default:
     330               0 :     return 0;
     331                 :   }
     332                 : }
     333                 : 
     334                 : static void
     335               0 : GetBasePrefKeyForMouseWheel(nsMouseScrollEvent* aEvent, nsACString& aPref)
     336                 : {
     337               0 :   NS_NAMED_LITERAL_CSTRING(prefbase,    "mousewheel");
     338               0 :   NS_NAMED_LITERAL_CSTRING(horizscroll, ".horizscroll");
     339               0 :   NS_NAMED_LITERAL_CSTRING(withshift,   ".withshiftkey");
     340               0 :   NS_NAMED_LITERAL_CSTRING(withalt,     ".withaltkey");
     341               0 :   NS_NAMED_LITERAL_CSTRING(withcontrol, ".withcontrolkey");
     342               0 :   NS_NAMED_LITERAL_CSTRING(withmetakey, ".withmetakey");
     343               0 :   NS_NAMED_LITERAL_CSTRING(withno,      ".withnokey");
     344                 : 
     345               0 :   aPref = prefbase;
     346               0 :   if (aEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
     347               0 :     aPref.Append(horizscroll);
     348                 :   }
     349               0 :   if (aEvent->isShift) {
     350               0 :     aPref.Append(withshift);
     351               0 :   } else if (aEvent->isControl) {
     352               0 :     aPref.Append(withcontrol);
     353               0 :   } else if (aEvent->isAlt) {
     354               0 :     aPref.Append(withalt);
     355               0 :   } else if (aEvent->isMeta) {
     356               0 :     aPref.Append(withmetakey);
     357                 :   } else {
     358               0 :     aPref.Append(withno);
     359                 :   }
     360               0 : }
     361                 : 
     362                 : class nsMouseWheelTransaction {
     363                 : public:
     364               0 :   static nsIFrame* GetTargetFrame() { return sTargetFrame; }
     365                 :   static void BeginTransaction(nsIFrame* aTargetFrame,
     366                 :                                PRInt32 aNumLines,
     367                 :                                bool aScrollHorizontal);
     368                 :   // Be careful, UpdateTransaction may fire a DOM event, therefore, the target
     369                 :   // frame might be destroyed in the event handler.
     370                 :   static bool UpdateTransaction(PRInt32 aNumLines,
     371                 :                                   bool aScrollHorizontal);
     372                 :   static void EndTransaction();
     373                 :   static void OnEvent(nsEvent* aEvent);
     374                 :   static void Shutdown();
     375                 :   static PRUint32 GetTimeoutTime();
     376                 :   static PRInt32 AccelerateWheelDelta(PRInt32 aScrollLines,
     377                 :                    bool aIsHorizontal, bool aAllowScrollSpeedOverride,
     378                 :                    nsIScrollableFrame::ScrollUnit *aScrollQuantity,
     379                 :                    bool aLimitToMaxOnePageScroll = true);
     380                 :   static bool IsAccelerationEnabled();
     381                 : 
     382                 :   enum {
     383                 :     kScrollSeriesTimeout = 80
     384                 :   };
     385                 : protected:
     386                 :   static nsIntPoint GetScreenPoint(nsGUIEvent* aEvent);
     387                 :   static void OnFailToScrollTarget();
     388                 :   static void OnTimeout(nsITimer *aTimer, void *aClosure);
     389                 :   static void SetTimeout();
     390                 :   static PRUint32 GetIgnoreMoveDelayTime();
     391                 :   static PRInt32 GetAccelerationStart();
     392                 :   static PRInt32 GetAccelerationFactor();
     393                 :   static PRInt32 OverrideSystemScrollSpeed(PRInt32 aScrollLines,
     394                 :                                            bool aIsHorizontal);
     395                 :   static PRInt32 ComputeAcceleratedWheelDelta(PRInt32 aDelta, PRInt32 aFactor);
     396                 :   static PRInt32 LimitToOnePageScroll(PRInt32 aScrollLines,
     397                 :                    bool aIsHorizontal,
     398                 :                    nsIScrollableFrame::ScrollUnit *aScrollQuantity);
     399                 : 
     400                 :   static nsWeakFrame sTargetFrame;
     401                 :   static PRUint32    sTime;        // in milliseconds
     402                 :   static PRUint32    sMouseMoved;  // in milliseconds
     403                 :   static nsITimer*   sTimer;
     404                 :   static PRInt32     sScrollSeriesCounter;
     405                 : };
     406                 : 
     407            1464 : nsWeakFrame nsMouseWheelTransaction::sTargetFrame(nsnull);
     408                 : PRUint32    nsMouseWheelTransaction::sTime        = 0;
     409                 : PRUint32    nsMouseWheelTransaction::sMouseMoved  = 0;
     410                 : nsITimer*   nsMouseWheelTransaction::sTimer       = nsnull;
     411                 : PRInt32     nsMouseWheelTransaction::sScrollSeriesCounter = 0;
     412                 : 
     413                 : static bool
     414               0 : OutOfTime(PRUint32 aBaseTime, PRUint32 aThreshold)
     415                 : {
     416               0 :   PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow());
     417               0 :   return (now - aBaseTime > aThreshold);
     418                 : }
     419                 : 
     420                 : static bool
     421               0 : CanScrollInRange(nscoord aMin, nscoord aValue, nscoord aMax, PRInt32 aDirection)
     422                 : {
     423               0 :   return aDirection > 0 ? aValue < aMax : aMin < aValue;
     424                 : }
     425                 : 
     426                 : static bool
     427               0 : CanScrollOn(nsIScrollableFrame* aScrollFrame, PRInt32 aNumLines,
     428                 :             bool aScrollHorizontal)
     429                 : {
     430               0 :   NS_PRECONDITION(aScrollFrame, "aScrollFrame is null");
     431               0 :   NS_PRECONDITION(aNumLines, "aNumLines must be non-zero");
     432               0 :   nsPoint scrollPt = aScrollFrame->GetScrollPosition();
     433               0 :   nsRect scrollRange = aScrollFrame->GetScrollRange();
     434                 : 
     435                 :   return aScrollHorizontal
     436               0 :     ? CanScrollInRange(scrollRange.x, scrollPt.x, scrollRange.XMost(), aNumLines)
     437               0 :     : CanScrollInRange(scrollRange.y, scrollPt.y, scrollRange.YMost(), aNumLines);
     438                 : }
     439                 : 
     440                 : void
     441               0 : nsMouseWheelTransaction::BeginTransaction(nsIFrame* aTargetFrame,
     442                 :                                           PRInt32 aNumLines,
     443                 :                                           bool aScrollHorizontal)
     444                 : {
     445               0 :   NS_ASSERTION(!sTargetFrame, "previous transaction is not finished!");
     446               0 :   sTargetFrame = aTargetFrame;
     447               0 :   sScrollSeriesCounter = 0;
     448               0 :   if (!UpdateTransaction(aNumLines, aScrollHorizontal)) {
     449               0 :     NS_ERROR("BeginTransaction is called even cannot scroll the frame");
     450               0 :     EndTransaction();
     451                 :   }
     452               0 : }
     453                 : 
     454                 : bool
     455               0 : nsMouseWheelTransaction::UpdateTransaction(PRInt32 aNumLines,
     456                 :                                            bool aScrollHorizontal)
     457                 : {
     458               0 :   nsIScrollableFrame* sf = GetTargetFrame()->GetScrollTargetFrame();
     459               0 :   NS_ENSURE_TRUE(sf, false);
     460                 : 
     461               0 :   if (!CanScrollOn(sf, aNumLines, aScrollHorizontal)) {
     462               0 :     OnFailToScrollTarget();
     463                 :     // We should not modify the transaction state when the view will not be
     464                 :     // scrolled actually.
     465               0 :     return false;
     466                 :   }
     467                 : 
     468               0 :   SetTimeout();
     469                 : 
     470               0 :   if (sScrollSeriesCounter != 0 && OutOfTime(sTime, kScrollSeriesTimeout))
     471               0 :     sScrollSeriesCounter = 0;
     472               0 :   sScrollSeriesCounter++;
     473                 : 
     474                 :   // We should use current time instead of nsEvent.time.
     475                 :   // 1. Some events doesn't have the correct creation time.
     476                 :   // 2. If the computer runs slowly by other processes eating the CPU resource,
     477                 :   //    the event creation time doesn't keep real time.
     478               0 :   sTime = PR_IntervalToMilliseconds(PR_IntervalNow());
     479               0 :   sMouseMoved = 0;
     480               0 :   return true;
     481                 : }
     482                 : 
     483                 : void
     484               0 : nsMouseWheelTransaction::EndTransaction()
     485                 : {
     486               0 :   if (sTimer)
     487               0 :     sTimer->Cancel();
     488               0 :   sTargetFrame = nsnull;
     489               0 :   sScrollSeriesCounter = 0;
     490               0 : }
     491                 : 
     492                 : void
     493               0 : nsMouseWheelTransaction::OnEvent(nsEvent* aEvent)
     494                 : {
     495               0 :   if (!sTargetFrame)
     496               0 :     return;
     497                 : 
     498               0 :   if (OutOfTime(sTime, GetTimeoutTime())) {
     499                 :     // Even if the scroll event which is handled after timeout, but onTimeout
     500                 :     // was not fired by timer, then the scroll event will scroll old frame,
     501                 :     // therefore, we should call OnTimeout here and ensure to finish the old
     502                 :     // transaction.
     503               0 :     OnTimeout(nsnull, nsnull);
     504               0 :     return;
     505                 :   }
     506                 : 
     507               0 :   PRInt32 message = aEvent->message;
     508                 :   // If the event is query scroll target info event, that causes modifying
     509                 :   // wheel transaction because DoScrollText() needs to use them.  Therefore,
     510                 :   // we should handle the event as its mouse scroll event here.
     511               0 :   if (message == NS_QUERY_SCROLL_TARGET_INFO) {
     512               0 :     nsQueryContentEvent* queryEvent = static_cast<nsQueryContentEvent*>(aEvent);
     513               0 :     message = queryEvent->mInput.mMouseScrollEvent->message;
     514                 :   }
     515                 : 
     516               0 :   switch (message) {
     517                 :     case NS_MOUSE_SCROLL:
     518                 :     case NS_MOUSE_PIXEL_SCROLL:
     519               0 :       if (sMouseMoved != 0 &&
     520               0 :           OutOfTime(sMouseMoved, GetIgnoreMoveDelayTime())) {
     521                 :         // Terminate the current mousewheel transaction if the mouse moved more
     522                 :         // than ignoremovedelay milliseconds ago
     523               0 :         EndTransaction();
     524                 :       }
     525               0 :       return;
     526                 :     case NS_MOUSE_MOVE:
     527                 :     case NS_DRAGDROP_OVER:
     528               0 :       if (IsMouseEventReal(aEvent)) {
     529                 :         // If the cursor is moving to be outside the frame,
     530                 :         // terminate the scrollwheel transaction.
     531               0 :         nsIntPoint pt = GetScreenPoint((nsGUIEvent*)aEvent);
     532               0 :         nsIntRect r = sTargetFrame->GetScreenRectExternal();
     533               0 :         if (!r.Contains(pt)) {
     534               0 :           EndTransaction();
     535               0 :           return;
     536                 :         }
     537                 : 
     538                 :         // If the cursor is moving inside the frame, and it is less than
     539                 :         // ignoremovedelay milliseconds since the last scroll operation, ignore
     540                 :         // the mouse move; otherwise, record the current mouse move time to be
     541                 :         // checked later
     542               0 :         if (OutOfTime(sTime, GetIgnoreMoveDelayTime())) {
     543               0 :           if (sMouseMoved == 0)
     544               0 :             sMouseMoved = PR_IntervalToMilliseconds(PR_IntervalNow());
     545                 :         }
     546                 :       }
     547               0 :       return;
     548                 :     case NS_KEY_PRESS:
     549                 :     case NS_KEY_UP:
     550                 :     case NS_KEY_DOWN:
     551                 :     case NS_MOUSE_BUTTON_UP:
     552                 :     case NS_MOUSE_BUTTON_DOWN:
     553                 :     case NS_MOUSE_DOUBLECLICK:
     554                 :     case NS_MOUSE_CLICK:
     555                 :     case NS_CONTEXTMENU:
     556                 :     case NS_DRAGDROP_DROP:
     557               0 :       EndTransaction();
     558               0 :       return;
     559                 :   }
     560                 : }
     561                 : 
     562                 : void
     563               0 : nsMouseWheelTransaction::Shutdown()
     564                 : {
     565               0 :   NS_IF_RELEASE(sTimer);
     566               0 : }
     567                 : 
     568                 : void
     569               0 : nsMouseWheelTransaction::OnFailToScrollTarget()
     570                 : {
     571               0 :   NS_PRECONDITION(sTargetFrame, "We don't have mouse scrolling transaction");
     572                 : 
     573               0 :   if (Preferences::GetBool("test.mousescroll", false)) {
     574                 :     // This event is used for automated tests, see bug 442774.
     575                 :     nsContentUtils::DispatchTrustedEvent(
     576               0 :                       sTargetFrame->GetContent()->OwnerDoc(),
     577               0 :                       sTargetFrame->GetContent(),
     578               0 :                       NS_LITERAL_STRING("MozMouseScrollFailed"),
     579               0 :                       true, true);
     580                 :   }
     581                 :   // The target frame might be destroyed in the event handler, at that time,
     582                 :   // we need to finish the current transaction
     583               0 :   if (!sTargetFrame)
     584               0 :     EndTransaction();
     585               0 : }
     586                 : 
     587                 : void
     588               0 : nsMouseWheelTransaction::OnTimeout(nsITimer* aTimer, void* aClosure)
     589                 : {
     590               0 :   if (!sTargetFrame) {
     591                 :     // The transaction target was destroyed already
     592               0 :     EndTransaction();
     593               0 :     return;
     594                 :   }
     595                 :   // Store the sTargetFrame, the variable becomes null in EndTransaction.
     596               0 :   nsIFrame* frame = sTargetFrame;
     597                 :   // We need to finish current transaction before DOM event firing. Because
     598                 :   // the next DOM event might create strange situation for us.
     599               0 :   EndTransaction();
     600                 : 
     601               0 :   if (Preferences::GetBool("test.mousescroll", false)) {
     602                 :     // This event is used for automated tests, see bug 442774.
     603                 :     nsContentUtils::DispatchTrustedEvent(
     604               0 :                       frame->GetContent()->OwnerDoc(),
     605               0 :                       frame->GetContent(),
     606               0 :                       NS_LITERAL_STRING("MozMouseScrollTransactionTimeout"),
     607               0 :                       true, true);
     608                 :   }
     609                 : }
     610                 : 
     611                 : void
     612               0 : nsMouseWheelTransaction::SetTimeout()
     613                 : {
     614               0 :   if (!sTimer) {
     615               0 :     nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
     616               0 :     if (!timer)
     617                 :       return;
     618               0 :     timer.swap(sTimer);
     619                 :   }
     620               0 :   sTimer->Cancel();
     621                 : #ifdef DEBUG
     622                 :   nsresult rv =
     623                 : #endif
     624                 :   sTimer->InitWithFuncCallback(OnTimeout, nsnull, GetTimeoutTime(),
     625               0 :                                nsITimer::TYPE_ONE_SHOT);
     626               0 :   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "nsITimer::InitWithFuncCallback failed");
     627                 : }
     628                 : 
     629                 : nsIntPoint
     630               0 : nsMouseWheelTransaction::GetScreenPoint(nsGUIEvent* aEvent)
     631                 : {
     632               0 :   NS_ASSERTION(aEvent, "aEvent is null");
     633               0 :   NS_ASSERTION(aEvent->widget, "aEvent-widget is null");
     634               0 :   return aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
     635                 : }
     636                 : 
     637                 : PRUint32
     638               0 : nsMouseWheelTransaction::GetTimeoutTime()
     639                 : {
     640               0 :   return Preferences::GetUint("mousewheel.transaction.timeout", 1500);
     641                 : }
     642                 : 
     643                 : PRUint32
     644               0 : nsMouseWheelTransaction::GetIgnoreMoveDelayTime()
     645                 : {
     646               0 :   return Preferences::GetUint("mousewheel.transaction.ignoremovedelay", 100);
     647                 : }
     648                 : 
     649                 : bool
     650               0 : nsMouseWheelTransaction::IsAccelerationEnabled()
     651                 : {
     652               0 :   return GetAccelerationStart() >= 0 && GetAccelerationFactor() > 0;
     653                 : }
     654                 : 
     655                 : PRInt32
     656               0 : nsMouseWheelTransaction::AccelerateWheelDelta(PRInt32 aScrollLines,
     657                 :                            bool aIsHorizontal,
     658                 :                            bool aAllowScrollSpeedOverride,
     659                 :                            nsIScrollableFrame::ScrollUnit *aScrollQuantity,
     660                 :                            bool aLimitToMaxOnePageScroll)
     661                 : {
     662               0 :   if (aAllowScrollSpeedOverride) {
     663               0 :     aScrollLines = OverrideSystemScrollSpeed(aScrollLines, aIsHorizontal);
     664                 :   }
     665                 : 
     666                 :   // Accelerate by the sScrollSeriesCounter
     667               0 :   PRInt32 start = GetAccelerationStart();
     668               0 :   if (start >= 0 && sScrollSeriesCounter >= start) {
     669               0 :     PRInt32 factor = GetAccelerationFactor();
     670               0 :     if (factor > 0) {
     671               0 :       aScrollLines = ComputeAcceleratedWheelDelta(aScrollLines, factor);
     672                 :     }
     673                 :   }
     674                 : 
     675                 :   // If the computed delta is larger than the page, we should limit
     676                 :   // the delta value to the one page size.
     677                 :   return !aLimitToMaxOnePageScroll ? aScrollLines :
     678               0 :     LimitToOnePageScroll(aScrollLines, aIsHorizontal, aScrollQuantity);
     679                 : }
     680                 : 
     681                 : PRInt32
     682               0 : nsMouseWheelTransaction::ComputeAcceleratedWheelDelta(PRInt32 aDelta,
     683                 :                                                       PRInt32 aFactor)
     684                 : {
     685               0 :   if (aDelta == 0)
     686               0 :     return 0;
     687                 : 
     688                 :   return PRInt32(NS_round(aDelta * sScrollSeriesCounter *
     689               0 :                           (double)aFactor / 10));
     690                 : }
     691                 : 
     692                 : PRInt32
     693               0 : nsMouseWheelTransaction::GetAccelerationStart()
     694                 : {
     695               0 :   return Preferences::GetInt("mousewheel.acceleration.start", -1);
     696                 : }
     697                 : 
     698                 : PRInt32
     699               0 : nsMouseWheelTransaction::GetAccelerationFactor()
     700                 : {
     701               0 :   return Preferences::GetInt("mousewheel.acceleration.factor", -1);
     702                 : }
     703                 : 
     704                 : PRInt32
     705               0 : nsMouseWheelTransaction::OverrideSystemScrollSpeed(PRInt32 aScrollLines,
     706                 :                                                    bool aIsHorizontal)
     707                 : {
     708               0 :   NS_PRECONDITION(sTargetFrame, "We don't have mouse scrolling transaction");
     709                 : 
     710               0 :   if (aScrollLines == 0) {
     711               0 :     return 0;
     712                 :   }
     713                 : 
     714                 :   // We shouldn't override the scrolling speed on non root scroll frame.
     715               0 :   if (sTargetFrame !=
     716               0 :         sTargetFrame->PresContext()->PresShell()->GetRootScrollFrame()) {
     717               0 :     return aScrollLines;
     718                 :   }
     719                 : 
     720                 :   // Compute the overridden speed to nsIWidget.  The widget can check the
     721                 :   // conditions (e.g., checking the prefs, and also whether the user customized
     722                 :   // the system settings of the mouse wheel scrolling or not), and can limit
     723                 :   // the speed for preventing the unexpected high speed scrolling.
     724               0 :   nsCOMPtr<nsIWidget> widget(sTargetFrame->GetNearestWidget());
     725               0 :   NS_ENSURE_TRUE(widget, aScrollLines);
     726                 :   PRInt32 overriddenDelta;
     727               0 :   nsresult rv = widget->OverrideSystemMouseScrollSpeed(aScrollLines,
     728                 :                                                        aIsHorizontal,
     729               0 :                                                        overriddenDelta);
     730               0 :   NS_ENSURE_SUCCESS(rv, aScrollLines);
     731               0 :   return overriddenDelta;
     732                 : }
     733                 : 
     734                 : PRInt32
     735               0 : nsMouseWheelTransaction::LimitToOnePageScroll(PRInt32 aScrollLines,
     736                 :                            bool aIsHorizontal,
     737                 :                            nsIScrollableFrame::ScrollUnit *aScrollQuantity)
     738                 : {
     739               0 :   NS_ENSURE_TRUE(aScrollQuantity, aScrollLines);
     740               0 :   NS_PRECONDITION(*aScrollQuantity == nsIScrollableFrame::LINES,
     741                 :                   "aScrollQuantity isn't by line");
     742                 : 
     743               0 :   NS_ENSURE_TRUE(sTargetFrame, aScrollLines);
     744               0 :   nsIScrollableFrame* sf = sTargetFrame->GetScrollTargetFrame();
     745               0 :   NS_ENSURE_TRUE(sf, aScrollLines);
     746                 : 
     747                 :   // Limit scrolling to be at most one page, but if possible, try to
     748                 :   // just adjust the number of scrolled lines.
     749               0 :   nsSize lineAmount = sf->GetLineScrollAmount();
     750               0 :   nscoord lineScroll = aIsHorizontal ? lineAmount.width : lineAmount.height;
     751                 : 
     752               0 :   if (lineScroll == 0)
     753               0 :     return aScrollLines;
     754                 : 
     755               0 :   nsSize pageAmount = sf->GetPageScrollAmount();
     756               0 :   nscoord pageScroll = aIsHorizontal ? pageAmount.width : pageAmount.height;
     757                 : 
     758               0 :   if (NS_ABS(aScrollLines) * lineScroll < pageScroll)
     759               0 :     return aScrollLines;
     760                 : 
     761               0 :   nscoord maxLines = (pageScroll / lineScroll);
     762               0 :   if (maxLines >= 1)
     763               0 :     return ((aScrollLines < 0) ? -1 : 1) * maxLines;
     764                 : 
     765               0 :   *aScrollQuantity = nsIScrollableFrame::PAGES;
     766               0 :   return (aScrollLines < 0) ? -1 : 1;
     767                 : }
     768                 : 
     769                 : /******************************************************************/
     770                 : /* nsEventStateManager                                            */
     771                 : /******************************************************************/
     772                 : 
     773               0 : nsEventStateManager::nsEventStateManager()
     774                 :   : mLockCursor(0),
     775                 :     mCurrentTarget(nsnull),
     776                 :     mLastMouseOverFrame(nsnull),
     777                 :     // init d&d gesture state machine variables
     778                 :     mGestureDownPoint(0,0),
     779                 :     mPresContext(nsnull),
     780                 :     mLClickCount(0),
     781                 :     mMClickCount(0),
     782                 :     mRClickCount(0),
     783                 :     m_haveShutdown(false),
     784                 :     mLastLineScrollConsumedX(false),
     785                 :     mLastLineScrollConsumedY(false),
     786               0 :     mClickHoldContextMenu(false)
     787                 : {
     788               0 :   if (sESMInstanceCount == 0) {
     789               0 :     gUserInteractionTimerCallback = new nsUITimerCallback();
     790               0 :     if (gUserInteractionTimerCallback)
     791               0 :       NS_ADDREF(gUserInteractionTimerCallback);
     792               0 :     UpdateUserActivityTimer();
     793                 :   }
     794               0 :   ++sESMInstanceCount;
     795               0 : }
     796                 : 
     797                 : nsresult
     798               0 : nsEventStateManager::UpdateUserActivityTimer(void)
     799                 : {
     800               0 :   if (!gUserInteractionTimerCallback)
     801               0 :     return NS_OK;
     802                 : 
     803               0 :   if (!gUserInteractionTimer)
     804               0 :     CallCreateInstance("@mozilla.org/timer;1", &gUserInteractionTimer);
     805                 : 
     806               0 :   if (gUserInteractionTimer) {
     807                 :     gUserInteractionTimer->InitWithCallback(gUserInteractionTimerCallback,
     808                 :                                             NS_USER_INTERACTION_INTERVAL,
     809               0 :                                             nsITimer::TYPE_ONE_SHOT);
     810                 :   }
     811               0 :   return NS_OK;
     812                 : }
     813                 : 
     814                 : static const char* kObservedPrefs[] = {
     815                 :   "accessibility.accesskeycausesactivation",
     816                 :   "nglayout.events.dispatchLeftClickOnly",
     817                 :   "ui.key.generalAccessKey",
     818                 :   "ui.key.chromeAccess",
     819                 :   "ui.key.contentAccess",
     820                 :   "ui.click_hold_context_menus",
     821                 : #if 0
     822                 :   "mousewheel.withaltkey.action",
     823                 :   "mousewheel.withaltkey.numlines",
     824                 :   "mousewheel.withaltkey.sysnumlines",
     825                 :   "mousewheel.withcontrolkey.action",
     826                 :   "mousewheel.withcontrolkey.numlines",
     827                 :   "mousewheel.withcontrolkey.sysnumlines",
     828                 :   "mousewheel.withnokey.action",
     829                 :   "mousewheel.withnokey.numlines",
     830                 :   "mousewheel.withnokey.sysnumlines",
     831                 :   "mousewheel.withshiftkey.action",
     832                 :   "mousewheel.withshiftkey.numlines",
     833                 :   "mousewheel.withshiftkey.sysnumlines",
     834                 : #endif
     835                 :   "dom.popup_allowed_events",
     836                 :   nsnull
     837                 : };
     838                 : 
     839                 : nsresult
     840               0 : nsEventStateManager::Init()
     841                 : {
     842                 :   nsCOMPtr<nsIObserverService> observerService =
     843               0 :     mozilla::services::GetObserverService();
     844               0 :   if (!observerService)
     845               0 :     return NS_ERROR_FAILURE;
     846                 : 
     847               0 :   observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
     848                 : 
     849               0 :   if (sESMInstanceCount == 1) {
     850                 :     sKeyCausesActivation =
     851                 :       Preferences::GetBool("accessibility.accesskeycausesactivation",
     852               0 :                            sKeyCausesActivation);
     853                 :     sLeftClickOnly =
     854                 :       Preferences::GetBool("nglayout.events.dispatchLeftClickOnly",
     855               0 :                            sLeftClickOnly);
     856                 :     sChromeAccessModifier =
     857               0 :       GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeChrome);
     858                 :     sContentAccessModifier =
     859               0 :       GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeContent);
     860                 :   }
     861               0 :   Preferences::AddWeakObservers(this, kObservedPrefs);
     862                 : 
     863                 :   mClickHoldContextMenu =
     864               0 :     Preferences::GetBool("ui.click_hold_context_menus", false);
     865                 : 
     866               0 :   return NS_OK;
     867                 : }
     868                 : 
     869               0 : nsEventStateManager::~nsEventStateManager()
     870                 : {
     871               0 :   if (sActiveESM == this) {
     872               0 :     sActiveESM = nsnull;
     873                 :   }
     874               0 :   if (mClickHoldContextMenu)
     875               0 :     KillClickHoldTimer();
     876                 : 
     877               0 :   if (mDocument == sMouseOverDocument)
     878               0 :     sMouseOverDocument = nsnull;
     879                 : 
     880               0 :   --sESMInstanceCount;
     881               0 :   if(sESMInstanceCount == 0) {
     882               0 :     nsMouseWheelTransaction::Shutdown();
     883               0 :     if (gUserInteractionTimerCallback) {
     884               0 :       gUserInteractionTimerCallback->Notify(nsnull);
     885               0 :       NS_RELEASE(gUserInteractionTimerCallback);
     886                 :     }
     887               0 :     if (gUserInteractionTimer) {
     888               0 :       gUserInteractionTimer->Cancel();
     889               0 :       NS_RELEASE(gUserInteractionTimer);
     890                 :     }
     891                 :   }
     892                 : 
     893               0 :   if (sDragOverContent && sDragOverContent->OwnerDoc() == mDocument) {
     894               0 :     sDragOverContent = nsnull;
     895                 :   }
     896                 : 
     897               0 :   if (!m_haveShutdown) {
     898               0 :     Shutdown();
     899                 : 
     900                 :     // Don't remove from Observer service in Shutdown because Shutdown also
     901                 :     // gets called from xpcom shutdown observer.  And we don't want to remove
     902                 :     // from the service in that case.
     903                 : 
     904                 :     nsCOMPtr<nsIObserverService> observerService =
     905               0 :       mozilla::services::GetObserverService();
     906               0 :     if (observerService) {
     907               0 :       observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
     908                 :     }
     909                 :   }
     910                 : 
     911               0 : }
     912                 : 
     913                 : nsresult
     914               0 : nsEventStateManager::Shutdown()
     915                 : {
     916               0 :   Preferences::RemoveObservers(this, kObservedPrefs);
     917               0 :   m_haveShutdown = true;
     918               0 :   return NS_OK;
     919                 : }
     920                 : 
     921                 : NS_IMETHODIMP
     922               0 : nsEventStateManager::Observe(nsISupports *aSubject,
     923                 :                              const char *aTopic,
     924                 :                              const PRUnichar *someData)
     925                 : {
     926               0 :   if (!nsCRT::strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))
     927               0 :     Shutdown();
     928               0 :   else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     929               0 :     if (!someData)
     930               0 :       return NS_OK;
     931                 : 
     932               0 :     nsDependentString data(someData);
     933               0 :     if (data.EqualsLiteral("accessibility.accesskeycausesactivation")) {
     934                 :       sKeyCausesActivation =
     935                 :         Preferences::GetBool("accessibility.accesskeycausesactivation",
     936               0 :                              sKeyCausesActivation);
     937               0 :     } else if (data.EqualsLiteral("nglayout.events.dispatchLeftClickOnly")) {
     938                 :       sLeftClickOnly =
     939                 :         Preferences::GetBool("nglayout.events.dispatchLeftClickOnly",
     940               0 :                              sLeftClickOnly);
     941               0 :     } else if (data.EqualsLiteral("ui.key.generalAccessKey")) {
     942                 :       sChromeAccessModifier =
     943               0 :         GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeChrome);
     944                 :       sContentAccessModifier =
     945               0 :         GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeContent);
     946               0 :     } else if (data.EqualsLiteral("ui.key.chromeAccess")) {
     947                 :       sChromeAccessModifier =
     948               0 :         GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeChrome);
     949               0 :     } else if (data.EqualsLiteral("ui.key.contentAccess")) {
     950                 :       sContentAccessModifier =
     951               0 :         GetAccessModifierMaskFromPref(nsIDocShellTreeItem::typeContent);
     952               0 :     } else if (data.EqualsLiteral("ui.click_hold_context_menus")) {
     953                 :       mClickHoldContextMenu =
     954               0 :         Preferences::GetBool("ui.click_hold_context_menus", false);
     955                 : #if 0
     956                 :     } else if (data.EqualsLiteral("mousewheel.withaltkey.action")) {
     957                 :     } else if (data.EqualsLiteral("mousewheel.withaltkey.numlines")) {
     958                 :     } else if (data.EqualsLiteral("mousewheel.withaltkey.sysnumlines")) {
     959                 :     } else if (data.EqualsLiteral("mousewheel.withcontrolkey.action")) {
     960                 :     } else if (data.EqualsLiteral("mousewheel.withcontrolkey.numlines")) {
     961                 :     } else if (data.EqualsLiteral("mousewheel.withcontrolkey.sysnumlines")) {
     962                 :     } else if (data.EqualsLiteral("mousewheel.withshiftkey.action")) {
     963                 :     } else if (data.EqualsLiteral("mousewheel.withshiftkey.numlines")) {
     964                 :     } else if (data.EqualsLiteral("mousewheel.withshiftkey.sysnumlines")) {
     965                 :     } else if (data.EqualsLiteral("mousewheel.withnokey.action")) {
     966                 :     } else if (data.EqualsLiteral("mousewheel.withnokey.numlines")) {
     967                 :     } else if (data.EqualsLiteral("mousewheel.withnokey.sysnumlines")) {
     968                 : #endif
     969               0 :     } else if (data.EqualsLiteral("dom.popup_allowed_events")) {
     970               0 :       nsDOMEvent::PopupAllowedEventsChanged();
     971                 :     }
     972                 :   }
     973                 : 
     974               0 :   return NS_OK;
     975                 : }
     976                 : 
     977            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsEventStateManager)
     978                 : 
     979               0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsEventStateManager)
     980               0 :    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
     981               0 :    NS_INTERFACE_MAP_ENTRY(nsIObserver)
     982               0 :    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     983               0 : NS_INTERFACE_MAP_END
     984                 : 
     985               0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsEventStateManager)
     986               0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsEventStateManager)
     987                 : 
     988               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsEventStateManager)
     989               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCurrentTargetContent);
     990               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastMouseOverElement);
     991               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGestureDownContent);
     992               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mGestureDownFrameOwner);
     993               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastLeftMouseDownContent);
     994               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastLeftMouseDownContentParent);
     995               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastMiddleMouseDownContent);
     996               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastMiddleMouseDownContentParent);
     997               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastRightMouseDownContent);
     998               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLastRightMouseDownContentParent);
     999               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mActiveContent);
    1000               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHoverContent);
    1001               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mURLTargetContent);
    1002               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstMouseOverEventElement);
    1003               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstMouseOutEventElement);
    1004               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument);
    1005               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mAccessKeys);
    1006               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1007                 : 
    1008               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsEventStateManager)
    1009               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCurrentTargetContent);
    1010               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastMouseOverElement);
    1011               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGestureDownContent);
    1012               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mGestureDownFrameOwner);
    1013               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastLeftMouseDownContent);
    1014               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastLeftMouseDownContentParent);
    1015               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastMiddleMouseDownContent);
    1016               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastMiddleMouseDownContentParent);
    1017               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastRightMouseDownContent);
    1018               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mLastRightMouseDownContentParent);
    1019               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mActiveContent);
    1020               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHoverContent);
    1021               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mURLTargetContent);
    1022               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstMouseOverEventElement);
    1023               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstMouseOutEventElement);
    1024               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument);
    1025               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mAccessKeys);
    1026               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1027                 : 
    1028                 : nsresult
    1029               0 : nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
    1030                 :                                     nsEvent *aEvent,
    1031                 :                                     nsIFrame* aTargetFrame,
    1032                 :                                     nsEventStatus* aStatus)
    1033                 : {
    1034               0 :   NS_ENSURE_ARG_POINTER(aStatus);
    1035               0 :   NS_ENSURE_ARG(aPresContext);
    1036               0 :   if (!aEvent) {
    1037               0 :     NS_ERROR("aEvent is null.  This should never happen.");
    1038               0 :     return NS_ERROR_NULL_POINTER;
    1039                 :   }
    1040                 : 
    1041               0 :   mCurrentTarget = aTargetFrame;
    1042               0 :   mCurrentTargetContent = nsnull;
    1043                 : 
    1044                 :   // Focus events don't necessarily need a frame.
    1045               0 :   if (NS_EVENT_NEEDS_FRAME(aEvent)) {
    1046               0 :     NS_ASSERTION(mCurrentTarget, "mCurrentTarget is null.  this should not happen.  see bug #13007");
    1047               0 :     if (!mCurrentTarget) return NS_ERROR_NULL_POINTER;
    1048                 :   }
    1049                 : 
    1050                 :   // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
    1051                 :   // when user is not active doesn't change the state to active.
    1052               0 :   if (NS_IS_TRUSTED_EVENT(aEvent) &&
    1053                 :       ((aEvent->eventStructType == NS_MOUSE_EVENT  &&
    1054               0 :         IsMouseEventReal(aEvent) &&
    1055                 :         aEvent->message != NS_MOUSE_ENTER &&
    1056                 :         aEvent->message != NS_MOUSE_EXIT) ||
    1057                 :        aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT ||
    1058                 :        aEvent->eventStructType == NS_KEY_EVENT)) {
    1059               0 :     if (gMouseOrKeyboardEventCounter == 0) {
    1060                 :       nsCOMPtr<nsIObserverService> obs =
    1061               0 :         mozilla::services::GetObserverService();
    1062               0 :       if (obs) {
    1063               0 :         obs->NotifyObservers(nsnull, "user-interaction-active", nsnull);
    1064               0 :         UpdateUserActivityTimer();
    1065                 :       }
    1066                 :     }
    1067               0 :     ++gMouseOrKeyboardEventCounter;
    1068                 :   }
    1069                 : 
    1070               0 :   *aStatus = nsEventStatus_eIgnore;
    1071                 : 
    1072               0 :   nsMouseWheelTransaction::OnEvent(aEvent);
    1073                 : 
    1074               0 :   switch (aEvent->message) {
    1075                 :   case NS_MOUSE_BUTTON_DOWN:
    1076               0 :     switch (static_cast<nsMouseEvent*>(aEvent)->button) {
    1077                 :     case nsMouseEvent::eLeftButton:
    1078                 : #ifndef XP_OS2
    1079               0 :       BeginTrackingDragGesture(aPresContext, (nsMouseEvent*)aEvent, aTargetFrame);
    1080                 : #endif
    1081               0 :       mLClickCount = ((nsMouseEvent*)aEvent)->clickCount;
    1082               0 :       SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
    1083               0 :       sNormalLMouseEventInProcess = true;
    1084               0 :       break;
    1085                 :     case nsMouseEvent::eMiddleButton:
    1086               0 :       mMClickCount = ((nsMouseEvent*)aEvent)->clickCount;
    1087               0 :       SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
    1088               0 :       break;
    1089                 :     case nsMouseEvent::eRightButton:
    1090                 : #ifdef XP_OS2
    1091                 :       BeginTrackingDragGesture(aPresContext, (nsMouseEvent*)aEvent, aTargetFrame);
    1092                 : #endif
    1093               0 :       mRClickCount = ((nsMouseEvent*)aEvent)->clickCount;
    1094               0 :       SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
    1095               0 :       break;
    1096                 :     }
    1097               0 :     break;
    1098                 :   case NS_MOUSE_BUTTON_UP:
    1099               0 :     switch (static_cast<nsMouseEvent*>(aEvent)->button) {
    1100                 :       case nsMouseEvent::eLeftButton:
    1101               0 :         if (mClickHoldContextMenu) {
    1102               0 :           KillClickHoldTimer();
    1103                 :         }
    1104                 : #ifndef XP_OS2
    1105               0 :         StopTrackingDragGesture();
    1106                 : #endif
    1107               0 :         sNormalLMouseEventInProcess = false;
    1108                 :         // then fall through...
    1109                 :       case nsMouseEvent::eRightButton:
    1110                 : #ifdef XP_OS2
    1111                 :         StopTrackingDragGesture();
    1112                 : #endif
    1113                 :         // then fall through...
    1114                 :       case nsMouseEvent::eMiddleButton:
    1115               0 :         SetClickCount(aPresContext, (nsMouseEvent*)aEvent, aStatus);
    1116               0 :         break;
    1117                 :     }
    1118               0 :     break;
    1119                 :   case NS_MOUSE_EXIT:
    1120                 :     // If the event is not a top-level window exit, then it's not
    1121                 :     // really an exit --- we may have traversed widget boundaries but
    1122                 :     // we're still in our toplevel window.
    1123                 :     {
    1124               0 :       nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
    1125               0 :       if (mouseEvent->exit != nsMouseEvent::eTopLevel) {
    1126                 :         // Treat it as a synthetic move so we don't generate spurious
    1127                 :         // "exit" or "move" events.  Any necessary "out" or "over" events
    1128                 :         // will be generated by GenerateMouseEnterExit
    1129               0 :         mouseEvent->message = NS_MOUSE_MOVE;
    1130               0 :         mouseEvent->reason = nsMouseEvent::eSynthesized;
    1131                 :         // then fall through...
    1132                 :       } else {
    1133               0 :         GenerateMouseEnterExit((nsGUIEvent*)aEvent);
    1134                 :         //This is a window level mouse exit event and should stop here
    1135               0 :         aEvent->message = 0;
    1136               0 :         break;
    1137                 :       }
    1138                 :     }
    1139                 :   case NS_MOUSE_MOVE:
    1140                 :     // on the Mac, GenerateDragGesture() may not return until the drag
    1141                 :     // has completed and so |aTargetFrame| may have been deleted (moving
    1142                 :     // a bookmark, for example).  If this is the case, however, we know
    1143                 :     // that ClearFrameRefs() has been called and it cleared out
    1144                 :     // |mCurrentTarget|. As a result, we should pass |mCurrentTarget|
    1145                 :     // into UpdateCursor().
    1146               0 :     GenerateDragGesture(aPresContext, (nsMouseEvent*)aEvent);
    1147               0 :     UpdateCursor(aPresContext, aEvent, mCurrentTarget, aStatus);
    1148               0 :     GenerateMouseEnterExit((nsGUIEvent*)aEvent);
    1149                 :     // Flush pending layout changes, so that later mouse move events
    1150                 :     // will go to the right nodes.
    1151               0 :     FlushPendingEvents(aPresContext);
    1152               0 :     break;
    1153                 :   case NS_DRAGDROP_GESTURE:
    1154               0 :     if (mClickHoldContextMenu) {
    1155                 :       // an external drag gesture event came in, not generated internally
    1156                 :       // by Gecko. Make sure we get rid of the click-hold timer.
    1157               0 :       KillClickHoldTimer();
    1158                 :     }
    1159               0 :     break;
    1160                 :   case NS_DRAGDROP_OVER:
    1161                 :     // NS_DRAGDROP_DROP is fired before NS_DRAGDROP_DRAGDROP so send
    1162                 :     // the enter/exit events before NS_DRAGDROP_DROP.
    1163               0 :     GenerateDragDropEnterExit(aPresContext, (nsGUIEvent*)aEvent);
    1164               0 :     break;
    1165                 : 
    1166                 :   case NS_KEY_PRESS:
    1167                 :     {
    1168                 : 
    1169               0 :       nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
    1170                 : 
    1171               0 :       PRInt32 modifierMask = 0;
    1172               0 :       if (keyEvent->isShift)
    1173               0 :         modifierMask |= NS_MODIFIER_SHIFT;
    1174               0 :       if (keyEvent->isControl)
    1175               0 :         modifierMask |= NS_MODIFIER_CONTROL;
    1176               0 :       if (keyEvent->isAlt)
    1177               0 :         modifierMask |= NS_MODIFIER_ALT;
    1178               0 :       if (keyEvent->isMeta)
    1179               0 :         modifierMask |= NS_MODIFIER_META;
    1180                 : 
    1181                 :       // Prevent keyboard scrolling while an accesskey modifier is in use.
    1182               0 :       if (modifierMask && (modifierMask == sChromeAccessModifier ||
    1183                 :                            modifierMask == sContentAccessModifier))
    1184                 :         HandleAccessKey(aPresContext, keyEvent, aStatus, nsnull,
    1185               0 :                         eAccessKeyProcessingNormal, modifierMask);
    1186                 :     }
    1187                 :     // then fall through...
    1188                 :   case NS_KEY_DOWN:
    1189                 :   case NS_KEY_UP:
    1190                 :     {
    1191               0 :       nsIContent* content = GetFocusedContent();
    1192               0 :       if (content)
    1193               0 :         mCurrentTargetContent = content;
    1194                 :     }
    1195               0 :     break;
    1196                 :   case NS_MOUSE_SCROLL:
    1197                 :     {
    1198               0 :       nsIContent* content = GetFocusedContent();
    1199               0 :       if (content)
    1200               0 :         mCurrentTargetContent = content;
    1201                 : 
    1202               0 :       nsMouseScrollEvent* msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
    1203                 : 
    1204               0 :       msEvent->delta = ComputeWheelDeltaFor(msEvent);
    1205                 :     }
    1206               0 :     break;
    1207                 :   case NS_MOUSE_PIXEL_SCROLL:
    1208                 :     {
    1209               0 :       nsIContent* content = GetFocusedContent();
    1210               0 :       if (content)
    1211               0 :         mCurrentTargetContent = content;
    1212                 : 
    1213               0 :       nsMouseScrollEvent *msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
    1214                 : 
    1215                 :       // Clear old deltas after a period of non action
    1216               0 :       if (OutOfTime(gPixelScrollDeltaTimeout, nsMouseWheelTransaction::GetTimeoutTime())) {
    1217               0 :         gPixelScrollDeltaX = gPixelScrollDeltaY = 0;
    1218                 :       }
    1219               0 :       gPixelScrollDeltaTimeout = PR_IntervalToMilliseconds(PR_IntervalNow());
    1220                 : 
    1221                 :       // If needed send a line scroll event for pixel scrolls with kNoLines
    1222               0 :       if (msEvent->scrollFlags & nsMouseScrollEvent::kNoLines) {
    1223                 :         nscoord pixelHeight = aPresContext->AppUnitsToIntCSSPixels(
    1224               0 :           GetScrollableLineHeight(aTargetFrame));
    1225                 : 
    1226               0 :         if (msEvent->scrollFlags & nsMouseScrollEvent::kIsVertical) {
    1227               0 :           gPixelScrollDeltaX += msEvent->delta;
    1228               0 :           if (!gPixelScrollDeltaX || !pixelHeight)
    1229               0 :             break;
    1230                 : 
    1231               0 :           if (NS_ABS(gPixelScrollDeltaX) >= pixelHeight) {
    1232               0 :             PRInt32 numLines = (PRInt32)ceil((float)gPixelScrollDeltaX/(float)pixelHeight);
    1233                 : 
    1234               0 :             gPixelScrollDeltaX -= numLines*pixelHeight;
    1235                 : 
    1236               0 :             nsWeakFrame weakFrame(aTargetFrame);
    1237                 :             SendLineScrollEvent(aTargetFrame, msEvent, aPresContext,
    1238               0 :               aStatus, numLines);
    1239               0 :             NS_ENSURE_STATE(weakFrame.IsAlive());
    1240                 :           }
    1241               0 :         } else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
    1242               0 :           gPixelScrollDeltaY += msEvent->delta;
    1243               0 :           if (!gPixelScrollDeltaY || !pixelHeight)
    1244               0 :             break;
    1245                 : 
    1246               0 :           if (NS_ABS(gPixelScrollDeltaY) >= pixelHeight) {
    1247               0 :             PRInt32 numLines = (PRInt32)ceil((float)gPixelScrollDeltaY/(float)pixelHeight);
    1248                 : 
    1249               0 :             gPixelScrollDeltaY -= numLines*pixelHeight;
    1250                 : 
    1251               0 :             nsWeakFrame weakFrame(aTargetFrame);
    1252                 :             SendLineScrollEvent(aTargetFrame, msEvent, aPresContext,
    1253               0 :               aStatus, numLines);
    1254               0 :             NS_ENSURE_STATE(weakFrame.IsAlive());
    1255                 :           }
    1256                 :         }
    1257                 :       }
    1258                 : 
    1259                 :       // When the last line scroll has been canceled, eat the pixel scroll event
    1260               0 :       if ((msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) ?
    1261                 :            mLastLineScrollConsumedX : mLastLineScrollConsumedY) {
    1262               0 :         *aStatus = nsEventStatus_eConsumeNoDefault;
    1263                 :       }
    1264                 :     }
    1265               0 :     break;
    1266                 :   case NS_QUERY_SELECTED_TEXT:
    1267               0 :     DoQuerySelectedText(static_cast<nsQueryContentEvent*>(aEvent));
    1268               0 :     break;
    1269                 :   case NS_QUERY_TEXT_CONTENT:
    1270                 :     {
    1271               0 :       if (RemoteQueryContentEvent(aEvent))
    1272               0 :         break;
    1273               0 :       nsContentEventHandler handler(mPresContext);
    1274               0 :       handler.OnQueryTextContent((nsQueryContentEvent*)aEvent);
    1275                 :     }
    1276               0 :     break;
    1277                 :   case NS_QUERY_CARET_RECT:
    1278                 :     {
    1279                 :       // XXX remote event
    1280               0 :       nsContentEventHandler handler(mPresContext);
    1281               0 :       handler.OnQueryCaretRect((nsQueryContentEvent*)aEvent);
    1282                 :     }
    1283               0 :     break;
    1284                 :   case NS_QUERY_TEXT_RECT:
    1285                 :     {
    1286                 :       // XXX remote event
    1287               0 :       nsContentEventHandler handler(mPresContext);
    1288               0 :       handler.OnQueryTextRect((nsQueryContentEvent*)aEvent);
    1289                 :     }
    1290               0 :     break;
    1291                 :   case NS_QUERY_EDITOR_RECT:
    1292                 :     {
    1293                 :       // XXX remote event
    1294               0 :       nsContentEventHandler handler(mPresContext);
    1295               0 :       handler.OnQueryEditorRect((nsQueryContentEvent*)aEvent);
    1296                 :     }
    1297               0 :     break;
    1298                 :   case NS_QUERY_CONTENT_STATE:
    1299                 :     {
    1300                 :       // XXX remote event
    1301               0 :       nsContentEventHandler handler(mPresContext);
    1302               0 :       handler.OnQueryContentState(static_cast<nsQueryContentEvent*>(aEvent));
    1303                 :     }
    1304               0 :     break;
    1305                 :   case NS_QUERY_SELECTION_AS_TRANSFERABLE:
    1306                 :     {
    1307                 :       // XXX remote event
    1308               0 :       nsContentEventHandler handler(mPresContext);
    1309               0 :       handler.OnQuerySelectionAsTransferable(static_cast<nsQueryContentEvent*>(aEvent));
    1310                 :     }
    1311               0 :     break;
    1312                 :   case NS_QUERY_CHARACTER_AT_POINT:
    1313                 :     {
    1314                 :       // XXX remote event
    1315               0 :       nsContentEventHandler handler(mPresContext);
    1316               0 :       handler.OnQueryCharacterAtPoint(static_cast<nsQueryContentEvent*>(aEvent));
    1317                 :     }
    1318               0 :     break;
    1319                 :   case NS_QUERY_DOM_WIDGET_HITTEST:
    1320                 :     {
    1321                 :       // XXX remote event
    1322               0 :       nsContentEventHandler handler(mPresContext);
    1323               0 :       handler.OnQueryDOMWidgetHittest(static_cast<nsQueryContentEvent*>(aEvent));
    1324                 :     }
    1325               0 :     break;
    1326                 :   case NS_QUERY_SCROLL_TARGET_INFO:
    1327                 :     {
    1328                 :       DoQueryScrollTargetInfo(static_cast<nsQueryContentEvent*>(aEvent),
    1329               0 :                               aTargetFrame);
    1330               0 :       break;
    1331                 :     }
    1332                 :   case NS_SELECTION_SET:
    1333                 :     {
    1334                 :       nsSelectionEvent *selectionEvent =
    1335               0 :           static_cast<nsSelectionEvent*>(aEvent);
    1336               0 :       if (IsTargetCrossProcess(selectionEvent)) {
    1337                 :         // Will not be handled locally, remote the event
    1338               0 :         if (GetCrossProcessTarget()->SendSelectionEvent(*selectionEvent))
    1339               0 :           selectionEvent->mSucceeded = true;
    1340               0 :         break;
    1341                 :       }
    1342               0 :       nsContentEventHandler handler(mPresContext);
    1343               0 :       handler.OnSelectionEvent((nsSelectionEvent*)aEvent);
    1344                 :     }
    1345               0 :     break;
    1346                 :   case NS_CONTENT_COMMAND_CUT:
    1347                 :   case NS_CONTENT_COMMAND_COPY:
    1348                 :   case NS_CONTENT_COMMAND_PASTE:
    1349                 :   case NS_CONTENT_COMMAND_DELETE:
    1350                 :   case NS_CONTENT_COMMAND_UNDO:
    1351                 :   case NS_CONTENT_COMMAND_REDO:
    1352                 :   case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE:
    1353                 :     {
    1354               0 :       DoContentCommandEvent(static_cast<nsContentCommandEvent*>(aEvent));
    1355                 :     }
    1356               0 :     break;
    1357                 :   case NS_CONTENT_COMMAND_SCROLL:
    1358                 :     {
    1359               0 :       DoContentCommandScrollEvent(static_cast<nsContentCommandEvent*>(aEvent));
    1360                 :     }
    1361               0 :     break;
    1362                 :   case NS_TEXT_TEXT:
    1363                 :     {
    1364               0 :       nsTextEvent *textEvent = static_cast<nsTextEvent*>(aEvent);
    1365               0 :       if (IsTargetCrossProcess(textEvent)) {
    1366                 :         // Will not be handled locally, remote the event
    1367               0 :         if (GetCrossProcessTarget()->SendTextEvent(*textEvent)) {
    1368                 :           // Cancel local dispatching
    1369               0 :           aEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
    1370                 :         }
    1371                 :       }
    1372                 :     }
    1373               0 :     break;
    1374                 :   case NS_COMPOSITION_START:
    1375               0 :     if (NS_IS_TRUSTED_EVENT(aEvent)) {
    1376                 :       // If the event is trusted event, set the selected text to data of
    1377                 :       // composition event.
    1378                 :       nsCompositionEvent *compositionEvent =
    1379               0 :         static_cast<nsCompositionEvent*>(aEvent);
    1380                 :       nsQueryContentEvent selectedText(true, NS_QUERY_SELECTED_TEXT,
    1381               0 :                                        compositionEvent->widget);
    1382               0 :       DoQuerySelectedText(&selectedText);
    1383               0 :       NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
    1384               0 :       compositionEvent->data = selectedText.mReply.mString;
    1385                 :     }
    1386                 :     // through to compositionend handling
    1387                 :   case NS_COMPOSITION_UPDATE:
    1388                 :   case NS_COMPOSITION_END:
    1389                 :     {
    1390                 :       nsCompositionEvent *compositionEvent =
    1391               0 :           static_cast<nsCompositionEvent*>(aEvent);
    1392               0 :       if (IsTargetCrossProcess(compositionEvent)) {
    1393                 :         // Will not be handled locally, remote the event
    1394               0 :         if (GetCrossProcessTarget()->SendCompositionEvent(*compositionEvent)) {
    1395                 :           // Cancel local dispatching
    1396               0 :           aEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
    1397                 :         }
    1398                 :       }
    1399                 :     }
    1400               0 :     break;
    1401                 :   }
    1402               0 :   return NS_OK;
    1403                 : }
    1404                 : 
    1405                 : static PRInt32
    1406               0 : GetAccessModifierMask(nsISupports* aDocShell)
    1407                 : {
    1408               0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(aDocShell));
    1409               0 :   if (!treeItem)
    1410               0 :     return -1; // invalid modifier
    1411                 : 
    1412                 :   PRInt32 itemType;
    1413               0 :   treeItem->GetItemType(&itemType);
    1414               0 :   switch (itemType) {
    1415                 : 
    1416                 :   case nsIDocShellTreeItem::typeChrome:
    1417               0 :     return sChromeAccessModifier;
    1418                 : 
    1419                 :   case nsIDocShellTreeItem::typeContent:
    1420               0 :     return sContentAccessModifier;
    1421                 : 
    1422                 :   default:
    1423               0 :     return -1; // invalid modifier
    1424                 :   }
    1425                 : }
    1426                 : 
    1427                 : static bool
    1428               0 : IsAccessKeyTarget(nsIContent* aContent, nsIFrame* aFrame, nsAString& aKey)
    1429                 : {
    1430               0 :   if (!aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::accesskey, aKey,
    1431               0 :                              eIgnoreCase))
    1432               0 :     return false;
    1433                 : 
    1434                 :   nsCOMPtr<nsIDOMXULDocument> xulDoc =
    1435               0 :     do_QueryInterface(aContent->OwnerDoc());
    1436               0 :   if (!xulDoc && !aContent->IsXUL())
    1437               0 :     return true;
    1438                 : 
    1439                 :     // For XUL we do visibility checks.
    1440               0 :   if (!aFrame)
    1441               0 :     return false;
    1442                 : 
    1443               0 :   if (aFrame->IsFocusable())
    1444               0 :     return true;
    1445                 : 
    1446               0 :   if (!aFrame->IsVisibleConsideringAncestors())
    1447               0 :     return false;
    1448                 : 
    1449                 :   // XUL controls can be activated.
    1450               0 :   nsCOMPtr<nsIDOMXULControlElement> control(do_QueryInterface(aContent));
    1451               0 :   if (control)
    1452               0 :     return true;
    1453                 : 
    1454               0 :   if (aContent->IsHTML()) {
    1455               0 :     nsIAtom* tag = aContent->Tag();
    1456                 : 
    1457                 :     // HTML area, label and legend elements are never focusable, so
    1458                 :     // we need to check for them explicitly before giving up.
    1459               0 :     if (tag == nsGkAtoms::area ||
    1460                 :         tag == nsGkAtoms::label ||
    1461                 :         tag == nsGkAtoms::legend)
    1462               0 :       return true;
    1463                 : 
    1464               0 :   } else if (aContent->IsXUL()) {
    1465                 :     // XUL label elements are never focusable, so we need to check for them
    1466                 :     // explicitly before giving up.
    1467               0 :     if (aContent->Tag() == nsGkAtoms::label)
    1468               0 :       return true;
    1469                 :   }
    1470                 : 
    1471               0 :   return false;
    1472                 : }
    1473                 : 
    1474                 : bool
    1475               0 : nsEventStateManager::ExecuteAccessKey(nsTArray<PRUint32>& aAccessCharCodes,
    1476                 :                                       bool aIsTrustedEvent)
    1477                 : {
    1478               0 :   PRInt32 count, start = -1;
    1479               0 :   nsIContent* focusedContent = GetFocusedContent();
    1480               0 :   if (focusedContent) {
    1481               0 :     start = mAccessKeys.IndexOf(focusedContent);
    1482               0 :     if (start == -1 && focusedContent->GetBindingParent())
    1483               0 :       start = mAccessKeys.IndexOf(focusedContent->GetBindingParent());
    1484                 :   }
    1485                 :   nsIContent *content;
    1486                 :   nsIFrame *frame;
    1487               0 :   PRInt32 length = mAccessKeys.Count();
    1488               0 :   for (PRUint32 i = 0; i < aAccessCharCodes.Length(); ++i) {
    1489               0 :     PRUint32 ch = aAccessCharCodes[i];
    1490               0 :     nsAutoString accessKey;
    1491               0 :     AppendUCS4ToUTF16(ch, accessKey);
    1492               0 :     for (count = 1; count <= length; ++count) {
    1493               0 :       content = mAccessKeys[(start + count) % length];
    1494               0 :       frame = content->GetPrimaryFrame();
    1495               0 :       if (IsAccessKeyTarget(content, frame, accessKey)) {
    1496               0 :         bool shouldActivate = sKeyCausesActivation;
    1497               0 :         while (shouldActivate && ++count <= length) {
    1498               0 :           nsIContent *oc = mAccessKeys[(start + count) % length];
    1499               0 :           nsIFrame *of = oc->GetPrimaryFrame();
    1500               0 :           if (IsAccessKeyTarget(oc, of, accessKey))
    1501               0 :             shouldActivate = false;
    1502                 :         }
    1503               0 :         if (shouldActivate)
    1504               0 :           content->PerformAccesskey(shouldActivate, aIsTrustedEvent);
    1505                 :         else {
    1506               0 :           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    1507               0 :           if (fm) {
    1508               0 :             nsCOMPtr<nsIDOMElement> element = do_QueryInterface(content);
    1509               0 :             fm->SetFocus(element, nsIFocusManager::FLAG_BYKEY);
    1510                 :           }
    1511                 :         }
    1512               0 :         return true;
    1513                 :       }
    1514                 :     }
    1515                 :   }
    1516               0 :   return false;
    1517                 : }
    1518                 : 
    1519                 : bool
    1520               0 : nsEventStateManager::GetAccessKeyLabelPrefix(nsAString& aPrefix)
    1521                 : {
    1522               0 :   aPrefix.Truncate();
    1523               0 :   nsAutoString separator, modifierText;
    1524               0 :   nsContentUtils::GetModifierSeparatorText(separator);
    1525                 : 
    1526               0 :   nsCOMPtr<nsISupports> container = mPresContext->GetContainer();
    1527               0 :   PRInt32 modifier = GetAccessModifierMask(container);
    1528                 : 
    1529               0 :   if (modifier & NS_MODIFIER_CONTROL) {
    1530               0 :     nsContentUtils::GetControlText(modifierText);
    1531               0 :     aPrefix.Append(modifierText + separator);
    1532                 :   }
    1533               0 :   if (modifier & NS_MODIFIER_META) {
    1534               0 :     nsContentUtils::GetMetaText(modifierText);
    1535               0 :     aPrefix.Append(modifierText + separator);
    1536                 :   }
    1537               0 :   if (modifier & NS_MODIFIER_ALT) {
    1538               0 :     nsContentUtils::GetAltText(modifierText);
    1539               0 :     aPrefix.Append(modifierText + separator);
    1540                 :   }
    1541               0 :   if (modifier & NS_MODIFIER_SHIFT) {
    1542               0 :     nsContentUtils::GetShiftText(modifierText);
    1543               0 :     aPrefix.Append(modifierText + separator);
    1544                 :   }
    1545               0 :   return !aPrefix.IsEmpty();
    1546                 : }
    1547                 : 
    1548                 : void
    1549               0 : nsEventStateManager::HandleAccessKey(nsPresContext* aPresContext,
    1550                 :                                      nsKeyEvent *aEvent,
    1551                 :                                      nsEventStatus* aStatus,
    1552                 :                                      nsIDocShellTreeItem* aBubbledFrom,
    1553                 :                                      ProcessingAccessKeyState aAccessKeyState,
    1554                 :                                      PRInt32 aModifierMask)
    1555                 : {
    1556               0 :   nsCOMPtr<nsISupports> pcContainer = aPresContext->GetContainer();
    1557                 : 
    1558                 :   // Alt or other accesskey modifier is down, we may need to do an accesskey
    1559               0 :   if (mAccessKeys.Count() > 0 &&
    1560               0 :       aModifierMask == GetAccessModifierMask(pcContainer)) {
    1561                 :     // Someone registered an accesskey.  Find and activate it.
    1562               0 :     bool isTrusted = NS_IS_TRUSTED_EVENT(aEvent);
    1563               0 :     nsAutoTArray<PRUint32, 10> accessCharCodes;
    1564               0 :     nsContentUtils::GetAccessKeyCandidates(aEvent, accessCharCodes);
    1565               0 :     if (ExecuteAccessKey(accessCharCodes, isTrusted)) {
    1566               0 :       *aStatus = nsEventStatus_eConsumeNoDefault;
    1567                 :       return;
    1568                 :     }
    1569                 :   }
    1570                 : 
    1571                 :   // after the local accesskey handling
    1572               0 :   if (nsEventStatus_eConsumeNoDefault != *aStatus) {
    1573                 :     // checking all sub docshells
    1574                 : 
    1575               0 :     nsCOMPtr<nsIDocShellTreeNode> docShell(do_QueryInterface(pcContainer));
    1576               0 :     if (!docShell) {
    1577               0 :       NS_WARNING("no docShellTreeNode for presContext");
    1578                 :       return;
    1579                 :     }
    1580                 : 
    1581                 :     PRInt32 childCount;
    1582               0 :     docShell->GetChildCount(&childCount);
    1583               0 :     for (PRInt32 counter = 0; counter < childCount; counter++) {
    1584                 :       // Not processing the child which bubbles up the handling
    1585               0 :       nsCOMPtr<nsIDocShellTreeItem> subShellItem;
    1586               0 :       docShell->GetChildAt(counter, getter_AddRefs(subShellItem));
    1587               0 :       if (aAccessKeyState == eAccessKeyProcessingUp &&
    1588               0 :           subShellItem == aBubbledFrom)
    1589               0 :         continue;
    1590                 : 
    1591               0 :       nsCOMPtr<nsIDocShell> subDS = do_QueryInterface(subShellItem);
    1592               0 :       if (subDS && IsShellVisible(subDS)) {
    1593               0 :         nsCOMPtr<nsIPresShell> subPS;
    1594               0 :         subDS->GetPresShell(getter_AddRefs(subPS));
    1595                 : 
    1596                 :         // Docshells need not have a presshell (eg. display:none
    1597                 :         // iframes, docshells in transition between documents, etc).
    1598               0 :         if (!subPS) {
    1599                 :           // Oh, well.  Just move on to the next child
    1600               0 :           continue;
    1601                 :         }
    1602                 : 
    1603               0 :         nsPresContext *subPC = subPS->GetPresContext();
    1604                 : 
    1605                 :         nsEventStateManager* esm =
    1606               0 :           static_cast<nsEventStateManager *>(subPC->EventStateManager());
    1607                 : 
    1608               0 :         if (esm)
    1609                 :           esm->HandleAccessKey(subPC, aEvent, aStatus, nsnull,
    1610               0 :                                eAccessKeyProcessingDown, aModifierMask);
    1611                 : 
    1612               0 :         if (nsEventStatus_eConsumeNoDefault == *aStatus)
    1613                 :           break;
    1614                 :       }
    1615                 :     }
    1616                 :   }// if end . checking all sub docshell ends here.
    1617                 : 
    1618                 :   // bubble up the process to the parent docshell if necessary
    1619               0 :   if (eAccessKeyProcessingDown != aAccessKeyState && nsEventStatus_eConsumeNoDefault != *aStatus) {
    1620               0 :     nsCOMPtr<nsIDocShellTreeItem> docShell(do_QueryInterface(pcContainer));
    1621               0 :     if (!docShell) {
    1622               0 :       NS_WARNING("no docShellTreeItem for presContext");
    1623                 :       return;
    1624                 :     }
    1625                 : 
    1626               0 :     nsCOMPtr<nsIDocShellTreeItem> parentShellItem;
    1627               0 :     docShell->GetParent(getter_AddRefs(parentShellItem));
    1628               0 :     nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parentShellItem);
    1629               0 :     if (parentDS) {
    1630               0 :       nsCOMPtr<nsIPresShell> parentPS;
    1631                 : 
    1632               0 :       parentDS->GetPresShell(getter_AddRefs(parentPS));
    1633               0 :       NS_ASSERTION(parentPS, "Our PresShell exists but the parent's does not?");
    1634                 : 
    1635               0 :       nsPresContext *parentPC = parentPS->GetPresContext();
    1636               0 :       NS_ASSERTION(parentPC, "PresShell without PresContext");
    1637                 : 
    1638                 :       nsEventStateManager* esm =
    1639               0 :         static_cast<nsEventStateManager *>(parentPC->EventStateManager());
    1640                 : 
    1641               0 :       if (esm)
    1642                 :         esm->HandleAccessKey(parentPC, aEvent, aStatus, docShell,
    1643               0 :                              eAccessKeyProcessingUp, aModifierMask);
    1644                 :     }
    1645                 :   }// if end. bubble up process
    1646                 : }// end of HandleAccessKey
    1647                 : 
    1648                 : void
    1649               0 : nsEventStateManager::DispatchCrossProcessEvent(nsEvent* aEvent, nsIFrameLoader* frameLoader) {
    1650               0 :   nsFrameLoader* fml = static_cast<nsFrameLoader*>(frameLoader);
    1651               0 :   PBrowserParent* remoteBrowser = fml->GetRemoteBrowser();
    1652               0 :   TabParent* remote = static_cast<TabParent*>(remoteBrowser);
    1653               0 :   if (!remote) {
    1654               0 :     return;
    1655                 :   }
    1656                 : 
    1657               0 :   if (aEvent->eventStructType == NS_MOUSE_EVENT) {
    1658               0 :     nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
    1659               0 :     remote->SendRealMouseEvent(*mouseEvent);
    1660                 :   }
    1661                 : 
    1662               0 :   if (aEvent->eventStructType == NS_KEY_EVENT) {
    1663               0 :     nsKeyEvent* keyEvent = static_cast<nsKeyEvent*>(aEvent);
    1664               0 :     remote->SendRealKeyEvent(*keyEvent);
    1665                 :   }
    1666                 : 
    1667               0 :   if (aEvent->eventStructType == NS_MOUSE_SCROLL_EVENT) {
    1668               0 :     nsMouseScrollEvent* scrollEvent = static_cast<nsMouseScrollEvent*>(aEvent);
    1669               0 :     remote->SendMouseScrollEvent(*scrollEvent);
    1670                 :   }
    1671                 : }
    1672                 : 
    1673                 : bool
    1674               0 : nsEventStateManager::IsRemoteTarget(nsIContent* target) {
    1675                 :   return target &&
    1676               0 :          (target->Tag() == nsGkAtoms::browser ||
    1677               0 :           target->Tag() == nsGkAtoms::iframe) &&
    1678               0 :          target->IsXUL() &&
    1679                 :          target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
    1680               0 :                              nsGkAtoms::_true, eIgnoreCase);
    1681                 : }
    1682                 : 
    1683                 : 
    1684                 : bool
    1685               0 : nsEventStateManager::HandleCrossProcessEvent(nsEvent *aEvent,
    1686                 :                                              nsIFrame* aTargetFrame,
    1687                 :                                              nsEventStatus *aStatus) {
    1688                 : 
    1689               0 :   switch (aEvent->eventStructType) {
    1690                 :     case NS_KEY_EVENT:
    1691                 :     case NS_MOUSE_SCROLL_EVENT:
    1692               0 :       break;
    1693                 :     case NS_MOUSE_EVENT:
    1694               0 :       if (aEvent->message == NS_MOUSE_BUTTON_DOWN ||
    1695                 :           aEvent->message == NS_MOUSE_BUTTON_UP ||
    1696                 :           aEvent->message == NS_MOUSE_MOVE) {
    1697               0 :         break;
    1698                 :       }
    1699                 :     default:
    1700               0 :       return false;
    1701                 :   }
    1702                 : 
    1703               0 :   nsIContent* target = mCurrentTargetContent;
    1704               0 :   if (!target && aTargetFrame) {
    1705               0 :     target = aTargetFrame->GetContent();
    1706                 :   }
    1707                 : 
    1708               0 :   if (*aStatus == nsEventStatus_eConsumeNoDefault ||
    1709                 :       !target ||
    1710               0 :       !IsRemoteTarget(target)) {
    1711               0 :     return false;
    1712                 :   }
    1713                 : 
    1714               0 :   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(target);
    1715               0 :   if (!loaderOwner) {
    1716               0 :     return false;
    1717                 :   }
    1718                 : 
    1719               0 :   nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
    1720               0 :   if (!frameLoader) {
    1721               0 :     return false;
    1722                 :   }
    1723                 : 
    1724                 :   PRUint32 eventMode;
    1725               0 :   frameLoader->GetEventMode(&eventMode);
    1726               0 :   if (eventMode == nsIFrameLoader::EVENT_MODE_DONT_FORWARD_TO_CHILD) {
    1727               0 :     return false;
    1728                 :   }
    1729                 : 
    1730               0 :   nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, aTargetFrame);
    1731               0 :   aEvent->refPoint = pt.ToNearestPixels(mPresContext->AppUnitsPerDevPixel());
    1732                 : 
    1733               0 :   DispatchCrossProcessEvent(aEvent, frameLoader);
    1734               0 :   return true;
    1735                 : }
    1736                 : 
    1737                 : //
    1738                 : // CreateClickHoldTimer
    1739                 : //
    1740                 : // Fire off a timer for determining if the user wants click-hold. This timer
    1741                 : // is a one-shot that will be cancelled when the user moves enough to fire
    1742                 : // a drag.
    1743                 : //
    1744                 : void
    1745               0 : nsEventStateManager::CreateClickHoldTimer(nsPresContext* inPresContext,
    1746                 :                                           nsIFrame* inDownFrame,
    1747                 :                                           nsGUIEvent* inMouseDownEvent)
    1748                 : {
    1749               0 :   if (!NS_IS_TRUSTED_EVENT(inMouseDownEvent))
    1750               0 :     return;
    1751                 : 
    1752                 :   // just to be anal (er, safe)
    1753               0 :   if (mClickHoldTimer) {
    1754               0 :     mClickHoldTimer->Cancel();
    1755               0 :     mClickHoldTimer = nsnull;
    1756                 :   }
    1757                 : 
    1758                 :   // if content clicked on has a popup, don't even start the timer
    1759                 :   // since we'll end up conflicting and both will show.
    1760               0 :   if (mGestureDownContent) {
    1761                 :     // check for the |popup| attribute
    1762               0 :     if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent, kNameSpaceID_None,
    1763               0 :                                         nsGkAtoms::popup))
    1764               0 :       return;
    1765                 :     
    1766                 :     // check for a <menubutton> like bookmarks
    1767               0 :     if (mGestureDownContent->Tag() == nsGkAtoms::menubutton)
    1768               0 :       return;
    1769                 :   }
    1770                 : 
    1771               0 :   mClickHoldTimer = do_CreateInstance("@mozilla.org/timer;1");
    1772               0 :   if (mClickHoldTimer) {
    1773                 :     PRInt32 clickHoldDelay =
    1774               0 :       Preferences::GetInt("ui.click_hold_context_menus.delay", 500);
    1775               0 :     mClickHoldTimer->InitWithFuncCallback(sClickHoldCallback, this,
    1776                 :                                           clickHoldDelay,
    1777               0 :                                           nsITimer::TYPE_ONE_SHOT);
    1778                 :   }
    1779                 : } // CreateClickHoldTimer
    1780                 : 
    1781                 : 
    1782                 : //
    1783                 : // KillClickHoldTimer
    1784                 : //
    1785                 : // Stop the timer that would show the context menu dead in its tracks
    1786                 : //
    1787                 : void
    1788               0 : nsEventStateManager::KillClickHoldTimer()
    1789                 : {
    1790               0 :   if (mClickHoldTimer) {
    1791               0 :     mClickHoldTimer->Cancel();
    1792               0 :     mClickHoldTimer = nsnull;
    1793                 :   }
    1794               0 : }
    1795                 : 
    1796                 : 
    1797                 : //
    1798                 : // sClickHoldCallback
    1799                 : //
    1800                 : // This fires after the mouse has been down for a certain length of time.
    1801                 : //
    1802                 : void
    1803               0 : nsEventStateManager::sClickHoldCallback(nsITimer *aTimer, void* aESM)
    1804                 : {
    1805               0 :   nsEventStateManager* self = static_cast<nsEventStateManager*>(aESM);
    1806               0 :   if (self)
    1807               0 :     self->FireContextClick();
    1808                 : 
    1809                 :   // NOTE: |aTimer| and |self->mAutoHideTimer| are invalid after calling ClosePopup();
    1810                 : 
    1811               0 : } // sAutoHideCallback
    1812                 : 
    1813                 : 
    1814                 : //
    1815                 : // FireContextClick
    1816                 : //
    1817                 : // If we're this far, our timer has fired, which means the mouse has been down
    1818                 : // for a certain period of time and has not moved enough to generate a dragGesture.
    1819                 : // We can be certain the user wants a context-click at this stage, so generate
    1820                 : // a dom event and fire it in.
    1821                 : //
    1822                 : // After the event fires, check if PreventDefault() has been set on the event which
    1823                 : // means that someone either ate the event or put up a context menu. This is our cue
    1824                 : // to stop tracking the drag gesture. If we always did this, draggable items w/out
    1825                 : // a context menu wouldn't be draggable after a certain length of time, which is
    1826                 : // _not_ what we want.
    1827                 : //
    1828                 : void
    1829               0 : nsEventStateManager::FireContextClick()
    1830                 : {
    1831               0 :   if (!mGestureDownContent)
    1832               0 :     return;
    1833                 : 
    1834                 : #ifdef XP_MACOSX
    1835                 :   // Hack to ensure that we don't show a context menu when the user
    1836                 :   // let go of the mouse after a long cpu-hogging operation prevented
    1837                 :   // us from handling any OS events. See bug 117589.
    1838                 :   if (!CGEventSourceButtonState(kCGEventSourceStateCombinedSessionState, kCGMouseButtonLeft))
    1839                 :     return;
    1840                 : #endif
    1841                 : 
    1842               0 :   nsEventStatus status = nsEventStatus_eIgnore;
    1843                 : 
    1844                 :   // Dispatch to the DOM. We have to fake out the ESM and tell it that the
    1845                 :   // current target frame is actually where the mouseDown occurred, otherwise it
    1846                 :   // will use the frame the mouse is currently over which may or may not be
    1847                 :   // the same. (Note: saari and I have decided that we don't have to reset |mCurrentTarget|
    1848                 :   // when we're through because no one else is doing anything more with this
    1849                 :   // event and it will get reset on the very next event to the correct frame).
    1850               0 :   mCurrentTarget = mPresContext->GetPrimaryFrameFor(mGestureDownContent);
    1851               0 :   if (mCurrentTarget) {
    1852               0 :     NS_ASSERTION(mPresContext == mCurrentTarget->PresContext(),
    1853                 :                  "a prescontext returned a primary frame that didn't belong to it?");
    1854                 : 
    1855                 :     // before dispatching, check that we're not on something that
    1856                 :     // doesn't get a context menu
    1857               0 :     nsIAtom *tag = mGestureDownContent->Tag();
    1858               0 :     bool allowedToDispatch = true;
    1859                 : 
    1860               0 :     if (mGestureDownContent->IsXUL()) {
    1861               0 :       if (tag == nsGkAtoms::scrollbar ||
    1862                 :           tag == nsGkAtoms::scrollbarbutton ||
    1863                 :           tag == nsGkAtoms::button)
    1864               0 :         allowedToDispatch = false;
    1865               0 :       else if (tag == nsGkAtoms::toolbarbutton) {
    1866                 :         // a <toolbarbutton> that has the container attribute set
    1867                 :         // will already have its own dropdown.
    1868               0 :         if (nsContentUtils::HasNonEmptyAttr(mGestureDownContent,
    1869               0 :                 kNameSpaceID_None, nsGkAtoms::container)) {
    1870               0 :           allowedToDispatch = false;
    1871                 :         } else {
    1872                 :           // If the toolbar button has an open menu, don't attempt to open
    1873                 :             // a second menu
    1874               0 :           if (mGestureDownContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::open,
    1875               0 :                                                nsGkAtoms::_true, eCaseMatters)) {
    1876               0 :             allowedToDispatch = false;
    1877                 :           }
    1878                 :         }
    1879                 :       }
    1880                 :     }
    1881               0 :     else if (mGestureDownContent->IsHTML()) {
    1882               0 :       nsCOMPtr<nsIFormControl> formCtrl(do_QueryInterface(mGestureDownContent));
    1883                 : 
    1884               0 :       if (formCtrl) {
    1885                 :         // of all form controls, only ones dealing with text are
    1886                 :         // allowed to have context menus
    1887               0 :         PRInt32 type = formCtrl->GetType();
    1888                 : 
    1889                 :         allowedToDispatch = (type == NS_FORM_INPUT_TEXT ||
    1890                 :                              type == NS_FORM_INPUT_EMAIL ||
    1891                 :                              type == NS_FORM_INPUT_SEARCH ||
    1892                 :                              type == NS_FORM_INPUT_TEL ||
    1893                 :                              type == NS_FORM_INPUT_URL ||
    1894                 :                              type == NS_FORM_INPUT_PASSWORD ||
    1895                 :                              type == NS_FORM_INPUT_FILE ||
    1896               0 :                              type == NS_FORM_TEXTAREA);
    1897                 :       }
    1898               0 :       else if (tag == nsGkAtoms::applet ||
    1899                 :                tag == nsGkAtoms::embed  ||
    1900                 :                tag == nsGkAtoms::object) {
    1901               0 :         allowedToDispatch = false;
    1902                 :       }
    1903                 :     }
    1904                 : 
    1905               0 :     if (allowedToDispatch) {
    1906                 :       // make sure the widget sticks around
    1907               0 :       nsCOMPtr<nsIWidget> targetWidget(mCurrentTarget->GetNearestWidget());
    1908                 :       // init the event while mCurrentTarget is still good
    1909                 :       nsMouseEvent event(true, NS_CONTEXTMENU,
    1910                 :                          targetWidget,
    1911               0 :                          nsMouseEvent::eReal);
    1912               0 :       event.clickCount = 1;
    1913               0 :       FillInEventFromGestureDown(&event);
    1914                 :         
    1915                 :       // stop selection tracking, we're in control now
    1916               0 :       if (mCurrentTarget)
    1917                 :       {
    1918                 :         nsRefPtr<nsFrameSelection> frameSel =
    1919               0 :           mCurrentTarget->GetFrameSelection();
    1920                 :         
    1921               0 :         if (frameSel && frameSel->GetMouseDownState()) {
    1922                 :           // note that this can cause selection changed events to fire if we're in
    1923                 :           // a text field, which will null out mCurrentTarget
    1924               0 :           frameSel->SetMouseDownState(false);
    1925                 :         }
    1926                 :       }
    1927                 : 
    1928                 :       // dispatch to DOM
    1929                 :       nsEventDispatcher::Dispatch(mGestureDownContent, mPresContext, &event,
    1930               0 :                                   nsnull, &status);
    1931                 : 
    1932                 :       // We don't need to dispatch to frame handling because no frames
    1933                 :       // watch NS_CONTEXTMENU except for nsMenuFrame and that's only for
    1934                 :       // dismissal. That's just as well since we don't really know
    1935                 :       // which frame to send it to.
    1936                 :     }
    1937                 :   }
    1938                 : 
    1939                 :   // now check if the event has been handled. If so, stop tracking a drag
    1940               0 :   if (status == nsEventStatus_eConsumeNoDefault) {
    1941               0 :     StopTrackingDragGesture();
    1942                 :   }
    1943                 : 
    1944               0 :   KillClickHoldTimer();
    1945                 : 
    1946                 : } // FireContextClick
    1947                 : 
    1948                 : 
    1949                 : //
    1950                 : // BeginTrackingDragGesture
    1951                 : //
    1952                 : // Record that the mouse has gone down and that we should move to TRACKING state
    1953                 : // of d&d gesture tracker.
    1954                 : //
    1955                 : // We also use this to track click-hold context menus. When the mouse goes down,
    1956                 : // fire off a short timer. If the timer goes off and we have yet to fire the
    1957                 : // drag gesture (ie, the mouse hasn't moved a certain distance), then we can
    1958                 : // assume the user wants a click-hold, so fire a context-click event. We only
    1959                 : // want to cancel the drag gesture if the context-click event is handled.
    1960                 : //
    1961                 : void
    1962               0 : nsEventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
    1963                 :                                               nsMouseEvent* inDownEvent,
    1964                 :                                               nsIFrame* inDownFrame)
    1965                 : {
    1966               0 :   if (!inDownEvent->widget)
    1967               0 :     return;
    1968                 : 
    1969                 :   // Note that |inDownEvent| could be either a mouse down event or a
    1970                 :   // synthesized mouse move event.
    1971                 :   mGestureDownPoint = inDownEvent->refPoint +
    1972               0 :     inDownEvent->widget->WidgetToScreenOffset();
    1973                 : 
    1974                 :   inDownFrame->GetContentForEvent(inDownEvent,
    1975               0 :                                   getter_AddRefs(mGestureDownContent));
    1976                 : 
    1977               0 :   mGestureDownFrameOwner = inDownFrame->GetContent();
    1978               0 :   mGestureDownShift = inDownEvent->isShift;
    1979               0 :   mGestureDownControl = inDownEvent->isControl;
    1980               0 :   mGestureDownAlt = inDownEvent->isAlt;
    1981               0 :   mGestureDownMeta = inDownEvent->isMeta;
    1982                 : 
    1983               0 :   if (mClickHoldContextMenu) {
    1984                 :     // fire off a timer to track click-hold
    1985               0 :     CreateClickHoldTimer(aPresContext, inDownFrame, inDownEvent);
    1986                 :   }
    1987                 : }
    1988                 : 
    1989                 : 
    1990                 : //
    1991                 : // StopTrackingDragGesture
    1992                 : //
    1993                 : // Record that the mouse has gone back up so that we should leave the TRACKING
    1994                 : // state of d&d gesture tracker and return to the START state.
    1995                 : //
    1996                 : void
    1997               0 : nsEventStateManager::StopTrackingDragGesture()
    1998                 : {
    1999               0 :   mGestureDownContent = nsnull;
    2000               0 :   mGestureDownFrameOwner = nsnull;
    2001               0 : }
    2002                 : 
    2003                 : void
    2004               0 : nsEventStateManager::FillInEventFromGestureDown(nsMouseEvent* aEvent)
    2005                 : {
    2006               0 :   NS_ASSERTION(aEvent->widget == mCurrentTarget->GetNearestWidget(),
    2007                 :                "Incorrect widget in event");
    2008                 : 
    2009                 :   // Set the coordinates in the new event to the coordinates of
    2010                 :   // the old event, adjusted for the fact that the widget might be
    2011                 :   // different
    2012               0 :   nsIntPoint tmpPoint = aEvent->widget->WidgetToScreenOffset();
    2013               0 :   aEvent->refPoint = mGestureDownPoint - tmpPoint;
    2014               0 :   aEvent->isShift = mGestureDownShift;
    2015               0 :   aEvent->isControl = mGestureDownControl;
    2016               0 :   aEvent->isAlt = mGestureDownAlt;
    2017               0 :   aEvent->isMeta = mGestureDownMeta;
    2018               0 : }
    2019                 : 
    2020                 : //
    2021                 : // GenerateDragGesture
    2022                 : //
    2023                 : // If we're in the TRACKING state of the d&d gesture tracker, check the current position
    2024                 : // of the mouse in relation to the old one. If we've moved a sufficient amount from
    2025                 : // the mouse down, then fire off a drag gesture event.
    2026                 : void
    2027               0 : nsEventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
    2028                 :                                          nsMouseEvent *aEvent)
    2029                 : {
    2030               0 :   NS_ASSERTION(aPresContext, "This shouldn't happen.");
    2031               0 :   if (IsTrackingDragGesture()) {
    2032               0 :     mCurrentTarget = mGestureDownFrameOwner->GetPrimaryFrame();
    2033                 : 
    2034               0 :     if (!mCurrentTarget) {
    2035               0 :       StopTrackingDragGesture();
    2036               0 :       return;
    2037                 :     }
    2038                 : 
    2039                 :     // Check if selection is tracking drag gestures, if so
    2040                 :     // don't interfere!
    2041               0 :     if (mCurrentTarget)
    2042                 :     {
    2043               0 :       nsRefPtr<nsFrameSelection> frameSel = mCurrentTarget->GetFrameSelection();
    2044               0 :       if (frameSel && frameSel->GetMouseDownState()) {
    2045               0 :         StopTrackingDragGesture();
    2046                 :         return;
    2047                 :       }
    2048                 :     }
    2049                 : 
    2050                 :     // If non-native code is capturing the mouse don't start a drag.
    2051               0 :     if (nsIPresShell::IsMouseCapturePreventingDrag()) {
    2052               0 :       StopTrackingDragGesture();
    2053               0 :       return;
    2054                 :     }
    2055                 : 
    2056                 :     static PRInt32 pixelThresholdX = 0;
    2057                 :     static PRInt32 pixelThresholdY = 0;
    2058                 : 
    2059               0 :     if (!pixelThresholdX) {
    2060                 :       pixelThresholdX =
    2061               0 :         LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdX, 0);
    2062                 :       pixelThresholdY =
    2063               0 :         LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0);
    2064               0 :       if (!pixelThresholdX)
    2065               0 :         pixelThresholdX = 5;
    2066               0 :       if (!pixelThresholdY)
    2067               0 :         pixelThresholdY = 5;
    2068                 :     }
    2069                 : 
    2070                 :     // fire drag gesture if mouse has moved enough
    2071               0 :     nsIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
    2072               0 :     if (NS_ABS(pt.x - mGestureDownPoint.x) > pixelThresholdX ||
    2073               0 :         NS_ABS(pt.y - mGestureDownPoint.y) > pixelThresholdY) {
    2074               0 :       if (mClickHoldContextMenu) {
    2075                 :         // stop the click-hold before we fire off the drag gesture, in case
    2076                 :         // it takes a long time
    2077               0 :         KillClickHoldTimer();
    2078                 :       }
    2079                 : 
    2080               0 :       nsRefPtr<nsDOMDataTransfer> dataTransfer = new nsDOMDataTransfer();
    2081               0 :       if (!dataTransfer)
    2082                 :         return;
    2083                 : 
    2084               0 :       nsCOMPtr<nsISelection> selection;
    2085               0 :       nsCOMPtr<nsIContent> eventContent, targetContent;
    2086               0 :       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(eventContent));
    2087               0 :       if (eventContent)
    2088                 :         DetermineDragTarget(aPresContext, eventContent, dataTransfer,
    2089               0 :                             getter_AddRefs(selection), getter_AddRefs(targetContent));
    2090                 : 
    2091                 :       // Stop tracking the drag gesture now. This should stop us from
    2092                 :       // reentering GenerateDragGesture inside DOM event processing.
    2093               0 :       StopTrackingDragGesture();
    2094                 : 
    2095               0 :       if (!targetContent)
    2096                 :         return;
    2097                 : 
    2098               0 :       sLastDragOverFrame = nsnull;
    2099               0 :       nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
    2100                 : 
    2101                 :       // get the widget from the target frame
    2102               0 :       nsDragEvent startEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_START, widget);
    2103               0 :       FillInEventFromGestureDown(&startEvent);
    2104                 : 
    2105               0 :       nsDragEvent gestureEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_GESTURE, widget);
    2106               0 :       FillInEventFromGestureDown(&gestureEvent);
    2107                 : 
    2108               0 :       startEvent.dataTransfer = gestureEvent.dataTransfer = dataTransfer;
    2109               0 :       startEvent.inputSource = gestureEvent.inputSource = aEvent->inputSource;
    2110                 : 
    2111                 :       // Dispatch to the DOM. By setting mCurrentTarget we are faking
    2112                 :       // out the ESM and telling it that the current target frame is
    2113                 :       // actually where the mouseDown occurred, otherwise it will use
    2114                 :       // the frame the mouse is currently over which may or may not be
    2115                 :       // the same. (Note: saari and I have decided that we don't have
    2116                 :       // to reset |mCurrentTarget| when we're through because no one
    2117                 :       // else is doing anything more with this event and it will get
    2118                 :       // reset on the very next event to the correct frame).
    2119                 : 
    2120                 :       // Hold onto old target content through the event and reset after.
    2121               0 :       nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
    2122                 : 
    2123                 :       // Set the current target to the content for the mouse down
    2124               0 :       mCurrentTargetContent = targetContent;
    2125                 : 
    2126                 :       // Dispatch both the dragstart and draggesture events to the DOM. For
    2127                 :       // elements in an editor, only fire the draggesture event so that the
    2128                 :       // editor code can handle it but content doesn't see a dragstart.
    2129               0 :       nsEventStatus status = nsEventStatus_eIgnore;
    2130                 :       nsEventDispatcher::Dispatch(targetContent, aPresContext, &startEvent, nsnull,
    2131               0 :                                   &status);
    2132                 : 
    2133               0 :       nsDragEvent* event = &startEvent;
    2134               0 :       if (status != nsEventStatus_eConsumeNoDefault) {
    2135               0 :         status = nsEventStatus_eIgnore;
    2136                 :         nsEventDispatcher::Dispatch(targetContent, aPresContext, &gestureEvent, nsnull,
    2137               0 :                                     &status);
    2138               0 :         event = &gestureEvent;
    2139                 :       }
    2140                 : 
    2141                 :       // now that the dataTransfer has been updated in the dragstart and
    2142                 :       // draggesture events, make it read only so that the data doesn't
    2143                 :       // change during the drag.
    2144               0 :       dataTransfer->SetReadOnly();
    2145                 : 
    2146               0 :       if (status != nsEventStatus_eConsumeNoDefault) {
    2147                 :         bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
    2148               0 :                                               targetContent, selection);
    2149               0 :         if (dragStarted) {
    2150               0 :           sActiveESM = nsnull;
    2151               0 :           aEvent->flags |= NS_EVENT_FLAG_STOP_DISPATCH;
    2152                 :         }
    2153                 :       }
    2154                 : 
    2155                 :       // Note that frame event handling doesn't care about NS_DRAGDROP_GESTURE,
    2156                 :       // which is just as well since we don't really know which frame to
    2157                 :       // send it to
    2158                 : 
    2159                 :       // Reset mCurretTargetContent to what it was
    2160               0 :       mCurrentTargetContent = targetBeforeEvent;
    2161                 :     }
    2162                 : 
    2163                 :     // Now flush all pending notifications, for better responsiveness
    2164                 :     // while dragging.
    2165               0 :     FlushPendingEvents(aPresContext);
    2166                 :   }
    2167                 : } // GenerateDragGesture
    2168                 : 
    2169                 : void
    2170               0 : nsEventStateManager::DetermineDragTarget(nsPresContext* aPresContext,
    2171                 :                                          nsIContent* aSelectionTarget,
    2172                 :                                          nsDOMDataTransfer* aDataTransfer,
    2173                 :                                          nsISelection** aSelection,
    2174                 :                                          nsIContent** aTargetNode)
    2175                 : {
    2176               0 :   *aTargetNode = nsnull;
    2177                 : 
    2178               0 :   nsCOMPtr<nsISupports> container = aPresContext->GetContainer();
    2179               0 :   nsCOMPtr<nsIDOMWindow> window = do_GetInterface(container);
    2180               0 :   if (!window)
    2181                 :     return;
    2182                 : 
    2183                 :   // GetDragData determines if a selection, link or image in the content
    2184                 :   // should be dragged, and places the data associated with the drag in the
    2185                 :   // data transfer.
    2186                 :   // mGestureDownContent is the node where the mousedown event for the drag
    2187                 :   // occurred, and aSelectionTarget is the node to use when a selection is used
    2188                 :   bool canDrag;
    2189               0 :   nsCOMPtr<nsIContent> dragDataNode;
    2190                 :   nsresult rv = nsContentAreaDragDrop::GetDragData(window, mGestureDownContent,
    2191                 :                                                    aSelectionTarget, mGestureDownAlt,
    2192                 :                                                    aDataTransfer, &canDrag, aSelection,
    2193               0 :                                                    getter_AddRefs(dragDataNode));
    2194               0 :   if (NS_FAILED(rv) || !canDrag)
    2195                 :     return;
    2196                 : 
    2197                 :   // if GetDragData returned a node, use that as the node being dragged.
    2198                 :   // Otherwise, if a selection is being dragged, use the node within the
    2199                 :   // selection that was dragged. Otherwise, just use the mousedown target.
    2200               0 :   nsIContent* dragContent = mGestureDownContent;
    2201               0 :   if (dragDataNode)
    2202               0 :     dragContent = dragDataNode;
    2203               0 :   else if (*aSelection)
    2204               0 :     dragContent = aSelectionTarget;
    2205                 : 
    2206               0 :   nsIContent* originalDragContent = dragContent;
    2207                 : 
    2208                 :   // If a selection isn't being dragged, look for an ancestor with the
    2209                 :   // draggable property set. If one is found, use that as the target of the
    2210                 :   // drag instead of the node that was clicked on. If a draggable node wasn't
    2211                 :   // found, just use the clicked node.
    2212               0 :   if (!*aSelection) {
    2213               0 :     while (dragContent) {
    2214               0 :       nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(dragContent);
    2215               0 :       if (htmlElement) {
    2216               0 :         bool draggable = false;
    2217               0 :         htmlElement->GetDraggable(&draggable);
    2218               0 :         if (draggable)
    2219                 :           break;
    2220                 :       }
    2221                 :       else {
    2222               0 :         nsCOMPtr<nsIDOMXULElement> xulElement = do_QueryInterface(dragContent);
    2223               0 :         if (xulElement) {
    2224                 :           // All XUL elements are draggable, so if a XUL element is
    2225                 :           // encountered, stop looking for draggable nodes and just use the
    2226                 :           // original clicked node instead.
    2227                 :           // XXXndeakin
    2228                 :           // In the future, we will want to improve this so that XUL has a
    2229                 :           // better way to specify whether something is draggable than just
    2230                 :           // on/off.
    2231               0 :           dragContent = mGestureDownContent;
    2232                 :           break;
    2233                 :         }
    2234                 :         // otherwise, it's not an HTML or XUL element, so just keep looking
    2235                 :       }
    2236               0 :       dragContent = dragContent->GetParent();
    2237                 :     }
    2238                 :   }
    2239                 : 
    2240                 :   // if no node in the hierarchy was found to drag, but the GetDragData method
    2241                 :   // returned a node, use that returned node. Otherwise, nothing is draggable.
    2242               0 :   if (!dragContent && dragDataNode)
    2243               0 :     dragContent = dragDataNode;
    2244                 : 
    2245               0 :   if (dragContent) {
    2246                 :     // if an ancestor node was used instead, clear the drag data
    2247                 :     // XXXndeakin rework this a bit. Find a way to just not call GetDragData if we don't need to.
    2248               0 :     if (dragContent != originalDragContent)
    2249               0 :       aDataTransfer->ClearAll();
    2250               0 :     *aTargetNode = dragContent;
    2251               0 :     NS_ADDREF(*aTargetNode);
    2252                 :   }
    2253                 : }
    2254                 : 
    2255                 : bool
    2256               0 : nsEventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
    2257                 :                                         nsDragEvent* aDragEvent,
    2258                 :                                         nsDOMDataTransfer* aDataTransfer,
    2259                 :                                         nsIContent* aDragTarget,
    2260                 :                                         nsISelection* aSelection)
    2261                 : {
    2262                 :   nsCOMPtr<nsIDragService> dragService =
    2263               0 :     do_GetService("@mozilla.org/widget/dragservice;1");
    2264               0 :   if (!dragService)
    2265               0 :     return false;
    2266                 : 
    2267                 :   // Default handling for the draggesture/dragstart event.
    2268                 :   //
    2269                 :   // First, check if a drag session already exists. This means that the drag
    2270                 :   // service was called directly within a draggesture handler. In this case,
    2271                 :   // don't do anything more, as it is assumed that the handler is managing
    2272                 :   // drag and drop manually. Make sure to return true to indicate that a drag
    2273                 :   // began.
    2274               0 :   nsCOMPtr<nsIDragSession> dragSession;
    2275               0 :   dragService->GetCurrentSession(getter_AddRefs(dragSession));
    2276               0 :   if (dragSession)
    2277               0 :     return true;
    2278                 : 
    2279                 :   // No drag session is currently active, so check if a handler added
    2280                 :   // any items to be dragged. If not, there isn't anything to drag.
    2281               0 :   PRUint32 count = 0;
    2282               0 :   if (aDataTransfer)
    2283               0 :     aDataTransfer->GetMozItemCount(&count);
    2284               0 :   if (!count)
    2285               0 :     return false;
    2286                 : 
    2287                 :   // Get the target being dragged, which may not be the same as the
    2288                 :   // target of the mouse event. If one wasn't set in the
    2289                 :   // aDataTransfer during the event handler, just use the original
    2290                 :   // target instead.
    2291               0 :   nsCOMPtr<nsIDOMNode> dragTarget;
    2292               0 :   nsCOMPtr<nsIDOMElement> dragTargetElement;
    2293               0 :   aDataTransfer->GetDragTarget(getter_AddRefs(dragTargetElement));
    2294               0 :   dragTarget = do_QueryInterface(dragTargetElement);
    2295               0 :   if (!dragTarget) {
    2296               0 :     dragTarget = do_QueryInterface(aDragTarget);
    2297               0 :     if (!dragTarget)
    2298               0 :       return false;
    2299                 :   }
    2300                 : 
    2301                 :   // check which drag effect should initially be used. If the effect was not
    2302                 :   // set, just use all actions, otherwise Windows won't allow a drop.
    2303                 :   PRUint32 action;
    2304               0 :   aDataTransfer->GetEffectAllowedInt(&action);
    2305               0 :   if (action == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
    2306                 :     action = nsIDragService::DRAGDROP_ACTION_COPY |
    2307                 :              nsIDragService::DRAGDROP_ACTION_MOVE |
    2308               0 :              nsIDragService::DRAGDROP_ACTION_LINK;
    2309                 : 
    2310                 :   // get any custom drag image that was set
    2311                 :   PRInt32 imageX, imageY;
    2312               0 :   nsIDOMElement* dragImage = aDataTransfer->GetDragImage(&imageX, &imageY);
    2313                 : 
    2314               0 :   nsCOMPtr<nsISupportsArray> transArray;
    2315               0 :   aDataTransfer->GetTransferables(getter_AddRefs(transArray));
    2316               0 :   if (!transArray)
    2317               0 :     return false;
    2318                 : 
    2319                 :   // XXXndeakin don't really want to create a new drag DOM event
    2320                 :   // here, but we need something to pass to the InvokeDragSession
    2321                 :   // methods.
    2322               0 :   nsCOMPtr<nsIDOMEvent> domEvent;
    2323               0 :   NS_NewDOMDragEvent(getter_AddRefs(domEvent), aPresContext, aDragEvent);
    2324                 : 
    2325               0 :   nsCOMPtr<nsIDOMDragEvent> domDragEvent = do_QueryInterface(domEvent);
    2326                 :   // if creating a drag event failed, starting a drag session will
    2327                 :   // just fail.
    2328                 : 
    2329                 :   // Use InvokeDragSessionWithSelection if a selection is being dragged,
    2330                 :   // such that the image can be generated from the selected text. However,
    2331                 :   // use InvokeDragSessionWithImage if a custom image was set or something
    2332                 :   // other than a selection is being dragged.
    2333               0 :   if (!dragImage && aSelection) {
    2334               0 :     dragService->InvokeDragSessionWithSelection(aSelection, transArray,
    2335                 :                                                 action, domDragEvent,
    2336               0 :                                                 aDataTransfer);
    2337                 :   }
    2338                 :   else {
    2339                 :     // if dragging within a XUL tree and no custom drag image was
    2340                 :     // set, the region argument to InvokeDragSessionWithImage needs
    2341                 :     // to be set to the area encompassing the selected rows of the
    2342                 :     // tree to ensure that the drag feedback gets clipped to those
    2343                 :     // rows. For other content, region should be null.
    2344               0 :     nsCOMPtr<nsIScriptableRegion> region;
    2345                 : #ifdef MOZ_XUL
    2346               0 :     if (dragTarget && !dragImage) {
    2347               0 :       nsCOMPtr<nsIContent> content = do_QueryInterface(dragTarget);
    2348               0 :       if (content->NodeInfo()->Equals(nsGkAtoms::treechildren,
    2349               0 :                                       kNameSpaceID_XUL)) {
    2350               0 :         nsTreeBodyFrame* treeBody = do_QueryFrame(content->GetPrimaryFrame());
    2351               0 :         if (treeBody) {
    2352               0 :           treeBody->GetSelectionRegion(getter_AddRefs(region));
    2353                 :         }
    2354                 :       }
    2355                 :     }
    2356                 : #endif
    2357                 : 
    2358               0 :     dragService->InvokeDragSessionWithImage(dragTarget, transArray,
    2359                 :                                             region, action, dragImage,
    2360                 :                                             imageX, imageY, domDragEvent,
    2361               0 :                                             aDataTransfer);
    2362                 :   }
    2363                 : 
    2364               0 :   return true;
    2365                 : }
    2366                 : 
    2367                 : nsresult
    2368               0 : nsEventStateManager::GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv)
    2369                 : {
    2370               0 :   *aMv = nsnull;
    2371                 : 
    2372               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    2373               0 :   if(!fm) return NS_ERROR_FAILURE;
    2374                 : 
    2375               0 :   nsCOMPtr<nsIDOMWindow> focusedWindow;
    2376               0 :   fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
    2377                 : 
    2378               0 :   nsCOMPtr<nsPIDOMWindow> ourWindow = do_QueryInterface(focusedWindow);
    2379               0 :   if(!ourWindow) return NS_ERROR_FAILURE;
    2380                 : 
    2381               0 :   nsIDOMWindow *rootWindow = ourWindow->GetPrivateRoot();
    2382               0 :   if(!rootWindow) return NS_ERROR_FAILURE;
    2383                 : 
    2384               0 :   nsCOMPtr<nsIDOMWindow> contentWindow;
    2385               0 :   rootWindow->GetContent(getter_AddRefs(contentWindow));
    2386               0 :   if(!contentWindow) return NS_ERROR_FAILURE;
    2387                 : 
    2388               0 :   nsIDocument *doc = GetDocumentFromWindow(contentWindow);
    2389               0 :   if(!doc) return NS_ERROR_FAILURE;
    2390                 : 
    2391               0 :   nsIPresShell *presShell = doc->GetShell();
    2392               0 :   if(!presShell) return NS_ERROR_FAILURE;
    2393               0 :   nsPresContext *presContext = presShell->GetPresContext();
    2394               0 :   if(!presContext) return NS_ERROR_FAILURE;
    2395                 : 
    2396               0 :   nsCOMPtr<nsISupports> pcContainer = presContext->GetContainer();
    2397               0 :   if(!pcContainer) return NS_ERROR_FAILURE;
    2398                 : 
    2399               0 :   nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(pcContainer));
    2400               0 :   if(!docshell) return NS_ERROR_FAILURE;
    2401                 : 
    2402               0 :   nsCOMPtr<nsIContentViewer> cv;
    2403               0 :   docshell->GetContentViewer(getter_AddRefs(cv));
    2404               0 :   if(!cv) return NS_ERROR_FAILURE;
    2405                 : 
    2406               0 :   nsCOMPtr<nsIMarkupDocumentViewer> mv(do_QueryInterface(cv));
    2407               0 :   if(!mv) return NS_ERROR_FAILURE;
    2408                 : 
    2409               0 :   *aMv = mv;
    2410               0 :   NS_IF_ADDREF(*aMv);
    2411                 : 
    2412               0 :   return NS_OK;
    2413                 : }
    2414                 : 
    2415                 : nsresult
    2416               0 : nsEventStateManager::ChangeTextSize(PRInt32 change)
    2417                 : {
    2418               0 :   nsCOMPtr<nsIMarkupDocumentViewer> mv;
    2419               0 :   nsresult rv = GetMarkupDocumentViewer(getter_AddRefs(mv));
    2420               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2421                 : 
    2422                 :   float textzoom;
    2423               0 :   float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100;
    2424               0 :   float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100;
    2425               0 :   mv->GetTextZoom(&textzoom);
    2426               0 :   textzoom += ((float)change) / 10;
    2427               0 :   if (textzoom < zoomMin)
    2428               0 :     textzoom = zoomMin;
    2429               0 :   else if (textzoom > zoomMax)
    2430               0 :     textzoom = zoomMax;
    2431               0 :   mv->SetTextZoom(textzoom);
    2432                 : 
    2433               0 :   return NS_OK;
    2434                 : }
    2435                 : 
    2436                 : nsresult
    2437               0 : nsEventStateManager::ChangeFullZoom(PRInt32 change)
    2438                 : {
    2439               0 :   nsCOMPtr<nsIMarkupDocumentViewer> mv;
    2440               0 :   nsresult rv = GetMarkupDocumentViewer(getter_AddRefs(mv));
    2441               0 :   NS_ENSURE_SUCCESS(rv, rv);
    2442                 : 
    2443                 :   float fullzoom;
    2444               0 :   float zoomMin = ((float)Preferences::GetInt("zoom.minPercent", 50)) / 100;
    2445               0 :   float zoomMax = ((float)Preferences::GetInt("zoom.maxPercent", 300)) / 100;
    2446               0 :   mv->GetFullZoom(&fullzoom);
    2447               0 :   fullzoom += ((float)change) / 10;
    2448               0 :   if (fullzoom < zoomMin)
    2449               0 :     fullzoom = zoomMin;
    2450               0 :   else if (fullzoom > zoomMax)
    2451               0 :     fullzoom = zoomMax;
    2452               0 :   mv->SetFullZoom(fullzoom);
    2453                 : 
    2454               0 :   return NS_OK;
    2455                 : }
    2456                 : 
    2457                 : void
    2458               0 : nsEventStateManager::DoScrollHistory(PRInt32 direction)
    2459                 : {
    2460               0 :   nsCOMPtr<nsISupports> pcContainer(mPresContext->GetContainer());
    2461               0 :   if (pcContainer) {
    2462               0 :     nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(pcContainer));
    2463               0 :     if (webNav) {
    2464                 :       // positive direction to go back one step, nonpositive to go forward
    2465               0 :       if (direction > 0)
    2466               0 :         webNav->GoBack();
    2467                 :       else
    2468               0 :         webNav->GoForward();
    2469                 :     }
    2470                 :   }
    2471               0 : }
    2472                 : 
    2473                 : void
    2474               0 : nsEventStateManager::DoScrollZoom(nsIFrame *aTargetFrame,
    2475                 :                                   PRInt32 adjustment)
    2476                 : {
    2477                 :   // Exclude form controls and XUL content.
    2478               0 :   nsIContent *content = aTargetFrame->GetContent();
    2479               0 :   if (content &&
    2480               0 :       !content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) &&
    2481               0 :       !content->IsXUL())
    2482                 :     {
    2483                 :       // positive adjustment to decrease zoom, negative to increase
    2484               0 :       PRInt32 change = (adjustment > 0) ? -1 : 1;
    2485                 : 
    2486               0 :       if (Preferences::GetBool("browser.zoom.full") || content->GetCurrentDoc()->IsSyntheticDocument()) {
    2487               0 :         ChangeFullZoom(change);
    2488                 :       } else {
    2489               0 :         ChangeTextSize(change);
    2490                 :       }
    2491                 :     }
    2492               0 : }
    2493                 : 
    2494                 : static nsIFrame*
    2495               0 : GetParentFrameToScroll(nsIFrame* aFrame)
    2496                 : {
    2497               0 :   if (!aFrame)
    2498               0 :     return nsnull;
    2499                 : 
    2500               0 :   if (aFrame->GetStyleDisplay()->mPosition == NS_STYLE_POSITION_FIXED &&
    2501               0 :       nsLayoutUtils::IsReallyFixedPos(aFrame))
    2502               0 :     return aFrame->PresContext()->GetPresShell()->GetRootScrollFrame();
    2503                 : 
    2504               0 :   return aFrame->GetParent();
    2505                 : }
    2506                 : 
    2507                 : static nscoord
    2508               0 : GetScrollableLineHeight(nsIFrame* aTargetFrame)
    2509                 : {
    2510               0 :   for (nsIFrame* f = aTargetFrame; f; f = GetParentFrameToScroll(f)) {
    2511               0 :     nsIScrollableFrame* sf = f->GetScrollTargetFrame();
    2512               0 :     if (sf)
    2513               0 :       return sf->GetLineScrollAmount().height;
    2514                 :   }
    2515                 : 
    2516                 :   // Fall back to the font height of the target frame.
    2517               0 :   nsRefPtr<nsFontMetrics> fm;
    2518                 :   nsLayoutUtils::GetFontMetricsForFrame(aTargetFrame, getter_AddRefs(fm),
    2519                 :     nsLayoutUtils::FontSizeInflationFor(aTargetFrame,
    2520               0 :                                         nsLayoutUtils::eNotInReflow));
    2521               0 :   NS_ASSERTION(fm, "FontMetrics is null!");
    2522               0 :   if (fm)
    2523               0 :     return fm->MaxHeight();
    2524               0 :   return 0;
    2525                 : }
    2526                 : 
    2527                 : void
    2528               0 : nsEventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
    2529                 :                                          nsMouseScrollEvent* aEvent,
    2530                 :                                          nsPresContext* aPresContext,
    2531                 :                                          nsEventStatus* aStatus,
    2532                 :                                          PRInt32 aNumLines)
    2533                 : {
    2534               0 :   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
    2535               0 :   if (!targetContent)
    2536               0 :     targetContent = GetFocusedContent();
    2537               0 :   if (!targetContent)
    2538                 :     return;
    2539                 : 
    2540               0 :   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
    2541               0 :     targetContent = targetContent->GetParent();
    2542                 :   }
    2543                 : 
    2544               0 :   bool isTrusted = (aEvent->flags & NS_EVENT_FLAG_TRUSTED) != 0;
    2545               0 :   nsMouseScrollEvent event(isTrusted, NS_MOUSE_SCROLL, nsnull);
    2546               0 :   event.refPoint = aEvent->refPoint;
    2547               0 :   event.widget = aEvent->widget;
    2548               0 :   event.time = aEvent->time;
    2549               0 :   event.isShift = aEvent->isShift;
    2550               0 :   event.isControl = aEvent->isControl;
    2551               0 :   event.isAlt = aEvent->isAlt;
    2552               0 :   event.isMeta = aEvent->isMeta;
    2553               0 :   event.scrollFlags = aEvent->scrollFlags;
    2554               0 :   event.delta = aNumLines;
    2555               0 :   event.inputSource = static_cast<nsMouseEvent_base*>(aEvent)->inputSource;
    2556                 : 
    2557               0 :   nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nsnull, aStatus);
    2558                 : }
    2559                 : 
    2560                 : void
    2561               0 : nsEventStateManager::SendPixelScrollEvent(nsIFrame* aTargetFrame,
    2562                 :                                           nsMouseScrollEvent* aEvent,
    2563                 :                                           nsPresContext* aPresContext,
    2564                 :                                           nsEventStatus* aStatus)
    2565                 : {
    2566               0 :   nsCOMPtr<nsIContent> targetContent = aTargetFrame->GetContent();
    2567               0 :   if (!targetContent) {
    2568               0 :     targetContent = GetFocusedContent();
    2569               0 :     if (!targetContent)
    2570                 :       return;
    2571                 :   }
    2572                 : 
    2573               0 :   while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
    2574               0 :     targetContent = targetContent->GetParent();
    2575                 :   }
    2576                 : 
    2577               0 :   nscoord lineHeight = GetScrollableLineHeight(aTargetFrame);
    2578                 : 
    2579               0 :   bool isTrusted = (aEvent->flags & NS_EVENT_FLAG_TRUSTED) != 0;
    2580               0 :   nsMouseScrollEvent event(isTrusted, NS_MOUSE_PIXEL_SCROLL, nsnull);
    2581               0 :   event.refPoint = aEvent->refPoint;
    2582               0 :   event.widget = aEvent->widget;
    2583               0 :   event.time = aEvent->time;
    2584               0 :   event.isShift = aEvent->isShift;
    2585               0 :   event.isControl = aEvent->isControl;
    2586               0 :   event.isAlt = aEvent->isAlt;
    2587               0 :   event.isMeta = aEvent->isMeta;
    2588               0 :   event.scrollFlags = aEvent->scrollFlags;
    2589               0 :   event.inputSource = static_cast<nsMouseEvent_base*>(aEvent)->inputSource;
    2590               0 :   event.delta = aPresContext->AppUnitsToIntCSSPixels(aEvent->delta * lineHeight);
    2591                 : 
    2592               0 :   nsEventDispatcher::Dispatch(targetContent, aPresContext, &event, nsnull, aStatus);
    2593                 : }
    2594                 : 
    2595                 : PRInt32
    2596               0 : nsEventStateManager::ComputeWheelDeltaFor(nsMouseScrollEvent* aMouseEvent)
    2597                 : {
    2598               0 :   PRInt32 delta = aMouseEvent->delta;
    2599               0 :   bool useSysNumLines = UseSystemScrollSettingFor(aMouseEvent);
    2600               0 :   if (!useSysNumLines) {
    2601                 :     // If the scroll event's delta isn't to our liking, we can
    2602                 :     // override it with the "numlines" parameter.  There are two
    2603                 :     // things we can do:
    2604                 :     //
    2605                 :     // (1) Pick a different number.  Instead of scrolling 3
    2606                 :     //     lines ("delta" in Gtk2), we would scroll 1 line.
    2607                 :     // (2) Swap directions.  Instead of scrolling down, scroll up.
    2608                 :     //
    2609                 :     // For the first item, the magnitude of the parameter is
    2610                 :     // used instead of the magnitude of the delta.  For the
    2611                 :     // second item, if the parameter is negative we swap
    2612                 :     // directions.
    2613                 : 
    2614               0 :     PRInt32 numLines = GetScrollLinesFor(aMouseEvent);
    2615                 : 
    2616               0 :     bool swapDirs = (numLines < 0);
    2617               0 :     PRInt32 userSize = swapDirs ? -numLines : numLines;
    2618                 : 
    2619               0 :     bool deltaUp = (delta < 0);
    2620               0 :     if (swapDirs) {
    2621               0 :       deltaUp = !deltaUp;
    2622                 :     }
    2623               0 :     delta = deltaUp ? -userSize : userSize;
    2624                 :   }
    2625                 : 
    2626               0 :   if (ComputeWheelActionFor(aMouseEvent, useSysNumLines) == MOUSE_SCROLL_PAGE) {
    2627                 :     delta = (delta > 0) ? PRInt32(nsIDOMUIEvent::SCROLL_PAGE_DOWN) :
    2628               0 :                           PRInt32(nsIDOMUIEvent::SCROLL_PAGE_UP);
    2629                 :   }
    2630                 : 
    2631               0 :   return delta;
    2632                 : }
    2633                 : 
    2634                 : PRInt32
    2635               0 : nsEventStateManager::ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent,
    2636                 :                                            bool aUseSystemSettings)
    2637                 : {
    2638               0 :   PRInt32 action = GetWheelActionFor(aMouseEvent);
    2639               0 :   if (aUseSystemSettings &&
    2640                 :       (aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage)) {
    2641               0 :     action = MOUSE_SCROLL_PAGE;
    2642                 :   }
    2643                 : 
    2644               0 :   if (aMouseEvent->message == NS_MOUSE_PIXEL_SCROLL) {
    2645               0 :     if (action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE ||
    2646                 :         (aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
    2647               0 :       action = MOUSE_SCROLL_PIXELS;
    2648                 :     } else {
    2649                 :       // Do not scroll pixels when zooming
    2650               0 :       action = -1;
    2651                 :     }
    2652               0 :   } else if (((aMouseEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) &&
    2653                 :               (aUseSystemSettings ||
    2654                 :                action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE)) ||
    2655                 :              ((aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum) &&
    2656                 :               (action == MOUSE_SCROLL_HISTORY || action == MOUSE_SCROLL_ZOOM))) {
    2657                 :     // Don't scroll lines or page when a pixel scroll event will follow.
    2658                 :     // Also, don't do history scrolling or zooming for momentum scrolls,
    2659                 :     // no matter what's going on with pixel scrolling.
    2660               0 :     action = -1;
    2661                 :   }
    2662                 : 
    2663               0 :   return action;
    2664                 : }
    2665                 : 
    2666                 : PRInt32
    2667               0 : nsEventStateManager::GetWheelActionFor(nsMouseScrollEvent* aMouseEvent)
    2668                 : {
    2669               0 :   nsCAutoString prefName;
    2670               0 :   GetBasePrefKeyForMouseWheel(aMouseEvent, prefName);
    2671               0 :   prefName.Append(".action");
    2672               0 :   return Preferences::GetInt(prefName.get());
    2673                 : }
    2674                 : 
    2675                 : PRInt32
    2676               0 : nsEventStateManager::GetScrollLinesFor(nsMouseScrollEvent* aMouseEvent)
    2677                 : {
    2678               0 :   NS_ASSERTION(!UseSystemScrollSettingFor(aMouseEvent),
    2679                 :     "GetScrollLinesFor() called when should use system settings");
    2680               0 :   nsCAutoString prefName;
    2681               0 :   GetBasePrefKeyForMouseWheel(aMouseEvent, prefName);
    2682               0 :   prefName.Append(".numlines");
    2683               0 :   return Preferences::GetInt(prefName.get());
    2684                 : }
    2685                 : 
    2686                 : bool
    2687               0 : nsEventStateManager::UseSystemScrollSettingFor(nsMouseScrollEvent* aMouseEvent)
    2688                 : {
    2689               0 :   nsCAutoString prefName;
    2690               0 :   GetBasePrefKeyForMouseWheel(aMouseEvent, prefName);
    2691               0 :   prefName.Append(".sysnumlines");
    2692               0 :   return Preferences::GetBool(prefName.get());
    2693                 : }
    2694                 : 
    2695                 : nsresult
    2696               0 : nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
    2697                 :                                   nsMouseScrollEvent* aMouseEvent,
    2698                 :                                   nsIScrollableFrame::ScrollUnit aScrollQuantity,
    2699                 :                                   bool aAllowScrollSpeedOverride,
    2700                 :                                   nsQueryContentEvent* aQueryEvent,
    2701                 :                                   nsIAtom *aOrigin)
    2702                 : {
    2703               0 :   nsIScrollableFrame* frameToScroll = nsnull;
    2704               0 :   nsIFrame* scrollFrame = aTargetFrame;
    2705               0 :   PRInt32 numLines = aMouseEvent->delta;
    2706               0 :   bool isHorizontal = aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal;
    2707               0 :   aMouseEvent->scrollOverflow = 0;
    2708                 : 
    2709                 :   // If the user recently scrolled with the mousewheel, then they probably want
    2710                 :   // to scroll the same view as before instead of the view under the cursor.
    2711                 :   // nsMouseWheelTransaction tracks the frame currently being scrolled with the
    2712                 :   // mousewheel. We consider the transaction ended when the mouse moves more than
    2713                 :   // "mousewheel.transaction.ignoremovedelay" milliseconds after the last scroll
    2714                 :   // operation, or any time the mouse moves out of the frame, or when more than
    2715                 :   // "mousewheel.transaction.timeout" milliseconds have passed after the last
    2716                 :   // operation, even if the mouse hasn't moved.
    2717               0 :   nsIFrame* lastScrollFrame = nsMouseWheelTransaction::GetTargetFrame();
    2718               0 :   if (lastScrollFrame) {
    2719               0 :     frameToScroll = lastScrollFrame->GetScrollTargetFrame();
    2720               0 :     if (frameToScroll) {
    2721               0 :       nsMouseWheelTransaction::UpdateTransaction(numLines, isHorizontal);
    2722                 :       // When the scroll event will not scroll any views, UpdateTransaction
    2723                 :       // fired MozMouseScrollFailed event which is for automated testing.
    2724                 :       // In the event handler, the target frame might be destroyed.  Then,
    2725                 :       // we should not keep handling this scroll event.
    2726               0 :       if (!nsMouseWheelTransaction::GetTargetFrame())
    2727               0 :         return NS_OK;
    2728                 :     } else {
    2729               0 :       nsMouseWheelTransaction::EndTransaction();
    2730               0 :       lastScrollFrame = nsnull;
    2731                 :     }
    2732                 :   }
    2733               0 :   bool passToParent = lastScrollFrame ? false : true;
    2734                 : 
    2735               0 :   for (; scrollFrame && passToParent;
    2736                 :        scrollFrame = GetParentFrameToScroll(scrollFrame)) {
    2737                 :     // Check whether the frame wants to provide us with a scrollable view.
    2738               0 :     frameToScroll = scrollFrame->GetScrollTargetFrame();
    2739               0 :     if (!frameToScroll) {
    2740               0 :       continue;
    2741                 :     }
    2742                 : 
    2743               0 :     nsPresContext::ScrollbarStyles ss = frameToScroll->GetScrollbarStyles();
    2744               0 :     if (NS_STYLE_OVERFLOW_HIDDEN ==
    2745                 :         (isHorizontal ? ss.mHorizontal : ss.mVertical)) {
    2746               0 :       continue;
    2747                 :     }
    2748                 : 
    2749                 :     // Check if the scrollable view can be scrolled any further.
    2750               0 :     nscoord lineHeight = frameToScroll->GetLineScrollAmount().height;
    2751               0 :     if (lineHeight != 0) {
    2752               0 :       if (CanScrollOn(frameToScroll, numLines, isHorizontal)) {
    2753               0 :         passToParent = false;
    2754                 :         nsMouseWheelTransaction::BeginTransaction(scrollFrame,
    2755               0 :                                                   numLines, isHorizontal);
    2756                 :       }
    2757                 : 
    2758                 :       // Comboboxes need special care.
    2759               0 :       nsIComboboxControlFrame* comboBox = do_QueryFrame(scrollFrame);
    2760               0 :       if (comboBox) {
    2761               0 :         if (comboBox->IsDroppedDown()) {
    2762                 :           // Don't propagate to parent when drop down menu is active.
    2763               0 :           if (passToParent) {
    2764               0 :             passToParent = false;
    2765               0 :             frameToScroll = nsnull;
    2766               0 :             nsMouseWheelTransaction::EndTransaction();
    2767                 :           }
    2768                 :         } else {
    2769                 :           // Always propagate when not dropped down (even if focused).
    2770               0 :           if (!passToParent) {
    2771               0 :             passToParent = true;
    2772               0 :             nsMouseWheelTransaction::EndTransaction();
    2773                 :           }
    2774                 :         }
    2775                 :       }
    2776                 :     }
    2777                 :   }
    2778                 : 
    2779               0 :   if (!passToParent && frameToScroll) {
    2780               0 :     if (aScrollQuantity == nsIScrollableFrame::LINES) {
    2781                 :       // When this is called for querying the scroll target information,
    2782                 :       // we shouldn't limit the scrolling amount to less one page.
    2783                 :       // Otherwise, we shouldn't scroll more one page at once.
    2784                 :       numLines =
    2785                 :         nsMouseWheelTransaction::AccelerateWheelDelta(numLines, isHorizontal,
    2786                 :                                                       aAllowScrollSpeedOverride,
    2787                 :                                                       &aScrollQuantity,
    2788               0 :                                                       !aQueryEvent);
    2789                 :     }
    2790                 : #ifdef DEBUG
    2791                 :     else {
    2792               0 :       NS_ASSERTION(!aAllowScrollSpeedOverride,
    2793                 :         "aAllowScrollSpeedOverride is true but the quantity isn't by-line scrolling.");
    2794                 :     }
    2795                 : #endif
    2796                 : 
    2797               0 :     if (aScrollQuantity == nsIScrollableFrame::PAGES) {
    2798               0 :       numLines = (numLines > 0) ? 1 : -1;
    2799                 :     }
    2800                 : 
    2801               0 :     if (aQueryEvent) {
    2802                 :       // If acceleration is enabled, pixel scroll shouldn't be used for
    2803                 :       // high resolution scrolling.
    2804               0 :       if (nsMouseWheelTransaction::IsAccelerationEnabled()) {
    2805               0 :         return NS_OK;
    2806                 :       }
    2807                 : 
    2808                 :       nscoord appUnitsPerDevPixel =
    2809               0 :         aTargetFrame->PresContext()->AppUnitsPerDevPixel();
    2810                 :       aQueryEvent->mReply.mLineHeight =
    2811               0 :         frameToScroll->GetLineScrollAmount().height / appUnitsPerDevPixel;
    2812                 :       aQueryEvent->mReply.mPageHeight =
    2813               0 :         frameToScroll->GetPageScrollAmount().height / appUnitsPerDevPixel;
    2814                 :       aQueryEvent->mReply.mPageWidth =
    2815               0 :         frameToScroll->GetPageScrollAmount().width / appUnitsPerDevPixel;
    2816                 : 
    2817                 :       // Returns computed numLines to widget which is needed to compute the
    2818                 :       // pixel scrolling amout for high resolution scrolling.
    2819               0 :       aQueryEvent->mReply.mComputedScrollAmount = numLines;
    2820                 : 
    2821               0 :       switch (aScrollQuantity) {
    2822                 :         case nsIScrollableFrame::LINES:
    2823                 :           aQueryEvent->mReply.mComputedScrollAction =
    2824               0 :             nsQueryContentEvent::SCROLL_ACTION_LINE;
    2825               0 :           break;
    2826                 :         case nsIScrollableFrame::PAGES:
    2827                 :           aQueryEvent->mReply.mComputedScrollAction =
    2828               0 :             nsQueryContentEvent::SCROLL_ACTION_PAGE;
    2829               0 :           break;
    2830                 :         default:
    2831                 :           aQueryEvent->mReply.mComputedScrollAction =
    2832               0 :             nsQueryContentEvent::SCROLL_ACTION_NONE;
    2833               0 :           break;
    2834                 :       }
    2835                 : 
    2836               0 :       aQueryEvent->mSucceeded = true;
    2837               0 :       return NS_OK;
    2838                 :     }
    2839                 : 
    2840               0 :     PRInt32 scrollX = 0;
    2841               0 :     PRInt32 scrollY = numLines;
    2842                 : 
    2843               0 :     if (isHorizontal) {
    2844               0 :       scrollX = scrollY;
    2845               0 :       scrollY = 0;
    2846                 :     }
    2847                 : 
    2848                 :     nsIScrollableFrame::ScrollMode mode;
    2849               0 :     if (aMouseEvent->scrollFlags & nsMouseScrollEvent::kNoDefer) {
    2850               0 :       mode = nsIScrollableFrame::INSTANT;
    2851               0 :     } else if (aScrollQuantity != nsIScrollableFrame::DEVICE_PIXELS ||
    2852                 :                (aMouseEvent->scrollFlags &
    2853                 :                   nsMouseScrollEvent::kAllowSmoothScroll) != 0) {
    2854               0 :       mode = nsIScrollableFrame::SMOOTH;
    2855                 :     } else {
    2856               0 :       mode = nsIScrollableFrame::NORMAL;
    2857                 :     }
    2858                 : 
    2859                 :     // XXX Why don't we limit the pixel scroll amount to less one page??
    2860                 : 
    2861               0 :     nsIntPoint overflow;
    2862                 :     frameToScroll->ScrollBy(nsIntPoint(scrollX, scrollY), aScrollQuantity,
    2863               0 :                             mode, &overflow, aOrigin);
    2864               0 :     aMouseEvent->scrollOverflow = isHorizontal ? overflow.x : overflow.y;
    2865               0 :     return NS_OK;
    2866                 :   }
    2867                 :   
    2868               0 :   if (passToParent) {
    2869                 :     nsIFrame* newFrame = nsLayoutUtils::GetCrossDocParentFrame(
    2870               0 :         aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
    2871               0 :     if (newFrame)
    2872                 :       return DoScrollText(newFrame, aMouseEvent, aScrollQuantity,
    2873               0 :                           aAllowScrollSpeedOverride, aQueryEvent, aOrigin);
    2874                 :   }
    2875                 : 
    2876               0 :   aMouseEvent->scrollOverflow = numLines;
    2877                 : 
    2878               0 :   return NS_OK;
    2879                 : }
    2880                 : 
    2881                 : void
    2882               0 : nsEventStateManager::DecideGestureEvent(nsGestureNotifyEvent* aEvent,
    2883                 :                                         nsIFrame* targetFrame)
    2884                 : {
    2885                 : 
    2886               0 :   NS_ASSERTION(aEvent->message == NS_GESTURENOTIFY_EVENT_START,
    2887                 :                "DecideGestureEvent called with a non-gesture event");
    2888                 : 
    2889                 :   /* Check the ancestor tree to decide if any frame is willing* to receive
    2890                 :    * a MozPixelScroll event. If that's the case, the current touch gesture
    2891                 :    * will be used as a pan gesture; otherwise it will be a regular
    2892                 :    * mousedown/mousemove/click event.
    2893                 :    *
    2894                 :    * *willing: determine if it makes sense to pan the element using scroll events:
    2895                 :    *  - For web content: if there are any visible scrollbars on the touch point
    2896                 :    *  - For XUL: if it's an scrollable element that can currently scroll in some
    2897                 :     *    direction.
    2898                 :    *
    2899                 :    * Note: we'll have to one-off various cases to ensure a good usable behavior
    2900                 :    */
    2901               0 :   nsGestureNotifyEvent::ePanDirection panDirection = nsGestureNotifyEvent::ePanNone;
    2902               0 :   bool displayPanFeedback = false;
    2903               0 :   for (nsIFrame* current = targetFrame; current;
    2904                 :        current = nsLayoutUtils::GetCrossDocParentFrame(current)) {
    2905                 : 
    2906               0 :     nsIAtom* currentFrameType = current->GetType();
    2907                 : 
    2908                 :     // Scrollbars should always be draggable
    2909               0 :     if (currentFrameType == nsGkAtoms::scrollbarFrame) {
    2910               0 :       panDirection = nsGestureNotifyEvent::ePanNone;
    2911               0 :       break;
    2912                 :     }
    2913                 : 
    2914                 : #ifdef MOZ_XUL
    2915                 :     // Special check for trees
    2916               0 :     nsTreeBodyFrame* treeFrame = do_QueryFrame(current);
    2917               0 :     if (treeFrame) {
    2918               0 :       if (treeFrame->GetHorizontalOverflow()) {
    2919               0 :         panDirection = nsGestureNotifyEvent::ePanHorizontal;
    2920                 :       }
    2921               0 :       if (treeFrame->GetVerticalOverflow()) {
    2922               0 :         panDirection = nsGestureNotifyEvent::ePanVertical;
    2923                 :       }
    2924               0 :       break;
    2925                 :     }
    2926                 : #endif
    2927                 : 
    2928               0 :     nsIScrollableFrame* scrollableFrame = do_QueryFrame(current);
    2929               0 :     if (scrollableFrame) {
    2930               0 :       if (current->IsFrameOfType(nsIFrame::eXULBox)) {
    2931               0 :         displayPanFeedback = true;
    2932                 : 
    2933               0 :         nsRect scrollRange = scrollableFrame->GetScrollRange();
    2934               0 :         bool canScrollHorizontally = scrollRange.width > 0;
    2935                 : 
    2936               0 :         if (targetFrame->GetType() == nsGkAtoms::menuFrame) {
    2937                 :           // menu frames report horizontal scroll when they have submenus
    2938                 :           // and we don't want that
    2939               0 :           canScrollHorizontally = false;
    2940               0 :           displayPanFeedback = false;
    2941                 :         }
    2942                 : 
    2943                 :         // Vertical panning has priority over horizontal panning, so
    2944                 :         // when vertical movement is possible we can just finish the loop.
    2945               0 :         if (scrollRange.height > 0) {
    2946               0 :           panDirection = nsGestureNotifyEvent::ePanVertical;
    2947                 :           break;
    2948                 :         }
    2949                 : 
    2950               0 :         if (canScrollHorizontally) {
    2951               0 :           panDirection = nsGestureNotifyEvent::ePanHorizontal;
    2952               0 :           displayPanFeedback = false;
    2953                 :         }
    2954                 :       } else { //Not a XUL box
    2955               0 :         PRUint32 scrollbarVisibility = scrollableFrame->GetScrollbarVisibility();
    2956                 : 
    2957                 :         //Check if we have visible scrollbars
    2958               0 :         if (scrollbarVisibility & nsIScrollableFrame::VERTICAL) {
    2959               0 :           panDirection = nsGestureNotifyEvent::ePanVertical;
    2960               0 :           displayPanFeedback = true;
    2961               0 :           break;
    2962                 :         }
    2963                 : 
    2964               0 :         if (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) {
    2965               0 :           panDirection = nsGestureNotifyEvent::ePanHorizontal;
    2966               0 :           displayPanFeedback = true;
    2967                 :         }
    2968                 :       }
    2969                 :     } //scrollableFrame
    2970                 :   } //ancestor chain
    2971                 : 
    2972               0 :   aEvent->displayPanFeedback = displayPanFeedback;
    2973               0 :   aEvent->panDirection = panDirection;
    2974               0 : }
    2975                 : 
    2976                 : #ifdef XP_MACOSX
    2977                 : static bool
    2978                 : NodeAllowsClickThrough(nsINode* aNode)
    2979                 : {
    2980                 :   while (aNode) {
    2981                 :     if (aNode->IsElement() && aNode->AsElement()->IsXUL()) {
    2982                 :       mozilla::dom::Element* element = aNode->AsElement();
    2983                 :       static nsIContent::AttrValuesArray strings[] =
    2984                 :         {&nsGkAtoms::always, &nsGkAtoms::never, nsnull};
    2985                 :       switch (element->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::clickthrough,
    2986                 :                                        strings, eCaseMatters)) {
    2987                 :         case 0:
    2988                 :           return true;
    2989                 :         case 1:
    2990                 :           return false;
    2991                 :       }
    2992                 :     }
    2993                 :     aNode = nsContentUtils::GetCrossDocParentNode(aNode);
    2994                 :   }
    2995                 :   return true;
    2996                 : }
    2997                 : #endif
    2998                 : 
    2999                 : nsresult
    3000               0 : nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
    3001                 :                                      nsEvent *aEvent,
    3002                 :                                      nsIFrame* aTargetFrame,
    3003                 :                                      nsEventStatus* aStatus)
    3004                 : {
    3005               0 :   NS_ENSURE_ARG(aPresContext);
    3006               0 :   NS_ENSURE_ARG_POINTER(aStatus);
    3007                 : 
    3008               0 :   HandleCrossProcessEvent(aEvent, aTargetFrame, aStatus);
    3009                 : 
    3010               0 :   mCurrentTarget = aTargetFrame;
    3011               0 :   mCurrentTargetContent = nsnull;
    3012                 : 
    3013                 :   // Most of the events we handle below require a frame.
    3014                 :   // Add special cases here.
    3015               0 :   if (!mCurrentTarget && aEvent->message != NS_MOUSE_BUTTON_UP &&
    3016                 :       aEvent->message != NS_MOUSE_BUTTON_DOWN) {
    3017               0 :     return NS_OK;
    3018                 :   }
    3019                 : 
    3020                 :   //Keep the prescontext alive, we might need it after event dispatch
    3021               0 :   nsRefPtr<nsPresContext> presContext = aPresContext;
    3022               0 :   nsresult ret = NS_OK;
    3023                 : 
    3024               0 :   switch (aEvent->message) {
    3025                 :   case NS_MOUSE_BUTTON_DOWN:
    3026                 :     {
    3027               0 :       if (static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton &&
    3028               0 :           !sNormalLMouseEventInProcess) {
    3029                 :         // We got a mouseup event while a mousedown event was being processed.
    3030                 :         // Make sure that the capturing content is cleared.
    3031               0 :         nsIPresShell::SetCapturingContent(nsnull, 0);
    3032               0 :         break;
    3033                 :       }
    3034                 : 
    3035               0 :       nsCOMPtr<nsIContent> activeContent;
    3036               0 :       if (nsEventStatus_eConsumeNoDefault != *aStatus) {
    3037               0 :         nsCOMPtr<nsIContent> newFocus;      
    3038               0 :         bool suppressBlur = false;
    3039               0 :         if (mCurrentTarget) {
    3040               0 :           mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(newFocus));
    3041               0 :           const nsStyleUserInterface* ui = mCurrentTarget->GetStyleUserInterface();
    3042               0 :           suppressBlur = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE);
    3043               0 :           activeContent = mCurrentTarget->GetContent();
    3044                 :         }
    3045                 : 
    3046               0 :         nsIFrame* currFrame = mCurrentTarget;
    3047                 : 
    3048                 :         // When a root content which isn't editable but has an editable HTML
    3049                 :         // <body> element is clicked, we should redirect the focus to the
    3050                 :         // the <body> element.  E.g., when an user click bottom of the editor
    3051                 :         // where is outside of the <body> element, the <body> should be focused
    3052                 :         // and the user can edit immediately after that.
    3053                 :         //
    3054                 :         // NOTE: The newFocus isn't editable that also means it's not in
    3055                 :         // designMode.  In designMode, all contents are not focusable.
    3056               0 :         if (newFocus && !newFocus->IsEditable()) {
    3057               0 :           nsIDocument *doc = newFocus->GetCurrentDoc();
    3058               0 :           if (doc && newFocus == doc->GetRootElement()) {
    3059                 :             nsIContent *bodyContent =
    3060               0 :               nsLayoutUtils::GetEditableRootContentByContentEditable(doc);
    3061               0 :             if (bodyContent) {
    3062               0 :               nsIFrame* bodyFrame = bodyContent->GetPrimaryFrame();
    3063               0 :               if (bodyFrame) {
    3064               0 :                 currFrame = bodyFrame;
    3065               0 :                 newFocus = bodyContent;
    3066                 :               }
    3067                 :             }
    3068                 :           }
    3069                 :         }
    3070                 : 
    3071                 :         // When the mouse is pressed, the default action is to focus the
    3072                 :         // target. Look for the nearest enclosing focusable frame.
    3073               0 :         while (currFrame) {
    3074                 :           // If the mousedown happened inside a popup, don't
    3075                 :           // try to set focus on one of its containing elements
    3076               0 :           const nsStyleDisplay* display = currFrame->GetStyleDisplay();
    3077               0 :           if (display->mDisplay == NS_STYLE_DISPLAY_POPUP) {
    3078               0 :             newFocus = nsnull;
    3079               0 :             break;
    3080                 :           }
    3081                 : 
    3082                 :           PRInt32 tabIndexUnused;
    3083               0 :           if (currFrame->IsFocusable(&tabIndexUnused, true)) {
    3084               0 :             newFocus = currFrame->GetContent();
    3085               0 :             nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocus));
    3086               0 :             if (domElement)
    3087                 :               break;
    3088                 :           }
    3089               0 :           currFrame = currFrame->GetParent();
    3090                 :         }
    3091                 : 
    3092               0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3093               0 :         if (fm) {
    3094                 :           // if something was found to focus, focus it. Otherwise, if the
    3095                 :           // element that was clicked doesn't have -moz-user-focus: ignore,
    3096                 :           // clear the existing focus. For -moz-user-focus: ignore, the focus
    3097                 :           // is just left as is.
    3098                 :           // Another effect of mouse clicking, handled in nsSelection, is that
    3099                 :           // it should update the caret position to where the mouse was
    3100                 :           // clicked. Because the focus is cleared when clicking on a
    3101                 :           // non-focusable node, the next press of the tab key will cause
    3102                 :           // focus to be shifted from the caret position instead of the root.
    3103               0 :           if (newFocus && currFrame) {
    3104                 :             // use the mouse flag and the noscroll flag so that the content
    3105                 :             // doesn't unexpectedly scroll when clicking an element that is
    3106                 :             // only hald visible
    3107               0 :             nsCOMPtr<nsIDOMElement> newFocusElement = do_QueryInterface(newFocus);
    3108                 :             fm->SetFocus(newFocusElement, nsIFocusManager::FLAG_BYMOUSE |
    3109               0 :                                           nsIFocusManager::FLAG_NOSCROLL);
    3110                 :           }
    3111               0 :           else if (!suppressBlur) {
    3112                 :             // clear the focus within the frame and then set it as the
    3113                 :             // focused frame
    3114               0 :             EnsureDocument(mPresContext);
    3115               0 :             if (mDocument) {
    3116                 : #ifdef XP_MACOSX
    3117                 :               if (!activeContent || !activeContent->IsXUL())
    3118                 : #endif
    3119               0 :                 fm->ClearFocus(mDocument->GetWindow());
    3120               0 :               fm->SetFocusedWindow(mDocument->GetWindow());
    3121                 :             }
    3122                 :           }
    3123                 :         }
    3124                 : 
    3125                 :         // The rest is left button-specific.
    3126               0 :         if (static_cast<nsMouseEvent*>(aEvent)->button !=
    3127                 :             nsMouseEvent::eLeftButton)
    3128                 :           break;
    3129                 : 
    3130               0 :         if (activeContent) {
    3131                 :           // The nearest enclosing element goes into the
    3132                 :           // :active state.  If we fail the QI to DOMElement,
    3133                 :           // then we know we're only a node, and that we need
    3134                 :           // to obtain our parent element and put it into :active
    3135                 :           // instead.
    3136               0 :           nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(activeContent));
    3137               0 :           if (!elt) {
    3138               0 :             nsIContent* par = activeContent->GetParent();
    3139               0 :             if (par)
    3140               0 :               activeContent = par;
    3141                 :           }
    3142                 :         }
    3143                 :       }
    3144                 :       else {
    3145                 :         // if we're here, the event handler returned false, so stop
    3146                 :         // any of our own processing of a drag. Workaround for bug 43258.
    3147               0 :         StopTrackingDragGesture();
    3148                 : 
    3149                 :         // When the event was cancelled, there is currently a chrome document
    3150                 :         // focused and a mousedown just occurred on a content document, ensure
    3151                 :         // that the window that was clicked is focused.
    3152               0 :         EnsureDocument(mPresContext);
    3153               0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3154               0 :         if (mDocument && fm) {
    3155               0 :           nsCOMPtr<nsIDOMWindow> currentWindow;
    3156               0 :           fm->GetFocusedWindow(getter_AddRefs(currentWindow));
    3157               0 :           if (currentWindow && currentWindow != mDocument->GetWindow() &&
    3158               0 :               !nsContentUtils::IsChromeDoc(mDocument)) {
    3159               0 :             nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(currentWindow);
    3160               0 :             nsCOMPtr<nsIDocument> currentDoc = do_QueryInterface(win->GetExtantDocument());
    3161               0 :             if (nsContentUtils::IsChromeDoc(currentDoc)) {
    3162               0 :               fm->SetFocusedWindow(mDocument->GetWindow());
    3163                 :             }
    3164                 :           }
    3165                 :         }
    3166                 :       }
    3167               0 :       SetActiveManager(this, activeContent);
    3168                 :     }
    3169               0 :     break;
    3170                 :   case NS_MOUSE_BUTTON_UP:
    3171                 :     {
    3172               0 :       ClearGlobalActiveContent(this);
    3173               0 :       if (IsMouseEventReal(aEvent)) {
    3174               0 :         if (!mCurrentTarget) {
    3175               0 :           GetEventTarget();
    3176                 :         }
    3177               0 :         if (mCurrentTarget) {
    3178                 :           ret = CheckForAndDispatchClick(presContext, (nsMouseEvent*)aEvent,
    3179               0 :                                          aStatus);
    3180                 :         }
    3181                 :       }
    3182                 : 
    3183               0 :       nsIPresShell *shell = presContext->GetPresShell();
    3184               0 :       if (shell) {
    3185               0 :         nsRefPtr<nsFrameSelection> frameSelection = shell->FrameSelection();
    3186               0 :         frameSelection->SetMouseDownState(false);
    3187                 :       }
    3188                 :     }
    3189               0 :     break;
    3190                 :   case NS_MOUSE_SCROLL:
    3191                 :   case NS_MOUSE_PIXEL_SCROLL:
    3192                 :     {
    3193               0 :       nsMouseScrollEvent *msEvent = static_cast<nsMouseScrollEvent*>(aEvent);
    3194                 : 
    3195               0 :       if (aEvent->message == NS_MOUSE_SCROLL) {
    3196                 :         // Mark the subsequent pixel scrolls as valid / invalid, based on the
    3197                 :         // observation if the previous line scroll has been canceled
    3198               0 :         if (msEvent->scrollFlags & nsMouseScrollEvent::kIsHorizontal) {
    3199               0 :           mLastLineScrollConsumedX = (nsEventStatus_eConsumeNoDefault == *aStatus);
    3200               0 :         } else if (msEvent->scrollFlags & nsMouseScrollEvent::kIsVertical) {
    3201               0 :           mLastLineScrollConsumedY = (nsEventStatus_eConsumeNoDefault == *aStatus);
    3202                 :         }
    3203               0 :         if (!(msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels)) {
    3204                 :           // No generated pixel scroll event will follow.
    3205                 :           // Create and send a pixel scroll DOM event now.
    3206               0 :           nsWeakFrame weakFrame(aTargetFrame);
    3207               0 :           SendPixelScrollEvent(aTargetFrame, msEvent, presContext, aStatus);
    3208               0 :           NS_ENSURE_STATE(weakFrame.IsAlive());
    3209                 :         }
    3210                 :       }
    3211                 : 
    3212               0 :       if (*aStatus != nsEventStatus_eConsumeNoDefault) {
    3213               0 :         bool useSysNumLines = UseSystemScrollSettingFor(msEvent);
    3214               0 :         PRInt32 action = ComputeWheelActionFor(msEvent, useSysNumLines);
    3215                 : 
    3216               0 :         switch (action) {
    3217                 :         case MOUSE_SCROLL_N_LINES:
    3218                 :           DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::LINES,
    3219               0 :                        useSysNumLines, nsnull, nsGkAtoms::mouseWheel);
    3220               0 :           break;
    3221                 : 
    3222                 :         case MOUSE_SCROLL_PAGE:
    3223                 :           DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::PAGES,
    3224               0 :                        false);
    3225               0 :           break;
    3226                 : 
    3227                 :         case MOUSE_SCROLL_PIXELS:
    3228                 :           {
    3229               0 :             bool fromLines = msEvent->scrollFlags & nsMouseScrollEvent::kFromLines;
    3230                 :             DoScrollText(aTargetFrame, msEvent, nsIScrollableFrame::DEVICE_PIXELS,
    3231               0 :                          false, nsnull, (fromLines ? nsGkAtoms::mouseWheel : nsnull));
    3232                 :           }
    3233               0 :           break;
    3234                 : 
    3235                 :         case MOUSE_SCROLL_HISTORY:
    3236               0 :           DoScrollHistory(msEvent->delta);
    3237               0 :           break;
    3238                 : 
    3239                 :         case MOUSE_SCROLL_ZOOM:
    3240               0 :           DoScrollZoom(aTargetFrame, msEvent->delta);
    3241               0 :           break;
    3242                 : 
    3243                 :         default:  // Including -1 (do nothing)
    3244               0 :           break;
    3245                 :         }
    3246               0 :         *aStatus = nsEventStatus_eConsumeNoDefault;
    3247                 :       }
    3248                 :     }
    3249               0 :     break;
    3250                 : 
    3251                 :   case NS_GESTURENOTIFY_EVENT_START:
    3252                 :     {
    3253               0 :       if (nsEventStatus_eConsumeNoDefault != *aStatus)
    3254               0 :         DecideGestureEvent(static_cast<nsGestureNotifyEvent*>(aEvent), mCurrentTarget);
    3255                 :     }
    3256               0 :     break;
    3257                 : 
    3258                 :   case NS_DRAGDROP_ENTER:
    3259                 :   case NS_DRAGDROP_OVER:
    3260                 :     {
    3261               0 :       NS_ASSERTION(aEvent->eventStructType == NS_DRAG_EVENT, "Expected a drag event");
    3262                 : 
    3263               0 :       nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    3264               0 :       if (!dragSession)
    3265                 :         break;
    3266                 : 
    3267                 :       // Reset the flag.
    3268               0 :       dragSession->SetOnlyChromeDrop(false);
    3269               0 :       if (mPresContext) {
    3270               0 :         EnsureDocument(mPresContext);
    3271                 :       }
    3272               0 :       bool isChromeDoc = nsContentUtils::IsChromeDoc(mDocument);
    3273                 : 
    3274                 :       // the initial dataTransfer is the one from the dragstart event that
    3275                 :       // was set on the dragSession when the drag began.
    3276               0 :       nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
    3277               0 :       nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
    3278               0 :       dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
    3279                 : 
    3280               0 :       nsDragEvent *dragEvent = (nsDragEvent*)aEvent;
    3281                 : 
    3282                 :       // collect any changes to moz cursor settings stored in the event's
    3283                 :       // data transfer.
    3284               0 :       UpdateDragDataTransfer(dragEvent);
    3285                 : 
    3286                 :       // cancelling a dragenter or dragover event means that a drop should be
    3287                 :       // allowed, so update the dropEffect and the canDrop state to indicate
    3288                 :       // that a drag is allowed. If the event isn't cancelled, a drop won't be
    3289                 :       // allowed. Essentially, to allow a drop somewhere, specify the effects
    3290                 :       // using the effectAllowed and dropEffect properties in a dragenter or
    3291                 :       // dragover event and cancel the event. To not allow a drop somewhere,
    3292                 :       // don't cancel the event or set the effectAllowed or dropEffect to
    3293                 :       // "none". This way, if the event is just ignored, no drop will be
    3294                 :       // allowed.
    3295               0 :       PRUint32 dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
    3296               0 :       if (nsEventStatus_eConsumeNoDefault == *aStatus) {
    3297                 :         // if the event has a dataTransfer set, use it.
    3298               0 :         if (dragEvent->dataTransfer) {
    3299                 :           // get the dataTransfer and the dropEffect that was set on it
    3300               0 :           dataTransfer = do_QueryInterface(dragEvent->dataTransfer);
    3301               0 :           dataTransfer->GetDropEffectInt(&dropEffect);
    3302                 :         }
    3303                 :         else {
    3304                 :           // if dragEvent->dataTransfer is null, it means that no attempt was
    3305                 :           // made to access the dataTransfer during the event, yet the event
    3306                 :           // was cancelled. Instead, use the initial data transfer available
    3307                 :           // from the drag session. The drop effect would not have been
    3308                 :           // initialized (which is done in nsDOMDragEvent::GetDataTransfer),
    3309                 :           // so set it from the drag action. We'll still want to filter it
    3310                 :           // based on the effectAllowed below.
    3311               0 :           dataTransfer = initialDataTransfer;
    3312                 : 
    3313                 :           PRUint32 action;
    3314               0 :           dragSession->GetDragAction(&action);
    3315                 : 
    3316                 :           // filter the drop effect based on the action. Use UNINITIALIZED as
    3317                 :           // any effect is allowed.
    3318                 :           dropEffect = nsContentUtils::FilterDropEffect(action,
    3319               0 :                          nsIDragService::DRAGDROP_ACTION_UNINITIALIZED);
    3320                 :         }
    3321                 : 
    3322                 :         // At this point, if the dataTransfer is null, it means that the
    3323                 :         // drag was originally started by directly calling the drag service.
    3324                 :         // Just assume that all effects are allowed.
    3325               0 :         PRUint32 effectAllowed = nsIDragService::DRAGDROP_ACTION_UNINITIALIZED;
    3326               0 :         if (dataTransfer)
    3327               0 :           dataTransfer->GetEffectAllowedInt(&effectAllowed);
    3328                 : 
    3329                 :         // set the drag action based on the drop effect and effect allowed.
    3330                 :         // The drop effect field on the drag transfer object specifies the
    3331                 :         // desired current drop effect. However, it cannot be used if the
    3332                 :         // effectAllowed state doesn't include that type of action. If the
    3333                 :         // dropEffect is "none", then the action will be 'none' so a drop will
    3334                 :         // not be allowed.
    3335               0 :         PRUint32 action = nsIDragService::DRAGDROP_ACTION_NONE;
    3336               0 :         if (effectAllowed == nsIDragService::DRAGDROP_ACTION_UNINITIALIZED ||
    3337                 :             dropEffect & effectAllowed)
    3338               0 :           action = dropEffect;
    3339                 : 
    3340               0 :         if (action == nsIDragService::DRAGDROP_ACTION_NONE)
    3341               0 :           dropEffect = nsIDragService::DRAGDROP_ACTION_NONE;
    3342                 : 
    3343                 :         // inform the drag session that a drop is allowed on this node.
    3344               0 :         dragSession->SetDragAction(action);
    3345               0 :         dragSession->SetCanDrop(action != nsIDragService::DRAGDROP_ACTION_NONE);
    3346                 : 
    3347                 :         // For now, do this only for dragover.
    3348                 :         //XXXsmaug dragenter needs some more work.
    3349               0 :         if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
    3350                 :           // Someone has called preventDefault(), check whether is was content.
    3351               0 :           dragSession->SetOnlyChromeDrop(
    3352               0 :             !(aEvent->flags & NS_EVENT_FLAG_NO_DEFAULT_CALLED_IN_CONTENT));
    3353                 :         }
    3354               0 :       } else if (aEvent->message == NS_DRAGDROP_OVER && !isChromeDoc) {
    3355                 :         // No one called preventDefault(), so handle drop only in chrome.
    3356               0 :         dragSession->SetOnlyChromeDrop(true);
    3357                 :       }
    3358                 : 
    3359                 :       // now set the drop effect in the initial dataTransfer. This ensures
    3360                 :       // that we can get the desired drop effect in the drop event.
    3361               0 :       if (initialDataTransfer)
    3362               0 :         initialDataTransfer->SetDropEffectInt(dropEffect);
    3363                 :     }
    3364               0 :     break;
    3365                 : 
    3366                 :   case NS_DRAGDROP_DROP:
    3367                 :     {
    3368                 :       // now fire the dragdrop event, for compatibility with XUL
    3369               0 :       if (mCurrentTarget && nsEventStatus_eConsumeNoDefault != *aStatus) {
    3370               0 :         nsCOMPtr<nsIContent> targetContent;
    3371               0 :         mCurrentTarget->GetContentForEvent(aEvent,
    3372               0 :                                            getter_AddRefs(targetContent));
    3373                 : 
    3374               0 :         nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
    3375               0 :         nsDragEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_DRAGDROP_DRAGDROP, widget);
    3376                 : 
    3377               0 :         nsMouseEvent* mouseEvent = static_cast<nsMouseEvent*>(aEvent);
    3378               0 :         event.refPoint = mouseEvent->refPoint;
    3379               0 :         if (mouseEvent->widget) {
    3380               0 :           event.refPoint += mouseEvent->widget->WidgetToScreenOffset();
    3381                 :         }
    3382               0 :         event.refPoint -= widget->WidgetToScreenOffset();
    3383               0 :         event.isShift = mouseEvent->isShift;
    3384               0 :         event.isControl = mouseEvent->isControl;
    3385               0 :         event.isAlt = mouseEvent->isAlt;
    3386               0 :         event.isMeta = mouseEvent->isMeta;
    3387               0 :         event.inputSource = mouseEvent->inputSource;
    3388                 : 
    3389               0 :         nsEventStatus status = nsEventStatus_eIgnore;
    3390               0 :         nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
    3391               0 :         if (presShell) {
    3392               0 :           presShell->HandleEventWithTarget(&event, mCurrentTarget,
    3393               0 :                                            targetContent, &status);
    3394                 :         }
    3395                 :       }
    3396               0 :       sLastDragOverFrame = nsnull;
    3397               0 :       ClearGlobalActiveContent(this);
    3398               0 :       break;
    3399                 :     }
    3400                 :   case NS_DRAGDROP_EXIT:
    3401                 :      // make sure to fire the enter and exit_synth events after the
    3402                 :      // NS_DRAGDROP_EXIT event, otherwise we'll clean up too early
    3403               0 :     GenerateDragDropEnterExit(presContext, (nsGUIEvent*)aEvent);
    3404               0 :     break;
    3405                 : 
    3406                 :   case NS_KEY_UP:
    3407               0 :     break;
    3408                 : 
    3409                 :   case NS_KEY_PRESS:
    3410               0 :     if (nsEventStatus_eConsumeNoDefault != *aStatus) {
    3411               0 :       nsKeyEvent* keyEvent = (nsKeyEvent*)aEvent;
    3412                 :       //This is to prevent keyboard scrolling while alt modifier in use.
    3413               0 :       if (!keyEvent->isAlt) {
    3414               0 :         switch(keyEvent->keyCode) {
    3415                 :           case NS_VK_TAB:
    3416                 :           case NS_VK_F6:
    3417               0 :             EnsureDocument(mPresContext);
    3418               0 :             nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3419               0 :             if (fm && mDocument) {
    3420                 :               // Shift focus forward or back depending on shift key
    3421                 :               bool isDocMove = ((nsInputEvent*)aEvent)->isControl ||
    3422               0 :                                  (keyEvent->keyCode == NS_VK_F6);
    3423                 :               PRUint32 dir =
    3424                 :                 static_cast<nsInputEvent*>(aEvent)->isShift ?
    3425                 :                   (isDocMove ? static_cast<PRUint32>(nsIFocusManager::MOVEFOCUS_BACKWARDDOC) :
    3426                 :                                static_cast<PRUint32>(nsIFocusManager::MOVEFOCUS_BACKWARD)) :
    3427                 :                   (isDocMove ? static_cast<PRUint32>(nsIFocusManager::MOVEFOCUS_FORWARDDOC) :
    3428               0 :                                static_cast<PRUint32>(nsIFocusManager::MOVEFOCUS_FORWARD));
    3429               0 :               nsCOMPtr<nsIDOMElement> result;
    3430               0 :               fm->MoveFocus(mDocument->GetWindow(), nsnull, dir,
    3431                 :                             nsIFocusManager::FLAG_BYKEY,
    3432               0 :                             getter_AddRefs(result));
    3433                 :             }
    3434               0 :             *aStatus = nsEventStatus_eConsumeNoDefault;
    3435               0 :             break;
    3436                 :         }
    3437                 :       }
    3438                 :     }
    3439               0 :     break;
    3440                 : 
    3441                 :   case NS_MOUSE_ENTER:
    3442               0 :     if (mCurrentTarget) {
    3443               0 :       nsCOMPtr<nsIContent> targetContent;
    3444               0 :       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    3445               0 :       SetContentState(targetContent, NS_EVENT_STATE_HOVER);
    3446                 :     }
    3447               0 :     break;
    3448                 : 
    3449                 : #ifdef XP_MACOSX
    3450                 :   case NS_MOUSE_ACTIVATE:
    3451                 :     if (mCurrentTarget) {
    3452                 :       nsCOMPtr<nsIContent> targetContent;
    3453                 :       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    3454                 :       if (!NodeAllowsClickThrough(targetContent)) {
    3455                 :         *aStatus = nsEventStatus_eConsumeNoDefault;
    3456                 :       }
    3457                 :     }
    3458                 :     break;
    3459                 : #endif
    3460                 :   }
    3461                 : 
    3462                 :   //Reset target frame to null to avoid mistargeting after reentrant event
    3463               0 :   mCurrentTarget = nsnull;
    3464               0 :   mCurrentTargetContent = nsnull;
    3465                 : 
    3466               0 :   return ret;
    3467                 : }
    3468                 : 
    3469                 : bool
    3470               0 : nsEventStateManager::RemoteQueryContentEvent(nsEvent *aEvent)
    3471                 : {
    3472                 :   nsQueryContentEvent *queryEvent =
    3473               0 :       static_cast<nsQueryContentEvent*>(aEvent);
    3474               0 :   if (!IsTargetCrossProcess(queryEvent)) {
    3475               0 :     return false;
    3476                 :   }
    3477                 :   // Will not be handled locally, remote the event
    3478               0 :   GetCrossProcessTarget()->HandleQueryContentEvent(*queryEvent);
    3479               0 :   return true;
    3480                 : }
    3481                 : 
    3482                 : TabParent*
    3483               0 : nsEventStateManager::GetCrossProcessTarget()
    3484                 : {
    3485               0 :   return TabParent::GetIMETabParent();
    3486                 : }
    3487                 : 
    3488                 : bool
    3489               0 : nsEventStateManager::IsTargetCrossProcess(nsGUIEvent *aEvent)
    3490                 : {
    3491                 :   // Check to see if there is a focused, editable content in chrome,
    3492                 :   // in that case, do not forward IME events to content
    3493               0 :   nsIContent *focusedContent = GetFocusedContent();
    3494               0 :   if (focusedContent && focusedContent->IsEditable())
    3495               0 :     return false;
    3496               0 :   return TabParent::GetIMETabParent() != nsnull;
    3497                 : }
    3498                 : 
    3499                 : void
    3500               0 : nsEventStateManager::NotifyDestroyPresContext(nsPresContext* aPresContext)
    3501                 : {
    3502               0 :   nsIMEStateManager::OnDestroyPresContext(aPresContext);
    3503               0 : }
    3504                 : 
    3505                 : void
    3506               0 : nsEventStateManager::SetPresContext(nsPresContext* aPresContext)
    3507                 : {
    3508               0 :   mPresContext = aPresContext;
    3509               0 : }
    3510                 : 
    3511                 : void
    3512               0 : nsEventStateManager::ClearFrameRefs(nsIFrame* aFrame)
    3513                 : {
    3514               0 :   if (aFrame && aFrame == mCurrentTarget) {
    3515               0 :     mCurrentTargetContent = aFrame->GetContent();
    3516                 :   }
    3517               0 : }
    3518                 : 
    3519                 : void
    3520               0 : nsEventStateManager::UpdateCursor(nsPresContext* aPresContext,
    3521                 :                                   nsEvent* aEvent, nsIFrame* aTargetFrame,
    3522                 :                                   nsEventStatus* aStatus)
    3523                 : {
    3524               0 :   if (aTargetFrame && IsRemoteTarget(aTargetFrame->GetContent())) {
    3525               0 :     return;
    3526                 :   }
    3527                 : 
    3528               0 :   PRInt32 cursor = NS_STYLE_CURSOR_DEFAULT;
    3529               0 :   imgIContainer* container = nsnull;
    3530               0 :   bool haveHotspot = false;
    3531               0 :   float hotspotX = 0.0f, hotspotY = 0.0f;
    3532                 : 
    3533                 :   //If cursor is locked just use the locked one
    3534               0 :   if (mLockCursor) {
    3535               0 :     cursor = mLockCursor;
    3536                 :   }
    3537                 :   //If not locked, look for correct cursor
    3538               0 :   else if (aTargetFrame) {
    3539               0 :       nsIFrame::Cursor framecursor;
    3540                 :       nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent,
    3541               0 :                                                                 aTargetFrame);
    3542               0 :       if (NS_FAILED(aTargetFrame->GetCursor(pt, framecursor)))
    3543                 :         return;  // don't update the cursor if we failed to get it from the frame see bug 118877
    3544               0 :       cursor = framecursor.mCursor;
    3545               0 :       container = framecursor.mContainer;
    3546               0 :       haveHotspot = framecursor.mHaveHotspot;
    3547               0 :       hotspotX = framecursor.mHotspotX;
    3548               0 :       hotspotY = framecursor.mHotspotY;
    3549                 :   }
    3550                 : 
    3551               0 :   if (Preferences::GetBool("ui.use_activity_cursor", false)) {
    3552                 :     // Check whether or not to show the busy cursor
    3553               0 :     nsCOMPtr<nsISupports> pcContainer = aPresContext->GetContainer();
    3554               0 :     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(pcContainer));
    3555               0 :     if (!docShell) return;
    3556               0 :     PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE;
    3557               0 :     docShell->GetBusyFlags(&busyFlags);
    3558                 : 
    3559                 :     // Show busy cursor everywhere before page loads
    3560                 :     // and just replace the arrow cursor after page starts loading
    3561               0 :     if (busyFlags & nsIDocShell::BUSY_FLAGS_BUSY &&
    3562                 :           (cursor == NS_STYLE_CURSOR_AUTO || cursor == NS_STYLE_CURSOR_DEFAULT))
    3563                 :     {
    3564               0 :       cursor = NS_STYLE_CURSOR_SPINNING;
    3565               0 :       container = nsnull;
    3566                 :     }
    3567                 :   }
    3568                 : 
    3569               0 :   if (aTargetFrame) {
    3570                 :     SetCursor(cursor, container, haveHotspot, hotspotX, hotspotY,
    3571               0 :               aTargetFrame->GetNearestWidget(), false);
    3572                 :   }
    3573                 : 
    3574               0 :   if (mLockCursor || NS_STYLE_CURSOR_AUTO != cursor) {
    3575               0 :     *aStatus = nsEventStatus_eConsumeDoDefault;
    3576                 :   }
    3577                 : }
    3578                 : 
    3579                 : nsresult
    3580               0 : nsEventStateManager::SetCursor(PRInt32 aCursor, imgIContainer* aContainer,
    3581                 :                                bool aHaveHotspot,
    3582                 :                                float aHotspotX, float aHotspotY,
    3583                 :                                nsIWidget* aWidget, bool aLockCursor)
    3584                 : {
    3585               0 :   EnsureDocument(mPresContext);
    3586               0 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
    3587               0 :   sMouseOverDocument = mDocument.get();
    3588                 : 
    3589                 :   nsCursor c;
    3590                 : 
    3591               0 :   NS_ENSURE_TRUE(aWidget, NS_ERROR_FAILURE);
    3592               0 :   if (aLockCursor) {
    3593               0 :     if (NS_STYLE_CURSOR_AUTO != aCursor) {
    3594               0 :       mLockCursor = aCursor;
    3595                 :     }
    3596                 :     else {
    3597                 :       //If cursor style is set to auto we unlock the cursor again.
    3598               0 :       mLockCursor = 0;
    3599                 :     }
    3600                 :   }
    3601               0 :   switch (aCursor) {
    3602                 :   default:
    3603                 :   case NS_STYLE_CURSOR_AUTO:
    3604                 :   case NS_STYLE_CURSOR_DEFAULT:
    3605               0 :     c = eCursor_standard;
    3606               0 :     break;
    3607                 :   case NS_STYLE_CURSOR_POINTER:
    3608               0 :     c = eCursor_hyperlink;
    3609               0 :     break;
    3610                 :   case NS_STYLE_CURSOR_CROSSHAIR:
    3611               0 :     c = eCursor_crosshair;
    3612               0 :     break;
    3613                 :   case NS_STYLE_CURSOR_MOVE:
    3614               0 :     c = eCursor_move;
    3615               0 :     break;
    3616                 :   case NS_STYLE_CURSOR_TEXT:
    3617               0 :     c = eCursor_select;
    3618               0 :     break;
    3619                 :   case NS_STYLE_CURSOR_WAIT:
    3620               0 :     c = eCursor_wait;
    3621               0 :     break;
    3622                 :   case NS_STYLE_CURSOR_HELP:
    3623               0 :     c = eCursor_help;
    3624               0 :     break;
    3625                 :   case NS_STYLE_CURSOR_N_RESIZE:
    3626               0 :     c = eCursor_n_resize;
    3627               0 :     break;
    3628                 :   case NS_STYLE_CURSOR_S_RESIZE:
    3629               0 :     c = eCursor_s_resize;
    3630               0 :     break;
    3631                 :   case NS_STYLE_CURSOR_W_RESIZE:
    3632               0 :     c = eCursor_w_resize;
    3633               0 :     break;
    3634                 :   case NS_STYLE_CURSOR_E_RESIZE:
    3635               0 :     c = eCursor_e_resize;
    3636               0 :     break;
    3637                 :   case NS_STYLE_CURSOR_NW_RESIZE:
    3638               0 :     c = eCursor_nw_resize;
    3639               0 :     break;
    3640                 :   case NS_STYLE_CURSOR_SE_RESIZE:
    3641               0 :     c = eCursor_se_resize;
    3642               0 :     break;
    3643                 :   case NS_STYLE_CURSOR_NE_RESIZE:
    3644               0 :     c = eCursor_ne_resize;
    3645               0 :     break;
    3646                 :   case NS_STYLE_CURSOR_SW_RESIZE:
    3647               0 :     c = eCursor_sw_resize;
    3648               0 :     break;
    3649                 :   case NS_STYLE_CURSOR_COPY: // CSS3
    3650               0 :     c = eCursor_copy;
    3651               0 :     break;
    3652                 :   case NS_STYLE_CURSOR_ALIAS:
    3653               0 :     c = eCursor_alias;
    3654               0 :     break;
    3655                 :   case NS_STYLE_CURSOR_CONTEXT_MENU:
    3656               0 :     c = eCursor_context_menu;
    3657               0 :     break;
    3658                 :   case NS_STYLE_CURSOR_CELL:
    3659               0 :     c = eCursor_cell;
    3660               0 :     break;
    3661                 :   case NS_STYLE_CURSOR_GRAB:
    3662               0 :     c = eCursor_grab;
    3663               0 :     break;
    3664                 :   case NS_STYLE_CURSOR_GRABBING:
    3665               0 :     c = eCursor_grabbing;
    3666               0 :     break;
    3667                 :   case NS_STYLE_CURSOR_SPINNING:
    3668               0 :     c = eCursor_spinning;
    3669               0 :     break;
    3670                 :   case NS_STYLE_CURSOR_MOZ_ZOOM_IN:
    3671               0 :     c = eCursor_zoom_in;
    3672               0 :     break;
    3673                 :   case NS_STYLE_CURSOR_MOZ_ZOOM_OUT:
    3674               0 :     c = eCursor_zoom_out;
    3675               0 :     break;
    3676                 :   case NS_STYLE_CURSOR_NOT_ALLOWED:
    3677               0 :     c = eCursor_not_allowed;
    3678               0 :     break;
    3679                 :   case NS_STYLE_CURSOR_COL_RESIZE:
    3680               0 :     c = eCursor_col_resize;
    3681               0 :     break;
    3682                 :   case NS_STYLE_CURSOR_ROW_RESIZE:
    3683               0 :     c = eCursor_row_resize;
    3684               0 :     break;
    3685                 :   case NS_STYLE_CURSOR_NO_DROP:
    3686               0 :     c = eCursor_no_drop;
    3687               0 :     break;
    3688                 :   case NS_STYLE_CURSOR_VERTICAL_TEXT:
    3689               0 :     c = eCursor_vertical_text;
    3690               0 :     break;
    3691                 :   case NS_STYLE_CURSOR_ALL_SCROLL:
    3692               0 :     c = eCursor_all_scroll;
    3693               0 :     break;
    3694                 :   case NS_STYLE_CURSOR_NESW_RESIZE:
    3695               0 :     c = eCursor_nesw_resize;
    3696               0 :     break;
    3697                 :   case NS_STYLE_CURSOR_NWSE_RESIZE:
    3698               0 :     c = eCursor_nwse_resize;
    3699               0 :     break;
    3700                 :   case NS_STYLE_CURSOR_NS_RESIZE:
    3701               0 :     c = eCursor_ns_resize;
    3702               0 :     break;
    3703                 :   case NS_STYLE_CURSOR_EW_RESIZE:
    3704               0 :     c = eCursor_ew_resize;
    3705               0 :     break;
    3706                 :   case NS_STYLE_CURSOR_NONE:
    3707               0 :     c = eCursor_none;
    3708               0 :     break;
    3709                 :   }
    3710                 : 
    3711                 :   // First, try the imgIContainer, if non-null
    3712               0 :   nsresult rv = NS_ERROR_FAILURE;
    3713               0 :   if (aContainer) {
    3714                 :     PRUint32 hotspotX, hotspotY;
    3715                 : 
    3716                 :     // css3-ui says to use the CSS-specified hotspot if present,
    3717                 :     // otherwise use the intrinsic hotspot, otherwise use the top left
    3718                 :     // corner.
    3719               0 :     if (aHaveHotspot) {
    3720                 :       PRInt32 imgWidth, imgHeight;
    3721               0 :       aContainer->GetWidth(&imgWidth);
    3722               0 :       aContainer->GetHeight(&imgHeight);
    3723                 : 
    3724                 :       // XXX NS_MAX(NS_lround(x), 0)?
    3725                 :       hotspotX = aHotspotX > 0.0f
    3726               0 :                    ? PRUint32(aHotspotX + 0.5f) : PRUint32(0);
    3727               0 :       if (hotspotX >= PRUint32(imgWidth))
    3728               0 :         hotspotX = imgWidth - 1;
    3729                 :       hotspotY = aHotspotY > 0.0f
    3730               0 :                    ? PRUint32(aHotspotY + 0.5f) : PRUint32(0);
    3731               0 :       if (hotspotY >= PRUint32(imgHeight))
    3732               0 :         hotspotY = imgHeight - 1;
    3733                 :     } else {
    3734               0 :       hotspotX = 0;
    3735               0 :       hotspotY = 0;
    3736               0 :       nsCOMPtr<nsIProperties> props(do_QueryInterface(aContainer));
    3737               0 :       if (props) {
    3738               0 :         nsCOMPtr<nsISupportsPRUint32> hotspotXWrap, hotspotYWrap;
    3739                 : 
    3740               0 :         props->Get("hotspotX", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotXWrap));
    3741               0 :         props->Get("hotspotY", NS_GET_IID(nsISupportsPRUint32), getter_AddRefs(hotspotYWrap));
    3742                 : 
    3743               0 :         if (hotspotXWrap)
    3744               0 :           hotspotXWrap->GetData(&hotspotX);
    3745               0 :         if (hotspotYWrap)
    3746               0 :           hotspotYWrap->GetData(&hotspotY);
    3747                 :       }
    3748                 :     }
    3749                 : 
    3750               0 :     rv = aWidget->SetCursor(aContainer, hotspotX, hotspotY);
    3751                 :   }
    3752                 : 
    3753               0 :   if (NS_FAILED(rv))
    3754               0 :     aWidget->SetCursor(c);
    3755                 : 
    3756               0 :   return NS_OK;
    3757                 : }
    3758                 : 
    3759                 : class NS_STACK_CLASS nsESMEventCB : public nsDispatchingCallback
    3760               0 : {
    3761                 : public:
    3762               0 :   nsESMEventCB(nsIContent* aTarget) : mTarget(aTarget) {}
    3763                 : 
    3764               0 :   virtual void HandleEvent(nsEventChainPostVisitor& aVisitor)
    3765                 :   {
    3766               0 :     if (aVisitor.mPresContext) {
    3767               0 :       nsIFrame* frame = aVisitor.mPresContext->GetPrimaryFrameFor(mTarget);
    3768               0 :       if (frame) {
    3769                 :         frame->HandleEvent(aVisitor.mPresContext,
    3770                 :                            (nsGUIEvent*) aVisitor.mEvent,
    3771               0 :                            &aVisitor.mEventStatus);
    3772                 :       }
    3773                 :     }
    3774               0 :   }
    3775                 : 
    3776                 :   nsCOMPtr<nsIContent> mTarget;
    3777                 : };
    3778                 : 
    3779                 : nsIFrame*
    3780               0 : nsEventStateManager::DispatchMouseEvent(nsGUIEvent* aEvent, PRUint32 aMessage,
    3781                 :                                         nsIContent* aTargetContent,
    3782                 :                                         nsIContent* aRelatedContent)
    3783                 : {
    3784               0 :   SAMPLE_LABEL("Input", "DispatchMouseEvent");
    3785               0 :   nsEventStatus status = nsEventStatus_eIgnore;
    3786                 :   nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMessage, aEvent->widget,
    3787               0 :                      nsMouseEvent::eReal);
    3788               0 :   event.refPoint = aEvent->refPoint;
    3789               0 :   event.isShift = ((nsMouseEvent*)aEvent)->isShift;
    3790               0 :   event.isControl = ((nsMouseEvent*)aEvent)->isControl;
    3791               0 :   event.isAlt = ((nsMouseEvent*)aEvent)->isAlt;
    3792               0 :   event.isMeta = ((nsMouseEvent*)aEvent)->isMeta;
    3793               0 :   event.pluginEvent = ((nsMouseEvent*)aEvent)->pluginEvent;
    3794               0 :   event.relatedTarget = aRelatedContent;
    3795               0 :   event.inputSource = static_cast<nsMouseEvent*>(aEvent)->inputSource;
    3796                 : 
    3797               0 :   nsWeakFrame previousTarget = mCurrentTarget;
    3798                 : 
    3799               0 :   mCurrentTargetContent = aTargetContent;
    3800                 : 
    3801               0 :   nsIFrame* targetFrame = nsnull;
    3802               0 :   if (aTargetContent) {
    3803               0 :     nsESMEventCB callback(aTargetContent);
    3804                 :     nsEventDispatcher::Dispatch(aTargetContent, mPresContext, &event, nsnull,
    3805               0 :                                 &status, &callback);
    3806                 : 
    3807                 :     // Although the primary frame was checked in event callback, 
    3808                 :     // it may not be the same object after event dispatching and handling.
    3809                 :     // So we need to refetch it.
    3810               0 :     if (mPresContext) {
    3811               0 :       targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent);
    3812                 :     }
    3813                 :   }
    3814                 : 
    3815               0 :   mCurrentTargetContent = nsnull;
    3816               0 :   mCurrentTarget = previousTarget;
    3817                 : 
    3818               0 :   return targetFrame;
    3819                 : }
    3820                 : 
    3821                 : class MouseEnterLeaveDispatcher
    3822                 : {
    3823                 : public:
    3824               0 :   MouseEnterLeaveDispatcher(nsEventStateManager* aESM,
    3825                 :                             nsIContent* aTarget, nsIContent* aRelatedTarget,
    3826                 :                             nsGUIEvent* aEvent, PRUint32 aType)
    3827               0 :   : mESM(aESM), mEvent(aEvent), mType(aType)
    3828                 :   {
    3829                 :     nsPIDOMWindow* win =
    3830               0 :       aTarget ? aTarget->OwnerDoc()->GetInnerWindow() : nsnull;
    3831               0 :     if (win && win->HasMouseEnterLeaveEventListeners()) {
    3832                 :       mRelatedTarget = aRelatedTarget ?
    3833               0 :         aRelatedTarget->FindFirstNonNativeAnonymous() : nsnull;
    3834               0 :       nsINode* commonParent = nsnull;
    3835               0 :       if (aTarget && aRelatedTarget) {
    3836                 :         commonParent =
    3837               0 :           nsContentUtils::GetCommonAncestor(aTarget, aRelatedTarget);
    3838                 :       }
    3839               0 :       nsIContent* current = aTarget;
    3840                 :       // Note, it is ok if commonParent is null!
    3841               0 :       while (current && current != commonParent) {
    3842               0 :         if (!current->IsInNativeAnonymousSubtree()) {
    3843               0 :           mTargets.AppendObject(current);
    3844                 :         }
    3845                 :         // mouseenter/leave is fired only on elements.
    3846               0 :         current = current->GetParent();
    3847                 :       }
    3848                 :     }
    3849               0 :   }
    3850                 : 
    3851               0 :   ~MouseEnterLeaveDispatcher()
    3852               0 :   {
    3853               0 :     for (PRInt32 i = 0; i < mTargets.Count(); ++i) {
    3854               0 :       mESM->DispatchMouseEvent(mEvent, mType, mTargets[i], mRelatedTarget);
    3855                 :     }
    3856               0 :   }
    3857                 : 
    3858                 :   nsEventStateManager*   mESM;
    3859                 :   nsCOMArray<nsIContent> mTargets;
    3860                 :   nsCOMPtr<nsIContent>   mRelatedTarget;
    3861                 :   nsGUIEvent*            mEvent;
    3862                 :   PRUint32               mType;
    3863                 : };
    3864                 : 
    3865                 : void
    3866               0 : nsEventStateManager::NotifyMouseOut(nsGUIEvent* aEvent, nsIContent* aMovingInto)
    3867                 : {
    3868               0 :   if (!mLastMouseOverElement)
    3869               0 :     return;
    3870                 :   // Before firing mouseout, check for recursion
    3871               0 :   if (mLastMouseOverElement == mFirstMouseOutEventElement)
    3872               0 :     return;
    3873                 : 
    3874               0 :   if (mLastMouseOverFrame) {
    3875                 :     // if the frame is associated with a subdocument,
    3876                 :     // tell the subdocument that we're moving out of it
    3877               0 :     nsSubDocumentFrame* subdocFrame = do_QueryFrame(mLastMouseOverFrame.GetFrame());
    3878               0 :     if (subdocFrame) {
    3879               0 :       nsCOMPtr<nsIDocShell> docshell;
    3880               0 :       subdocFrame->GetDocShell(getter_AddRefs(docshell));
    3881               0 :       if (docshell) {
    3882               0 :         nsRefPtr<nsPresContext> presContext;
    3883               0 :         docshell->GetPresContext(getter_AddRefs(presContext));
    3884                 : 
    3885               0 :         if (presContext) {
    3886               0 :           nsEventStateManager* kidESM = presContext->EventStateManager();
    3887                 :           // Not moving into any element in this subdocument
    3888               0 :           kidESM->NotifyMouseOut(aEvent, nsnull);
    3889                 :         }
    3890                 :       }
    3891                 :     }
    3892                 :   }
    3893                 :   // That could have caused DOM events which could wreak havoc. Reverify
    3894                 :   // things and be careful.
    3895               0 :   if (!mLastMouseOverElement)
    3896               0 :     return;
    3897                 : 
    3898                 :   // Store the first mouseOut event we fire and don't refire mouseOut
    3899                 :   // to that element while the first mouseOut is still ongoing.
    3900               0 :   mFirstMouseOutEventElement = mLastMouseOverElement;
    3901                 : 
    3902                 :   // Don't touch hover state if aMovingInto is non-null.  Caller will update
    3903                 :   // hover state itself, and we have optimizations for hover switching between
    3904                 :   // two nearby elements both deep in the DOM tree that would be defeated by
    3905                 :   // switching the hover state to null here.
    3906               0 :   if (!aMovingInto) {
    3907                 :     // Unset :hover
    3908               0 :     SetContentState(nsnull, NS_EVENT_STATE_HOVER);
    3909                 :   }
    3910                 : 
    3911                 :   MouseEnterLeaveDispatcher leaveDispatcher(this, mLastMouseOverElement, aMovingInto,
    3912               0 :                                             aEvent, NS_MOUSELEAVE);
    3913                 : 
    3914                 :   // Fire mouseout
    3915                 :   DispatchMouseEvent(aEvent, NS_MOUSE_EXIT_SYNTH,
    3916               0 :                      mLastMouseOverElement, aMovingInto);
    3917                 :   
    3918               0 :   mLastMouseOverFrame = nsnull;
    3919               0 :   mLastMouseOverElement = nsnull;
    3920                 :   
    3921                 :   // Turn recursion protection back off
    3922               0 :   mFirstMouseOutEventElement = nsnull;
    3923                 : }
    3924                 : 
    3925                 : void
    3926               0 : nsEventStateManager::NotifyMouseOver(nsGUIEvent* aEvent, nsIContent* aContent)
    3927                 : {
    3928               0 :   NS_ASSERTION(aContent, "Mouse must be over something");
    3929                 : 
    3930               0 :   if (mLastMouseOverElement == aContent)
    3931               0 :     return;
    3932                 : 
    3933                 :   // Before firing mouseover, check for recursion
    3934               0 :   if (aContent == mFirstMouseOverEventElement)
    3935               0 :     return;
    3936                 : 
    3937                 :   // Check to see if we're a subdocument and if so update the parent
    3938                 :   // document's ESM state to indicate that the mouse is over the
    3939                 :   // content associated with our subdocument.
    3940               0 :   EnsureDocument(mPresContext);
    3941               0 :   nsIDocument *parentDoc = mDocument->GetParentDocument();
    3942               0 :   if (parentDoc) {
    3943               0 :     nsIContent *docContent = parentDoc->FindContentForSubDocument(mDocument);
    3944               0 :     if (docContent) {
    3945               0 :       nsIPresShell *parentShell = parentDoc->GetShell();
    3946               0 :       if (parentShell) {
    3947               0 :         nsEventStateManager* parentESM = parentShell->GetPresContext()->EventStateManager();
    3948               0 :         parentESM->NotifyMouseOver(aEvent, docContent);
    3949                 :       }
    3950                 :     }
    3951                 :   }
    3952                 :   // Firing the DOM event in the parent document could cause all kinds
    3953                 :   // of havoc.  Reverify and take care.
    3954               0 :   if (mLastMouseOverElement == aContent)
    3955               0 :     return;
    3956                 : 
    3957                 :   // Remember mLastMouseOverElement as the related content for the
    3958                 :   // DispatchMouseEvent() call below, since NotifyMouseOut() resets it, bug 298477.
    3959               0 :   nsCOMPtr<nsIContent> lastMouseOverElement = mLastMouseOverElement;
    3960                 : 
    3961                 :   MouseEnterLeaveDispatcher enterDispatcher(this, aContent, lastMouseOverElement,
    3962               0 :                                             aEvent, NS_MOUSEENTER);
    3963                 :   
    3964               0 :   NotifyMouseOut(aEvent, aContent);
    3965                 : 
    3966                 :   // Store the first mouseOver event we fire and don't refire mouseOver
    3967                 :   // to that element while the first mouseOver is still ongoing.
    3968               0 :   mFirstMouseOverEventElement = aContent;
    3969                 :   
    3970               0 :   SetContentState(aContent, NS_EVENT_STATE_HOVER);
    3971                 :   
    3972                 :   // Fire mouseover
    3973                 :   mLastMouseOverFrame = DispatchMouseEvent(aEvent, NS_MOUSE_ENTER_SYNTH,
    3974               0 :                                            aContent, lastMouseOverElement);
    3975               0 :   mLastMouseOverElement = aContent;
    3976                 :   
    3977                 :   // Turn recursion protection back off
    3978               0 :   mFirstMouseOverEventElement = nsnull;
    3979                 : }
    3980                 : 
    3981                 : void
    3982               0 : nsEventStateManager::GenerateMouseEnterExit(nsGUIEvent* aEvent)
    3983                 : {
    3984               0 :   EnsureDocument(mPresContext);
    3985               0 :   if (!mDocument)
    3986               0 :     return;
    3987                 : 
    3988                 :   // Hold onto old target content through the event and reset after.
    3989               0 :   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
    3990                 : 
    3991               0 :   switch(aEvent->message) {
    3992                 :   case NS_MOUSE_MOVE:
    3993                 :     {
    3994                 :       // Get the target content target (mousemove target == mouseover target)
    3995               0 :       nsCOMPtr<nsIContent> targetElement = GetEventTargetContent(aEvent);
    3996               0 :       if (!targetElement) {
    3997                 :         // We're always over the document root, even if we're only
    3998                 :         // over dead space in a page (whose frame is not associated with
    3999                 :         // any content) or in print preview dead space
    4000               0 :         targetElement = mDocument->GetRootElement();
    4001                 :       }
    4002               0 :       if (targetElement) {
    4003               0 :         NotifyMouseOver(aEvent, targetElement);
    4004                 :       }
    4005                 :     }
    4006               0 :     break;
    4007                 :   case NS_MOUSE_EXIT:
    4008                 :     {
    4009                 :       // This is actually the window mouse exit event. We're not moving
    4010                 :       // into any new element.
    4011                 : 
    4012               0 :       if (mLastMouseOverFrame &&
    4013               0 :           nsContentUtils::GetTopLevelWidget(aEvent->widget) !=
    4014               0 :           nsContentUtils::GetTopLevelWidget(mLastMouseOverFrame->GetNearestWidget())) {
    4015                 :         // the MouseOut event widget doesn't have same top widget with
    4016                 :         // mLastMouseOverFrame, it's a spurious event for mLastMouseOverFrame
    4017               0 :         break;
    4018                 :       }
    4019                 : 
    4020               0 :       NotifyMouseOut(aEvent, nsnull);
    4021                 :     }
    4022               0 :     break;
    4023                 :   }
    4024                 : 
    4025                 :   // reset mCurretTargetContent to what it was
    4026               0 :   mCurrentTargetContent = targetBeforeEvent;
    4027                 : }
    4028                 : 
    4029                 : void
    4030               0 : nsEventStateManager::GenerateDragDropEnterExit(nsPresContext* aPresContext,
    4031                 :                                                nsGUIEvent* aEvent)
    4032                 : {
    4033                 :   //Hold onto old target content through the event and reset after.
    4034               0 :   nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
    4035                 : 
    4036               0 :   switch(aEvent->message) {
    4037                 :   case NS_DRAGDROP_OVER:
    4038                 :     {
    4039                 :       // when dragging from one frame to another, events are fired in the
    4040                 :       // order: dragexit, dragenter, dragleave
    4041               0 :       if (sLastDragOverFrame != mCurrentTarget) {
    4042                 :         //We'll need the content, too, to check if it changed separately from the frames.
    4043               0 :         nsCOMPtr<nsIContent> lastContent;
    4044               0 :         nsCOMPtr<nsIContent> targetContent;
    4045               0 :         mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
    4046                 : 
    4047               0 :         if (sLastDragOverFrame) {
    4048                 :           //The frame has changed but the content may not have. Check before dispatching to content
    4049               0 :           sLastDragOverFrame->GetContentForEvent(aEvent, getter_AddRefs(lastContent));
    4050                 : 
    4051                 :           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
    4052                 :                               aEvent, NS_DRAGDROP_EXIT_SYNTH,
    4053               0 :                               targetContent, lastContent, sLastDragOverFrame);
    4054                 :         }
    4055                 : 
    4056                 :         FireDragEnterOrExit(aPresContext, aEvent, NS_DRAGDROP_ENTER,
    4057               0 :                             lastContent, targetContent, mCurrentTarget);
    4058                 : 
    4059               0 :         if (sLastDragOverFrame) {
    4060                 :           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
    4061                 :                               aEvent, NS_DRAGDROP_LEAVE_SYNTH,
    4062               0 :                               targetContent, lastContent, sLastDragOverFrame);
    4063                 :         }
    4064                 : 
    4065               0 :         sLastDragOverFrame = mCurrentTarget;
    4066                 :       }
    4067                 :     }
    4068               0 :     break;
    4069                 : 
    4070                 :   case NS_DRAGDROP_EXIT:
    4071                 :     {
    4072                 :       //This is actually the window mouse exit event.
    4073               0 :       if (sLastDragOverFrame) {
    4074               0 :         nsCOMPtr<nsIContent> lastContent;
    4075               0 :         sLastDragOverFrame->GetContentForEvent(aEvent, getter_AddRefs(lastContent));
    4076                 : 
    4077               0 :         nsRefPtr<nsPresContext> lastDragOverFramePresContext = sLastDragOverFrame->PresContext();
    4078                 :         FireDragEnterOrExit(lastDragOverFramePresContext,
    4079                 :                             aEvent, NS_DRAGDROP_EXIT_SYNTH,
    4080               0 :                             nsnull, lastContent, sLastDragOverFrame);
    4081                 :         FireDragEnterOrExit(lastDragOverFramePresContext,
    4082                 :                             aEvent, NS_DRAGDROP_LEAVE_SYNTH,
    4083               0 :                             nsnull, lastContent, sLastDragOverFrame);
    4084                 : 
    4085               0 :         sLastDragOverFrame = nsnull;
    4086                 :       }
    4087                 :     }
    4088               0 :     break;
    4089                 :   }
    4090                 : 
    4091                 :   //reset mCurretTargetContent to what it was
    4092               0 :   mCurrentTargetContent = targetBeforeEvent;
    4093                 : 
    4094                 :   // Now flush all pending notifications, for better responsiveness.
    4095               0 :   FlushPendingEvents(aPresContext);
    4096               0 : }
    4097                 : 
    4098                 : void
    4099               0 : nsEventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
    4100                 :                                          nsGUIEvent* aEvent,
    4101                 :                                          PRUint32 aMsg,
    4102                 :                                          nsIContent* aRelatedTarget,
    4103                 :                                          nsIContent* aTargetContent,
    4104                 :                                          nsWeakFrame& aTargetFrame)
    4105                 : {
    4106               0 :   nsEventStatus status = nsEventStatus_eIgnore;
    4107               0 :   nsDragEvent event(NS_IS_TRUSTED_EVENT(aEvent), aMsg, aEvent->widget);
    4108               0 :   event.refPoint = aEvent->refPoint;
    4109               0 :   event.isShift = ((nsMouseEvent*)aEvent)->isShift;
    4110               0 :   event.isControl = ((nsMouseEvent*)aEvent)->isControl;
    4111               0 :   event.isAlt = ((nsMouseEvent*)aEvent)->isAlt;
    4112               0 :   event.isMeta = ((nsMouseEvent*)aEvent)->isMeta;
    4113               0 :   event.relatedTarget = aRelatedTarget;
    4114               0 :   event.inputSource = static_cast<nsMouseEvent*>(aEvent)->inputSource;
    4115                 : 
    4116               0 :   mCurrentTargetContent = aTargetContent;
    4117                 : 
    4118               0 :   if (aTargetContent != aRelatedTarget) {
    4119                 :     //XXX This event should still go somewhere!!
    4120               0 :     if (aTargetContent)
    4121                 :       nsEventDispatcher::Dispatch(aTargetContent, aPresContext, &event,
    4122               0 :                                   nsnull, &status);
    4123                 : 
    4124                 :     // adjust the drag hover if the dragenter event was cancelled or this is a drag exit
    4125               0 :     if (status == nsEventStatus_eConsumeNoDefault || aMsg == NS_DRAGDROP_EXIT)
    4126                 :       SetContentState((aMsg == NS_DRAGDROP_ENTER) ? aTargetContent : nsnull,
    4127               0 :                       NS_EVENT_STATE_DRAGOVER);
    4128                 : 
    4129                 :     // collect any changes to moz cursor settings stored in the event's
    4130                 :     // data transfer.
    4131               0 :     if (aMsg == NS_DRAGDROP_LEAVE_SYNTH || aMsg == NS_DRAGDROP_EXIT_SYNTH ||
    4132                 :         aMsg == NS_DRAGDROP_ENTER)
    4133               0 :       UpdateDragDataTransfer(&event);
    4134                 :   }
    4135                 : 
    4136                 :   // Finally dispatch the event to the frame
    4137               0 :   if (aTargetFrame)
    4138               0 :     aTargetFrame->HandleEvent(aPresContext, &event, &status);
    4139               0 : }
    4140                 : 
    4141                 : void
    4142               0 : nsEventStateManager::UpdateDragDataTransfer(nsDragEvent* dragEvent)
    4143                 : {
    4144               0 :   NS_ASSERTION(dragEvent, "drag event is null in UpdateDragDataTransfer!");
    4145               0 :   if (!dragEvent->dataTransfer)
    4146               0 :     return;
    4147                 : 
    4148               0 :   nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
    4149                 : 
    4150               0 :   if (dragSession) {
    4151                 :     // the initial dataTransfer is the one from the dragstart event that
    4152                 :     // was set on the dragSession when the drag began.
    4153               0 :     nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
    4154               0 :     dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
    4155               0 :     if (initialDataTransfer) {
    4156                 :       // retrieve the current moz cursor setting and save it.
    4157               0 :       nsAutoString mozCursor;
    4158               0 :       dragEvent->dataTransfer->GetMozCursor(mozCursor);
    4159               0 :       initialDataTransfer->SetMozCursor(mozCursor);
    4160                 :     }
    4161                 :   }
    4162                 : }
    4163                 : 
    4164                 : nsresult
    4165               0 : nsEventStateManager::SetClickCount(nsPresContext* aPresContext,
    4166                 :                                    nsMouseEvent *aEvent,
    4167                 :                                    nsEventStatus* aStatus)
    4168                 : {
    4169               0 :   nsCOMPtr<nsIContent> mouseContent;
    4170               0 :   nsIContent* mouseContentParent = nsnull;
    4171               0 :   mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(mouseContent));
    4172               0 :   if (mouseContent) {
    4173               0 :     if (mouseContent->IsNodeOfType(nsINode::eTEXT)) {
    4174               0 :       mouseContent = mouseContent->GetParent();
    4175                 :     }
    4176               0 :     if (mouseContent && mouseContent->IsRootOfNativeAnonymousSubtree()) {
    4177               0 :       mouseContentParent = mouseContent->GetParent();
    4178                 :     }
    4179                 :   }
    4180                 : 
    4181               0 :   switch (aEvent->button) {
    4182                 :   case nsMouseEvent::eLeftButton:
    4183               0 :     if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
    4184               0 :       mLastLeftMouseDownContent = mouseContent;
    4185               0 :       mLastLeftMouseDownContentParent = mouseContentParent;
    4186               0 :     } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
    4187               0 :       if (mLastLeftMouseDownContent == mouseContent ||
    4188               0 :           mLastLeftMouseDownContentParent == mouseContent ||
    4189               0 :           mLastLeftMouseDownContent == mouseContentParent) {
    4190               0 :         aEvent->clickCount = mLClickCount;
    4191               0 :         mLClickCount = 0;
    4192                 :       } else {
    4193               0 :         aEvent->clickCount = 0;
    4194                 :       }
    4195               0 :       mLastLeftMouseDownContent = nsnull;
    4196               0 :       mLastLeftMouseDownContentParent = nsnull;
    4197                 :     }
    4198               0 :     break;
    4199                 : 
    4200                 :   case nsMouseEvent::eMiddleButton:
    4201               0 :     if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
    4202               0 :       mLastMiddleMouseDownContent = mouseContent;
    4203               0 :       mLastMiddleMouseDownContentParent = mouseContentParent;
    4204               0 :     } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
    4205               0 :       if (mLastMiddleMouseDownContent == mouseContent ||
    4206               0 :           mLastMiddleMouseDownContentParent == mouseContent ||
    4207               0 :           mLastMiddleMouseDownContent == mouseContentParent) {
    4208               0 :         aEvent->clickCount = mMClickCount;
    4209               0 :         mMClickCount = 0;
    4210                 :       } else {
    4211               0 :         aEvent->clickCount = 0;
    4212                 :       }
    4213               0 :       mLastMiddleMouseDownContent = nsnull;
    4214               0 :       mLastMiddleMouseDownContentParent = nsnull;
    4215                 :     }
    4216               0 :     break;
    4217                 : 
    4218                 :   case nsMouseEvent::eRightButton:
    4219               0 :     if (aEvent->message == NS_MOUSE_BUTTON_DOWN) {
    4220               0 :       mLastRightMouseDownContent = mouseContent;
    4221               0 :       mLastRightMouseDownContentParent = mouseContentParent;
    4222               0 :     } else if (aEvent->message == NS_MOUSE_BUTTON_UP) {
    4223               0 :       if (mLastRightMouseDownContent == mouseContent ||
    4224               0 :           mLastRightMouseDownContentParent == mouseContent ||
    4225               0 :           mLastRightMouseDownContent == mouseContentParent) {
    4226               0 :         aEvent->clickCount = mRClickCount;
    4227               0 :         mRClickCount = 0;
    4228                 :       } else {
    4229               0 :         aEvent->clickCount = 0;
    4230                 :       }
    4231               0 :       mLastRightMouseDownContent = nsnull;
    4232               0 :       mLastRightMouseDownContentParent = nsnull;
    4233                 :     }
    4234               0 :     break;
    4235                 :   }
    4236                 : 
    4237               0 :   return NS_OK;
    4238                 : }
    4239                 : 
    4240                 : nsresult
    4241               0 : nsEventStateManager::CheckForAndDispatchClick(nsPresContext* aPresContext,
    4242                 :                                               nsMouseEvent *aEvent,
    4243                 :                                               nsEventStatus* aStatus)
    4244                 : {
    4245               0 :   nsresult ret = NS_OK;
    4246               0 :   PRInt32 flags = NS_EVENT_FLAG_NONE;
    4247                 : 
    4248                 :   //If mouse is still over same element, clickcount will be > 1.
    4249                 :   //If it has moved it will be zero, so no click.
    4250               0 :   if (0 != aEvent->clickCount) {
    4251                 :     //Check that the window isn't disabled before firing a click
    4252                 :     //(see bug 366544).
    4253               0 :     if (aEvent->widget) {
    4254                 :       bool enabled;
    4255               0 :       aEvent->widget->IsEnabled(&enabled);
    4256               0 :       if (!enabled) {
    4257               0 :         return ret;
    4258                 :       }
    4259                 :     }
    4260                 :     //fire click
    4261               0 :     if (aEvent->button == nsMouseEvent::eMiddleButton ||
    4262                 :         aEvent->button == nsMouseEvent::eRightButton) {
    4263                 :       flags |=
    4264               0 :         sLeftClickOnly ? NS_EVENT_FLAG_NO_CONTENT_DISPATCH : NS_EVENT_FLAG_NONE;
    4265                 :     }
    4266                 : 
    4267                 :     nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent), NS_MOUSE_CLICK, aEvent->widget,
    4268               0 :                        nsMouseEvent::eReal);
    4269               0 :     event.refPoint = aEvent->refPoint;
    4270               0 :     event.clickCount = aEvent->clickCount;
    4271               0 :     event.isShift = aEvent->isShift;
    4272               0 :     event.isControl = aEvent->isControl;
    4273               0 :     event.isAlt = aEvent->isAlt;
    4274               0 :     event.isMeta = aEvent->isMeta;
    4275               0 :     event.time = aEvent->time;
    4276               0 :     event.flags |= flags;
    4277               0 :     event.button = aEvent->button;
    4278               0 :     event.inputSource = aEvent->inputSource;
    4279                 : 
    4280               0 :     nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
    4281               0 :     if (presShell) {
    4282               0 :       nsCOMPtr<nsIContent> mouseContent = GetEventTargetContent(aEvent);
    4283                 : 
    4284               0 :       ret = presShell->HandleEventWithTarget(&event, mCurrentTarget,
    4285               0 :                                              mouseContent, aStatus);
    4286               0 :       if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2) {
    4287                 :         //fire double click
    4288                 :         nsMouseEvent event2(NS_IS_TRUSTED_EVENT(aEvent), NS_MOUSE_DOUBLECLICK,
    4289               0 :                             aEvent->widget, nsMouseEvent::eReal);
    4290               0 :         event2.refPoint = aEvent->refPoint;
    4291               0 :         event2.clickCount = aEvent->clickCount;
    4292               0 :         event2.isShift = aEvent->isShift;
    4293               0 :         event2.isControl = aEvent->isControl;
    4294               0 :         event2.isAlt = aEvent->isAlt;
    4295               0 :         event2.isMeta = aEvent->isMeta;
    4296               0 :         event2.flags |= flags;
    4297               0 :         event2.button = aEvent->button;
    4298               0 :         event2.inputSource = aEvent->inputSource;
    4299                 : 
    4300               0 :         ret = presShell->HandleEventWithTarget(&event2, mCurrentTarget,
    4301               0 :                                                mouseContent, aStatus);
    4302                 :       }
    4303                 :     }
    4304                 :   }
    4305               0 :   return ret;
    4306                 : }
    4307                 : 
    4308                 : nsIFrame*
    4309               0 : nsEventStateManager::GetEventTarget()
    4310                 : {
    4311                 :   nsIPresShell *shell;
    4312               0 :   if (mCurrentTarget ||
    4313               0 :       !mPresContext ||
    4314               0 :       !(shell = mPresContext->GetPresShell())) {
    4315               0 :     return mCurrentTarget;
    4316                 :   }
    4317                 : 
    4318               0 :   if (mCurrentTargetContent) {
    4319               0 :     mCurrentTarget = mPresContext->GetPrimaryFrameFor(mCurrentTargetContent);
    4320               0 :     if (mCurrentTarget) {
    4321               0 :       return mCurrentTarget;
    4322                 :     }
    4323                 :   }
    4324                 : 
    4325               0 :   nsIFrame* frame = shell->GetEventTargetFrame();
    4326               0 :   return (mCurrentTarget = frame);
    4327                 : }
    4328                 : 
    4329                 : already_AddRefed<nsIContent>
    4330               0 : nsEventStateManager::GetEventTargetContent(nsEvent* aEvent)
    4331                 : {
    4332               0 :   if (aEvent &&
    4333                 :       (aEvent->message == NS_FOCUS_CONTENT ||
    4334                 :        aEvent->message == NS_BLUR_CONTENT)) {
    4335               0 :     nsCOMPtr<nsIContent> content = GetFocusedContent();
    4336               0 :     return content.forget();
    4337                 :   }
    4338                 : 
    4339               0 :   if (mCurrentTargetContent) {
    4340               0 :     nsCOMPtr<nsIContent> content = mCurrentTargetContent;
    4341               0 :     return content.forget();
    4342                 :   }
    4343                 : 
    4344               0 :   nsIContent *content = nsnull;
    4345                 : 
    4346               0 :   nsIPresShell *presShell = mPresContext->GetPresShell();
    4347               0 :   if (presShell) {
    4348               0 :     content = presShell->GetEventTargetContent(aEvent).get();
    4349                 :   }
    4350                 : 
    4351                 :   // Some events here may set mCurrentTarget but not set the corresponding
    4352                 :   // event target in the PresShell.
    4353               0 :   if (!content && mCurrentTarget) {
    4354               0 :     mCurrentTarget->GetContentForEvent(aEvent, &content);
    4355                 :   }
    4356                 : 
    4357               0 :   return content;
    4358                 : }
    4359                 : 
    4360                 : static Element*
    4361               0 : GetLabelTarget(nsIContent* aPossibleLabel)
    4362                 : {
    4363               0 :   nsHTMLLabelElement* label = nsHTMLLabelElement::FromContent(aPossibleLabel);
    4364               0 :   if (!label)
    4365               0 :     return nsnull;
    4366                 : 
    4367               0 :   return label->GetLabeledElement();
    4368                 : }
    4369                 : 
    4370               0 : static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
    4371                 : {
    4372                 :   // Find closest common ancestor
    4373               0 :   if (aNode1 && aNode2) {
    4374                 :     // Find the nearest common ancestor by counting the distance to the
    4375                 :     // root and then walking up again, in pairs.
    4376               0 :     PRInt32 offset = 0;
    4377               0 :     nsIContent *anc1 = aNode1;
    4378               0 :     for (;;) {
    4379               0 :       ++offset;
    4380               0 :       nsIContent* parent = anc1->GetParent();
    4381               0 :       if (!parent)
    4382                 :         break;
    4383               0 :       anc1 = parent;
    4384                 :     }
    4385               0 :     nsIContent *anc2 = aNode2;
    4386               0 :     for (;;) {
    4387               0 :       --offset;
    4388               0 :       nsIContent* parent = anc2->GetParent();
    4389               0 :       if (!parent)
    4390                 :         break;
    4391               0 :       anc2 = parent;
    4392                 :     }
    4393               0 :     if (anc1 == anc2) {
    4394               0 :       anc1 = aNode1;
    4395               0 :       anc2 = aNode2;
    4396               0 :       while (offset > 0) {
    4397               0 :         anc1 = anc1->GetParent();
    4398               0 :         --offset;
    4399                 :       }
    4400               0 :       while (offset < 0) {
    4401               0 :         anc2 = anc2->GetParent();
    4402               0 :         ++offset;
    4403                 :       }
    4404               0 :       while (anc1 != anc2) {
    4405               0 :         anc1 = anc1->GetParent();
    4406               0 :         anc2 = anc2->GetParent();
    4407                 :       }
    4408               0 :       return anc1;
    4409                 :     }
    4410                 :   }
    4411               0 :   return nsnull;
    4412                 : }
    4413                 : 
    4414                 : static Element*
    4415               0 : GetParentElement(Element* aElement)
    4416                 : {
    4417               0 :   nsIContent* p = aElement->GetParent();
    4418               0 :   return (p && p->IsElement()) ? p->AsElement() : nsnull;
    4419                 : }
    4420                 : 
    4421                 : /* static */
    4422                 : void
    4423               0 : nsEventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
    4424                 : {
    4425               0 :   DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
    4426               0 :   Element* ancestor = aElement;
    4427               0 :   while ((ancestor = GetParentElement(ancestor))) {
    4428               0 :     DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen);
    4429                 :   }
    4430               0 : }
    4431                 : 
    4432                 : /* static */
    4433                 : inline void
    4434               0 : nsEventStateManager::DoStateChange(Element* aElement, nsEventStates aState,
    4435                 :                                    bool aAddState)
    4436                 : {
    4437               0 :   if (aAddState) {
    4438               0 :     aElement->AddStates(aState);
    4439                 :   } else {
    4440               0 :     aElement->RemoveStates(aState);
    4441                 :   }
    4442               0 : }
    4443                 : 
    4444                 : /* static */
    4445                 : inline void
    4446               0 : nsEventStateManager::DoStateChange(nsIContent* aContent, nsEventStates aState,
    4447                 :                                    bool aStateAdded)
    4448                 : {
    4449               0 :   if (aContent->IsElement()) {
    4450               0 :     DoStateChange(aContent->AsElement(), aState, aStateAdded);
    4451                 :   }
    4452               0 : }
    4453                 : 
    4454                 : /* static */
    4455                 : void
    4456               0 : nsEventStateManager::UpdateAncestorState(nsIContent* aStartNode,
    4457                 :                                          nsIContent* aStopBefore,
    4458                 :                                          nsEventStates aState,
    4459                 :                                          bool aAddState)
    4460                 : {
    4461               0 :   for (; aStartNode && aStartNode != aStopBefore;
    4462               0 :        aStartNode = aStartNode->GetParent()) {
    4463                 :     // We might be starting with a non-element (e.g. a text node) and
    4464                 :     // if someone is doing something weird might be ending with a
    4465                 :     // non-element too (e.g. a document fragment)
    4466               0 :     if (!aStartNode->IsElement()) {
    4467               0 :       continue;
    4468                 :     }
    4469               0 :     Element* element = aStartNode->AsElement();
    4470               0 :     DoStateChange(element, aState, aAddState);
    4471               0 :     Element* labelTarget = GetLabelTarget(element);
    4472               0 :     if (labelTarget) {
    4473               0 :       DoStateChange(labelTarget, aState, aAddState);
    4474                 :     }
    4475                 :   }
    4476                 : 
    4477               0 :   if (aAddState) {
    4478                 :     // We might be in a situation where a node was in hover both
    4479                 :     // because it was hovered and because the label for it was
    4480                 :     // hovered, and while we stopped hovering the node the label is
    4481                 :     // still hovered.  Or we might have had two nested labels for the
    4482                 :     // same node, and while one is no longer hovered the other still
    4483                 :     // is.  In that situation, the label that's still hovered will be
    4484                 :     // aStopBefore or some ancestor of it, and the call we just made
    4485                 :     // to UpdateAncestorState with aAddState = false would have
    4486                 :     // removed the hover state from the node.  But the node should
    4487                 :     // still be in hover state.  To handle this situation we need to
    4488                 :     // keep walking up the tree and any time we find a label mark its
    4489                 :     // corresponding node as still in our state.
    4490               0 :     for ( ; aStartNode; aStartNode = aStartNode->GetParent()) {
    4491               0 :       if (!aStartNode->IsElement()) {
    4492               0 :         continue;
    4493                 :       }
    4494                 : 
    4495               0 :       Element* labelTarget = GetLabelTarget(aStartNode->AsElement());
    4496               0 :       if (labelTarget && !labelTarget->State().HasState(aState)) {
    4497               0 :         DoStateChange(labelTarget, aState, true);
    4498                 :       }
    4499                 :     }
    4500                 :   }
    4501               0 : }
    4502                 : 
    4503                 : bool
    4504               0 : nsEventStateManager::SetContentState(nsIContent *aContent, nsEventStates aState)
    4505                 : {
    4506                 :   // We manage 4 states here: ACTIVE, HOVER, DRAGOVER, URLTARGET
    4507                 :   // The input must be exactly one of them.
    4508               0 :   NS_PRECONDITION(aState == NS_EVENT_STATE_ACTIVE ||
    4509                 :                   aState == NS_EVENT_STATE_HOVER ||
    4510                 :                   aState == NS_EVENT_STATE_DRAGOVER ||
    4511                 :                   aState == NS_EVENT_STATE_URLTARGET,
    4512                 :                   "Unexpected state");
    4513                 : 
    4514               0 :   nsCOMPtr<nsIContent> notifyContent1;
    4515               0 :   nsCOMPtr<nsIContent> notifyContent2;
    4516                 :   bool updateAncestors;
    4517                 : 
    4518               0 :   if (aState == NS_EVENT_STATE_HOVER || aState == NS_EVENT_STATE_ACTIVE) {
    4519                 :     // Hover and active are hierarchical
    4520               0 :     updateAncestors = true;
    4521                 : 
    4522                 :     // check to see that this state is allowed by style. Check dragover too?
    4523                 :     // XXX Is this even what we want?
    4524               0 :     if (mCurrentTarget)
    4525                 :     {
    4526               0 :       const nsStyleUserInterface* ui = mCurrentTarget->GetStyleUserInterface();
    4527               0 :       if (ui->mUserInput == NS_STYLE_USER_INPUT_NONE)
    4528               0 :         return false;
    4529                 :     }
    4530                 : 
    4531               0 :     if (aState == NS_EVENT_STATE_ACTIVE) {
    4532               0 :       if (aContent != mActiveContent) {
    4533               0 :         notifyContent1 = aContent;
    4534               0 :         notifyContent2 = mActiveContent;
    4535               0 :         mActiveContent = aContent;
    4536                 :       }
    4537                 :     } else {
    4538               0 :       NS_ASSERTION(aState == NS_EVENT_STATE_HOVER, "How did that happen?");
    4539                 :       nsIContent* newHover;
    4540                 :       
    4541               0 :       if (mPresContext->IsDynamic()) {
    4542               0 :         newHover = aContent;
    4543                 :       } else {
    4544               0 :         NS_ASSERTION(!aContent ||
    4545                 :                      aContent->GetCurrentDoc() == mPresContext->PresShell()->GetDocument(),
    4546                 :                      "Unexpected document");
    4547               0 :         nsIFrame *frame = aContent ? aContent->GetPrimaryFrame() : nsnull;
    4548               0 :         if (frame && nsLayoutUtils::IsViewportScrollbarFrame(frame)) {
    4549                 :           // The scrollbars of viewport should not ignore the hover state.
    4550                 :           // Because they are *not* the content of the web page.
    4551               0 :           newHover = aContent;
    4552                 :         } else {
    4553                 :           // All contents of the web page should ignore the hover state.
    4554               0 :           newHover = nsnull;
    4555                 :         }
    4556                 :       }
    4557                 : 
    4558               0 :       if (newHover != mHoverContent) {
    4559               0 :         notifyContent1 = newHover;
    4560               0 :         notifyContent2 = mHoverContent;
    4561               0 :         mHoverContent = newHover;
    4562                 :       }
    4563                 :     }
    4564                 :   } else {
    4565               0 :     updateAncestors = false;
    4566               0 :     if (aState == NS_EVENT_STATE_DRAGOVER) {
    4567               0 :       if (aContent != sDragOverContent) {
    4568               0 :         notifyContent1 = aContent;
    4569               0 :         notifyContent2 = sDragOverContent;
    4570               0 :         sDragOverContent = aContent;
    4571                 :       }
    4572               0 :     } else if (aState == NS_EVENT_STATE_URLTARGET) {
    4573               0 :       if (aContent != mURLTargetContent) {
    4574               0 :         notifyContent1 = aContent;
    4575               0 :         notifyContent2 = mURLTargetContent;
    4576               0 :         mURLTargetContent = aContent;
    4577                 :       }
    4578                 :     }
    4579                 :   }
    4580                 : 
    4581                 :   // We need to keep track of which of notifyContent1 and notifyContent2 is
    4582                 :   // getting the state set and which is getting it unset.  If both are
    4583                 :   // non-null, then notifyContent1 is having the state set and notifyContent2
    4584                 :   // is having it unset.  But if one of them is null, we need to keep track of
    4585                 :   // the right thing for notifyContent1 explicitly.
    4586               0 :   bool content1StateSet = true;
    4587               0 :   if (!notifyContent1) {
    4588                 :     // This is ok because FindCommonAncestor wouldn't find anything
    4589                 :     // anyway if notifyContent1 is null.
    4590               0 :     notifyContent1 = notifyContent2;
    4591               0 :     notifyContent2 = nsnull;
    4592               0 :     content1StateSet = false;
    4593                 :   }
    4594                 : 
    4595               0 :   if (notifyContent1 && mPresContext) {
    4596               0 :     EnsureDocument(mPresContext);
    4597               0 :     if (mDocument) {
    4598               0 :       nsAutoScriptBlocker scriptBlocker;
    4599                 : 
    4600               0 :       if (updateAncestors) {
    4601                 :         nsCOMPtr<nsIContent> commonAncestor =
    4602               0 :           FindCommonAncestor(notifyContent1, notifyContent2);
    4603               0 :         if (notifyContent2) {
    4604                 :           // It's very important to first notify the state removal and
    4605                 :           // then the state addition, because due to labels it's
    4606                 :           // possible that we're removing state from some element but
    4607                 :           // then adding it again (say because mHoverContent changed
    4608                 :           // from a control to its label).
    4609               0 :           UpdateAncestorState(notifyContent2, commonAncestor, aState, false);
    4610                 :         }
    4611                 :         UpdateAncestorState(notifyContent1, commonAncestor, aState,
    4612               0 :                             content1StateSet);
    4613                 :       } else {
    4614               0 :         if (notifyContent2) {
    4615               0 :           DoStateChange(notifyContent2, aState, false);
    4616                 :         }
    4617               0 :         DoStateChange(notifyContent1, aState, content1StateSet);
    4618                 :       }
    4619                 :     }
    4620                 :   }
    4621                 : 
    4622               0 :   return true;
    4623                 : }
    4624                 : 
    4625                 : void
    4626               0 : nsEventStateManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
    4627                 : {
    4628                 :   // inform the focus manager that the content is being removed. If this
    4629                 :   // content is focused, the focus will be removed without firing events.
    4630               0 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    4631               0 :   if (fm)
    4632               0 :     fm->ContentRemoved(aDocument, aContent);
    4633                 : 
    4634               0 :   if (mHoverContent &&
    4635               0 :       nsContentUtils::ContentIsDescendantOf(mHoverContent, aContent)) {
    4636                 :     // Since hover is hierarchical, set the current hover to the
    4637                 :     // content's parent node.
    4638               0 :     SetContentState(aContent->GetParent(), NS_EVENT_STATE_HOVER);
    4639                 :   }
    4640                 : 
    4641               0 :   if (mActiveContent &&
    4642               0 :       nsContentUtils::ContentIsDescendantOf(mActiveContent, aContent)) {
    4643                 :     // Active is hierarchical, so set the current active to the
    4644                 :     // content's parent node.
    4645               0 :     SetContentState(aContent->GetParent(), NS_EVENT_STATE_ACTIVE);
    4646                 :   }
    4647                 : 
    4648               0 :   if (sDragOverContent &&
    4649               0 :       sDragOverContent->OwnerDoc() == aContent->OwnerDoc() &&
    4650               0 :       nsContentUtils::ContentIsDescendantOf(sDragOverContent, aContent)) {
    4651               0 :     sDragOverContent = nsnull;
    4652                 :   }
    4653                 : 
    4654               0 :   if (mLastMouseOverElement &&
    4655               0 :       nsContentUtils::ContentIsDescendantOf(mLastMouseOverElement, aContent)) {
    4656                 :     // See bug 292146 for why we want to null this out
    4657               0 :     mLastMouseOverElement = nsnull;
    4658                 :   }
    4659               0 : }
    4660                 : 
    4661                 : bool
    4662               0 : nsEventStateManager::EventStatusOK(nsGUIEvent* aEvent)
    4663                 : {
    4664                 :   return !(aEvent->message == NS_MOUSE_BUTTON_DOWN &&
    4665                 :       static_cast<nsMouseEvent*>(aEvent)->button == nsMouseEvent::eLeftButton  && 
    4666               0 :       !sNormalLMouseEventInProcess);
    4667                 : }
    4668                 : 
    4669                 : //-------------------------------------------
    4670                 : // Access Key Registration
    4671                 : //-------------------------------------------
    4672                 : void
    4673               0 : nsEventStateManager::RegisterAccessKey(nsIContent* aContent, PRUint32 aKey)
    4674                 : {
    4675               0 :   if (aContent && mAccessKeys.IndexOf(aContent) == -1)
    4676               0 :     mAccessKeys.AppendObject(aContent);
    4677               0 : }
    4678                 : 
    4679                 : void
    4680               0 : nsEventStateManager::UnregisterAccessKey(nsIContent* aContent, PRUint32 aKey)
    4681                 : {
    4682               0 :   if (aContent)
    4683               0 :     mAccessKeys.RemoveObject(aContent);
    4684               0 : }
    4685                 : 
    4686                 : PRUint32
    4687               0 : nsEventStateManager::GetRegisteredAccessKey(nsIContent* aContent)
    4688                 : {
    4689               0 :   NS_ENSURE_ARG(aContent);
    4690                 : 
    4691               0 :   if (mAccessKeys.IndexOf(aContent) == -1)
    4692               0 :     return 0;
    4693                 : 
    4694               0 :   nsAutoString accessKey;
    4695               0 :   aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
    4696               0 :   return accessKey.First();
    4697                 : }
    4698                 : 
    4699                 : void
    4700               0 : nsEventStateManager::EnsureDocument(nsPresContext* aPresContext)
    4701                 : {
    4702               0 :   if (!mDocument)
    4703               0 :     mDocument = aPresContext->Document();
    4704               0 : }
    4705                 : 
    4706                 : void
    4707               0 : nsEventStateManager::FlushPendingEvents(nsPresContext* aPresContext)
    4708                 : {
    4709               0 :   NS_PRECONDITION(nsnull != aPresContext, "nsnull ptr");
    4710               0 :   nsIPresShell *shell = aPresContext->GetPresShell();
    4711               0 :   if (shell) {
    4712               0 :     shell->FlushPendingNotifications(Flush_InterruptibleLayout);
    4713                 :   }
    4714               0 : }
    4715                 : 
    4716                 : nsIContent*
    4717               0 : nsEventStateManager::GetFocusedContent()
    4718                 : {
    4719               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    4720               0 :   if (!fm || !mDocument)
    4721               0 :     return nsnull;
    4722                 : 
    4723               0 :   nsCOMPtr<nsPIDOMWindow> focusedWindow;
    4724                 :   return nsFocusManager::GetFocusedDescendant(mDocument->GetWindow(), false,
    4725               0 :                                               getter_AddRefs(focusedWindow));
    4726                 : }
    4727                 : 
    4728                 : //-------------------------------------------------------
    4729                 : // Return true if the docshell is visible
    4730                 : 
    4731                 : bool
    4732               0 : nsEventStateManager::IsShellVisible(nsIDocShell* aShell)
    4733                 : {
    4734               0 :   NS_ASSERTION(aShell, "docshell is null");
    4735                 : 
    4736               0 :   nsCOMPtr<nsIBaseWindow> basewin = do_QueryInterface(aShell);
    4737               0 :   if (!basewin)
    4738               0 :     return true;
    4739                 : 
    4740               0 :   bool isVisible = true;
    4741               0 :   basewin->GetVisibility(&isVisible);
    4742                 : 
    4743                 :   // We should be doing some additional checks here so that
    4744                 :   // we don't tab into hidden tabs of tabbrowser.  -bryner
    4745                 : 
    4746               0 :   return isVisible;
    4747                 : }
    4748                 : 
    4749                 : nsresult
    4750               0 : nsEventStateManager::DoContentCommandEvent(nsContentCommandEvent* aEvent)
    4751                 : {
    4752               0 :   EnsureDocument(mPresContext);
    4753               0 :   NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE);
    4754               0 :   nsCOMPtr<nsPIDOMWindow> window(mDocument->GetWindow());
    4755               0 :   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
    4756                 : 
    4757               0 :   nsCOMPtr<nsPIWindowRoot> root = window->GetTopWindowRoot();
    4758               0 :   NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
    4759                 :   const char* cmd;
    4760               0 :   switch (aEvent->message) {
    4761                 :     case NS_CONTENT_COMMAND_CUT:
    4762               0 :       cmd = "cmd_cut";
    4763               0 :       break;
    4764                 :     case NS_CONTENT_COMMAND_COPY:
    4765               0 :       cmd = "cmd_copy";
    4766               0 :       break;
    4767                 :     case NS_CONTENT_COMMAND_PASTE:
    4768               0 :       cmd = "cmd_paste";
    4769               0 :       break;
    4770                 :     case NS_CONTENT_COMMAND_DELETE:
    4771               0 :       cmd = "cmd_delete";
    4772               0 :       break;
    4773                 :     case NS_CONTENT_COMMAND_UNDO:
    4774               0 :       cmd = "cmd_undo";
    4775               0 :       break;
    4776                 :     case NS_CONTENT_COMMAND_REDO:
    4777               0 :       cmd = "cmd_redo";
    4778               0 :       break;
    4779                 :     case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE:
    4780               0 :       cmd = "cmd_pasteTransferable";
    4781               0 :       break;
    4782                 :     default:
    4783               0 :       return NS_ERROR_NOT_IMPLEMENTED;
    4784                 :   }
    4785               0 :   nsCOMPtr<nsIController> controller;
    4786               0 :   nsresult rv = root->GetControllerForCommand(cmd, getter_AddRefs(controller));
    4787               0 :   NS_ENSURE_SUCCESS(rv, rv);
    4788               0 :   if (!controller) {
    4789                 :     // When GetControllerForCommand succeeded but there is no controller, the
    4790                 :     // command isn't supported.
    4791               0 :     aEvent->mIsEnabled = false;
    4792                 :   } else {
    4793                 :     bool canDoIt;
    4794               0 :     rv = controller->IsCommandEnabled(cmd, &canDoIt);
    4795               0 :     NS_ENSURE_SUCCESS(rv, rv);
    4796               0 :     aEvent->mIsEnabled = canDoIt;
    4797               0 :     if (canDoIt && !aEvent->mOnlyEnabledCheck) {
    4798               0 :       switch (aEvent->message) {
    4799                 :         case NS_CONTENT_COMMAND_PASTE_TRANSFERABLE: {
    4800               0 :           nsCOMPtr<nsICommandController> commandController = do_QueryInterface(controller);
    4801               0 :           NS_ENSURE_STATE(commandController);
    4802                 : 
    4803               0 :           nsCOMPtr<nsICommandParams> params = do_CreateInstance("@mozilla.org/embedcomp/command-params;1", &rv);
    4804               0 :           NS_ENSURE_SUCCESS(rv, rv);
    4805                 : 
    4806               0 :           rv = params->SetISupportsValue("transferable", aEvent->mTransferable);
    4807               0 :           NS_ENSURE_SUCCESS(rv, rv);
    4808                 : 
    4809               0 :           rv = commandController->DoCommandWithParams(cmd, params);
    4810               0 :           break;
    4811                 :         }
    4812                 :         
    4813                 :         default:
    4814               0 :           rv = controller->DoCommand(cmd);
    4815               0 :           break;
    4816                 :       }
    4817               0 :       NS_ENSURE_SUCCESS(rv, rv);
    4818                 :     }
    4819                 :   }
    4820               0 :   aEvent->mSucceeded = true;
    4821               0 :   return NS_OK;
    4822                 : }
    4823                 : 
    4824                 : nsresult
    4825               0 : nsEventStateManager::DoContentCommandScrollEvent(nsContentCommandEvent* aEvent)
    4826                 : {
    4827               0 :   NS_ENSURE_TRUE(mPresContext, NS_ERROR_NOT_AVAILABLE);
    4828               0 :   nsIPresShell* ps = mPresContext->GetPresShell();
    4829               0 :   NS_ENSURE_TRUE(ps, NS_ERROR_NOT_AVAILABLE);
    4830               0 :   NS_ENSURE_TRUE(aEvent->mScroll.mAmount != 0, NS_ERROR_INVALID_ARG);
    4831                 : 
    4832                 :   nsIScrollableFrame::ScrollUnit scrollUnit;
    4833               0 :   switch (aEvent->mScroll.mUnit) {
    4834                 :     case nsContentCommandEvent::eCmdScrollUnit_Line:
    4835               0 :       scrollUnit = nsIScrollableFrame::LINES;
    4836               0 :       break;
    4837                 :     case nsContentCommandEvent::eCmdScrollUnit_Page:
    4838               0 :       scrollUnit = nsIScrollableFrame::PAGES;
    4839               0 :       break;
    4840                 :     case nsContentCommandEvent::eCmdScrollUnit_Whole:
    4841               0 :       scrollUnit = nsIScrollableFrame::WHOLE;
    4842               0 :       break;
    4843                 :     default:
    4844               0 :       return NS_ERROR_INVALID_ARG;
    4845                 :   }
    4846                 : 
    4847               0 :   aEvent->mSucceeded = true;
    4848                 : 
    4849                 :   nsIScrollableFrame* sf =
    4850               0 :     ps->GetFrameToScrollAsScrollable(nsIPresShell::eEither);
    4851                 :   aEvent->mIsEnabled = sf ? CanScrollOn(sf, aEvent->mScroll.mAmount,
    4852               0 :                                         aEvent->mScroll.mIsHorizontal) :
    4853               0 :                             false;
    4854                 : 
    4855               0 :   if (!aEvent->mIsEnabled || aEvent->mOnlyEnabledCheck) {
    4856               0 :     return NS_OK;
    4857                 :   }
    4858                 : 
    4859               0 :   nsIntPoint pt(0, 0);
    4860               0 :   if (aEvent->mScroll.mIsHorizontal) {
    4861               0 :     pt.x = aEvent->mScroll.mAmount;
    4862                 :   } else {
    4863               0 :     pt.y = aEvent->mScroll.mAmount;
    4864                 :   }
    4865                 : 
    4866                 :   // The caller may want synchronous scrolling.
    4867               0 :   sf->ScrollBy(pt, scrollUnit, nsIScrollableFrame::INSTANT);
    4868               0 :   return NS_OK;
    4869                 : }
    4870                 : 
    4871                 : void
    4872               0 : nsEventStateManager::DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
    4873                 :                                              nsIFrame* aTargetFrame)
    4874                 : {
    4875                 :   // Don't modify the test event which in mInput.
    4876                 :   nsMouseScrollEvent msEvent(
    4877                 :     NS_IS_TRUSTED_EVENT(aEvent->mInput.mMouseScrollEvent),
    4878                 :     aEvent->mInput.mMouseScrollEvent->message,
    4879               0 :     aEvent->mInput.mMouseScrollEvent->widget);
    4880                 : 
    4881               0 :   msEvent.isShift = aEvent->mInput.mMouseScrollEvent->isShift;
    4882               0 :   msEvent.isControl = aEvent->mInput.mMouseScrollEvent->isControl;
    4883               0 :   msEvent.isAlt = aEvent->mInput.mMouseScrollEvent->isAlt;
    4884               0 :   msEvent.isMeta = aEvent->mInput.mMouseScrollEvent->isMeta;
    4885                 : 
    4886               0 :   msEvent.scrollFlags = aEvent->mInput.mMouseScrollEvent->scrollFlags;
    4887               0 :   msEvent.delta = ComputeWheelDeltaFor(aEvent->mInput.mMouseScrollEvent);
    4888               0 :   msEvent.scrollOverflow = aEvent->mInput.mMouseScrollEvent->scrollOverflow;
    4889                 : 
    4890               0 :   bool useSystemSettings = UseSystemScrollSettingFor(&msEvent);
    4891                 : 
    4892                 :   nsIScrollableFrame::ScrollUnit unit;
    4893                 :   bool allowOverrideSystemSettings;
    4894               0 :   switch (ComputeWheelActionFor(&msEvent, useSystemSettings)) {
    4895                 :     case MOUSE_SCROLL_N_LINES:
    4896               0 :       unit = nsIScrollableFrame::LINES;
    4897               0 :       allowOverrideSystemSettings = useSystemSettings;
    4898               0 :       break;
    4899                 :     case MOUSE_SCROLL_PAGE:
    4900               0 :       unit = nsIScrollableFrame::PAGES;
    4901               0 :       allowOverrideSystemSettings = false;
    4902               0 :       break;
    4903                 :     default:
    4904                 :       // Don't use high resolution scrolling when the action doesn't scroll
    4905                 :       // contents.
    4906                 :       return;
    4907                 :   }
    4908                 : 
    4909                 :   DoScrollText(aTargetFrame, &msEvent, unit,
    4910               0 :                allowOverrideSystemSettings, aEvent);
    4911                 : }
    4912                 : 
    4913                 : void
    4914               0 : nsEventStateManager::DoQuerySelectedText(nsQueryContentEvent* aEvent)
    4915                 : {
    4916               0 :   if (RemoteQueryContentEvent(aEvent)) {
    4917               0 :     return;
    4918                 :   }
    4919               0 :   nsContentEventHandler handler(mPresContext);
    4920               0 :   handler.OnQuerySelectedText(aEvent);
    4921                 : }
    4922                 : 
    4923                 : void
    4924               0 : nsEventStateManager::SetActiveManager(nsEventStateManager* aNewESM,
    4925                 :                                       nsIContent* aContent)
    4926                 : {
    4927               0 :   if (sActiveESM && aNewESM != sActiveESM) {
    4928               0 :     sActiveESM->SetContentState(nsnull, NS_EVENT_STATE_ACTIVE);
    4929                 :   }
    4930               0 :   sActiveESM = aNewESM;
    4931               0 :   if (sActiveESM && aContent) {
    4932               0 :     sActiveESM->SetContentState(aContent, NS_EVENT_STATE_ACTIVE);
    4933                 :   }
    4934               0 : }
    4935                 : 
    4936                 : void
    4937               0 : nsEventStateManager::ClearGlobalActiveContent(nsEventStateManager* aClearer)
    4938                 : {
    4939               0 :   if (aClearer) {
    4940               0 :     aClearer->SetContentState(nsnull, NS_EVENT_STATE_ACTIVE);
    4941               0 :     if (sDragOverContent) {
    4942               0 :       aClearer->SetContentState(nsnull, NS_EVENT_STATE_DRAGOVER);
    4943                 :     }
    4944                 :   }
    4945               0 :   if (sActiveESM && aClearer != sActiveESM) {
    4946               0 :     sActiveESM->SetContentState(nsnull, NS_EVENT_STATE_ACTIVE);
    4947                 :   }
    4948               0 :   sActiveESM = nsnull;
    4949            4392 : }

Generated by: LCOV version 1.7