LCOV - code coverage report
Current view: directory - dom/base - nsFocusManager.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 1506 72 4.8 %
Date: 2012-06-02 Functions: 75 14 18.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozila.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Mozilla Foundation
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "mozilla/dom/TabParent.h"
      38                 : 
      39                 : #include "nsFocusManager.h"
      40                 : 
      41                 : #include "nsIInterfaceRequestor.h"
      42                 : #include "nsIInterfaceRequestorUtils.h"
      43                 : #include "nsIServiceManager.h"
      44                 : #include "nsIEnumerator.h"
      45                 : #include "nsGkAtoms.h"
      46                 : #include "nsContentUtils.h"
      47                 : #include "nsIDocument.h"
      48                 : #include "nsIDOMWindow.h"
      49                 : #include "nsPIDOMWindow.h"
      50                 : #include "nsIDOMElement.h"
      51                 : #include "nsIDOMXULElement.h"
      52                 : #include "nsIDOMHTMLFrameElement.h"
      53                 : #include "nsIDOMHTMLInputElement.h"
      54                 : #include "nsIDOMHTMLMapElement.h"
      55                 : #include "nsIDOMHTMLLegendElement.h"
      56                 : #include "nsIDOMDocument.h"
      57                 : #include "nsIDOMRange.h"
      58                 : #include "nsIHTMLDocument.h"
      59                 : #include "nsIFormControlFrame.h"
      60                 : #include "nsGenericHTMLElement.h"
      61                 : #include "nsIDocShell.h"
      62                 : #include "nsIEditorDocShell.h"
      63                 : #include "nsIDocShellTreeItem.h"
      64                 : #include "nsIDocShellTreeOwner.h"
      65                 : #include "nsLayoutUtils.h"
      66                 : #include "nsIPresShell.h"
      67                 : #include "nsIContentViewer.h"
      68                 : #include "nsFrameTraversal.h"
      69                 : #include "nsObjectFrame.h"
      70                 : #include "nsEventDispatcher.h"
      71                 : #include "nsEventStateManager.h"
      72                 : #include "nsIMEStateManager.h"
      73                 : #include "nsIWebNavigation.h"
      74                 : #include "nsCaret.h"
      75                 : #include "nsIBaseWindow.h"
      76                 : #include "nsIViewManager.h"
      77                 : #include "nsFrameSelection.h"
      78                 : #include "nsXULPopupManager.h"
      79                 : #include "nsIDOMNodeFilter.h"
      80                 : #include "nsIScriptObjectPrincipal.h"
      81                 : #include "nsIPrincipal.h"
      82                 : #include "mozilla/dom/Element.h"
      83                 : #include "mozAutoDocUpdate.h"
      84                 : #include "mozilla/Preferences.h"
      85                 : #include "mozilla/LookAndFeel.h"
      86                 : #include "nsIScriptError.h"
      87                 : 
      88                 : #ifdef MOZ_XUL
      89                 : #include "nsIDOMXULTextboxElement.h"
      90                 : #include "nsIDOMXULMenuListElement.h"
      91                 : #endif
      92                 : 
      93                 : #ifdef ACCESSIBILITY
      94                 : #include "nsAccessibilityService.h"
      95                 : #endif
      96                 : 
      97                 : using namespace mozilla;
      98                 : using namespace mozilla::dom;
      99                 : using namespace mozilla::widget;
     100                 : 
     101                 : //#define DEBUG_FOCUS 1
     102                 : //#define DEBUG_FOCUS_NAVIGATION 1
     103                 : #define PRINTTAGF(format, content)                     \
     104                 :   {                                                    \
     105                 :     nsAutoString tag(NS_LITERAL_STRING("(none)"));     \
     106                 :     if (content)                                       \
     107                 :       content->Tag()->ToString(tag);                   \
     108                 :     printf(format, NS_ConvertUTF16toUTF8(tag).get());  \
     109                 :   }
     110                 : 
     111                 : struct nsDelayedBlurOrFocusEvent
     112               0 : {
     113               0 :   nsDelayedBlurOrFocusEvent(PRUint32 aType,
     114                 :                             nsIPresShell* aPresShell,
     115                 :                             nsIDocument* aDocument,
     116                 :                             nsIDOMEventTarget* aTarget)
     117                 :    : mType(aType),
     118                 :      mPresShell(aPresShell),
     119                 :      mDocument(aDocument),
     120               0 :      mTarget(aTarget) { }
     121                 : 
     122               0 :   nsDelayedBlurOrFocusEvent(const nsDelayedBlurOrFocusEvent& aOther)
     123                 :    : mType(aOther.mType),
     124                 :      mPresShell(aOther.mPresShell),
     125                 :      mDocument(aOther.mDocument),
     126               0 :      mTarget(aOther.mTarget) { }
     127                 : 
     128                 :   PRUint32 mType;
     129                 :   nsCOMPtr<nsIPresShell> mPresShell;
     130                 :   nsCOMPtr<nsIDocument> mDocument;
     131                 :   nsCOMPtr<nsIDOMEventTarget> mTarget;
     132                 : };
     133                 : 
     134           51400 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFocusManager)
     135           34533 :   NS_INTERFACE_MAP_ENTRY(nsIFocusManager)
     136           34529 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
     137           24986 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     138           11242 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIFocusManager)
     139              12 : NS_INTERFACE_MAP_END
     140                 : 
     141           44055 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFocusManager)
     142           45457 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFocusManager)
     143                 : 
     144            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsFocusManager)
     145               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFocusManager)
     146               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mActiveWindow)
     147               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedWindow)
     148               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFocusedContent)
     149               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBlurEvent)
     150               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstFocusEvent)
     151               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWindowBeingLowered)
     152               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     153             339 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFocusManager)
     154             339 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mActiveWindow)
     155             339 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedWindow)
     156             339 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFocusedContent)
     157             339 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBlurEvent)
     158             339 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstFocusEvent)
     159             339 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWindowBeingLowered)
     160             339 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     161                 : 
     162                 : nsFocusManager* nsFocusManager::sInstance = nsnull;
     163                 : bool nsFocusManager::sMouseFocusesFormControl = false;
     164                 : bool nsFocusManager::sTestMode = false;
     165                 : 
     166                 : static const char* kObservedPrefs[] = {
     167                 :   "accessibility.browsewithcaret",
     168                 :   "accessibility.tabfocus_applies_to_xul",
     169                 :   "accessibility.mouse_focuses_formcontrol",
     170                 :   "focusmanager.testmode",
     171                 :   NULL
     172                 : };
     173                 : 
     174            1404 : nsFocusManager::nsFocusManager()
     175            1404 : { }
     176                 : 
     177            2806 : nsFocusManager::~nsFocusManager()
     178                 : {
     179            1403 :   Preferences::RemoveObservers(this, kObservedPrefs);
     180                 : 
     181            2806 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     182            1403 :   if (obs) {
     183            1108 :     obs->RemoveObserver(this, "xpcom-shutdown");
     184                 :   }
     185            1403 : }
     186                 : 
     187                 : // static
     188                 : nsresult
     189            1404 : nsFocusManager::Init()
     190                 : {
     191            1404 :   nsFocusManager* fm = new nsFocusManager();
     192            1404 :   NS_ENSURE_TRUE(fm, NS_ERROR_OUT_OF_MEMORY);
     193            1404 :   NS_ADDREF(fm);
     194            1404 :   sInstance = fm;
     195                 : 
     196                 :   nsIContent::sTabFocusModelAppliesToXUL =
     197                 :     Preferences::GetBool("accessibility.tabfocus_applies_to_xul",
     198            1404 :                          nsIContent::sTabFocusModelAppliesToXUL);
     199                 : 
     200                 :   sMouseFocusesFormControl =
     201            1404 :     Preferences::GetBool("accessibility.mouse_focuses_formcontrol", false);
     202                 : 
     203            1404 :   sTestMode = Preferences::GetBool("focusmanager.testmode", false);
     204                 : 
     205            1404 :   Preferences::AddWeakObservers(fm, kObservedPrefs);
     206                 : 
     207            2808 :   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     208            1404 :   if (obs) {
     209            1404 :     obs->AddObserver(fm, "xpcom-shutdown", true);
     210                 :   }
     211                 : 
     212            1404 :   return NS_OK;
     213                 : }
     214                 : 
     215                 : // static
     216                 : void
     217            1403 : nsFocusManager::Shutdown()
     218                 : {
     219            1403 :   NS_IF_RELEASE(sInstance);
     220            1403 : }
     221                 : 
     222                 : NS_IMETHODIMP
     223            1409 : nsFocusManager::Observe(nsISupports *aSubject,
     224                 :                         const char *aTopic,
     225                 :                         const PRUnichar *aData)
     226                 : {
     227            1409 :   if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
     228              10 :     nsDependentString data(aData);
     229               5 :     if (data.EqualsLiteral("accessibility.browsewithcaret")) {
     230               1 :       UpdateCaret(false, true, mFocusedContent);
     231                 :     }
     232               4 :     else if (data.EqualsLiteral("accessibility.tabfocus_applies_to_xul")) {
     233                 :       nsIContent::sTabFocusModelAppliesToXUL =
     234                 :         Preferences::GetBool("accessibility.tabfocus_applies_to_xul",
     235               1 :                              nsIContent::sTabFocusModelAppliesToXUL);
     236                 :     }
     237               3 :     else if (data.EqualsLiteral("accessibility.mouse_focuses_formcontrol")) {
     238                 :       sMouseFocusesFormControl =
     239                 :         Preferences::GetBool("accessibility.mouse_focuses_formcontrol",
     240               1 :                              false);
     241                 :     }
     242               2 :     else if (data.EqualsLiteral("focusmanager.testmode")) {
     243               1 :       sTestMode = Preferences::GetBool("focusmanager.testmode", false);
     244                 :     }
     245            1404 :   } else if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) {
     246            1404 :     mActiveWindow = nsnull;
     247            1404 :     mFocusedWindow = nsnull;
     248            1404 :     mFocusedContent = nsnull;
     249            1404 :     mFirstBlurEvent = nsnull;
     250            1404 :     mFirstFocusEvent = nsnull;
     251            1404 :     mWindowBeingLowered = nsnull;
     252            1404 :     mDelayedBlurFocusEvents.Clear();
     253            1404 :     mMouseDownEventHandlingDocument = nsnull;
     254                 :   }
     255                 : 
     256            1409 :   return NS_OK;
     257                 : }
     258                 : 
     259                 : // given a frame content node, retrieve the nsIDOMWindow displayed in it 
     260                 : static nsPIDOMWindow*
     261               0 : GetContentWindow(nsIContent* aContent)
     262                 : {
     263               0 :   nsIDocument* doc = aContent->GetCurrentDoc();
     264               0 :   if (doc) {
     265               0 :     nsIDocument* subdoc = doc->GetSubDocumentFor(aContent);
     266               0 :     if (subdoc)
     267               0 :       return subdoc->GetWindow();
     268                 :   }
     269                 : 
     270               0 :   return nsnull;
     271                 : }
     272                 : 
     273                 : // get the current window for the given content node 
     274                 : static nsPIDOMWindow*
     275               0 : GetCurrentWindow(nsIContent* aContent)
     276                 : {
     277               0 :   nsIDocument *doc = aContent->GetCurrentDoc();
     278               0 :   return doc ? doc->GetWindow() : nsnull;
     279                 : }
     280                 : 
     281                 : // static
     282                 : nsIContent*
     283               0 : nsFocusManager::GetFocusedDescendant(nsPIDOMWindow* aWindow, bool aDeep,
     284                 :                                      nsPIDOMWindow** aFocusedWindow)
     285                 : {
     286               0 :   NS_ENSURE_TRUE(aWindow, nsnull);
     287                 : 
     288               0 :   *aFocusedWindow = nsnull;
     289                 : 
     290               0 :   nsIContent* currentContent = nsnull;
     291               0 :   nsPIDOMWindow* window = aWindow->GetOuterWindow();
     292               0 :   while (window) {
     293               0 :     *aFocusedWindow = window;
     294               0 :     currentContent = window->GetFocusedNode();
     295               0 :     if (!currentContent || !aDeep)
     296               0 :       break;
     297                 : 
     298               0 :     window = GetContentWindow(currentContent);
     299                 :   }
     300                 : 
     301               0 :   NS_IF_ADDREF(*aFocusedWindow);
     302                 : 
     303               0 :   return currentContent;
     304                 : }
     305                 : 
     306                 : // static
     307                 : nsIContent*
     308               0 : nsFocusManager::GetRedirectedFocus(nsIContent* aContent)
     309                 : {
     310                 : #ifdef MOZ_XUL
     311               0 :   if (aContent->IsXUL()) {
     312               0 :     nsCOMPtr<nsIDOMNode> inputField;
     313                 : 
     314               0 :     nsCOMPtr<nsIDOMXULTextBoxElement> textbox = do_QueryInterface(aContent);
     315               0 :     if (textbox) {
     316               0 :       textbox->GetInputField(getter_AddRefs(inputField));
     317                 :     }
     318                 :     else {
     319               0 :       nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aContent);
     320               0 :       if (menulist) {
     321               0 :         menulist->GetInputField(getter_AddRefs(inputField));
     322                 :       }
     323               0 :       else if (aContent->Tag() == nsGkAtoms::scale) {
     324               0 :         nsCOMPtr<nsIDocument> doc = aContent->GetCurrentDoc();
     325               0 :         if (!doc)
     326               0 :           return nsnull;
     327                 : 
     328               0 :         nsINodeList* children = doc->BindingManager()->GetXBLChildNodesFor(aContent);
     329               0 :         if (children) {
     330               0 :           nsIContent* child = children->GetNodeAt(0);
     331               0 :           if (child && child->Tag() == nsGkAtoms::slider)
     332               0 :             return child;
     333                 :         }
     334                 :       }
     335                 :     }
     336                 : 
     337               0 :     if (inputField) {
     338               0 :       nsCOMPtr<nsIContent> retval = do_QueryInterface(inputField);
     339               0 :       return retval;
     340                 :     }
     341                 :   }
     342                 : #endif
     343                 : 
     344               0 :   return nsnull;
     345                 : }
     346                 : 
     347                 : // static
     348                 : InputContextAction::Cause
     349               0 : nsFocusManager::GetFocusMoveActionCause(PRUint32 aFlags)
     350                 : {
     351               0 :   if (aFlags & nsIFocusManager::FLAG_BYMOUSE) {
     352               0 :     return InputContextAction::CAUSE_MOUSE;
     353               0 :   } else if (aFlags & nsIFocusManager::FLAG_BYKEY) {
     354               0 :     return InputContextAction::CAUSE_KEY;
     355                 :   }
     356               0 :   return InputContextAction::CAUSE_UNKNOWN;
     357                 : }
     358                 : 
     359                 : NS_IMETHODIMP
     360              28 : nsFocusManager::GetActiveWindow(nsIDOMWindow** aWindow)
     361                 : {
     362              28 :   NS_IF_ADDREF(*aWindow = mActiveWindow);
     363              28 :   return NS_OK;
     364                 : }
     365                 : 
     366                 : NS_IMETHODIMP
     367               0 : nsFocusManager::SetActiveWindow(nsIDOMWindow* aWindow)
     368                 : {
     369                 :   // only top-level windows can be made active
     370               0 :   nsCOMPtr<nsPIDOMWindow> piWindow = do_QueryInterface(aWindow);
     371               0 :   if (piWindow)
     372               0 :       piWindow = piWindow->GetOuterWindow();
     373                 : 
     374               0 :   NS_ENSURE_TRUE(piWindow && (piWindow == piWindow->GetPrivateRoot()),
     375                 :                  NS_ERROR_INVALID_ARG);
     376                 : 
     377               0 :   RaiseWindow(piWindow);
     378               0 :   return NS_OK;
     379                 : }
     380                 : 
     381                 : NS_IMETHODIMP
     382               0 : nsFocusManager::GetFocusedWindow(nsIDOMWindow** aFocusedWindow)
     383                 : {
     384               0 :   NS_IF_ADDREF(*aFocusedWindow = mFocusedWindow);
     385               0 :   return NS_OK;
     386                 : }
     387                 : 
     388               0 : NS_IMETHODIMP nsFocusManager::SetFocusedWindow(nsIDOMWindow* aWindowToFocus)
     389                 : {
     390                 : #ifdef DEBUG_FOCUS
     391                 :   printf("<<SetFocusedWindow begin>>\n");
     392                 : #endif
     393                 : 
     394               0 :   nsCOMPtr<nsPIDOMWindow> windowToFocus(do_QueryInterface(aWindowToFocus));
     395               0 :   NS_ENSURE_TRUE(windowToFocus, NS_ERROR_FAILURE);
     396                 : 
     397               0 :   windowToFocus = windowToFocus->GetOuterWindow();
     398                 : 
     399                 :   nsCOMPtr<nsIContent> frameContent =
     400               0 :     do_QueryInterface(windowToFocus->GetFrameElementInternal());
     401               0 :   if (frameContent) {
     402                 :     // pass false for aFocusChanged so that the caret does not get updated
     403                 :     // and scrolling does not occur.
     404               0 :     SetFocusInner(frameContent, 0, false, true);
     405                 :   }
     406                 :   else {
     407                 :     // this is a top-level window. If the window has a child frame focused,
     408                 :     // clear the focus. Otherwise, focus should already be in this frame, or
     409                 :     // already cleared. This ensures that focus will be in this frame and not
     410                 :     // in a child.
     411               0 :     nsIContent* content = windowToFocus->GetFocusedNode();
     412               0 :     if (content) {
     413               0 :       nsCOMPtr<nsIDOMWindow> childWindow = GetContentWindow(content);
     414               0 :       if (childWindow)
     415               0 :         ClearFocus(windowToFocus);
     416                 :     }
     417                 :   }
     418                 : 
     419               0 :   nsCOMPtr<nsPIDOMWindow> rootWindow = windowToFocus->GetPrivateRoot();
     420               0 :   if (rootWindow)
     421               0 :     RaiseWindow(rootWindow);
     422                 : 
     423                 : #ifdef DEBUG_FOCUS
     424                 :   printf("<<SetFocusedWindow end>>\n");
     425                 : #endif
     426                 : 
     427               0 :   return NS_OK;
     428                 : }
     429                 : 
     430                 : NS_IMETHODIMP
     431               0 : nsFocusManager::GetFocusedElement(nsIDOMElement** aFocusedElement)
     432                 : {
     433               0 :   if (mFocusedContent)
     434               0 :     CallQueryInterface(mFocusedContent, aFocusedElement);
     435                 :   else
     436               0 :     *aFocusedElement = nsnull;
     437               0 :   return NS_OK;
     438                 : }
     439                 : 
     440                 : NS_IMETHODIMP
     441               0 : nsFocusManager::GetLastFocusMethod(nsIDOMWindow* aWindow, PRUint32* aLastFocusMethod)
     442                 : {
     443                 :   // the focus method is stored on the inner window
     444               0 :   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
     445               0 :   if (window)
     446               0 :     window = window->GetCurrentInnerWindow();
     447               0 :   if (!window)
     448               0 :     window = mFocusedWindow;
     449                 : 
     450               0 :   *aLastFocusMethod = window ? window->GetFocusMethod() : 0;
     451                 : 
     452               0 :   NS_ASSERTION((*aLastFocusMethod & FOCUSMETHOD_MASK) == *aLastFocusMethod,
     453                 :                "invalid focus method");
     454               0 :   return NS_OK;
     455                 : }
     456                 : 
     457                 : NS_IMETHODIMP
     458               0 : nsFocusManager::SetFocus(nsIDOMElement* aElement, PRUint32 aFlags)
     459                 : {
     460                 : #ifdef DEBUG_FOCUS
     461                 :   printf("<<SetFocus>>\n");
     462                 : #endif
     463                 : 
     464               0 :   nsCOMPtr<nsIContent> newFocus = do_QueryInterface(aElement);
     465               0 :   NS_ENSURE_ARG(newFocus);
     466                 : 
     467               0 :   SetFocusInner(newFocus, aFlags, true, true);
     468                 : 
     469               0 :   return NS_OK;
     470                 : }
     471                 : 
     472                 : NS_IMETHODIMP
     473               0 : nsFocusManager::ElementIsFocusable(nsIDOMElement* aElement, PRUint32 aFlags,
     474                 :                                    bool* aIsFocusable)
     475                 : {
     476               0 :   NS_ENSURE_TRUE(aElement, NS_ERROR_INVALID_ARG);
     477                 : 
     478               0 :   nsCOMPtr<nsIContent> aContent = do_QueryInterface(aElement);
     479                 : 
     480               0 :   *aIsFocusable = CheckIfFocusable(aContent, aFlags) != nsnull;
     481                 : 
     482               0 :   return NS_OK;
     483                 : }
     484                 : 
     485                 : NS_IMETHODIMP
     486               0 : nsFocusManager::MoveFocus(nsIDOMWindow* aWindow, nsIDOMElement* aStartElement,
     487                 :                           PRUint32 aType, PRUint32 aFlags, nsIDOMElement** aElement)
     488                 : {
     489               0 :   *aElement = nsnull;
     490                 : 
     491                 : #ifdef DEBUG_FOCUS
     492                 :   printf("<<MoveFocus Type: %d Flags: %x>>\n<<", aType, aFlags);
     493                 : 
     494                 :   nsCOMPtr<nsPIDOMWindow> focusedWindow = mFocusedWindow;
     495                 :   if (focusedWindow) {
     496                 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(focusedWindow->GetExtantDocument());
     497                 :     if (doc) {
     498                 :       nsCAutoString spec;
     499                 :       doc->GetDocumentURI()->GetSpec(spec);
     500                 :       printf(" [%p] Focused Window: %s", mFocusedWindow.get(), spec.get());
     501                 :     }
     502                 :   }
     503                 :   PRINTTAGF(">> $[[%s]]\n", mFocusedContent);
     504                 : #endif
     505                 : 
     506                 :   // use FLAG_BYMOVEFOCUS when switching focus with MoveFocus unless one of
     507                 :   // the other focus methods is already set, or we're just moving to the root
     508                 :   // or caret position.
     509               0 :   if (aType != MOVEFOCUS_ROOT && aType != MOVEFOCUS_CARET &&
     510                 :       (aFlags & FOCUSMETHOD_MASK) == 0) {
     511               0 :     aFlags |= FLAG_BYMOVEFOCUS;
     512                 :   }
     513                 : 
     514               0 :   nsCOMPtr<nsPIDOMWindow> window;
     515               0 :   nsCOMPtr<nsIContent> startContent;
     516               0 :   if (aStartElement) {
     517               0 :     startContent = do_QueryInterface(aStartElement);
     518               0 :     NS_ENSURE_TRUE(startContent, NS_ERROR_INVALID_ARG);
     519                 : 
     520               0 :     window = GetCurrentWindow(startContent);
     521                 :   }
     522                 :   else {
     523               0 :     window = aWindow ? do_QueryInterface(aWindow) : mFocusedWindow;
     524               0 :     NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
     525               0 :     window = window->GetOuterWindow();
     526                 :   }
     527                 : 
     528               0 :   NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
     529                 : 
     530               0 :   bool noParentTraversal = aFlags & FLAG_NOPARENTFRAME;
     531               0 :   nsCOMPtr<nsIContent> newFocus;
     532                 :   nsresult rv = DetermineElementToMoveFocus(window, startContent, aType, noParentTraversal,
     533               0 :                                             getter_AddRefs(newFocus));
     534               0 :   NS_ENSURE_SUCCESS(rv, rv);
     535                 : 
     536                 : #ifdef DEBUG_FOCUS_NAVIGATION
     537                 :   PRINTTAGF("-> Element to be focused: %s\n", newFocus);
     538                 : #endif
     539                 : 
     540               0 :   if (newFocus) {
     541                 :     // for caret movement, pass false for the aFocusChanged argument,
     542                 :     // otherwise the caret will end up moving to the focus position. This
     543                 :     // would be a problem because the caret would move to the beginning of the
     544                 :     // focused link making it impossible to navigate the caret over a link.
     545               0 :     SetFocusInner(newFocus, aFlags, aType != MOVEFOCUS_CARET, true);
     546               0 :     CallQueryInterface(newFocus, aElement);
     547                 :   }
     548               0 :   else if (aType == MOVEFOCUS_ROOT || aType == MOVEFOCUS_CARET) {
     549                 :     // no content was found, so clear the focus for these two types.
     550               0 :     ClearFocus(window);
     551                 :   }
     552                 : 
     553                 : #ifdef DEBUG_FOCUS
     554                 :   printf("<<MoveFocus end>>\n");
     555                 : #endif
     556                 : 
     557               0 :   return NS_OK;
     558                 : }
     559                 : 
     560                 : NS_IMETHODIMP
     561               0 : nsFocusManager::ClearFocus(nsIDOMWindow* aWindow)
     562                 : {
     563                 : #ifdef DEBUG_FOCUS
     564                 :   printf("<<ClearFocus begin>>\n");
     565                 : #endif
     566                 : 
     567                 :   // if the window to clear is the focused window or an ancestor of the
     568                 :   // focused window, then blur the existing focused content. Otherwise, the
     569                 :   // focus is somewhere else so just update the current node.
     570               0 :   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
     571               0 :   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
     572                 : 
     573               0 :   window = window->GetOuterWindow();
     574               0 :   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
     575                 : 
     576               0 :   if (IsSameOrAncestor(window, mFocusedWindow)) {
     577               0 :     bool isAncestor = (window != mFocusedWindow);
     578               0 :     if (Blur(window, nsnull, isAncestor, true)) {
     579                 :       // if we are clearing the focus on an ancestor of the focused window,
     580                 :       // the ancestor will become the new focused window, so focus it
     581               0 :       if (isAncestor)
     582               0 :         Focus(window, nsnull, 0, true, false, false, true);
     583                 :     }
     584                 :   }
     585                 :   else {
     586               0 :     window->SetFocusedNode(nsnull);
     587                 :   }
     588                 : 
     589                 : #ifdef DEBUG_FOCUS
     590                 :   printf("<<ClearFocus end>>\n");
     591                 : #endif
     592                 : 
     593               0 :   return NS_OK;
     594                 : }
     595                 : 
     596                 : NS_IMETHODIMP
     597               0 : nsFocusManager::GetFocusedElementForWindow(nsIDOMWindow* aWindow,
     598                 :                                            bool aDeep,
     599                 :                                            nsIDOMWindow** aFocusedWindow,
     600                 :                                            nsIDOMElement** aElement)
     601                 : {
     602               0 :   *aElement = nsnull;
     603               0 :   if (aFocusedWindow)
     604               0 :     *aFocusedWindow = nsnull;
     605                 : 
     606               0 :   nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
     607               0 :   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
     608                 : 
     609               0 :   window = window->GetOuterWindow();
     610               0 :   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
     611                 : 
     612               0 :   nsCOMPtr<nsPIDOMWindow> focusedWindow;
     613                 :   nsCOMPtr<nsIContent> focusedContent =
     614               0 :     GetFocusedDescendant(window, aDeep, getter_AddRefs(focusedWindow));
     615               0 :   if (focusedContent)
     616               0 :     CallQueryInterface(focusedContent, aElement);
     617                 : 
     618               0 :   if (aFocusedWindow)
     619               0 :     NS_IF_ADDREF(*aFocusedWindow = focusedWindow);
     620                 : 
     621               0 :   return NS_OK;
     622                 : }
     623                 : 
     624                 : NS_IMETHODIMP
     625               0 : nsFocusManager::MoveCaretToFocus(nsIDOMWindow* aWindow)
     626                 : {
     627               0 :   PRInt32 itemType = nsIDocShellTreeItem::typeChrome;
     628                 : 
     629               0 :   nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(aWindow);
     630               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
     631               0 :   if (dsti) {
     632               0 :     dsti->GetItemType(&itemType);
     633               0 :     if (itemType != nsIDocShellTreeItem::typeChrome) {
     634                 :       // don't move the caret for editable documents
     635               0 :       nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(dsti));
     636               0 :       if (editorDocShell) {
     637                 :         bool isEditable;
     638               0 :         editorDocShell->GetEditable(&isEditable);
     639               0 :         if (isEditable)
     640               0 :           return NS_OK;
     641                 :       }
     642                 : 
     643               0 :       nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(dsti);
     644               0 :       NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
     645                 : 
     646               0 :       nsCOMPtr<nsIPresShell> presShell;
     647               0 :       docShell->GetPresShell(getter_AddRefs(presShell));
     648               0 :       NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
     649                 : 
     650               0 :       nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
     651               0 :       nsCOMPtr<nsIContent> content = window->GetFocusedNode();
     652               0 :       if (content)
     653               0 :         MoveCaretToFocus(presShell, content);
     654                 :     }
     655                 :   }
     656                 : 
     657               0 :   return NS_OK;
     658                 : }
     659                 : 
     660                 : NS_IMETHODIMP
     661               0 : nsFocusManager::WindowRaised(nsIDOMWindow* aWindow)
     662                 : {
     663               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
     664               0 :   NS_ENSURE_TRUE(window && window->IsOuterWindow(), NS_ERROR_INVALID_ARG);
     665                 : 
     666                 : #ifdef DEBUG_FOCUS
     667                 :   printf("Window %p Raised [Currently: %p %p] <<", aWindow, mActiveWindow.get(), mFocusedWindow.get());
     668                 :   nsCAutoString spec;
     669                 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
     670                 :   if (doc) {
     671                 :     doc->GetDocumentURI()->GetSpec(spec);
     672                 :     printf("[%p] Raised Window: %s", aWindow, spec.get());
     673                 :   }
     674                 :   if (mActiveWindow) {
     675                 :     doc = do_QueryInterface(mActiveWindow->GetExtantDocument());
     676                 :     if (doc) {
     677                 :       doc->GetDocumentURI()->GetSpec(spec);
     678                 :       printf(" [%p] Active Window: %s", mActiveWindow.get(), spec.get());
     679                 :     }
     680                 :   }
     681                 :   printf(">>\n");
     682                 : #endif
     683                 : 
     684               0 :   if (mActiveWindow == window) {
     685                 :     // The window is already active, so there is no need to focus anything,
     686                 :     // but make sure that the right widget is focused. This is a special case
     687                 :     // for Windows because when restoring a minimized window, a second
     688                 :     // activation will occur and the top-level widget could be focused instead
     689                 :     // of the child we want. We solve this by calling SetFocus to ensure that
     690                 :     // what the focus manager thinks should be the current widget is actually
     691                 :     // focused.
     692               0 :     EnsureCurrentWidgetFocused();
     693               0 :     return NS_OK;
     694                 :   }
     695                 : 
     696                 :   // lower the existing window, if any. This shouldn't happen usually.
     697               0 :   if (mActiveWindow)
     698               0 :     WindowLowered(mActiveWindow);
     699                 : 
     700               0 :   nsCOMPtr<nsIWebNavigation> webnav(do_GetInterface(aWindow));
     701               0 :   nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(webnav));
     702                 :   // If there's no docShellAsItem, this window must have been closed,
     703                 :   // in that case there is no tree owner.
     704               0 :   NS_ENSURE_TRUE(docShellAsItem, NS_OK);
     705                 : 
     706                 :   // set this as the active window
     707               0 :   mActiveWindow = window;
     708                 : 
     709                 :   // ensure that the window is enabled and visible
     710               0 :   nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
     711               0 :   docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner));
     712               0 :   nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(treeOwner);
     713               0 :   if (baseWindow) {
     714               0 :     bool isEnabled = true;
     715               0 :     if (NS_SUCCEEDED(baseWindow->GetEnabled(&isEnabled)) && !isEnabled) {
     716               0 :       return NS_ERROR_FAILURE;
     717                 :     }
     718                 : 
     719               0 :     baseWindow->SetVisibility(true);
     720                 :   }
     721                 : 
     722                 :   // inform the DOM window that it has activated, so that the active attribute
     723                 :   // is updated on the window
     724               0 :   window->ActivateOrDeactivate(true);
     725                 : 
     726                 :   // send activate event
     727               0 :   nsCOMPtr<nsIDocument> document = do_QueryInterface(window->GetExtantDocument());
     728                 :   nsContentUtils::DispatchTrustedEvent(document,
     729                 :                                        window,
     730               0 :                                        NS_LITERAL_STRING("activate"),
     731               0 :                                        true, true, nsnull);
     732                 : 
     733                 :   // retrieve the last focused element within the window that was raised
     734               0 :   nsCOMPtr<nsPIDOMWindow> currentWindow;
     735                 :   nsCOMPtr<nsIContent> currentFocus =
     736               0 :     GetFocusedDescendant(window, true, getter_AddRefs(currentWindow));
     737                 : 
     738               0 :   NS_ASSERTION(currentWindow, "window raised with no window current");
     739               0 :   if (!currentWindow)
     740               0 :     return NS_OK;
     741                 : 
     742               0 :   nsCOMPtr<nsIDocShell> currentDocShell = currentWindow->GetDocShell();
     743                 : 
     744               0 :   nsCOMPtr<nsIPresShell> presShell;
     745               0 :   currentDocShell->GetPresShell(getter_AddRefs(presShell));
     746               0 :   if (presShell) {
     747                 :     // disable selection mousedown state on activation
     748                 :     // XXXndeakin P3 not sure if this is necessary, but it doesn't hurt
     749               0 :     nsRefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection();
     750               0 :     frameSelection->SetMouseDownState(false);
     751                 :   }
     752                 : 
     753               0 :   Focus(currentWindow, currentFocus, 0, true, false, true, true);
     754                 : 
     755               0 :   return NS_OK;
     756                 : }
     757                 : 
     758                 : NS_IMETHODIMP
     759               0 : nsFocusManager::WindowLowered(nsIDOMWindow* aWindow)
     760                 : {
     761               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
     762               0 :   NS_ENSURE_TRUE(window && window->IsOuterWindow(), NS_ERROR_INVALID_ARG);
     763                 : 
     764                 : #ifdef DEBUG_FOCUS
     765                 :   printf("Window %p Lowered [Currently: %p %p] <<", aWindow, mActiveWindow.get(), mFocusedWindow.get());
     766                 :   nsCAutoString spec;
     767                 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
     768                 :   if (doc) {
     769                 :     doc->GetDocumentURI()->GetSpec(spec);
     770                 :     printf("[%p] Lowered Window: %s", aWindow, spec.get());
     771                 :   }
     772                 :   if (mActiveWindow) {
     773                 :     doc = do_QueryInterface(mActiveWindow->GetExtantDocument());
     774                 :     if (doc) {
     775                 :       doc->GetDocumentURI()->GetSpec(spec);
     776                 :       printf(" [%p] Active Window: %s", mActiveWindow.get(), spec.get());
     777                 :     }
     778                 :   }
     779                 :   printf(">>\n");
     780                 : #endif
     781                 : 
     782               0 :   if (mActiveWindow != window)
     783               0 :     return NS_OK;
     784                 : 
     785                 :   // clear the mouse capture as the active window has changed
     786               0 :   nsIPresShell::SetCapturingContent(nsnull, 0);
     787                 : 
     788                 :   // inform the DOM window that it has deactivated, so that the active
     789                 :   // attribute is updated on the window
     790               0 :   window->ActivateOrDeactivate(false);
     791                 : 
     792                 :   // send deactivate event
     793               0 :   nsCOMPtr<nsIDocument> document = do_QueryInterface(window->GetExtantDocument());
     794                 :   nsContentUtils::DispatchTrustedEvent(document,
     795                 :                                        window,
     796               0 :                                        NS_LITERAL_STRING("deactivate"),
     797               0 :                                        true, true, nsnull);
     798                 : 
     799                 :   // keep track of the window being lowered, so that attempts to raise the
     800                 :   // window can be prevented until we return. Otherwise, focus can get into
     801                 :   // an unusual state.
     802               0 :   mWindowBeingLowered = mActiveWindow;
     803               0 :   mActiveWindow = nsnull;
     804                 : 
     805               0 :   if (mFocusedWindow)
     806               0 :     Blur(nsnull, nsnull, true, true);
     807                 : 
     808               0 :   mWindowBeingLowered = nsnull;
     809                 : 
     810               0 :   return NS_OK;
     811                 : }
     812                 : 
     813                 : nsresult
     814               0 : nsFocusManager::ContentRemoved(nsIDocument* aDocument, nsIContent* aContent)
     815                 : {
     816               0 :   NS_ENSURE_ARG(aDocument);
     817               0 :   NS_ENSURE_ARG(aContent);
     818                 : 
     819               0 :   nsPIDOMWindow *window = aDocument->GetWindow();
     820               0 :   if (!window)
     821               0 :     return NS_OK;
     822                 : 
     823                 :   // if the content is currently focused in the window, or is an ancestor
     824                 :   // of the currently focused element, reset the focus within that window.
     825               0 :   nsIContent* content = window->GetFocusedNode();
     826               0 :   if (content && nsContentUtils::ContentIsDescendantOf(content, aContent)) {
     827               0 :     bool shouldShowFocusRing = window->ShouldShowFocusRing();
     828               0 :     window->SetFocusedNode(nsnull);
     829                 : 
     830               0 :     nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
     831               0 :     if (docShell) {
     832               0 :       nsCOMPtr<nsIPresShell> presShell;
     833               0 :       docShell->GetPresShell(getter_AddRefs(presShell));
     834               0 :       nsIMEStateManager::OnRemoveContent(presShell->GetPresContext(), content);
     835                 :     }
     836                 : 
     837                 :     // if this window is currently focused, clear the global focused
     838                 :     // element as well, but don't fire any events.
     839               0 :     if (window == mFocusedWindow) {
     840               0 :       mFocusedContent = nsnull;
     841                 :     }
     842                 :     else {
     843                 :       // Check if the node that was focused is an iframe or similar by looking
     844                 :       // if it has a subdocument. This would indicate that this focused iframe
     845                 :       // and its descendants will be going away. We will need to move the
     846                 :       // focus somewhere else, so just clear the focus in the toplevel window
     847                 :       // so that no element is focused.
     848               0 :       nsIDocument* subdoc = aDocument->GetSubDocumentFor(content);
     849               0 :       if (subdoc) {
     850               0 :         nsCOMPtr<nsISupports> container = subdoc->GetContainer();
     851               0 :         nsCOMPtr<nsPIDOMWindow> childWindow = do_GetInterface(container);
     852               0 :         if (childWindow && IsSameOrAncestor(childWindow, mFocusedWindow)) {
     853               0 :           ClearFocus(mActiveWindow);
     854                 :         }
     855                 :       }
     856                 :     }
     857                 : 
     858               0 :     NotifyFocusStateChange(content, shouldShowFocusRing, false);
     859                 :   }
     860                 : 
     861               0 :   return NS_OK;
     862                 : }
     863                 : 
     864                 : NS_IMETHODIMP
     865               0 : nsFocusManager::WindowShown(nsIDOMWindow* aWindow, bool aNeedsFocus)
     866                 : {
     867               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
     868               0 :   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
     869                 : 
     870               0 :   window = window->GetOuterWindow();
     871                 : 
     872                 : #ifdef DEBUG_FOCUS
     873                 :   printf("Window %p Shown [Currently: %p %p] <<", window.get(), mActiveWindow.get(), mFocusedWindow.get());
     874                 :   nsCAutoString spec;
     875                 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
     876                 :   if (doc) {
     877                 :     doc->GetDocumentURI()->GetSpec(spec);
     878                 :     printf("Shown Window: %s", spec.get());
     879                 :   }
     880                 : 
     881                 :   if (mFocusedWindow) {
     882                 :     doc = do_QueryInterface(mFocusedWindow->GetExtantDocument());
     883                 :     if (doc) {
     884                 :       doc->GetDocumentURI()->GetSpec(spec);
     885                 :       printf(" Focused Window: %s", spec.get());
     886                 :     }
     887                 :   }
     888                 :   printf(">>\n");
     889                 : #endif
     890                 : 
     891               0 :   if (mFocusedWindow != window)
     892               0 :     return NS_OK;
     893                 : 
     894               0 :   if (aNeedsFocus) {
     895               0 :     nsCOMPtr<nsPIDOMWindow> currentWindow;
     896                 :     nsCOMPtr<nsIContent> currentFocus =
     897               0 :       GetFocusedDescendant(window, true, getter_AddRefs(currentWindow));
     898               0 :     if (currentWindow)
     899               0 :       Focus(currentWindow, currentFocus, 0, true, false, false, true);
     900                 :   }
     901                 :   else {
     902                 :     // Sometimes, an element in a window can be focused before the window is
     903                 :     // visible, which would mean that the widget may not be properly focused.
     904                 :     // When the window becomes visible, make sure the right widget is focused.
     905               0 :     EnsureCurrentWidgetFocused();
     906                 :   }
     907                 : 
     908               0 :   return NS_OK;
     909                 : }
     910                 : 
     911                 : NS_IMETHODIMP
     912               0 : nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
     913                 : {
     914                 :   // if there is no window or it is not the same or an ancestor of the
     915                 :   // currently focused window, just return, as the current focus will not
     916                 :   // be affected.
     917                 : 
     918               0 :   nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
     919               0 :   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
     920                 : 
     921               0 :   window = window->GetOuterWindow();
     922                 : 
     923                 : #ifdef DEBUG_FOCUS
     924                 :   printf("Window %p Hidden [Currently: %p %p] <<", window.get(), mActiveWindow.get(), mFocusedWindow.get());
     925                 :   nsCAutoString spec;
     926                 :   nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
     927                 :   if (doc) {
     928                 :     doc->GetDocumentURI()->GetSpec(spec);
     929                 :     printf("Hide Window: %s", spec.get());
     930                 :   }
     931                 : 
     932                 :   if (mFocusedWindow) {
     933                 :     doc = do_QueryInterface(mFocusedWindow->GetExtantDocument());
     934                 :     if (doc) {
     935                 :       doc->GetDocumentURI()->GetSpec(spec);
     936                 :       printf(" Focused Window: %s", spec.get());
     937                 :     }
     938                 :   }
     939                 : 
     940                 :   if (mActiveWindow) {
     941                 :     doc = do_QueryInterface(mActiveWindow->GetExtantDocument());
     942                 :     if (doc) {
     943                 :       doc->GetDocumentURI()->GetSpec(spec);
     944                 :       printf(" Active Window: %s", spec.get());
     945                 :     }
     946                 :   }
     947                 :   printf(">>\n");
     948                 : #endif
     949                 : 
     950               0 :   if (!IsSameOrAncestor(window, mFocusedWindow))
     951               0 :     return NS_OK;
     952                 : 
     953                 :   // at this point, we know that the window being hidden is either the focused
     954                 :   // window, or an ancestor of the focused window. Either way, the focus is no
     955                 :   // longer valid, so it needs to be updated.
     956                 : 
     957               0 :   nsIContent* oldFocusedContent = mFocusedContent;
     958               0 :   mFocusedContent = nsnull;
     959                 : 
     960               0 :   if (oldFocusedContent && oldFocusedContent->IsInDoc()) {
     961                 :     NotifyFocusStateChange(oldFocusedContent,
     962               0 :                            mFocusedWindow->ShouldShowFocusRing(),
     963               0 :                            false);
     964                 :   }
     965                 : 
     966               0 :   nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
     967               0 :   nsCOMPtr<nsIPresShell> presShell;
     968               0 :   focusedDocShell->GetPresShell(getter_AddRefs(presShell));
     969                 : 
     970               0 :   nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
     971               0 :   if (presShell) {
     972                 :     nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull,
     973               0 :                                      GetFocusMoveActionCause(0));
     974               0 :     SetCaretVisible(presShell, false, nsnull);
     975                 :   }
     976                 : 
     977                 :   // if the docshell being hidden is being destroyed, then we want to move
     978                 :   // focus somewhere else. Call ClearFocus on the toplevel window, which
     979                 :   // will have the effect of clearing the focus and moving the focused window
     980                 :   // to the toplevel window. But if the window isn't being destroyed, we are
     981                 :   // likely just loading a new document in it, so we want to maintain the
     982                 :   // focused window so that the new document gets properly focused.
     983                 :   bool beingDestroyed;
     984               0 :   nsCOMPtr<nsIDocShell> docShellBeingHidden = window->GetDocShell();
     985               0 :   docShellBeingHidden->IsBeingDestroyed(&beingDestroyed);
     986               0 :   if (beingDestroyed) {
     987                 :     // There is usually no need to do anything if a toplevel window is going
     988                 :     // away, as we assume that WindowLowered will be called. However, this may
     989                 :     // not happen if nsIAppStartup::eForceQuit is used to quit, and can cause
     990                 :     // a leak. So if the active window is being destroyed, call WindowLowered
     991                 :     // directly.
     992               0 :     NS_ASSERTION(mFocusedWindow->IsOuterWindow(), "outer window expected");
     993               0 :     if (mActiveWindow == mFocusedWindow || mActiveWindow == window)
     994               0 :       WindowLowered(mActiveWindow);
     995                 :     else
     996               0 :       ClearFocus(mActiveWindow);
     997               0 :     return NS_OK;
     998                 :   }
     999                 : 
    1000                 :   // if the window being hidden is an ancestor of the focused window, adjust
    1001                 :   // the focused window so that it points to the one being hidden. This
    1002                 :   // ensures that the focused window isn't in a chain of frames that doesn't
    1003                 :   // exist any more.
    1004               0 :   if (window != mFocusedWindow) {
    1005               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_GetInterface(mFocusedWindow));
    1006               0 :     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
    1007               0 :     if (dsti) {
    1008               0 :       nsCOMPtr<nsIDocShellTreeItem> parentDsti;
    1009               0 :       dsti->GetParent(getter_AddRefs(parentDsti));
    1010               0 :       nsCOMPtr<nsPIDOMWindow> parentWindow = do_GetInterface(parentDsti);
    1011               0 :       if (parentWindow)
    1012               0 :         parentWindow->SetFocusedNode(nsnull);
    1013                 :     }
    1014                 : 
    1015               0 :     mFocusedWindow = window;
    1016                 :   }
    1017                 : 
    1018               0 :   return NS_OK;
    1019                 : }
    1020                 : 
    1021                 : NS_IMETHODIMP
    1022               0 : nsFocusManager::FireDelayedEvents(nsIDocument* aDocument)
    1023                 : {
    1024               0 :   NS_ENSURE_ARG(aDocument);
    1025                 : 
    1026                 :   // fire any delayed focus and blur events in the same order that they were added
    1027               0 :   for (PRUint32 i = 0; i < mDelayedBlurFocusEvents.Length(); i++)
    1028                 :   {
    1029               0 :     if (mDelayedBlurFocusEvents[i].mDocument == aDocument &&
    1030               0 :         !aDocument->EventHandlingSuppressed()) {
    1031               0 :       PRUint32 type = mDelayedBlurFocusEvents[i].mType;
    1032               0 :       nsCOMPtr<nsIDOMEventTarget> target = mDelayedBlurFocusEvents[i].mTarget;
    1033               0 :       nsCOMPtr<nsIPresShell> presShell = mDelayedBlurFocusEvents[i].mPresShell;
    1034               0 :       mDelayedBlurFocusEvents.RemoveElementAt(i);
    1035               0 :       SendFocusOrBlurEvent(type, presShell, aDocument, target, 0, false);
    1036               0 :       --i;
    1037                 :     }
    1038                 :   }
    1039                 : 
    1040               0 :   return NS_OK;
    1041                 : }
    1042                 : 
    1043                 : NS_IMETHODIMP
    1044               0 : nsFocusManager::FocusPlugin(nsIContent* aContent)
    1045                 : {
    1046               0 :   NS_ENSURE_ARG(aContent);
    1047               0 :   SetFocusInner(aContent, 0, true, false);
    1048               0 :   return NS_OK;
    1049                 : }
    1050                 : 
    1051                 : /* static */
    1052                 : void
    1053               0 : nsFocusManager::NotifyFocusStateChange(nsIContent* aContent,
    1054                 :                                        bool aWindowShouldShowFocusRing,
    1055                 :                                        bool aGettingFocus)
    1056                 : {
    1057               0 :   if (!aContent->IsElement()) {
    1058               0 :     return;
    1059                 :   }
    1060               0 :   nsEventStates eventState = NS_EVENT_STATE_FOCUS;
    1061               0 :   if (aWindowShouldShowFocusRing) {
    1062               0 :     eventState |= NS_EVENT_STATE_FOCUSRING;
    1063                 :   }
    1064               0 :   if (aGettingFocus) {
    1065               0 :     aContent->AsElement()->AddStates(eventState);
    1066                 :   } else {
    1067               0 :     aContent->AsElement()->RemoveStates(eventState);
    1068                 :   }
    1069                 : }
    1070                 : 
    1071                 : // static
    1072                 : void
    1073               0 : nsFocusManager::EnsureCurrentWidgetFocused()
    1074                 : {
    1075               0 :   if (!mFocusedWindow || sTestMode)
    1076               0 :     return;
    1077                 : 
    1078                 :   // get the main child widget for the focused window and ensure that the
    1079                 :   // platform knows that this widget is focused.
    1080               0 :   nsCOMPtr<nsIDocShell> docShell = mFocusedWindow->GetDocShell();
    1081               0 :   if (docShell) {
    1082               0 :     nsCOMPtr<nsIPresShell> presShell;
    1083               0 :     docShell->GetPresShell(getter_AddRefs(presShell));
    1084               0 :     if (presShell) {
    1085               0 :       nsIViewManager* vm = presShell->GetViewManager();
    1086               0 :       if (vm) {
    1087               0 :         nsCOMPtr<nsIWidget> widget;
    1088               0 :         vm->GetRootWidget(getter_AddRefs(widget));
    1089               0 :         if (widget)
    1090               0 :           widget->SetFocus(false);
    1091                 :       }
    1092                 :     }
    1093                 :   }
    1094                 : }
    1095                 : 
    1096                 : void
    1097               0 : nsFocusManager::SetFocusInner(nsIContent* aNewContent, PRInt32 aFlags,
    1098                 :                               bool aFocusChanged, bool aAdjustWidget)
    1099                 : {
    1100                 :   // if the element is not focusable, just return and leave the focus as is
    1101               0 :   nsCOMPtr<nsIContent> contentToFocus = CheckIfFocusable(aNewContent, aFlags);
    1102               0 :   if (!contentToFocus)
    1103                 :     return;
    1104                 : 
    1105                 :   // check if the element to focus is a frame (iframe) containing a child
    1106                 :   // document. Frames are never directly focused; instead focusing a frame
    1107                 :   // means focus what is inside the frame. To do this, the descendant content
    1108                 :   // within the frame is retrieved and that will be focused instead.
    1109               0 :   nsCOMPtr<nsPIDOMWindow> newWindow;
    1110               0 :   nsCOMPtr<nsPIDOMWindow> subWindow = GetContentWindow(contentToFocus);
    1111               0 :   if (subWindow) {
    1112               0 :     contentToFocus = GetFocusedDescendant(subWindow, true, getter_AddRefs(newWindow));
    1113                 :     // since a window is being refocused, clear aFocusChanged so that the
    1114                 :     // caret position isn't updated.
    1115               0 :     aFocusChanged = false;
    1116                 :   }
    1117                 : 
    1118                 :   // unless it was set above, retrieve the window for the element to focus
    1119               0 :   if (!newWindow)
    1120               0 :     newWindow = GetCurrentWindow(contentToFocus);
    1121                 : 
    1122                 :   // if the element is already focused, just return. Note that this happens
    1123                 :   // after the frame check above so that we compare the element that will be
    1124                 :   // focused rather than the frame it is in.
    1125               0 :   if (!newWindow || (newWindow == mFocusedWindow && contentToFocus == mFocusedContent))
    1126                 :     return;
    1127                 : 
    1128                 :   // don't allow focus to be placed in docshells or descendants of docshells
    1129                 :   // that are being destroyed. Also, ensure that the page hasn't been
    1130                 :   // unloaded. The prevents content from being refocused during an unload event.
    1131               0 :   nsCOMPtr<nsIDocShell> newDocShell = newWindow->GetDocShell();
    1132               0 :   nsCOMPtr<nsIDocShell> docShell = newDocShell;
    1133               0 :   while (docShell) {
    1134                 :     bool inUnload;
    1135               0 :     docShell->GetIsInUnload(&inUnload);
    1136               0 :     if (inUnload)
    1137                 :       return;
    1138                 : 
    1139                 :     bool beingDestroyed;
    1140               0 :     docShell->IsBeingDestroyed(&beingDestroyed);
    1141               0 :     if (beingDestroyed)
    1142                 :       return;
    1143                 : 
    1144               0 :     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(docShell);
    1145               0 :     nsCOMPtr<nsIDocShellTreeItem> parentDsti;
    1146               0 :     dsti->GetParent(getter_AddRefs(parentDsti));
    1147               0 :     docShell = do_QueryInterface(parentDsti);
    1148                 :   }
    1149                 : 
    1150                 :   // if the new element is in the same window as the currently focused element 
    1151               0 :   bool isElementInFocusedWindow = (mFocusedWindow == newWindow);
    1152                 : 
    1153               0 :   if (!isElementInFocusedWindow && mFocusedWindow && newWindow &&
    1154               0 :       nsContentUtils::IsHandlingKeyBoardEvent()) {
    1155                 :     nsCOMPtr<nsIScriptObjectPrincipal> focused =
    1156               0 :       do_QueryInterface(mFocusedWindow);
    1157                 :     nsCOMPtr<nsIScriptObjectPrincipal> newFocus =
    1158               0 :       do_QueryInterface(newWindow);
    1159               0 :     nsIPrincipal* focusedPrincipal = focused->GetPrincipal();
    1160               0 :     nsIPrincipal* newPrincipal = newFocus->GetPrincipal();
    1161               0 :     if (!focusedPrincipal || !newPrincipal) {
    1162                 :       return;
    1163                 :     }
    1164               0 :     bool subsumes = false;
    1165               0 :     focusedPrincipal->Subsumes(newPrincipal, &subsumes);
    1166               0 :     if (!subsumes && !nsContentUtils::IsCallerTrustedForWrite()) {
    1167               0 :       NS_WARNING("Not allowed to focus the new window!");
    1168                 :       return;
    1169                 :     }
    1170                 :   }
    1171                 : 
    1172                 :   // to check if the new element is in the active window, compare the
    1173                 :   // new root docshell for the new element with the active window's docshell.
    1174               0 :   bool isElementInActiveWindow = false;
    1175                 : 
    1176               0 :   nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(newWindow);
    1177               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
    1178               0 :   nsCOMPtr<nsPIDOMWindow> newRootWindow;
    1179               0 :   if (dsti) {
    1180               0 :     nsCOMPtr<nsIDocShellTreeItem> root;
    1181               0 :     dsti->GetRootTreeItem(getter_AddRefs(root));
    1182               0 :     newRootWindow = do_GetInterface(root);
    1183                 : 
    1184               0 :     isElementInActiveWindow = (mActiveWindow && newRootWindow == mActiveWindow);
    1185                 :   }
    1186                 : 
    1187                 : #ifdef DEBUG_FOCUS
    1188                 :   PRINTTAGF("Shift Focus: %s", contentToFocus);
    1189                 :   printf(" Flags: %x Current Window: %p New Window: %p Current Element: %p",
    1190                 :          aFlags, mFocusedWindow.get(), newWindow.get(), mFocusedContent.get());
    1191                 :   printf(" In Active Window: %d In Focused Window: %d\n",
    1192                 :          isElementInActiveWindow, isElementInFocusedWindow);
    1193                 : #endif
    1194                 : 
    1195                 :   // Exit full-screen if we're focusing a windowed plugin on a non-MacOSX
    1196                 :   // system. We don't control event dispatch to windowed plugins on non-MacOSX,
    1197                 :   // so we can't display the "Press ESC to leave full-screen mode" warning on
    1198                 :   // key input if a windowed plugin is focused, so just exit full-screen
    1199                 :   // to guard against phishing.
    1200                 : #ifndef XP_MACOSX
    1201               0 :   if (contentToFocus &&
    1202               0 :       nsContentUtils::GetRootDocument(contentToFocus->OwnerDoc())->IsFullScreenDoc() &&
    1203               0 :       nsContentUtils::HasPluginWithUncontrolledEventDispatch(contentToFocus)) {
    1204                 :     nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    1205                 :                                     "DOM",
    1206               0 :                                     contentToFocus->OwnerDoc(),
    1207                 :                                     nsContentUtils::eDOM_PROPERTIES,
    1208               0 :                                     "FocusedWindowedPluginWhileFullScreen");
    1209               0 :     nsIDocument::ExitFullScreen(true);
    1210                 :   }
    1211                 : #endif
    1212                 : 
    1213                 :   // if the FLAG_NOSWITCHFRAME flag is used, only allow the focus to be
    1214                 :   // shifted away from the current element if the new shell to focus is
    1215                 :   // the same or an ancestor shell of the currently focused shell.
    1216               0 :   bool allowFrameSwitch = !(aFlags & FLAG_NOSWITCHFRAME) ||
    1217               0 :                             IsSameOrAncestor(newWindow, mFocusedWindow);
    1218                 : 
    1219                 :   // if the element is in the active window, frame switching is allowed and
    1220                 :   // the content is in a visible window, fire blur and focus events.
    1221                 :   bool sendFocusEvent =
    1222               0 :     isElementInActiveWindow && allowFrameSwitch && IsWindowVisible(newWindow);
    1223                 : 
    1224                 :   // When the following conditions are true:
    1225                 :   //  * an element has focus
    1226                 :   //  * isn't called by trusted event (i.e., called by untrusted event or by js)
    1227                 :   //  * the focus is moved to another document's element
    1228                 :   // we need to check the permission.
    1229               0 :   if (sendFocusEvent && mFocusedContent &&
    1230               0 :       mFocusedContent->OwnerDoc() != aNewContent->OwnerDoc()) {
    1231                 :     // If the caller cannot access the current focused node, the caller should
    1232                 :     // not be able to steal focus from it. E.g., When the current focused node
    1233                 :     // is in chrome, any web contents should not be able to steal the focus.
    1234               0 :     nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mFocusedContent));
    1235               0 :     sendFocusEvent = nsContentUtils::CanCallerAccess(domNode);
    1236               0 :     if (!sendFocusEvent && mMouseDownEventHandlingDocument) {
    1237                 :       // However, while mouse down event is handling, the handling document's
    1238                 :       // script should be able to steal focus.
    1239               0 :       domNode = do_QueryInterface(mMouseDownEventHandlingDocument);
    1240               0 :       sendFocusEvent = nsContentUtils::CanCallerAccess(domNode);
    1241                 :     }
    1242                 :   }
    1243                 : 
    1244               0 :   if (sendFocusEvent) {
    1245                 :     // return if blurring fails or the focus changes during the blur
    1246               0 :     if (mFocusedWindow) {
    1247                 :       // if the focus is being moved to another element in the same document,
    1248                 :       // or to a descendant, pass the existing window to Blur so that the
    1249                 :       // current node in the existing window is cleared. If moving to a
    1250                 :       // window elsewhere, we want to maintain the current node in the
    1251                 :       // window but still blur it.
    1252               0 :       bool currentIsSameOrAncestor = IsSameOrAncestor(mFocusedWindow, newWindow);
    1253                 :       // find the common ancestor of the currently focused window and the new
    1254                 :       // window. The ancestor will need to have its currently focused node
    1255                 :       // cleared once the document has been blurred. Otherwise, we'll be in a
    1256                 :       // state where a document is blurred yet the chain of windows above it
    1257                 :       // still points to that document.
    1258                 :       // For instance, in the following frame tree:
    1259                 :       //   A
    1260                 :       //  B C
    1261                 :       //  D
    1262                 :       // D is focused and we want to focus C. Once D has been blurred, we need
    1263                 :       // to clear out the focus in A, otherwise A would still maintain that B
    1264                 :       // was focused, and B that D was focused.
    1265               0 :       nsCOMPtr<nsPIDOMWindow> commonAncestor;
    1266               0 :       if (!isElementInFocusedWindow)
    1267               0 :         commonAncestor = GetCommonAncestor(newWindow, mFocusedWindow);
    1268                 : 
    1269               0 :       if (!Blur(currentIsSameOrAncestor ? mFocusedWindow.get() : nsnull,
    1270               0 :                 commonAncestor, !isElementInFocusedWindow, aAdjustWidget))
    1271                 :         return;
    1272                 :     }
    1273                 : 
    1274               0 :     Focus(newWindow, contentToFocus, aFlags, !isElementInFocusedWindow,
    1275               0 :           aFocusChanged, false, aAdjustWidget);
    1276                 :   }
    1277                 :   else {
    1278                 :     // otherwise, for inactive windows and when the caller cannot steal the
    1279                 :     // focus, update the node in the window, and  raise the window if desired.
    1280               0 :     if (allowFrameSwitch)
    1281               0 :       AdjustWindowFocus(newWindow, true);
    1282                 : 
    1283                 :     // set the focus node and method as needed
    1284                 :     PRUint32 focusMethod = aFocusChanged ? aFlags & FOCUSMETHODANDRING_MASK :
    1285               0 :                            newWindow->GetFocusMethod() | (aFlags & FLAG_SHOWRING);
    1286               0 :     newWindow->SetFocusedNode(contentToFocus, focusMethod);
    1287               0 :     if (aFocusChanged) {
    1288               0 :       nsCOMPtr<nsIDocShell> docShell = newWindow->GetDocShell();
    1289                 : 
    1290               0 :       nsCOMPtr<nsIPresShell> presShell;
    1291               0 :       docShell->GetPresShell(getter_AddRefs(presShell));
    1292               0 :       if (presShell)
    1293               0 :         ScrollIntoView(presShell, contentToFocus, aFlags);
    1294                 :     }
    1295                 : 
    1296                 :     // update the commands even when inactive so that the attributes for that
    1297                 :     // window are up to date.
    1298               0 :     if (allowFrameSwitch)
    1299               0 :       newWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
    1300                 : 
    1301               0 :     if (aFlags & FLAG_RAISE)
    1302               0 :       RaiseWindow(newRootWindow);
    1303                 :   }
    1304                 : }
    1305                 : 
    1306                 : bool
    1307               0 : nsFocusManager::IsSameOrAncestor(nsPIDOMWindow* aPossibleAncestor,
    1308                 :                                  nsPIDOMWindow* aWindow)
    1309                 : {
    1310               0 :   nsCOMPtr<nsIWebNavigation> awebnav(do_GetInterface(aPossibleAncestor));
    1311               0 :   nsCOMPtr<nsIDocShellTreeItem> ancestordsti = do_QueryInterface(awebnav);
    1312                 : 
    1313               0 :   nsCOMPtr<nsIWebNavigation> fwebnav(do_GetInterface(aWindow));
    1314               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(fwebnav);
    1315               0 :   while (dsti) {
    1316               0 :     if (dsti == ancestordsti)
    1317               0 :       return true;
    1318               0 :     nsCOMPtr<nsIDocShellTreeItem> parentDsti;
    1319               0 :     dsti->GetParent(getter_AddRefs(parentDsti));
    1320               0 :     dsti.swap(parentDsti);
    1321                 :   }
    1322                 : 
    1323               0 :   return false;
    1324                 : }
    1325                 : 
    1326                 : already_AddRefed<nsPIDOMWindow>
    1327               0 : nsFocusManager::GetCommonAncestor(nsPIDOMWindow* aWindow1,
    1328                 :                                   nsPIDOMWindow* aWindow2)
    1329                 : {
    1330               0 :   nsCOMPtr<nsIWebNavigation> webnav(do_GetInterface(aWindow1));
    1331               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti1 = do_QueryInterface(webnav);
    1332               0 :   NS_ENSURE_TRUE(dsti1, nsnull);
    1333                 : 
    1334               0 :   webnav = do_GetInterface(aWindow2);
    1335               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti2 = do_QueryInterface(webnav);
    1336               0 :   NS_ENSURE_TRUE(dsti2, nsnull);
    1337                 : 
    1338               0 :   nsAutoTArray<nsIDocShellTreeItem*, 30> parents1, parents2;
    1339               0 :   do {
    1340               0 :     parents1.AppendElement(dsti1);
    1341               0 :     nsCOMPtr<nsIDocShellTreeItem> parentDsti1;
    1342               0 :     dsti1->GetParent(getter_AddRefs(parentDsti1));
    1343               0 :     dsti1.swap(parentDsti1);
    1344               0 :   } while (dsti1);
    1345               0 :   do {
    1346               0 :     parents2.AppendElement(dsti2);
    1347               0 :     nsCOMPtr<nsIDocShellTreeItem> parentDsti2;
    1348               0 :     dsti2->GetParent(getter_AddRefs(parentDsti2));
    1349               0 :     dsti2.swap(parentDsti2);
    1350               0 :   } while (dsti2);
    1351                 : 
    1352               0 :   PRUint32 pos1 = parents1.Length();
    1353               0 :   PRUint32 pos2 = parents2.Length();
    1354               0 :   nsIDocShellTreeItem* parent = nsnull;
    1355                 :   PRUint32 len;
    1356               0 :   for (len = NS_MIN(pos1, pos2); len > 0; --len) {
    1357               0 :     nsIDocShellTreeItem* child1 = parents1.ElementAt(--pos1);
    1358               0 :     nsIDocShellTreeItem* child2 = parents2.ElementAt(--pos2);
    1359               0 :     if (child1 != child2) {
    1360               0 :       break;
    1361                 :     }
    1362               0 :     parent = child1;
    1363                 :   }
    1364                 : 
    1365               0 :   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(parent);
    1366               0 :   return window.forget();
    1367                 : }
    1368                 : 
    1369                 : void
    1370               0 : nsFocusManager::AdjustWindowFocus(nsPIDOMWindow* aWindow,
    1371                 :                                   bool aCheckPermission)
    1372                 : {
    1373               0 :   bool isVisible = IsWindowVisible(aWindow);
    1374                 : 
    1375               0 :   nsCOMPtr<nsPIDOMWindow> window(aWindow);
    1376               0 :   while (window) {
    1377                 :     // get the containing <iframe> or equivalent element so that it can be
    1378                 :     // focused below.
    1379                 :     nsCOMPtr<nsIContent> frameContent =
    1380               0 :       do_QueryInterface(window->GetFrameElementInternal());
    1381                 : 
    1382               0 :     nsCOMPtr<nsIWebNavigation> webnav(do_GetInterface(window));
    1383               0 :     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(webnav);
    1384               0 :     if (!dsti) 
    1385                 :       return;
    1386               0 :     nsCOMPtr<nsIDocShellTreeItem> parentDsti;
    1387               0 :     dsti->GetParent(getter_AddRefs(parentDsti));
    1388                 : 
    1389               0 :     window = do_GetInterface(parentDsti);
    1390               0 :     if (window) {
    1391                 :       // if the parent window is visible but aWindow was not, then we have
    1392                 :       // likely moved up and out from a hidden tab to the browser window, or a
    1393                 :       // similar such arrangement. Stop adjusting the current nodes.
    1394               0 :       if (IsWindowVisible(window) != isVisible)
    1395                 :         break;
    1396                 : 
    1397                 :       // When aCheckPermission is true, we should check whether the caller can
    1398                 :       // access the window or not.  If it cannot access, we should stop the
    1399                 :       // adjusting.
    1400               0 :       if (aCheckPermission && !nsContentUtils::CanCallerAccess(window))
    1401                 :         break;
    1402                 : 
    1403               0 :       window->SetFocusedNode(frameContent);
    1404                 :     }
    1405                 :   }
    1406                 : }
    1407                 : 
    1408                 : bool
    1409               0 : nsFocusManager::IsWindowVisible(nsPIDOMWindow* aWindow)
    1410                 : {
    1411               0 :   if (!aWindow)
    1412               0 :     return false;
    1413                 : 
    1414               0 :   nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
    1415               0 :   nsCOMPtr<nsIBaseWindow> baseWin(do_QueryInterface(docShell));
    1416               0 :   if (!baseWin)
    1417               0 :     return false;
    1418                 : 
    1419               0 :   bool visible = false;
    1420               0 :   baseWin->GetVisibility(&visible);
    1421               0 :   return visible;
    1422                 : }
    1423                 : 
    1424                 : bool
    1425               0 : nsFocusManager::IsNonFocusableRoot(nsIContent* aContent)
    1426                 : {
    1427               0 :   NS_PRECONDITION(aContent, "aContent must not be NULL");
    1428               0 :   NS_PRECONDITION(aContent->IsInDoc(), "aContent must be in a document");
    1429                 : 
    1430                 :   // If aContent is in designMode, the root element is not focusable.
    1431                 :   // NOTE: in designMode, most elements are not focusable, just the document is
    1432                 :   //       focusable.
    1433                 :   // Also, if aContent is not editable but it isn't in designMode, it's not
    1434                 :   // focusable.
    1435               0 :   nsIDocument* doc = aContent->GetCurrentDoc();
    1436               0 :   NS_ASSERTION(doc, "aContent must have current document");
    1437               0 :   return aContent == doc->GetRootElement() &&
    1438               0 :            (doc->HasFlag(NODE_IS_EDITABLE) || !aContent->IsEditable());
    1439                 : }
    1440                 : 
    1441                 : nsIContent*
    1442               0 : nsFocusManager::CheckIfFocusable(nsIContent* aContent, PRUint32 aFlags)
    1443                 : {
    1444               0 :   if (!aContent)
    1445               0 :     return nsnull;
    1446                 : 
    1447                 :   // this is a special case for some XUL elements where an anonymous child is
    1448                 :   // actually focusable and not the element itself.
    1449               0 :   nsIContent* redirectedFocus = GetRedirectedFocus(aContent);
    1450               0 :   if (redirectedFocus)
    1451               0 :     return CheckIfFocusable(redirectedFocus, aFlags);
    1452                 : 
    1453               0 :   nsCOMPtr<nsIDocument> doc = aContent->GetCurrentDoc();
    1454                 :   // can't focus elements that are not in documents
    1455               0 :   if (!doc)
    1456               0 :     return nsnull;
    1457                 : 
    1458                 :   // Make sure that our frames are up to date
    1459               0 :   doc->FlushPendingNotifications(Flush_Layout);
    1460                 : 
    1461               0 :   nsIPresShell *shell = doc->GetShell();
    1462               0 :   if (!shell)
    1463               0 :     return nsnull;
    1464                 : 
    1465                 :   // the root content can always be focused
    1466               0 :   if (aContent == doc->GetRootElement())
    1467               0 :     return aContent;
    1468                 : 
    1469                 :   // cannot focus content in print preview mode. Only the root can be focused.
    1470               0 :   nsPresContext* presContext = shell->GetPresContext();
    1471               0 :   if (presContext && presContext->Type() == nsPresContext::eContext_PrintPreview)
    1472               0 :     return nsnull;
    1473                 : 
    1474               0 :   nsIFrame* frame = aContent->GetPrimaryFrame();
    1475               0 :   if (!frame)
    1476               0 :     return nsnull;
    1477                 : 
    1478               0 :   if (aContent->Tag() == nsGkAtoms::area && aContent->IsHTML()) {
    1479                 :     // HTML areas do not have their own frame, and the img frame we get from
    1480                 :     // GetPrimaryFrame() is not relevant as to whether it is focusable or
    1481                 :     // not, so we have to do all the relevant checks manually for them.
    1482               0 :     return frame->IsVisibleConsideringAncestors() &&
    1483               0 :            aContent->IsFocusable() ? aContent : nsnull;
    1484                 :   }
    1485                 : 
    1486                 :   // if this is a child frame content node, check if it is visible and
    1487                 :   // call the content node's IsFocusable method instead of the frame's
    1488                 :   // IsFocusable method. This skips checking the style system and ensures that
    1489                 :   // offscreen browsers can still be focused.
    1490               0 :   nsIDocument* subdoc = doc->GetSubDocumentFor(aContent);
    1491               0 :   if (subdoc && IsWindowVisible(subdoc->GetWindow())) {
    1492               0 :     const nsStyleUserInterface* ui = frame->GetStyleUserInterface();
    1493                 :     PRInt32 tabIndex = (ui->mUserFocus == NS_STYLE_USER_FOCUS_IGNORE ||
    1494               0 :                         ui->mUserFocus == NS_STYLE_USER_FOCUS_NONE) ? -1 : 0;
    1495               0 :     return aContent->IsFocusable(&tabIndex, aFlags & FLAG_BYMOUSE) ? aContent : nsnull;
    1496                 :   }
    1497                 :   
    1498               0 :   return frame->IsFocusable(nsnull, aFlags & FLAG_BYMOUSE) ? aContent : nsnull;
    1499                 : }
    1500                 : 
    1501                 : bool
    1502               0 : nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
    1503                 :                      nsPIDOMWindow* aAncestorWindowToFocus,
    1504                 :                      bool aIsLeavingDocument,
    1505                 :                      bool aAdjustWidgets)
    1506                 : {
    1507                 :   // hold a reference to the focused content, which may be null
    1508               0 :   nsCOMPtr<nsIContent> content = mFocusedContent;
    1509               0 :   if (content) {
    1510               0 :     if (!content->IsInDoc()) {
    1511               0 :       mFocusedContent = nsnull;
    1512               0 :       return true;
    1513                 :     }
    1514               0 :     if (content == mFirstBlurEvent)
    1515               0 :       return true;
    1516                 :   }
    1517                 : 
    1518                 :   // hold a reference to the focused window
    1519               0 :   nsCOMPtr<nsPIDOMWindow> window = mFocusedWindow;
    1520               0 :   if (!window) {
    1521               0 :     mFocusedContent = nsnull;
    1522               0 :     return true;
    1523                 :   }
    1524                 : 
    1525               0 :   nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
    1526               0 :   if (!docShell) {
    1527               0 :     mFocusedContent = nsnull;
    1528               0 :     return true;
    1529                 :   }
    1530                 : 
    1531                 :   // Keep a ref to presShell since dispatching the DOM event may cause
    1532                 :   // the document to be destroyed.
    1533               0 :   nsCOMPtr<nsIPresShell> presShell;
    1534               0 :   docShell->GetPresShell(getter_AddRefs(presShell));
    1535               0 :   if (!presShell) {
    1536               0 :     mFocusedContent = nsnull;
    1537               0 :     return true;
    1538                 :   }
    1539                 : 
    1540               0 :   bool clearFirstBlurEvent = false;
    1541               0 :   if (!mFirstBlurEvent) {
    1542               0 :     mFirstBlurEvent = content;
    1543               0 :     clearFirstBlurEvent = true;
    1544                 :   }
    1545                 : 
    1546                 :   // if there is still an active window, adjust the IME state.
    1547                 :   // This has to happen before the focus is cleared below, otherwise, the IME
    1548                 :   // compositionend event won't get fired at the element being blurred.
    1549               0 :   nsIMEStateManager::OnTextStateBlur(nsnull, nsnull);
    1550               0 :   if (mActiveWindow) {
    1551                 :     nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nsnull,
    1552               0 :                                      GetFocusMoveActionCause(0));
    1553                 :   }
    1554                 : 
    1555                 :   // now adjust the actual focus, by clearing the fields in the focus manager
    1556                 :   // and in the window.
    1557               0 :   mFocusedContent = nsnull;
    1558               0 :   bool shouldShowFocusRing = window->ShouldShowFocusRing();
    1559               0 :   if (aWindowToClear)
    1560               0 :     aWindowToClear->SetFocusedNode(nsnull);
    1561                 : 
    1562                 : #ifdef DEBUG_FOCUS
    1563                 :   PRINTTAGF("**Element %s has been blurred\n", content);
    1564                 : #endif
    1565                 : 
    1566                 :   // Don't fire blur event on the root content which isn't editable.
    1567                 :   bool sendBlurEvent =
    1568               0 :     content && content->IsInDoc() && !IsNonFocusableRoot(content);
    1569               0 :   if (content) {
    1570               0 :     if (sendBlurEvent) {
    1571               0 :       NotifyFocusStateChange(content, shouldShowFocusRing, false);
    1572                 :     }
    1573                 : 
    1574                 :     // if an object/plug-in/remote browser is being blurred, move the system focus
    1575                 :     // to the parent window, otherwise events will still get fired at the plugin.
    1576                 :     // But don't do this if we are blurring due to the window being lowered,
    1577                 :     // otherwise, the parent window can get raised again.
    1578               0 :     if (mActiveWindow) {
    1579               0 :       nsIFrame* contentFrame = content->GetPrimaryFrame();
    1580               0 :       nsIObjectFrame* objectFrame = do_QueryFrame(contentFrame);
    1581               0 :       if (aAdjustWidgets && objectFrame && !sTestMode) {
    1582                 :         // note that the presshell's widget is being retrieved here, not the one
    1583                 :         // for the object frame.
    1584               0 :         nsIViewManager* vm = presShell->GetViewManager();
    1585               0 :         if (vm) {
    1586               0 :           nsCOMPtr<nsIWidget> widget;
    1587               0 :           vm->GetRootWidget(getter_AddRefs(widget));
    1588               0 :           if (widget)
    1589               0 :             widget->SetFocus(false);
    1590                 :         }
    1591                 :       }
    1592                 : 
    1593                 :       // if the object being blurred is a remote browser, deactivate remote content
    1594               0 :       TabParent* remote = GetRemoteForContent(content);
    1595               0 :       if (remote) {
    1596               0 :         remote->Deactivate();
    1597                 :   #ifdef DEBUG_FOCUS
    1598                 :       printf("*Remote browser deactivated\n");
    1599                 :   #endif
    1600                 :       }
    1601                 :     }
    1602                 :   }
    1603                 : 
    1604               0 :   bool result = true;
    1605               0 :   if (sendBlurEvent) {
    1606                 :     // if there is an active window, update commands. If there isn't an active
    1607                 :     // window, then this was a blur caused by the active window being lowered,
    1608                 :     // so there is no need to update the commands
    1609               0 :     if (mActiveWindow)
    1610               0 :       window->UpdateCommands(NS_LITERAL_STRING("focus"));
    1611                 : 
    1612                 :     SendFocusOrBlurEvent(NS_BLUR_CONTENT, presShell,
    1613               0 :                          content->GetCurrentDoc(), content, 1, false);
    1614                 :   }
    1615                 : 
    1616                 :   // if we are leaving the document or the window was lowered, make the caret
    1617                 :   // invisible.
    1618               0 :   if (aIsLeavingDocument || !mActiveWindow)
    1619               0 :     SetCaretVisible(presShell, false, nsnull);
    1620                 : 
    1621                 :   // at this point, it is expected that this window will be still be
    1622                 :   // focused, but the focused content will be null, as it was cleared before
    1623                 :   // the event. If this isn't the case, then something else was focused during
    1624                 :   // the blur event above and we should just return. However, if
    1625                 :   // aIsLeavingDocument is set, a new document is desired, so make sure to
    1626                 :   // blur the document and window.
    1627               0 :   if (mFocusedWindow != window ||
    1628               0 :       (mFocusedContent != nsnull && !aIsLeavingDocument)) {
    1629               0 :     result = false;
    1630                 :   }
    1631               0 :   else if (aIsLeavingDocument) {
    1632               0 :     window->TakeFocus(false, 0);
    1633                 : 
    1634                 :     // clear the focus so that the ancestor frame hierarchy is in the correct
    1635                 :     // state. Pass true because aAncestorWindowToFocus is thought to be
    1636                 :     // focused at this point.
    1637               0 :     if (aAncestorWindowToFocus)
    1638               0 :       aAncestorWindowToFocus->SetFocusedNode(nsnull, 0, true);
    1639                 : 
    1640               0 :     mFocusedWindow = nsnull;
    1641               0 :     mFocusedContent = nsnull;
    1642                 : 
    1643                 :     // pass 1 for the focus method when calling SendFocusOrBlurEvent just so
    1644                 :     // that the check is made for suppressed documents. Check to ensure that
    1645                 :     // the document isn't null in case someone closed it during the blur above
    1646               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(window->GetExtantDocument());
    1647               0 :     if (doc)
    1648               0 :       SendFocusOrBlurEvent(NS_BLUR_CONTENT, presShell, doc, doc, 1, false);
    1649               0 :     if (mFocusedWindow == nsnull)
    1650               0 :       SendFocusOrBlurEvent(NS_BLUR_CONTENT, presShell, doc, window, 1, false);
    1651                 : 
    1652                 :     // check if a different window was focused
    1653               0 :     result = (mFocusedWindow == nsnull && mActiveWindow);
    1654                 :   }
    1655               0 :   else if (mActiveWindow) {
    1656                 :     // Otherwise, the blur of the element without blurring the document
    1657                 :     // occurred normally. Call UpdateCaret to redisplay the caret at the right
    1658                 :     // location within the document. This is needed to ensure that the caret
    1659                 :     // used for caret browsing is made visible again when an input field is
    1660                 :     // blurred.
    1661               0 :     UpdateCaret(false, true, nsnull);
    1662                 :   }
    1663                 : 
    1664               0 :   if (clearFirstBlurEvent)
    1665               0 :     mFirstBlurEvent = nsnull;
    1666                 : 
    1667               0 :   return result;
    1668                 : }
    1669                 : 
    1670                 : void
    1671               0 : nsFocusManager::Focus(nsPIDOMWindow* aWindow,
    1672                 :                       nsIContent* aContent,
    1673                 :                       PRUint32 aFlags,
    1674                 :                       bool aIsNewDocument,
    1675                 :                       bool aFocusChanged,
    1676                 :                       bool aWindowRaised,
    1677                 :                       bool aAdjustWidgets)
    1678                 : {
    1679               0 :   if (!aWindow)
    1680               0 :     return;
    1681                 : 
    1682               0 :   if (aContent && (aContent == mFirstFocusEvent || aContent == mFirstBlurEvent))
    1683               0 :     return;
    1684                 : 
    1685                 :   // Keep a reference to the presShell since dispatching the DOM event may
    1686                 :   // cause the document to be destroyed.
    1687               0 :   nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
    1688               0 :   if (!docShell)
    1689                 :     return;
    1690                 : 
    1691               0 :   nsCOMPtr<nsIPresShell> presShell;
    1692               0 :   docShell->GetPresShell(getter_AddRefs(presShell));
    1693               0 :   if (!presShell)
    1694                 :     return;
    1695                 : 
    1696                 :   // If the focus actually changed, set the focus method (mouse, keyboard, etc).
    1697                 :   // Otherwise, just get the current focus method and use that. This ensures
    1698                 :   // that the method is set during the document and window focus events.
    1699                 :   PRUint32 focusMethod = aFocusChanged ? aFlags & FOCUSMETHODANDRING_MASK :
    1700               0 :                          aWindow->GetFocusMethod() | (aFlags & FLAG_SHOWRING);
    1701                 : 
    1702               0 :   if (!IsWindowVisible(aWindow)) {
    1703                 :     // if the window isn't visible, for instance because it is a hidden tab,
    1704                 :     // update the current focus and scroll it into view but don't do anything else
    1705               0 :     if (CheckIfFocusable(aContent, aFlags)) {
    1706               0 :       aWindow->SetFocusedNode(aContent, focusMethod);
    1707               0 :       if (aFocusChanged)
    1708               0 :         ScrollIntoView(presShell, aContent, aFlags);
    1709                 :     }
    1710                 :     return;
    1711                 :   }
    1712                 : 
    1713               0 :   bool clearFirstFocusEvent = false;
    1714               0 :   if (!mFirstFocusEvent) {
    1715               0 :     mFirstFocusEvent = aContent;
    1716               0 :     clearFirstFocusEvent = true;
    1717                 :   }
    1718                 : 
    1719                 : #ifdef DEBUG_FOCUS
    1720                 :   PRINTTAGF("**Element %s has been focused", aContent);
    1721                 :   nsCOMPtr<nsIDocument> docm = do_QueryInterface(aWindow->GetExtantDocument());
    1722                 :   if (docm)
    1723                 :     PRINTTAGF(" from %s", docm->GetRootElement());
    1724                 :   printf(" [Newdoc: %d FocusChanged: %d Raised: %d Flags: %x]\n",
    1725                 :          aIsNewDocument, aFocusChanged, aWindowRaised, aFlags);
    1726                 : #endif
    1727                 : 
    1728               0 :   if (aIsNewDocument) {
    1729                 :     // if this is a new document, update the parent chain of frames so that
    1730                 :     // focus can be traversed from the top level down to the newly focused
    1731                 :     // window.
    1732               0 :     AdjustWindowFocus(aWindow, false);
    1733                 : 
    1734                 :     // Update the window touch registration to reflect the state of
    1735                 :     // the new document that got focus
    1736               0 :     aWindow->UpdateTouchState();
    1737                 :   }
    1738                 : 
    1739                 :   // indicate that the window has taken focus.
    1740               0 :   if (aWindow->TakeFocus(true, focusMethod))
    1741               0 :     aIsNewDocument = true;
    1742                 : 
    1743               0 :   mFocusedWindow = aWindow;
    1744                 : 
    1745                 :   // Update the system focus by focusing the root widget.  But avoid this
    1746                 :   // if 1) aAdjustWidgets is false or 2) aContent is a plugin that has its
    1747                 :   // own widget and is either already focused or is about to be focused.
    1748               0 :   nsCOMPtr<nsIWidget> objectFrameWidget;
    1749               0 :   if (aContent) {
    1750               0 :     nsIFrame* contentFrame = aContent->GetPrimaryFrame();
    1751               0 :     nsIObjectFrame* objectFrame = do_QueryFrame(contentFrame);
    1752               0 :     if (objectFrame)
    1753               0 :       objectFrameWidget = objectFrame->GetWidget();
    1754                 :   }
    1755               0 :   if (aAdjustWidgets && !objectFrameWidget && !sTestMode) {
    1756               0 :     nsIViewManager* vm = presShell->GetViewManager();
    1757               0 :     if (vm) {
    1758               0 :       nsCOMPtr<nsIWidget> widget;
    1759               0 :       vm->GetRootWidget(getter_AddRefs(widget));
    1760               0 :       if (widget)
    1761               0 :         widget->SetFocus(false);
    1762                 :     }
    1763                 :   }
    1764                 : 
    1765                 :   // if switching to a new document, first fire the focus event on the
    1766                 :   // document and then the window.
    1767               0 :   if (aIsNewDocument) {
    1768               0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aWindow->GetExtantDocument());
    1769               0 :     if (doc)
    1770                 :       SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell, doc,
    1771               0 :                            doc, aFlags & FOCUSMETHOD_MASK, aWindowRaised);
    1772               0 :     if (mFocusedWindow == aWindow && mFocusedContent == nsnull)
    1773                 :       SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell, doc,
    1774               0 :                            aWindow, aFlags & FOCUSMETHOD_MASK, aWindowRaised);
    1775                 :   }
    1776                 : 
    1777                 :   // check to ensure that the element is still focusable, and that nothing
    1778                 :   // else was focused during the events above.
    1779               0 :   if (CheckIfFocusable(aContent, aFlags) &&
    1780               0 :       mFocusedWindow == aWindow && mFocusedContent == nsnull) {
    1781               0 :     mFocusedContent = aContent;
    1782                 : 
    1783               0 :     nsIContent* focusedNode = aWindow->GetFocusedNode();
    1784               0 :     bool isRefocus = focusedNode && focusedNode->IsEqualTo(aContent);
    1785                 : 
    1786               0 :     aWindow->SetFocusedNode(aContent, focusMethod);
    1787                 : 
    1788                 :     bool sendFocusEvent =
    1789               0 :       aContent && aContent->IsInDoc() && !IsNonFocusableRoot(aContent);
    1790               0 :     nsPresContext* presContext = presShell->GetPresContext();
    1791               0 :     if (sendFocusEvent) {
    1792                 :       // if the focused element changed, scroll it into view
    1793               0 :       if (aFocusChanged)
    1794               0 :         ScrollIntoView(presShell, aContent, aFlags);
    1795                 : 
    1796               0 :       NotifyFocusStateChange(aContent, aWindow->ShouldShowFocusRing(), true);
    1797                 : 
    1798                 :       // if this is an object/plug-in/remote browser, focus its widget.  Note that we might
    1799                 :       // no longer be in the same document, due to the events we fired above when
    1800                 :       // aIsNewDocument.
    1801               0 :       if (presShell->GetDocument() == aContent->GetDocument()) {
    1802               0 :         if (aAdjustWidgets && objectFrameWidget && !sTestMode)
    1803               0 :           objectFrameWidget->SetFocus(false);
    1804                 : 
    1805                 :         // if the object being focused is a remote browser, activate remote content
    1806               0 :         TabParent* remote = GetRemoteForContent(aContent);
    1807               0 :         if (remote) {
    1808               0 :           remote->Activate();
    1809                 : #ifdef DEBUG_FOCUS
    1810                 :           printf("*Remote browser activated\n");
    1811                 : #endif
    1812                 :         }
    1813                 :       }
    1814                 : 
    1815                 :       nsIMEStateManager::OnChangeFocus(presContext, aContent,
    1816               0 :                                        GetFocusMoveActionCause(aFlags));
    1817                 : 
    1818                 :       // as long as this focus wasn't because a window was raised, update the
    1819                 :       // commands
    1820                 :       // XXXndeakin P2 someone could adjust the focus during the update
    1821               0 :       if (!aWindowRaised)
    1822               0 :         aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
    1823                 : 
    1824                 :       SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell,
    1825                 :                            aContent->GetCurrentDoc(),
    1826                 :                            aContent, aFlags & FOCUSMETHOD_MASK,
    1827               0 :                            aWindowRaised, isRefocus);
    1828                 : 
    1829               0 :       nsIMEStateManager::OnTextStateFocus(presContext, aContent);
    1830                 :     } else {
    1831               0 :       nsIMEStateManager::OnTextStateBlur(presContext, nsnull);
    1832                 :       nsIMEStateManager::OnChangeFocus(presContext, nsnull,
    1833               0 :                                        GetFocusMoveActionCause(aFlags));
    1834               0 :       if (!aWindowRaised) {
    1835               0 :         aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
    1836                 :       }
    1837                 :     }
    1838                 :   }
    1839                 :   else {
    1840                 :     // If the window focus event (fired above when aIsNewDocument) caused
    1841                 :     // the plugin not to be focusable, update the system focus by focusing
    1842                 :     // the root widget.
    1843               0 :     if (aAdjustWidgets && objectFrameWidget &&
    1844               0 :         mFocusedWindow == aWindow && mFocusedContent == nsnull &&
    1845               0 :         !sTestMode) {
    1846               0 :       nsIViewManager* vm = presShell->GetViewManager();
    1847               0 :       if (vm) {
    1848               0 :         nsCOMPtr<nsIWidget> widget;
    1849               0 :         vm->GetRootWidget(getter_AddRefs(widget));
    1850               0 :         if (widget)
    1851               0 :           widget->SetFocus(false);
    1852                 :       }
    1853                 :     }
    1854                 : 
    1855               0 :     nsPresContext* presContext = presShell->GetPresContext();
    1856               0 :     nsIMEStateManager::OnTextStateBlur(presContext, nsnull);
    1857                 :     nsIMEStateManager::OnChangeFocus(presContext, nsnull,
    1858               0 :                                      GetFocusMoveActionCause(aFlags));
    1859                 : 
    1860               0 :     if (!aWindowRaised)
    1861               0 :       aWindow->UpdateCommands(NS_LITERAL_STRING("focus"));
    1862                 :   }
    1863                 : 
    1864                 :   // update the caret visibility and position to match the newly focused
    1865                 :   // element. However, don't update the position if this was a focus due to a
    1866                 :   // mouse click as the selection code would already have moved the caret as
    1867                 :   // needed. If this is a different document than was focused before, also
    1868                 :   // update the caret's visibility. If this is the same document, the caret
    1869                 :   // visibility should be the same as before so there is no need to update it.
    1870               0 :   if (mFocusedContent == aContent)
    1871               0 :     UpdateCaret(aFocusChanged && !(aFlags & FLAG_BYMOUSE), aIsNewDocument,
    1872               0 :                 mFocusedContent);
    1873                 : 
    1874               0 :   if (clearFirstFocusEvent)
    1875               0 :     mFirstFocusEvent = nsnull;
    1876                 : }
    1877                 : 
    1878                 : class FocusBlurEvent : public nsRunnable
    1879               0 : {
    1880                 : public:
    1881               0 :   FocusBlurEvent(nsISupports* aTarget, PRUint32 aType,
    1882                 :                  nsPresContext* aContext, bool aWindowRaised,
    1883                 :                  bool aIsRefocus)
    1884                 :   : mTarget(aTarget), mType(aType), mContext(aContext),
    1885               0 :     mWindowRaised(aWindowRaised), mIsRefocus(aIsRefocus) {}
    1886                 : 
    1887               0 :   NS_IMETHOD Run()
    1888                 :   {
    1889               0 :     nsFocusEvent event(true, mType);
    1890               0 :     event.flags |= NS_EVENT_FLAG_CANT_BUBBLE;
    1891               0 :     event.fromRaise = mWindowRaised;
    1892               0 :     event.isRefocus = mIsRefocus;
    1893               0 :     return nsEventDispatcher::Dispatch(mTarget, mContext, &event);
    1894                 :   }
    1895                 : 
    1896                 :   nsCOMPtr<nsISupports>   mTarget;
    1897                 :   PRUint32                mType;
    1898                 :   nsRefPtr<nsPresContext> mContext;
    1899                 :   bool                    mWindowRaised;
    1900                 :   bool                    mIsRefocus;
    1901                 : };
    1902                 : 
    1903                 : void
    1904               0 : nsFocusManager::SendFocusOrBlurEvent(PRUint32 aType,
    1905                 :                                      nsIPresShell* aPresShell,
    1906                 :                                      nsIDocument* aDocument,
    1907                 :                                      nsISupports* aTarget,
    1908                 :                                      PRUint32 aFocusMethod,
    1909                 :                                      bool aWindowRaised,
    1910                 :                                      bool aIsRefocus)
    1911                 : {
    1912               0 :   NS_ASSERTION(aType == NS_FOCUS_CONTENT || aType == NS_BLUR_CONTENT,
    1913                 :                "Wrong event type for SendFocusOrBlurEvent");
    1914                 : 
    1915               0 :   nsCOMPtr<nsIDOMEventTarget> eventTarget = do_QueryInterface(aTarget);
    1916                 : 
    1917                 :   // for focus events, if this event was from a mouse or key and event
    1918                 :   // handling on the document is suppressed, queue the event and fire it
    1919                 :   // later. For blur events, a non-zero value would be set for aFocusMethod.
    1920               0 :   if (aFocusMethod && aDocument && aDocument->EventHandlingSuppressed()) {
    1921                 :     // aFlags is always 0 when aWindowRaised is true so this won't be called
    1922                 :     // on a window raise.
    1923               0 :     NS_ASSERTION(!aWindowRaised, "aWindowRaised should not be set");
    1924                 : 
    1925               0 :     for (PRUint32 i = mDelayedBlurFocusEvents.Length(); i > 0; --i) {
    1926                 :       // if this event was already queued, remove it and append it to the end
    1927               0 :       if (mDelayedBlurFocusEvents[i - 1].mType == aType &&
    1928               0 :           mDelayedBlurFocusEvents[i - 1].mPresShell == aPresShell &&
    1929               0 :           mDelayedBlurFocusEvents[i - 1].mDocument == aDocument &&
    1930               0 :           mDelayedBlurFocusEvents[i - 1].mTarget == eventTarget) {
    1931               0 :         mDelayedBlurFocusEvents.RemoveElementAt(i - 1);
    1932                 :       }
    1933                 :     }
    1934                 : 
    1935                 :     mDelayedBlurFocusEvents.AppendElement(
    1936               0 :       nsDelayedBlurOrFocusEvent(aType, aPresShell, aDocument, eventTarget));
    1937                 :     return;
    1938                 :   }
    1939                 : 
    1940                 : #ifdef ACCESSIBILITY
    1941               0 :   nsAccessibilityService* accService = GetAccService();
    1942               0 :   if (accService) {
    1943               0 :     if (aType == NS_FOCUS_CONTENT)
    1944               0 :       accService->NotifyOfDOMFocus(aTarget);
    1945                 :     else
    1946               0 :       accService->NotifyOfDOMBlur(aTarget);
    1947                 :   }
    1948                 : #endif
    1949                 : 
    1950                 :   nsContentUtils::AddScriptRunner(
    1951                 :     new FocusBlurEvent(aTarget, aType, aPresShell->GetPresContext(),
    1952               0 :                        aWindowRaised, aIsRefocus));
    1953                 : }
    1954                 : 
    1955                 : void
    1956               0 : nsFocusManager::ScrollIntoView(nsIPresShell* aPresShell,
    1957                 :                                nsIContent* aContent,
    1958                 :                                PRUint32 aFlags)
    1959                 : {
    1960                 :   // if the noscroll flag isn't set, scroll the newly focused element into view
    1961               0 :   if (!(aFlags & FLAG_NOSCROLL))
    1962                 :     aPresShell->ScrollContentIntoView(aContent,
    1963                 :                                       NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
    1964                 :                                       NS_PRESSHELL_SCROLL_IF_NOT_VISIBLE,
    1965               0 :                                       nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
    1966               0 : }
    1967                 : 
    1968                 : 
    1969                 : void
    1970               0 : nsFocusManager::RaiseWindow(nsPIDOMWindow* aWindow)
    1971                 : {
    1972                 :   // don't raise windows that are already raised or are in the process of
    1973                 :   // being lowered
    1974               0 :   if (!aWindow || aWindow == mActiveWindow || aWindow == mWindowBeingLowered)
    1975               0 :     return;
    1976                 : 
    1977               0 :   if (sTestMode) {
    1978                 :     // In test mode, emulate the existing window being lowered and the new
    1979                 :     // window being raised.
    1980               0 :     if (mActiveWindow)
    1981               0 :       WindowLowered(mActiveWindow);
    1982               0 :     WindowRaised(aWindow);
    1983               0 :     return;
    1984                 :   }
    1985                 : 
    1986                 : #if defined(XP_WIN) || defined(XP_OS2)
    1987                 :   // Windows would rather we focus the child widget, otherwise, the toplevel
    1988                 :   // widget will always end up being focused. Fortunately, focusing the child
    1989                 :   // widget will also have the effect of raising the window this widget is in.
    1990                 :   // But on other platforms, we can just focus the toplevel widget to raise
    1991                 :   // the window.
    1992                 :   nsCOMPtr<nsPIDOMWindow> childWindow;
    1993                 :   GetFocusedDescendant(aWindow, true, getter_AddRefs(childWindow));
    1994                 :   if (!childWindow)
    1995                 :     childWindow = aWindow;
    1996                 : 
    1997                 :   nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
    1998                 :   if (!docShell)
    1999                 :     return;
    2000                 : 
    2001                 :   nsCOMPtr<nsIPresShell> presShell;
    2002                 :   docShell->GetPresShell(getter_AddRefs(presShell));
    2003                 :   if (!presShell)
    2004                 :     return;
    2005                 : 
    2006                 :   nsIViewManager* vm = presShell->GetViewManager();
    2007                 :   if (vm) {
    2008                 :     nsCOMPtr<nsIWidget> widget;
    2009                 :     vm->GetRootWidget(getter_AddRefs(widget));
    2010                 :     if (widget)
    2011                 :       widget->SetFocus(true);
    2012                 :   }
    2013                 : #else
    2014               0 :   nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(aWindow);
    2015               0 :   nsCOMPtr<nsIBaseWindow> treeOwnerAsWin = do_QueryInterface(webnav);
    2016               0 :   if (treeOwnerAsWin) {
    2017               0 :     nsCOMPtr<nsIWidget> widget;
    2018               0 :     treeOwnerAsWin->GetMainWidget(getter_AddRefs(widget));
    2019               0 :     if (widget)
    2020               0 :       widget->SetFocus(true);
    2021                 :   }
    2022                 : #endif
    2023                 : }
    2024                 : 
    2025                 : void
    2026               1 : nsFocusManager::UpdateCaret(bool aMoveCaretToFocus,
    2027                 :                             bool aUpdateVisibility,
    2028                 :                             nsIContent* aContent)
    2029                 : {
    2030                 : #ifdef DEBUG_FOCUS
    2031                 :   printf("Update Caret: %d %d\n", aMoveCaretToFocus, aUpdateVisibility);
    2032                 : #endif
    2033                 : 
    2034               1 :   if (!mFocusedWindow)
    2035               1 :     return;
    2036                 : 
    2037                 :   // this is called when a document is focused or when the caretbrowsing
    2038                 :   // preference is changed
    2039               0 :   nsCOMPtr<nsIDocShell> focusedDocShell = mFocusedWindow->GetDocShell();
    2040               0 :   nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(focusedDocShell);
    2041               0 :   if (!dsti)
    2042                 :     return;
    2043                 : 
    2044                 :   PRInt32 itemType;
    2045               0 :   dsti->GetItemType(&itemType);
    2046               0 :   if (itemType == nsIDocShellTreeItem::typeChrome)
    2047                 :     return;  // Never browse with caret in chrome
    2048                 : 
    2049                 :   bool browseWithCaret =
    2050               0 :     Preferences::GetBool("accessibility.browsewithcaret");
    2051                 : 
    2052               0 :   nsCOMPtr<nsIPresShell> presShell;
    2053               0 :   focusedDocShell->GetPresShell(getter_AddRefs(presShell));
    2054               0 :   if (!presShell)
    2055                 :     return;
    2056                 : 
    2057                 :   // If this is an editable document which isn't contentEditable, or a
    2058                 :   // contentEditable document and the node to focus is contentEditable,
    2059                 :   // return, so that we don't mess with caret visibility.
    2060               0 :   bool isEditable = false;
    2061               0 :   nsCOMPtr<nsIEditorDocShell> editorDocShell(do_QueryInterface(dsti));
    2062               0 :   if (editorDocShell) {
    2063               0 :     editorDocShell->GetEditable(&isEditable);
    2064                 : 
    2065               0 :     if (isEditable) {
    2066                 :       nsCOMPtr<nsIHTMLDocument> doc =
    2067               0 :         do_QueryInterface(presShell->GetDocument());
    2068                 : 
    2069                 :       bool isContentEditableDoc =
    2070               0 :         doc && doc->GetEditingState() == nsIHTMLDocument::eContentEditable;
    2071                 : 
    2072                 :       bool isFocusEditable =
    2073               0 :         aContent && aContent->HasFlag(NODE_IS_EDITABLE);
    2074               0 :       if (!isContentEditableDoc || isFocusEditable)
    2075                 :         return;
    2076                 :     }
    2077                 :   }
    2078                 : 
    2079               0 :   if (!isEditable && aMoveCaretToFocus)
    2080               0 :     MoveCaretToFocus(presShell, aContent);
    2081                 : 
    2082               0 :   if (!aUpdateVisibility)
    2083                 :     return;
    2084                 : 
    2085                 :   // XXXndeakin this doesn't seem right. It should be checking for this only
    2086                 :   // on the nearest ancestor frame which is a chrome frame. But this is
    2087                 :   // what the existing code does, so just leave it for now.
    2088               0 :   if (!browseWithCaret) {
    2089                 :     nsCOMPtr<nsIContent> docContent =
    2090               0 :       do_QueryInterface(mFocusedWindow->GetFrameElementInternal());
    2091               0 :     if (docContent)
    2092               0 :       browseWithCaret = docContent->AttrValueIs(kNameSpaceID_None,
    2093                 :                                                 nsGkAtoms::showcaret,
    2094               0 :                                                 NS_LITERAL_STRING("true"),
    2095               0 :                                                 eCaseMatters);
    2096                 :   }
    2097                 : 
    2098               0 :   SetCaretVisible(presShell, browseWithCaret, aContent);
    2099                 : }
    2100                 : 
    2101                 : void
    2102               0 : nsFocusManager::MoveCaretToFocus(nsIPresShell* aPresShell, nsIContent* aContent)
    2103                 : {
    2104                 :   // domDoc is a document interface we can create a range with
    2105               0 :   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aPresShell->GetDocument());
    2106               0 :   if (domDoc) {
    2107               0 :     nsRefPtr<nsFrameSelection> frameSelection = aPresShell->FrameSelection();
    2108                 :     nsCOMPtr<nsISelection> domSelection = frameSelection->
    2109               0 :       GetSelection(nsISelectionController::SELECTION_NORMAL);
    2110               0 :     if (domSelection) {
    2111               0 :       nsCOMPtr<nsIDOMNode> currentFocusNode(do_QueryInterface(aContent));
    2112                 :       // First clear the selection. This way, if there is no currently focused
    2113                 :       // content, the selection will just be cleared.
    2114               0 :       domSelection->RemoveAllRanges();
    2115               0 :       if (currentFocusNode) {
    2116               0 :         nsCOMPtr<nsIDOMRange> newRange;
    2117               0 :         nsresult rv = domDoc->CreateRange(getter_AddRefs(newRange));
    2118               0 :         if (NS_SUCCEEDED(rv)) {
    2119                 :           // Set the range to the start of the currently focused node
    2120                 :           // Make sure it's collapsed
    2121               0 :           newRange->SelectNodeContents(currentFocusNode);
    2122               0 :           nsCOMPtr<nsIDOMNode> firstChild;
    2123               0 :           currentFocusNode->GetFirstChild(getter_AddRefs(firstChild));
    2124               0 :           if (!firstChild ||
    2125               0 :               aContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
    2126                 :             // If current focus node is a leaf, set range to before the
    2127                 :             // node by using the parent as a container.
    2128                 :             // This prevents it from appearing as selected.
    2129               0 :             newRange->SetStartBefore(currentFocusNode);
    2130               0 :             newRange->SetEndBefore(currentFocusNode);
    2131                 :           }
    2132               0 :           domSelection->AddRange(newRange);
    2133               0 :           domSelection->CollapseToStart();
    2134                 :         }
    2135                 :       }
    2136                 :     }
    2137                 :   }
    2138               0 : }
    2139                 : 
    2140                 : nsresult
    2141               0 : nsFocusManager::SetCaretVisible(nsIPresShell* aPresShell,
    2142                 :                                 bool aVisible,
    2143                 :                                 nsIContent* aContent)
    2144                 : {
    2145                 :   // When browsing with caret, make sure caret is visible after new focus
    2146                 :   // Return early if there is no caret. This can happen for the testcase
    2147                 :   // for bug 308025 where a window is closed in a blur handler.
    2148               0 :   nsRefPtr<nsCaret> caret = aPresShell->GetCaret();
    2149               0 :   if (!caret)
    2150               0 :     return NS_OK;
    2151                 : 
    2152               0 :   bool caretVisible = false;
    2153               0 :   caret->GetCaretVisible(&caretVisible);
    2154               0 :   if (!aVisible && !caretVisible)
    2155               0 :     return NS_OK;
    2156                 : 
    2157               0 :   nsRefPtr<nsFrameSelection> frameSelection;
    2158               0 :   if (aContent) {
    2159               0 :     NS_ASSERTION(aContent->GetDocument() == aPresShell->GetDocument(),
    2160                 :                  "Wrong document?");
    2161               0 :     nsIFrame *focusFrame = aContent->GetPrimaryFrame();
    2162               0 :     if (focusFrame)
    2163               0 :       frameSelection = focusFrame->GetFrameSelection();
    2164                 :   }
    2165                 : 
    2166               0 :   nsRefPtr<nsFrameSelection> docFrameSelection = aPresShell->FrameSelection();
    2167                 : 
    2168               0 :   if (docFrameSelection && caret &&
    2169               0 :      (frameSelection == docFrameSelection || !aContent)) {
    2170                 :     nsISelection* domSelection = docFrameSelection->
    2171               0 :       GetSelection(nsISelectionController::SELECTION_NORMAL);
    2172               0 :     if (domSelection) {
    2173                 :       // First, hide the caret to prevent attempting to show it in SetCaretDOMSelection
    2174               0 :       caret->SetCaretVisible(false);
    2175                 : 
    2176                 :       // Tell the caret which selection to use
    2177               0 :       caret->SetCaretDOMSelection(domSelection);
    2178                 : 
    2179                 :       // In content, we need to set the caret. The only special case is edit
    2180                 :       // fields, which have a different frame selection from the document.
    2181                 :       // They will take care of making the caret visible themselves.
    2182                 : 
    2183               0 :       nsCOMPtr<nsISelectionController> selCon(do_QueryInterface(aPresShell));
    2184               0 :       if (!selCon)
    2185               0 :         return NS_ERROR_FAILURE;
    2186                 : 
    2187               0 :       selCon->SetCaretEnabled(aVisible);
    2188               0 :       caret->SetCaretVisible(aVisible);
    2189                 :     }
    2190                 :   }
    2191                 : 
    2192               0 :   return NS_OK;
    2193                 : }
    2194                 : 
    2195                 : nsresult
    2196               0 : nsFocusManager::GetSelectionLocation(nsIDocument* aDocument,
    2197                 :                                      nsIPresShell* aPresShell,
    2198                 :                                      nsIContent **aStartContent,
    2199                 :                                      nsIContent **aEndContent)
    2200                 : {
    2201               0 :   *aStartContent = *aEndContent = nsnull;
    2202               0 :   nsresult rv = NS_ERROR_FAILURE;
    2203                 : 
    2204               0 :   nsPresContext* presContext = aPresShell->GetPresContext();
    2205               0 :   NS_ASSERTION(presContext, "mPresContent is null!!");
    2206                 : 
    2207               0 :   nsRefPtr<nsFrameSelection> frameSelection = aPresShell->FrameSelection();
    2208                 : 
    2209               0 :   nsCOMPtr<nsISelection> domSelection;
    2210               0 :   if (frameSelection) {
    2211                 :     domSelection = frameSelection->
    2212               0 :       GetSelection(nsISelectionController::SELECTION_NORMAL);
    2213                 :   }
    2214                 : 
    2215               0 :   nsCOMPtr<nsIDOMNode> startNode, endNode;
    2216               0 :   bool isCollapsed = false;
    2217               0 :   nsCOMPtr<nsIContent> startContent, endContent;
    2218               0 :   PRInt32 startOffset = 0;
    2219               0 :   if (domSelection) {
    2220               0 :     domSelection->GetIsCollapsed(&isCollapsed);
    2221               0 :     nsCOMPtr<nsIDOMRange> domRange;
    2222               0 :     rv = domSelection->GetRangeAt(0, getter_AddRefs(domRange));
    2223               0 :     if (domRange) {
    2224               0 :       domRange->GetStartContainer(getter_AddRefs(startNode));
    2225               0 :       domRange->GetEndContainer(getter_AddRefs(endNode));
    2226               0 :       domRange->GetStartOffset(&startOffset);
    2227                 : 
    2228               0 :       nsIContent *childContent = nsnull;
    2229                 : 
    2230               0 :       startContent = do_QueryInterface(startNode);
    2231               0 :       if (startContent && startContent->IsElement()) {
    2232               0 :         NS_ASSERTION(startOffset >= 0, "Start offset cannot be negative");  
    2233               0 :         childContent = startContent->GetChildAt(startOffset);
    2234               0 :         if (childContent) {
    2235               0 :           startContent = childContent;
    2236                 :         }
    2237                 :       }
    2238                 : 
    2239               0 :       endContent = do_QueryInterface(endNode);
    2240               0 :       if (endContent && endContent->IsElement()) {
    2241               0 :         PRInt32 endOffset = 0;
    2242               0 :         domRange->GetEndOffset(&endOffset);
    2243               0 :         NS_ASSERTION(endOffset >= 0, "End offset cannot be negative");
    2244               0 :         childContent = endContent->GetChildAt(endOffset);
    2245               0 :         if (childContent) {
    2246               0 :           endContent = childContent;
    2247                 :         }
    2248                 :       }
    2249                 :     }
    2250                 :   }
    2251                 :   else {
    2252               0 :     rv = NS_ERROR_INVALID_ARG;
    2253                 :   }
    2254                 : 
    2255               0 :   nsIFrame *startFrame = nsnull;
    2256               0 :   if (startContent) {
    2257               0 :     startFrame = startContent->GetPrimaryFrame();
    2258               0 :     if (isCollapsed) {
    2259                 :       // Next check to see if our caret is at the very end of a node
    2260                 :       // If so, the caret is actually sitting in front of the next
    2261                 :       // logical frame's primary node - so for this case we need to
    2262                 :       // change caretContent to that node.
    2263                 : 
    2264               0 :       if (startContent->NodeType() == nsIDOMNode::TEXT_NODE) {
    2265               0 :         nsAutoString nodeValue;
    2266               0 :         startContent->AppendTextTo(nodeValue);
    2267                 : 
    2268                 :         bool isFormControl =
    2269               0 :           startContent->IsNodeOfType(nsINode::eHTML_FORM_CONTROL);
    2270                 : 
    2271               0 :         if (nodeValue.Length() == (PRUint32)startOffset && !isFormControl &&
    2272               0 :             startContent != aDocument->GetRootElement()) {
    2273                 :           // Yes, indeed we were at the end of the last node
    2274               0 :           nsCOMPtr<nsIFrameEnumerator> frameTraversal;
    2275               0 :           nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
    2276                 :                                              presContext, startFrame,
    2277                 :                                              eLeaf,
    2278                 :                                              false, // aVisual
    2279                 :                                              false, // aLockInScrollView
    2280                 :                                              true      // aFollowOOFs
    2281               0 :                                              );
    2282               0 :           NS_ENSURE_SUCCESS(rv, rv);
    2283                 : 
    2284               0 :           nsIFrame *newCaretFrame = nsnull;
    2285               0 :           nsCOMPtr<nsIContent> newCaretContent = startContent;
    2286               0 :           bool endOfSelectionInStartNode(startContent == endContent);
    2287               0 :           do {
    2288                 :             // Continue getting the next frame until the primary content for the frame
    2289                 :             // we are on changes - we don't want to be stuck in the same place
    2290               0 :             frameTraversal->Next();
    2291               0 :             newCaretFrame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
    2292               0 :             if (nsnull == newCaretFrame)
    2293               0 :               break;
    2294               0 :             newCaretContent = newCaretFrame->GetContent();            
    2295               0 :           } while (!newCaretContent || newCaretContent == startContent);
    2296                 : 
    2297               0 :           if (newCaretFrame && newCaretContent) {
    2298                 :             // If the caret is exactly at the same position of the new frame,
    2299                 :             // then we can use the newCaretFrame and newCaretContent for our position
    2300               0 :             nsRefPtr<nsCaret> caret = aPresShell->GetCaret();
    2301               0 :             nsRect caretRect;
    2302               0 :             nsIFrame *frame = caret->GetGeometry(domSelection, &caretRect);
    2303               0 :             if (frame) {
    2304               0 :               nsPoint caretWidgetOffset;
    2305               0 :               nsIWidget *widget = frame->GetNearestWidget(caretWidgetOffset);
    2306               0 :               caretRect.MoveBy(caretWidgetOffset);
    2307               0 :               nsPoint newCaretOffset;
    2308               0 :               nsIWidget *newCaretWidget = newCaretFrame->GetNearestWidget(newCaretOffset);
    2309               0 :               if (widget == newCaretWidget && caretRect.y == newCaretOffset.y &&
    2310                 :                   caretRect.x == newCaretOffset.x) {
    2311                 :                 // The caret is at the start of the new element.
    2312               0 :                 startFrame = newCaretFrame;
    2313               0 :                 startContent = newCaretContent;
    2314               0 :                 if (endOfSelectionInStartNode) {
    2315               0 :                   endContent = newCaretContent; // Ensure end of selection is not before start
    2316                 :                 }
    2317                 :               }
    2318                 :             }
    2319                 :           }
    2320                 :         }
    2321                 :       }
    2322                 :     }
    2323                 :   }
    2324                 : 
    2325               0 :   *aStartContent = startContent;
    2326               0 :   *aEndContent = endContent;
    2327               0 :   NS_IF_ADDREF(*aStartContent);
    2328               0 :   NS_IF_ADDREF(*aEndContent);
    2329                 : 
    2330               0 :   return rv;
    2331                 : }
    2332                 : 
    2333                 : nsresult
    2334               0 : nsFocusManager::DetermineElementToMoveFocus(nsPIDOMWindow* aWindow,
    2335                 :                                             nsIContent* aStartContent,
    2336                 :                                             PRInt32 aType, bool aNoParentTraversal,
    2337                 :                                             nsIContent** aNextContent)
    2338                 : {
    2339               0 :   *aNextContent = nsnull;
    2340                 : 
    2341               0 :   nsCOMPtr<nsIDocShell> docShell = aWindow->GetDocShell();
    2342               0 :   if (!docShell)
    2343               0 :     return NS_OK;
    2344                 : 
    2345               0 :   nsCOMPtr<nsIContent> startContent = aStartContent;
    2346               0 :   if (!startContent && aType != MOVEFOCUS_CARET) {
    2347               0 :     if (aType == MOVEFOCUS_FORWARDDOC || aType == MOVEFOCUS_BACKWARDDOC) {
    2348                 :       // When moving between documents, make sure to get the right
    2349                 :       // starting content in a descendant.
    2350               0 :       nsCOMPtr<nsPIDOMWindow> focusedWindow;
    2351               0 :       startContent = GetFocusedDescendant(aWindow, true, getter_AddRefs(focusedWindow));
    2352                 :     }
    2353                 :     else {
    2354               0 :       startContent = aWindow->GetFocusedNode();
    2355                 :     }
    2356                 :   }
    2357                 : 
    2358               0 :   nsCOMPtr<nsIDocument> doc;
    2359               0 :   if (startContent)
    2360               0 :     doc = startContent->GetCurrentDoc();
    2361                 :   else
    2362               0 :     doc = do_QueryInterface(aWindow->GetExtantDocument());
    2363               0 :   if (!doc)
    2364               0 :     return NS_OK;
    2365                 : 
    2366                 :   LookAndFeel::GetInt(LookAndFeel::eIntID_TabFocusModel,
    2367               0 :                       &nsIContent::sTabFocusModel);
    2368                 : 
    2369               0 :   if (aType == MOVEFOCUS_ROOT) {
    2370               0 :     NS_IF_ADDREF(*aNextContent = GetRootForFocus(aWindow, doc, false, false));
    2371               0 :     return NS_OK;
    2372                 :   }
    2373               0 :   if (aType == MOVEFOCUS_FORWARDDOC) {
    2374               0 :     NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(startContent, true));
    2375               0 :     return NS_OK;
    2376                 :   }
    2377               0 :   if (aType == MOVEFOCUS_BACKWARDDOC) {
    2378               0 :     NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(startContent, false));
    2379               0 :     return NS_OK;
    2380                 :   }
    2381                 :   
    2382               0 :   nsIContent* rootContent = doc->GetRootElement();
    2383               0 :   NS_ENSURE_TRUE(rootContent, NS_OK);
    2384                 : 
    2385               0 :   nsIPresShell *presShell = doc->GetShell();
    2386               0 :   NS_ENSURE_TRUE(presShell, NS_OK);
    2387                 : 
    2388               0 :   if (aType == MOVEFOCUS_FIRST) {
    2389               0 :     if (!aStartContent)
    2390               0 :       startContent = rootContent;
    2391                 :     return GetNextTabbableContent(presShell, startContent,
    2392                 :                                   nsnull, startContent,
    2393               0 :                                   true, 1, false, aNextContent);
    2394                 :   }
    2395               0 :   if (aType == MOVEFOCUS_LAST) {
    2396               0 :     if (!aStartContent)
    2397               0 :       startContent = rootContent;
    2398                 :     return GetNextTabbableContent(presShell, startContent,
    2399                 :                                   nsnull, startContent,
    2400               0 :                                   false, 0, false, aNextContent);
    2401                 :   }
    2402                 : 
    2403               0 :   bool forward = (aType == MOVEFOCUS_FORWARD || aType == MOVEFOCUS_CARET);
    2404               0 :   bool doNavigation = true;
    2405               0 :   bool ignoreTabIndex = false;
    2406                 :   // when a popup is open, we want to ensure that tab navigation occurs only
    2407                 :   // within the most recently opened panel. If a popup is open, its frame will
    2408                 :   // be stored in popupFrame.
    2409               0 :   nsIFrame* popupFrame = nsnull;
    2410                 : 
    2411               0 :   PRInt32 tabIndex = forward ? 1 : 0;
    2412               0 :   if (startContent) {
    2413               0 :     nsIFrame* frame = startContent->GetPrimaryFrame();
    2414               0 :     if (startContent->Tag() == nsGkAtoms::area &&
    2415               0 :         startContent->IsHTML())
    2416               0 :       startContent->IsFocusable(&tabIndex);
    2417               0 :     else if (frame)
    2418               0 :       frame->IsFocusable(&tabIndex, 0);
    2419                 :     else
    2420               0 :       startContent->IsFocusable(&tabIndex);
    2421                 : 
    2422                 :     // if the current element isn't tabbable, ignore the tabindex and just
    2423                 :     // look for the next element. The root content won't have a tabindex
    2424                 :     // so just treat this as the beginning of the tab order.
    2425               0 :     if (tabIndex < 0) {
    2426               0 :       tabIndex = 1;
    2427               0 :       if (startContent != rootContent)
    2428               0 :         ignoreTabIndex = true;
    2429                 :     }
    2430                 : 
    2431                 :     // check if the focus is currently inside a popup. Elements such as the
    2432                 :     // autocomplete widget use the noautofocus attribute to allow the focus to
    2433                 :     // remain outside the popup when it is opened.
    2434               0 :     if (frame) {
    2435                 :       popupFrame = nsLayoutUtils::GetClosestFrameOfType(frame,
    2436               0 :                                                         nsGkAtoms::menuPopupFrame);
    2437                 :     }
    2438                 : 
    2439               0 :     if (popupFrame) {
    2440                 :       // Don't navigate outside of a popup, so pretend that the
    2441                 :       // root content is the popup itself
    2442               0 :       rootContent = popupFrame->GetContent();
    2443               0 :       NS_ASSERTION(rootContent, "Popup frame doesn't have a content node");
    2444                 :     }
    2445               0 :     else if (!forward) {
    2446                 :       // If focus moves backward and when current focused node is root
    2447                 :       // content or <body> element which is editable by contenteditable
    2448                 :       // attribute, focus should move to its parent document.
    2449               0 :       if (startContent == rootContent) {
    2450               0 :         doNavigation = false;
    2451                 :       } else {
    2452               0 :         nsIDocument* doc = startContent->GetCurrentDoc();
    2453               0 :         if (startContent ==
    2454               0 :               nsLayoutUtils::GetEditableRootContentByContentEditable(doc)) {
    2455               0 :           doNavigation = false;
    2456                 :         }
    2457                 :       }
    2458                 :     }
    2459                 :   }
    2460                 :   else {
    2461                 : #ifdef MOZ_XUL
    2462                 :     // if there is no focus, yet a panel is open, focus the first item in
    2463                 :     // the panel
    2464               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    2465               0 :     if (pm)
    2466               0 :       popupFrame = pm->GetTopPopup(ePopupTypePanel);
    2467                 : #endif
    2468               0 :     if (popupFrame) {
    2469               0 :       rootContent = popupFrame->GetContent();
    2470               0 :       NS_ASSERTION(rootContent, "Popup frame doesn't have a content node");
    2471               0 :       startContent = rootContent;
    2472                 :     }
    2473                 :     else {
    2474                 :       // Otherwise, for content shells, start from the location of the caret.
    2475                 :       PRInt32 itemType;
    2476               0 :       nsCOMPtr<nsIDocShellTreeItem> shellItem = do_QueryInterface(docShell);
    2477               0 :       shellItem->GetItemType(&itemType);
    2478               0 :       if (itemType != nsIDocShellTreeItem::typeChrome) {
    2479               0 :         nsCOMPtr<nsIContent> endSelectionContent;
    2480                 :         GetSelectionLocation(doc, presShell,
    2481               0 :                              getter_AddRefs(startContent),
    2482               0 :                              getter_AddRefs(endSelectionContent));
    2483                 :         // If the selection is on the rootContent, then there is no selection
    2484               0 :         if (startContent == rootContent) {
    2485               0 :           startContent = nsnull;
    2486                 :         }
    2487                 : 
    2488               0 :         if (aType == MOVEFOCUS_CARET) {
    2489                 :           // GetFocusInSelection finds a focusable link near the caret.
    2490                 :           // If there is no start content though, don't do this to avoid
    2491                 :           // focusing something unexpected.
    2492               0 :           if (startContent) {
    2493                 :             GetFocusInSelection(aWindow, startContent,
    2494               0 :                                 endSelectionContent, aNextContent);
    2495                 :           }
    2496               0 :           return NS_OK;
    2497                 :         }
    2498                 : 
    2499               0 :         if (startContent) {
    2500                 :           // when starting from a selection, we always want to find the next or
    2501                 :           // previous element in the document. So the tabindex on elements
    2502                 :           // should be ignored.
    2503               0 :           ignoreTabIndex = true;
    2504                 :         }
    2505                 :       }
    2506                 : 
    2507               0 :       if (!startContent) {
    2508                 :         // otherwise, just use the root content as the starting point
    2509               0 :         startContent = rootContent;
    2510               0 :         NS_ENSURE_TRUE(startContent, NS_OK);
    2511                 :       }
    2512                 :     }
    2513                 :   }
    2514                 : 
    2515               0 :   NS_ASSERTION(startContent, "starting content not set");
    2516                 : 
    2517                 :   // keep a reference to the starting content. If we find that again, it means
    2518                 :   // we've iterated around completely and we don't want to adjust the focus.
    2519                 :   // The skipOriginalContentCheck will be set to true only for the first time
    2520                 :   // GetNextTabbableContent is called. This ensures that we don't break out
    2521                 :   // when nothing is focused to start with. Specifically,
    2522                 :   // GetNextTabbableContent first checks the root content -- which happens to
    2523                 :   // be the same as the start content -- when nothing is focused and tabbing
    2524                 :   // forward. Without skipOriginalContentCheck set to true, we'd end up
    2525                 :   // returning right away and focusing nothing. Luckily, GetNextTabbableContent
    2526                 :   // will never wrap around on its own, and can only return the original
    2527                 :   // content when it is called a second time or later.
    2528               0 :   bool skipOriginalContentCheck = true;
    2529               0 :   nsIContent* originalStartContent = startContent;
    2530                 : 
    2531                 : #ifdef DEBUG_FOCUS_NAVIGATION
    2532                 :   PRINTTAGF("Focus Navigation Start Content %s\n", startContent);
    2533                 :   printf("[Tabindex: %d Ignore: %d]", tabIndex, ignoreTabIndex);
    2534                 : #endif
    2535                 : 
    2536               0 :   while (doc) {
    2537               0 :     if (doNavigation) {
    2538               0 :       nsCOMPtr<nsIContent> nextFocus;
    2539                 :       nsresult rv = GetNextTabbableContent(presShell, rootContent,
    2540                 :                                            skipOriginalContentCheck ? nsnull : originalStartContent,
    2541                 :                                            startContent, forward,
    2542                 :                                            tabIndex, ignoreTabIndex,
    2543               0 :                                            getter_AddRefs(nextFocus));
    2544               0 :       NS_ENSURE_SUCCESS(rv, rv);
    2545                 : 
    2546                 :       // found a content node to focus.
    2547               0 :       if (nextFocus) {
    2548                 : #ifdef DEBUG_FOCUS_NAVIGATION
    2549                 :         PRINTTAGF("Next Content: %s\n", nextFocus);
    2550                 : #endif
    2551                 :         // as long as the found node was not the same as the starting node,
    2552                 :         // set it as the return value.
    2553               0 :         if (nextFocus != originalStartContent)
    2554               0 :           NS_ADDREF(*aNextContent = nextFocus);
    2555               0 :         return NS_OK;
    2556                 :       }
    2557                 : 
    2558               0 :       if (popupFrame) {
    2559                 :         // in a popup, so start again from the beginning of the popup. However,
    2560                 :         // if we already started at the beginning, then there isn't anything to
    2561                 :         // focus, so just return
    2562               0 :         if (startContent != rootContent) {
    2563               0 :           startContent = rootContent;
    2564               0 :           tabIndex = forward ? 1 : 0;
    2565               0 :           continue;
    2566                 :         }
    2567               0 :         return NS_OK;
    2568                 :       }
    2569                 :     }
    2570                 : 
    2571               0 :     doNavigation = true;
    2572               0 :     skipOriginalContentCheck = false;
    2573               0 :     ignoreTabIndex = false;
    2574                 : 
    2575               0 :     if (aNoParentTraversal) {
    2576               0 :       startContent = rootContent;
    2577               0 :       tabIndex = forward ? 1 : 0;
    2578               0 :       continue;
    2579                 :     }
    2580                 : 
    2581                 :     // reached the beginning or end of the document. Traverse up to the parent
    2582                 :     // document and try again.
    2583               0 :     nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(docShell);
    2584                 : 
    2585               0 :     nsCOMPtr<nsIDocShellTreeItem> docShellParent;
    2586               0 :     dsti->GetParent(getter_AddRefs(docShellParent));
    2587               0 :     if (docShellParent) {
    2588                 :       // move up to the parent shell and try again from there.
    2589                 : 
    2590                 :       // first, get the frame element this window is inside.
    2591               0 :       nsCOMPtr<nsPIDOMWindow> piWindow = do_GetInterface(docShell);
    2592               0 :       NS_ENSURE_TRUE(piWindow, NS_ERROR_FAILURE);
    2593                 : 
    2594                 :       // Next, retrieve the parent docshell, document and presshell.
    2595               0 :       docShell = do_QueryInterface(docShellParent);
    2596               0 :       NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
    2597                 : 
    2598               0 :       nsCOMPtr<nsPIDOMWindow> piParentWindow = do_GetInterface(docShellParent);
    2599               0 :       NS_ENSURE_TRUE(piParentWindow, NS_ERROR_FAILURE);
    2600               0 :       doc = do_QueryInterface(piParentWindow->GetExtantDocument());
    2601               0 :       NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
    2602                 : 
    2603               0 :       presShell = doc->GetShell();
    2604                 : 
    2605               0 :       rootContent = doc->GetRootElement();
    2606               0 :       startContent = do_QueryInterface(piWindow->GetFrameElementInternal());
    2607               0 :       if (startContent) {
    2608               0 :         nsIFrame* frame = startContent->GetPrimaryFrame();
    2609               0 :         if (!frame)
    2610               0 :           return NS_OK;
    2611                 : 
    2612               0 :         frame->IsFocusable(&tabIndex, 0);
    2613               0 :         if (tabIndex < 0) {
    2614               0 :           tabIndex = 1;
    2615               0 :           ignoreTabIndex = true;
    2616                 :         }
    2617                 : 
    2618                 :         // if the frame is inside a popup, make sure to scan only within the
    2619                 :         // popup. This handles the situation of tabbing amongst elements
    2620                 :         // inside an iframe which is itself inside a popup. Otherwise,
    2621                 :         // navigation would move outside the popup when tabbing outside the
    2622                 :         // iframe.
    2623                 :         popupFrame = nsLayoutUtils::GetClosestFrameOfType(frame,
    2624               0 :                                                           nsGkAtoms::menuPopupFrame);
    2625               0 :         if (popupFrame) {
    2626               0 :           rootContent = popupFrame->GetContent();
    2627               0 :           NS_ASSERTION(rootContent, "Popup frame doesn't have a content node");
    2628                 :         }
    2629                 :       }
    2630                 :       else {
    2631               0 :         startContent = rootContent;
    2632               0 :         tabIndex = forward ? 1 : 0;
    2633                 :       }
    2634                 :     }
    2635                 :     else {
    2636                 :       // no parent, so call the tree owner. This will tell the embedder that
    2637                 :       // it should take the focus.
    2638                 :       bool tookFocus;
    2639               0 :       docShell->TabToTreeOwner(forward, &tookFocus);
    2640                 :       // if the tree owner, took the focus, blur the current content
    2641               0 :       if (tookFocus) {
    2642               0 :         nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(docShell);
    2643               0 :         if (window->GetFocusedNode() == mFocusedContent)
    2644               0 :           Blur(mFocusedWindow, nsnull, true, true);
    2645                 :         else
    2646               0 :           window->SetFocusedNode(nsnull);
    2647               0 :         return NS_OK;
    2648                 :       }
    2649                 : 
    2650                 :       // reset the tab index and start again from the beginning or end
    2651               0 :       startContent = rootContent;
    2652               0 :       tabIndex = forward ? 1 : 0;
    2653                 :     }
    2654                 : 
    2655                 :     // wrapped all the way around and didn't find anything to move the focus
    2656                 :     // to, so just break out
    2657               0 :     if (startContent == originalStartContent)
    2658                 :       break;
    2659                 :   }
    2660                 : 
    2661               0 :   return NS_OK;
    2662                 : }
    2663                 : 
    2664                 : nsresult
    2665               0 : nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell,
    2666                 :                                        nsIContent* aRootContent,
    2667                 :                                        nsIContent* aOriginalStartContent,
    2668                 :                                        nsIContent* aStartContent,
    2669                 :                                        bool aForward,
    2670                 :                                        PRInt32 aCurrentTabIndex,
    2671                 :                                        bool aIgnoreTabIndex,
    2672                 :                                        nsIContent** aResultContent)
    2673                 : {
    2674               0 :   *aResultContent = nsnull;
    2675                 : 
    2676               0 :   nsCOMPtr<nsIContent> startContent = aStartContent;
    2677               0 :   if (!startContent)
    2678               0 :     return NS_OK;
    2679                 : 
    2680                 : #ifdef DEBUG_FOCUS_NAVIGATION
    2681                 :   PRINTTAGF("GetNextTabbable: %s", aStartContent);
    2682                 :   printf(" tabindex: %d\n", aCurrentTabIndex);
    2683                 : #endif
    2684                 : 
    2685               0 :   nsPresContext* presContext = aPresShell->GetPresContext();
    2686                 : 
    2687               0 :   bool getNextFrame = true;
    2688               0 :   nsCOMPtr<nsIContent> iterStartContent = aStartContent;
    2689               0 :   while (1) {
    2690               0 :     nsIFrame* startFrame = iterStartContent->GetPrimaryFrame();
    2691                 :     // if there is no frame, look for another content node that has a frame
    2692               0 :     if (!startFrame) {
    2693                 :       // if the root content doesn't have a frame, just return
    2694               0 :       if (iterStartContent == aRootContent)
    2695               0 :         return NS_OK;
    2696                 : 
    2697                 :       // look for the next or previous content node in tree order
    2698               0 :       iterStartContent = aForward ? iterStartContent->GetNextNode() : iterStartContent->GetPreviousContent();
    2699                 :       // we've already skipped over the initial focused content, so we
    2700                 :       // don't want to traverse frames.
    2701               0 :       getNextFrame = false;
    2702               0 :       if (iterStartContent)
    2703               0 :         continue;
    2704                 : 
    2705                 :       // otherwise, as a last attempt, just look at the root content
    2706               0 :       iterStartContent = aRootContent;
    2707               0 :       continue;
    2708                 :     }
    2709                 : 
    2710               0 :     nsCOMPtr<nsIFrameEnumerator> frameTraversal;
    2711               0 :     nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
    2712                 :                                        presContext, startFrame,
    2713                 :                                        ePreOrder,
    2714                 :                                        false, // aVisual
    2715                 :                                        false, // aLockInScrollView
    2716                 :                                        true      // aFollowOOFs
    2717               0 :                                        );
    2718               0 :     NS_ENSURE_SUCCESS(rv, rv);
    2719                 : 
    2720               0 :     if (iterStartContent == aRootContent) {
    2721               0 :       if (!aForward) {
    2722               0 :         frameTraversal->Last();
    2723               0 :       } else if (aRootContent->IsFocusable()) {
    2724               0 :         frameTraversal->Next();
    2725                 :       }
    2726                 :     }
    2727               0 :     else if (getNextFrame &&
    2728               0 :              (!iterStartContent || iterStartContent->Tag() != nsGkAtoms::area ||
    2729               0 :               !iterStartContent->IsHTML())) {
    2730                 :       // Need to do special check in case we're in an imagemap which has multiple
    2731                 :       // content nodes per frame, so don't skip over the starting frame.
    2732               0 :       if (aForward)
    2733               0 :         frameTraversal->Next();
    2734                 :       else
    2735               0 :         frameTraversal->Prev();
    2736                 :     }
    2737                 : 
    2738                 :     // Walk frames to find something tabbable matching mCurrentTabIndex
    2739               0 :     nsIFrame* frame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
    2740               0 :     while (frame) {
    2741                 :       // TabIndex not set defaults to 0 for form elements, anchors and other
    2742                 :       // elements that are normally focusable. Tabindex defaults to -1
    2743                 :       // for elements that are not normally focusable.
    2744                 :       // The returned computed tabindex from IsFocusable() is as follows:
    2745                 :       //          < 0 not tabbable at all
    2746                 :       //          == 0 in normal tab order (last after positive tabindexed items)
    2747                 :       //          > 0 can be tabbed to in the order specified by this value
    2748                 : 
    2749                 :       PRInt32 tabIndex;
    2750               0 :       frame->IsFocusable(&tabIndex, 0);
    2751                 : 
    2752                 : #ifdef DEBUG_FOCUS_NAVIGATION
    2753                 :       if (frame->GetContent()) {
    2754                 :         PRINTTAGF("Next Tabbable %s:", frame->GetContent());
    2755                 :         printf(" with tabindex: %d expected: %d\n", tabIndex, aCurrentTabIndex);
    2756                 :       }
    2757                 : #endif
    2758                 : 
    2759               0 :       nsIContent* currentContent = frame->GetContent();
    2760               0 :       if (tabIndex >= 0) {
    2761               0 :         NS_ASSERTION(currentContent, "IsFocusable set a tabindex for a frame with no content");
    2762               0 :         if (currentContent->Tag() == nsGkAtoms::img &&
    2763               0 :             currentContent->HasAttr(kNameSpaceID_None, nsGkAtoms::usemap)) {
    2764                 :           // This is an image with a map. Image map areas are not traversed by
    2765                 :           // nsIFrameTraversal so look for the next or previous area element.
    2766                 :           nsIContent *areaContent =
    2767                 :             GetNextTabbableMapArea(aForward, aCurrentTabIndex,
    2768               0 :                                    currentContent, iterStartContent);
    2769               0 :           if (areaContent) {
    2770               0 :             NS_ADDREF(*aResultContent = areaContent);
    2771               0 :             return NS_OK;
    2772                 :           }
    2773                 :         }
    2774               0 :         else if (aIgnoreTabIndex || aCurrentTabIndex == tabIndex) {
    2775                 :           // break out if we've wrapped around to the start again.
    2776               0 :           if (aOriginalStartContent && currentContent == aOriginalStartContent) {
    2777               0 :             NS_ADDREF(*aResultContent = currentContent);
    2778               0 :             return NS_OK;
    2779                 :           }
    2780                 : 
    2781                 :           // found a node with a matching tab index. Check if it is a child
    2782                 :           // frame. If so, navigate into the child frame instead.
    2783               0 :           nsIDocument* doc = currentContent->GetCurrentDoc();
    2784               0 :           NS_ASSERTION(doc, "content not in document");
    2785               0 :           nsIDocument* subdoc = doc->GetSubDocumentFor(currentContent);
    2786               0 :           if (subdoc) {
    2787               0 :             if (!subdoc->EventHandlingSuppressed()) {
    2788               0 :               if (aForward) {
    2789                 :                 // when tabbing forward into a frame, return the root
    2790                 :                 // frame so that the canvas becomes focused.
    2791               0 :                 nsCOMPtr<nsPIDOMWindow> subframe = subdoc->GetWindow();
    2792               0 :                 if (subframe) {
    2793                 :                   // If the subframe body is editable by contenteditable,
    2794                 :                   // we should set the editor's root element rather than the
    2795                 :                   // actual root element.  Otherwise, we should set the focus
    2796                 :                   // to the root content.
    2797                 :                   *aResultContent =
    2798               0 :                     nsLayoutUtils::GetEditableRootContentByContentEditable(subdoc);
    2799               0 :                   if (!*aResultContent ||
    2800               0 :                       !((*aResultContent)->GetPrimaryFrame())) {
    2801                 :                     *aResultContent =
    2802               0 :                       GetRootForFocus(subframe, subdoc, false, true);
    2803                 :                   }
    2804               0 :                   if (*aResultContent) {
    2805               0 :                     NS_ADDREF(*aResultContent);
    2806               0 :                     return NS_OK;
    2807                 :                   }
    2808                 :                 }
    2809                 :               }
    2810               0 :               Element* rootElement = subdoc->GetRootElement();
    2811               0 :               nsIPresShell* subShell = subdoc->GetShell();
    2812               0 :               if (rootElement && subShell) {
    2813                 :                 rv = GetNextTabbableContent(subShell, rootElement,
    2814                 :                                             aOriginalStartContent, rootElement,
    2815                 :                                             aForward, (aForward ? 1 : 0),
    2816               0 :                                             false, aResultContent);
    2817               0 :                 NS_ENSURE_SUCCESS(rv, rv);
    2818               0 :                 if (*aResultContent)
    2819               0 :                   return NS_OK;
    2820                 :               }
    2821                 :             }
    2822                 :           }
    2823                 :           // otherwise, use this as the next content node to tab to, unless
    2824                 :           // this was the element we started on. This would happen for
    2825                 :           // instance on an element with child frames, where frame navigation
    2826                 :           // could return the original element again. In that case, just skip
    2827                 :           // it. Also, if the next content node is the root content, then
    2828                 :           // return it. This latter case would happen only if someone made a
    2829                 :           // popup focusable.
    2830                 :           // Also, when going backwards, check to ensure that the focus
    2831                 :           // wouldn't be redirected. Otherwise, for example, when an input in
    2832                 :           // a textbox is focused, the enclosing textbox would be found and
    2833                 :           // the same inner input would be returned again.
    2834               0 :           else if (currentContent == aRootContent ||
    2835               0 :                    (currentContent != startContent &&
    2836               0 :                     (aForward || !GetRedirectedFocus(currentContent)))) {
    2837               0 :             NS_ADDREF(*aResultContent = currentContent);
    2838               0 :             return NS_OK;
    2839                 :           }
    2840                 :         }
    2841                 :       }
    2842               0 :       else if (aOriginalStartContent && currentContent == aOriginalStartContent) {
    2843                 :         // not focusable, so return if we have wrapped around to the original
    2844                 :         // content. This is necessary in case the original starting content was
    2845                 :         // not focusable.
    2846               0 :         NS_ADDREF(*aResultContent = currentContent);
    2847               0 :         return NS_OK;
    2848                 :       }
    2849                 : 
    2850                 :       // Move to the next or previous frame, but ignore continuation frames
    2851                 :       // since only the first frame should be involved in focusability.
    2852                 :       // Otherwise, a loop will occur in the following example:
    2853                 :       //   <span tabindex="1">...<a/><a/>...</span>
    2854                 :       // where the text wraps onto multiple lines. Tabbing from the second
    2855                 :       // link can find one of the span's continuation frames between the link
    2856                 :       // and the end of the span, and the span would end up getting focused
    2857                 :       // again.
    2858               0 :       do {
    2859               0 :         if (aForward)
    2860               0 :           frameTraversal->Next();
    2861                 :         else
    2862               0 :           frameTraversal->Prev();
    2863               0 :         frame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
    2864               0 :       } while (frame && frame->GetPrevContinuation());
    2865                 :     }
    2866                 : 
    2867                 :     // If already at lowest priority tab (0), end search completely.
    2868                 :     // A bit counterintuitive but true, tabindex order goes 1, 2, ... 32767, 0
    2869               0 :     if (aCurrentTabIndex == (aForward ? 0 : 1)) {
    2870                 :       // if going backwards, the canvas should be focused once the beginning
    2871                 :       // has been reached.
    2872               0 :       if (!aForward) {
    2873               0 :         nsCOMPtr<nsPIDOMWindow> window = GetCurrentWindow(aRootContent);
    2874               0 :         NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
    2875               0 :         NS_IF_ADDREF(*aResultContent =
    2876               0 :                      GetRootForFocus(window, aRootContent->GetCurrentDoc(), false, true));
    2877                 :       }
    2878                 :       break;
    2879                 :     }
    2880                 : 
    2881                 :     // continue looking for next highest priority tabindex
    2882               0 :     aCurrentTabIndex = GetNextTabIndex(aRootContent, aCurrentTabIndex, aForward);
    2883               0 :     startContent = iterStartContent = aRootContent;
    2884                 :   }
    2885                 : 
    2886               0 :   return NS_OK;
    2887                 : }
    2888                 : 
    2889                 : nsIContent*
    2890               0 : nsFocusManager::GetNextTabbableMapArea(bool aForward,
    2891                 :                                        PRInt32 aCurrentTabIndex,
    2892                 :                                        nsIContent* aImageContent,
    2893                 :                                        nsIContent* aStartContent)
    2894                 : {
    2895               0 :   nsAutoString useMap;
    2896               0 :   aImageContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, useMap);
    2897                 : 
    2898               0 :   nsCOMPtr<nsIDocument> doc = aImageContent->GetDocument();
    2899               0 :   if (doc) {
    2900               0 :     nsCOMPtr<nsIContent> mapContent = doc->FindImageMap(useMap);
    2901               0 :     if (!mapContent)
    2902               0 :       return nsnull;
    2903               0 :     PRUint32 count = mapContent->GetChildCount();
    2904                 :     // First see if the the start content is in this map
    2905                 : 
    2906               0 :     PRInt32 index = mapContent->IndexOf(aStartContent);
    2907                 :     PRInt32 tabIndex;
    2908               0 :     if (index < 0 || (aStartContent->IsFocusable(&tabIndex) &&
    2909                 :                       tabIndex != aCurrentTabIndex)) {
    2910                 :       // If aStartContent is in this map we must start iterating past it.
    2911                 :       // We skip the case where aStartContent has tabindex == aStartContent
    2912                 :       // since the next tab ordered element might be before it
    2913                 :       // (or after for backwards) in the child list.
    2914               0 :       index = aForward ? -1 : (PRInt32)count;
    2915                 :     }
    2916                 : 
    2917                 :     // GetChildAt will return nsnull if our index < 0 or index >= count
    2918               0 :     nsCOMPtr<nsIContent> areaContent;
    2919               0 :     while ((areaContent = mapContent->GetChildAt(aForward ? ++index : --index)) != nsnull) {
    2920               0 :       if (areaContent->IsFocusable(&tabIndex) && tabIndex == aCurrentTabIndex) {
    2921               0 :         return areaContent;
    2922                 :       }
    2923                 :     }
    2924                 :   }
    2925                 : 
    2926               0 :   return nsnull;
    2927                 : }
    2928                 : 
    2929                 : PRInt32
    2930               0 : nsFocusManager::GetNextTabIndex(nsIContent* aParent,
    2931                 :                                 PRInt32 aCurrentTabIndex,
    2932                 :                                 bool aForward)
    2933                 : {
    2934                 :   PRInt32 tabIndex, childTabIndex;
    2935                 : 
    2936               0 :   if (aForward) {
    2937               0 :     tabIndex = 0;
    2938               0 :     for (nsIContent* child = aParent->GetFirstChild();
    2939                 :          child;
    2940               0 :          child = child->GetNextSibling()) {
    2941               0 :       childTabIndex = GetNextTabIndex(child, aCurrentTabIndex, aForward);
    2942               0 :       if (childTabIndex > aCurrentTabIndex && childTabIndex != tabIndex) {
    2943               0 :         tabIndex = (tabIndex == 0 || childTabIndex < tabIndex) ? childTabIndex : tabIndex;
    2944                 :       }
    2945                 : 
    2946               0 :       nsAutoString tabIndexStr;
    2947               0 :       child->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr);
    2948               0 :       PRInt32 ec, val = tabIndexStr.ToInteger(&ec);
    2949               0 :       if (NS_SUCCEEDED (ec) && val > aCurrentTabIndex && val != tabIndex) {
    2950               0 :         tabIndex = (tabIndex == 0 || val < tabIndex) ? val : tabIndex;
    2951                 :       }
    2952                 :     }
    2953                 :   }
    2954                 :   else { /* !aForward */
    2955               0 :     tabIndex = 1;
    2956               0 :     for (nsIContent* child = aParent->GetFirstChild();
    2957                 :          child;
    2958               0 :          child = child->GetNextSibling()) {
    2959               0 :       childTabIndex = GetNextTabIndex(child, aCurrentTabIndex, aForward);
    2960               0 :       if ((aCurrentTabIndex == 0 && childTabIndex > tabIndex) ||
    2961                 :           (childTabIndex < aCurrentTabIndex && childTabIndex > tabIndex)) {
    2962               0 :         tabIndex = childTabIndex;
    2963                 :       }
    2964                 : 
    2965               0 :       nsAutoString tabIndexStr;
    2966               0 :       child->GetAttr(kNameSpaceID_None, nsGkAtoms::tabindex, tabIndexStr);
    2967               0 :       PRInt32 ec, val = tabIndexStr.ToInteger(&ec);
    2968               0 :       if (NS_SUCCEEDED (ec)) {
    2969               0 :         if ((aCurrentTabIndex == 0 && val > tabIndex) ||
    2970                 :             (val < aCurrentTabIndex && val > tabIndex) ) {
    2971               0 :           tabIndex = val;
    2972                 :         }
    2973                 :       }
    2974                 :     }
    2975                 :   }
    2976                 : 
    2977               0 :   return tabIndex;
    2978                 : }
    2979                 : 
    2980                 : nsIContent*
    2981               0 : nsFocusManager::GetRootForFocus(nsPIDOMWindow* aWindow,
    2982                 :                                 nsIDocument* aDocument,
    2983                 :                                 bool aIsForDocNavigation,
    2984                 :                                 bool aCheckVisibility)
    2985                 : {
    2986                 :   // the root element's canvas may be focused as long as the document is in a
    2987                 :   // a non-chrome shell and does not contain a frameset.
    2988               0 :   if (aIsForDocNavigation) {
    2989                 :     nsCOMPtr<nsIContent> docContent =
    2990               0 :       do_QueryInterface(aWindow->GetFrameElementInternal());
    2991                 :     // document navigation skips iframes and frames that are specifically non-focusable
    2992               0 :     if (docContent) {
    2993               0 :       if (docContent->Tag() == nsGkAtoms::iframe)
    2994               0 :         return nsnull;
    2995                 : 
    2996               0 :       nsIFrame* frame = docContent->GetPrimaryFrame();
    2997               0 :       if (!frame || !frame->IsFocusable(nsnull, 0))
    2998               0 :         return nsnull;
    2999                 :     }
    3000                 :   }
    3001                 :   else  {
    3002                 :     PRInt32 itemType;
    3003               0 :     nsCOMPtr<nsIDocShellTreeItem> shellItem = do_QueryInterface(aWindow->GetDocShell());
    3004               0 :     shellItem->GetItemType(&itemType);
    3005                 : 
    3006               0 :     if (itemType == nsIDocShellTreeItem::typeChrome)
    3007               0 :       return nsnull;
    3008                 :   }
    3009                 : 
    3010               0 :   if (aCheckVisibility && !IsWindowVisible(aWindow))
    3011               0 :     return nsnull;
    3012                 : 
    3013               0 :   Element *rootElement = aDocument->GetRootElement();
    3014               0 :   if (!rootElement) {
    3015               0 :     return nsnull;
    3016                 :   }
    3017                 : 
    3018               0 :   if (aCheckVisibility && !rootElement->GetPrimaryFrame()) {
    3019               0 :     return nsnull;
    3020                 :   }
    3021                 : 
    3022                 :   // Finally, check if this is a frameset
    3023               0 :   nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(aDocument);
    3024               0 :   if (htmlDoc && aDocument->GetHtmlChildElement(nsGkAtoms::frameset)) {
    3025               0 :     return nsnull;
    3026                 :   }
    3027                 : 
    3028               0 :   return rootElement;
    3029                 : }
    3030                 : 
    3031                 : TabParent*
    3032               0 : nsFocusManager::GetRemoteForContent(nsIContent* aContent) {
    3033               0 :   if (!aContent ||
    3034               0 :       (aContent->Tag() != nsGkAtoms::browser &&
    3035               0 :        aContent->Tag() != nsGkAtoms::iframe) ||
    3036               0 :       !aContent->IsXUL() ||
    3037                 :       !aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
    3038               0 :                              nsGkAtoms::_true, eIgnoreCase))
    3039               0 :     return nsnull;
    3040                 : 
    3041               0 :   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
    3042               0 :   if (!loaderOwner)
    3043               0 :     return nsnull;
    3044                 : 
    3045               0 :   nsRefPtr<nsFrameLoader> frameLoader = loaderOwner->GetFrameLoader();
    3046               0 :   if (!frameLoader)
    3047               0 :     return nsnull;
    3048                 : 
    3049               0 :   PBrowserParent* remoteBrowser = frameLoader->GetRemoteBrowser();
    3050               0 :   TabParent* remote = static_cast<TabParent*>(remoteBrowser);
    3051               0 :   return remote;
    3052                 : }
    3053                 : 
    3054                 : void
    3055               0 : nsFocusManager::GetLastDocShell(nsIDocShellTreeItem* aItem,
    3056                 :                                 nsIDocShellTreeItem** aResult)
    3057                 : {
    3058               0 :   *aResult = nsnull;
    3059                 : 
    3060               0 :   nsCOMPtr<nsIDocShellTreeItem> curItem = aItem;
    3061               0 :   while (curItem) {
    3062               0 :     PRInt32 childCount = 0;
    3063               0 :     curItem->GetChildCount(&childCount);
    3064               0 :     if (!childCount) {
    3065               0 :       *aResult = curItem;
    3066               0 :       NS_ADDREF(*aResult);
    3067                 :       return;
    3068                 :     }
    3069                 : 
    3070                 :     
    3071               0 :     curItem->GetChildAt(childCount - 1, getter_AddRefs(curItem));
    3072                 :   }
    3073                 : }
    3074                 : 
    3075                 : void
    3076               0 : nsFocusManager::GetNextDocShell(nsIDocShellTreeItem* aItem,
    3077                 :                                 nsIDocShellTreeItem** aResult)
    3078                 : {
    3079               0 :   *aResult = nsnull;
    3080                 : 
    3081               0 :   PRInt32 childCount = 0;
    3082               0 :   aItem->GetChildCount(&childCount);
    3083               0 :   if (childCount) {
    3084               0 :     aItem->GetChildAt(0, aResult);
    3085               0 :     if (*aResult)
    3086               0 :       return;
    3087                 :   }
    3088                 : 
    3089               0 :   nsCOMPtr<nsIDocShellTreeItem> curItem = aItem;
    3090               0 :   while (curItem) {
    3091               0 :     nsCOMPtr<nsIDocShellTreeItem> parentItem;
    3092               0 :     curItem->GetParent(getter_AddRefs(parentItem));
    3093               0 :     if (!parentItem)
    3094                 :       return;
    3095                 : 
    3096                 :     // Note that we avoid using GetChildOffset() here because docshell
    3097                 :     // child offsets can't be trusted to be correct. bug 162283.
    3098               0 :     nsCOMPtr<nsIDocShellTreeItem> iterItem;
    3099               0 :     childCount = 0;
    3100               0 :     parentItem->GetChildCount(&childCount);
    3101               0 :     for (PRInt32 index = 0; index < childCount; ++index) {
    3102               0 :       parentItem->GetChildAt(index, getter_AddRefs(iterItem));
    3103               0 :       if (iterItem == curItem) {
    3104               0 :         ++index;
    3105               0 :         if (index < childCount) {
    3106               0 :           parentItem->GetChildAt(index, aResult);
    3107               0 :           if (*aResult)
    3108                 :             return;
    3109                 :         }
    3110               0 :         break;
    3111                 :       }
    3112                 :     }
    3113                 : 
    3114               0 :     curItem = parentItem;
    3115                 :   }
    3116                 : }
    3117                 : 
    3118                 : void
    3119               0 : nsFocusManager::GetPreviousDocShell(nsIDocShellTreeItem* aItem,
    3120                 :                                     nsIDocShellTreeItem** aResult)
    3121                 : {
    3122               0 :   *aResult = nsnull;
    3123                 : 
    3124               0 :   nsCOMPtr<nsIDocShellTreeItem> parentItem;
    3125               0 :   aItem->GetParent(getter_AddRefs(parentItem));
    3126               0 :   if (!parentItem)
    3127                 :     return;
    3128                 : 
    3129                 :   // Note that we avoid using GetChildOffset() here because docshell
    3130                 :   // child offsets can't be trusted to be correct. bug 162283.
    3131               0 :   PRInt32 childCount = 0;
    3132               0 :   parentItem->GetChildCount(&childCount);
    3133               0 :   nsCOMPtr<nsIDocShellTreeItem> prevItem, iterItem;
    3134               0 :   for (PRInt32 index = 0; index < childCount; ++index) {
    3135               0 :     parentItem->GetChildAt(index, getter_AddRefs(iterItem));
    3136               0 :     if (iterItem == aItem)
    3137               0 :       break;
    3138               0 :     prevItem = iterItem;
    3139                 :   }
    3140                 : 
    3141               0 :   if (prevItem)
    3142               0 :     GetLastDocShell(prevItem, aResult);
    3143                 :   else
    3144               0 :     NS_ADDREF(*aResult = parentItem);
    3145                 : }
    3146                 : 
    3147                 : nsIContent*
    3148               0 : nsFocusManager::GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward)
    3149                 : {
    3150               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
    3151               0 :   if (!pm)
    3152               0 :     return nsnull;
    3153                 : 
    3154                 :   // Iterate through the array backwards if aForward is false.
    3155               0 :   nsTArray<nsIFrame *> popups = pm->GetVisiblePopups();
    3156               0 :   PRInt32 i = aForward ? 0 : popups.Length() - 1;
    3157               0 :   PRInt32 end = aForward ? popups.Length() : -1;
    3158                 : 
    3159               0 :   for (; i != end; aForward ? i++ : i--) {
    3160               0 :     nsIFrame* popupFrame = popups[i];
    3161               0 :     if (aCurrentPopup) {
    3162                 :       // If the current popup is set, then we need to skip over this popup and
    3163                 :       // wait until the currently focused popup is found. Once found, the
    3164                 :       // current popup will be cleared so that the next popup is used.
    3165               0 :       if (aCurrentPopup == popupFrame)
    3166               0 :         aCurrentPopup = nsnull;
    3167               0 :       continue;
    3168                 :     }
    3169                 : 
    3170                 :     // Skip over non-panels
    3171               0 :     if (popupFrame->GetContent()->Tag() != nsGkAtoms::panel ||
    3172               0 :         (aDocument && popupFrame->GetContent()->GetCurrentDoc() != aDocument)) {
    3173               0 :       continue;
    3174                 :     }
    3175                 : 
    3176                 :     // Find the first focusable content within the popup. If there isn't any
    3177                 :     // focusable content in the popup, skip to the next popup.
    3178               0 :     nsIPresShell* presShell = popupFrame->PresContext()->GetPresShell();
    3179               0 :     if (presShell) {
    3180               0 :       nsCOMPtr<nsIContent> nextFocus;
    3181               0 :       nsIContent* popup = popupFrame->GetContent();
    3182                 :       nsresult rv = GetNextTabbableContent(presShell, popup,
    3183                 :                                            nsnull, popup,
    3184                 :                                            true, 1, false,
    3185               0 :                                            getter_AddRefs(nextFocus));
    3186               0 :       if (NS_SUCCEEDED(rv) && nextFocus) {
    3187               0 :         return nextFocus.get();
    3188                 :       }
    3189                 :     }
    3190                 :   }
    3191                 : 
    3192               0 :   return nsnull;
    3193                 : }
    3194                 : 
    3195                 : nsIContent*
    3196               0 : nsFocusManager::GetNextTabbableDocument(nsIContent* aStartContent, bool aForward)
    3197                 : {
    3198                 :   // If currentPopup is set, then the starting content is in a panel.
    3199               0 :   nsIFrame* currentPopup = nsnull;
    3200               0 :   nsCOMPtr<nsIDocument> doc;
    3201               0 :   nsCOMPtr<nsIDocShellTreeItem> startItem;
    3202                 : 
    3203               0 :   if (aStartContent) {
    3204               0 :     doc = aStartContent->GetCurrentDoc();
    3205               0 :     if (doc) {
    3206               0 :       startItem = do_QueryInterface(doc->GetWindow()->GetDocShell());
    3207                 :     }
    3208                 : 
    3209                 :     // Check if the starting content is inside a panel. Document navigation
    3210                 :     // must start from this panel instead of the document root.
    3211               0 :     nsIContent* content = aStartContent;
    3212               0 :     while (content) {
    3213               0 :       if (content->NodeInfo()->Equals(nsGkAtoms::panel, kNameSpaceID_XUL)) {
    3214               0 :         currentPopup = content->GetPrimaryFrame();
    3215               0 :         break;
    3216                 :       }
    3217               0 :       content = content->GetParent();
    3218                 :     }
    3219                 :   }
    3220               0 :   else if (mFocusedWindow) {
    3221               0 :     startItem = do_QueryInterface(mFocusedWindow->GetDocShell());
    3222               0 :     doc = do_QueryInterface(mFocusedWindow->GetExtantDocument());
    3223                 :   }
    3224                 :   else {
    3225               0 :     nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(mActiveWindow);
    3226               0 :     startItem = do_QueryInterface(webnav);
    3227                 : 
    3228               0 :     if (mActiveWindow) {
    3229               0 :       doc = do_QueryInterface(mActiveWindow->GetExtantDocument());
    3230                 :     }
    3231                 :   }
    3232                 : 
    3233               0 :   if (!startItem)
    3234               0 :     return nsnull;
    3235                 : 
    3236                 :   // perform a depth first search (preorder) of the docshell tree
    3237                 :   // looking for an HTML Frame or a chrome document
    3238               0 :   nsIContent* content = aStartContent;
    3239               0 :   nsCOMPtr<nsIDocShellTreeItem> curItem = startItem;
    3240               0 :   nsCOMPtr<nsIDocShellTreeItem> nextItem;
    3241               0 :   do {
    3242                 :     // If moving forward, check for a panel in the starting document. If one
    3243                 :     // exists with focusable content, return that content instead of the next
    3244                 :     // document. If currentPopup is set, then, another panel may exist. If no
    3245                 :     // such panel exists, then continue on to check the next document.
    3246                 :     // When moving backwards, and the starting content is in a panel, then
    3247                 :     // check for additional panels in the starting document. If the starting
    3248                 :     // content is not in a panel, move back to the previous document and check
    3249                 :     // for panels there.
    3250                 : 
    3251               0 :     bool checkPopups = false;
    3252               0 :     nsCOMPtr<nsPIDOMWindow> nextFrame = nsnull;
    3253                 : 
    3254               0 :     if (doc && (aForward || currentPopup)) {
    3255               0 :       nsIContent* popupContent = GetNextTabbablePanel(doc, currentPopup, aForward);
    3256               0 :       if (popupContent)
    3257               0 :         return popupContent;
    3258                 : 
    3259               0 :       if (!aForward && currentPopup) {
    3260                 :         // The starting content was in a popup, yet no other popups were
    3261                 :         // found. Move onto the starting content's document.
    3262               0 :         nextFrame = doc->GetWindow();
    3263                 :       }
    3264                 :     }
    3265                 : 
    3266                 :     // Look for the next or previous document.
    3267               0 :     if (!nextFrame) {
    3268               0 :       if (aForward) {
    3269               0 :         GetNextDocShell(curItem, getter_AddRefs(nextItem));
    3270               0 :         if (!nextItem) {
    3271                 :           // wrap around to the beginning, which is the top of the tree
    3272               0 :           startItem->GetRootTreeItem(getter_AddRefs(nextItem));
    3273                 :         }
    3274                 :       }
    3275                 :       else {
    3276               0 :         GetPreviousDocShell(curItem, getter_AddRefs(nextItem));
    3277               0 :         if (!nextItem) {
    3278                 :           // wrap around to the end, which is the last item in the tree
    3279               0 :           nsCOMPtr<nsIDocShellTreeItem> rootItem;
    3280               0 :           startItem->GetRootTreeItem(getter_AddRefs(rootItem));
    3281               0 :           GetLastDocShell(rootItem, getter_AddRefs(nextItem));
    3282                 :         }
    3283                 : 
    3284                 :         // When going back to the previous document, check for any focusable
    3285                 :         // popups in that previous document first.
    3286               0 :         checkPopups = true;
    3287                 :       }
    3288                 : 
    3289               0 :       curItem = nextItem;
    3290               0 :       nextFrame = do_GetInterface(nextItem);
    3291                 :     }
    3292                 : 
    3293               0 :     if (!nextFrame)
    3294               0 :       return nsnull;
    3295                 : 
    3296                 :     // Clear currentPopup for the next iteration
    3297               0 :     currentPopup = nsnull;
    3298                 : 
    3299                 :     // If event handling is suppressed, move on to the next document. Set
    3300                 :     // content to null so that the popup check will be skipped on the next
    3301                 :     // loop iteration.
    3302               0 :     doc = do_QueryInterface(nextFrame->GetExtantDocument());
    3303               0 :     if (!doc || doc->EventHandlingSuppressed()) {
    3304               0 :       content = nsnull;
    3305               0 :       continue;
    3306                 :     }
    3307                 : 
    3308               0 :     if (checkPopups) {
    3309                 :       // When iterating backwards, check the panels of the previous document
    3310                 :       // first. If a panel exists that has focusable content, focus that.
    3311                 :       // Otherwise, continue on to focus the document.
    3312               0 :       nsIContent* popupContent = GetNextTabbablePanel(doc, nsnull, false);
    3313               0 :       if (popupContent)
    3314               0 :         return popupContent;
    3315                 :     }
    3316                 : 
    3317               0 :     content = GetRootForFocus(nextFrame, doc, true, true);
    3318               0 :     if (content && !GetRootForFocus(nextFrame, doc, false, false)) {
    3319                 :       // if the found content is in a chrome shell or a frameset, navigate
    3320                 :       // forward one tabbable item so that the first item is focused. Note
    3321                 :       // that we always go forward and not back here.
    3322               0 :       nsCOMPtr<nsIContent> nextFocus;
    3323               0 :       Element* rootElement = doc->GetRootElement();
    3324               0 :       nsIPresShell* presShell = doc->GetShell();
    3325               0 :       if (presShell) {
    3326                 :         nsresult rv = GetNextTabbableContent(presShell, rootElement,
    3327                 :                                              nsnull, rootElement,
    3328                 :                                              true, 1, false,
    3329               0 :                                              getter_AddRefs(nextFocus));
    3330               0 :         return NS_SUCCEEDED(rv) ? nextFocus.get() : nsnull;
    3331                 :       }
    3332                 :     }
    3333                 : 
    3334               0 :   } while (!content);
    3335                 : 
    3336               0 :   return content;
    3337                 : }
    3338                 : 
    3339                 : void
    3340               0 : nsFocusManager::GetFocusInSelection(nsPIDOMWindow* aWindow,
    3341                 :                                     nsIContent* aStartSelection,
    3342                 :                                     nsIContent* aEndSelection,
    3343                 :                                     nsIContent** aFocusedContent)
    3344                 : {
    3345               0 :   *aFocusedContent = nsnull;
    3346                 : 
    3347               0 :   nsCOMPtr<nsIContent> testContent = aStartSelection;
    3348               0 :   nsCOMPtr<nsIContent> nextTestContent = aEndSelection;
    3349                 : 
    3350               0 :   nsCOMPtr<nsIContent> currentFocus = aWindow->GetFocusedNode();
    3351                 : 
    3352                 :   // We now have the correct start node in selectionContent!
    3353                 :   // Search for focusable elements, starting with selectionContent
    3354                 : 
    3355                 :   // Method #1: Keep going up while we look - an ancestor might be focusable
    3356                 :   // We could end the loop earlier, such as when we're no longer
    3357                 :   // in the same frame, by comparing selectionContent->GetPrimaryFrame()
    3358                 :   // with a variable holding the starting selectionContent
    3359               0 :   while (testContent) {
    3360                 :     // Keep testing while selectionContent is equal to something,
    3361                 :     // eventually we'll run out of ancestors
    3362                 : 
    3363               0 :     nsCOMPtr<nsIURI> uri;
    3364               0 :     if (testContent == currentFocus ||
    3365               0 :         testContent->IsLink(getter_AddRefs(uri))) {
    3366               0 :       NS_ADDREF(*aFocusedContent = testContent);
    3367                 :       return;
    3368                 :     }
    3369                 : 
    3370                 :     // Get the parent
    3371               0 :     testContent = testContent->GetParent();
    3372                 : 
    3373               0 :     if (!testContent) {
    3374                 :       // We run this loop again, checking the ancestor chain of the selection's end point
    3375               0 :       testContent = nextTestContent;
    3376               0 :       nextTestContent = nsnull;
    3377                 :     }
    3378                 :   }
    3379                 : 
    3380                 :   // We couldn't find an anchor that was an ancestor of the selection start
    3381                 :   // Method #2: look for anchor in selection's primary range (depth first search)
    3382                 : 
    3383                 :   // Turn into nodes so that we can use GetNextSibling() and GetFirstChild()
    3384               0 :   nsCOMPtr<nsIDOMNode> selectionNode(do_QueryInterface(aStartSelection));
    3385               0 :   nsCOMPtr<nsIDOMNode> endSelectionNode(do_QueryInterface(aEndSelection));
    3386               0 :   nsCOMPtr<nsIDOMNode> testNode;
    3387                 : 
    3388               0 :   do {
    3389               0 :     testContent = do_QueryInterface(selectionNode);
    3390                 : 
    3391                 :     // We're looking for any focusable link that could be part of the
    3392                 :     // main document's selection.
    3393               0 :     nsCOMPtr<nsIURI> uri;
    3394               0 :     if (testContent == currentFocus ||
    3395               0 :         testContent->IsLink(getter_AddRefs(uri))) {
    3396               0 :       NS_ADDREF(*aFocusedContent = testContent);
    3397                 :       return;
    3398                 :     }
    3399                 : 
    3400               0 :     selectionNode->GetFirstChild(getter_AddRefs(testNode));
    3401               0 :     if (testNode) {
    3402               0 :       selectionNode = testNode;
    3403               0 :       continue;
    3404                 :     }
    3405                 : 
    3406               0 :     if (selectionNode == endSelectionNode)
    3407                 :       break;
    3408               0 :     selectionNode->GetNextSibling(getter_AddRefs(testNode));
    3409               0 :     if (testNode) {
    3410               0 :       selectionNode = testNode;
    3411               0 :       continue;
    3412                 :     }
    3413                 : 
    3414               0 :     do {
    3415               0 :       selectionNode->GetParentNode(getter_AddRefs(testNode));
    3416               0 :       if (!testNode || testNode == endSelectionNode) {
    3417               0 :         selectionNode = nsnull;
    3418               0 :         break;
    3419                 :       }
    3420               0 :       testNode->GetNextSibling(getter_AddRefs(selectionNode));
    3421               0 :       if (selectionNode)
    3422               0 :         break;
    3423               0 :       selectionNode = testNode;
    3424                 :     } while (true);
    3425                 :   }
    3426               0 :   while (selectionNode && selectionNode != endSelectionNode);
    3427                 : }
    3428                 : 
    3429                 : nsresult
    3430               2 : NS_NewFocusManager(nsIFocusManager** aResult)
    3431                 : {
    3432               2 :   NS_IF_ADDREF(*aResult = nsFocusManager::GetFocusManager());
    3433               2 :   return NS_OK;
    3434            4392 : }

Generated by: LCOV version 1.7