LCOV - code coverage report
Current view: directory - toolkit/components/typeaheadfind - nsTypeAheadFind.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 565 0 0.0 %
Date: 2012-06-02 Functions: 28 0 0.0 %

       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 mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Aaron Leventhal (aaronl@netscape.com)
      24                 :  *   Blake Ross      (blake@cs.stanford.edu)
      25                 :  *   Masayuki Nakano (masayuki@d-toybox.com)
      26                 :  *   Asaf Romano     (mano@mozilla.com)
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsMemory.h"
      44                 : #include "nsIServiceManager.h"
      45                 : #include "mozilla/ModuleUtils.h"
      46                 : #include "nsIWebBrowserChrome.h"
      47                 : #include "nsCURILoader.h"
      48                 : #include "nsNetUtil.h"
      49                 : #include "nsIURL.h"
      50                 : #include "nsIURI.h"
      51                 : #include "nsIDocShell.h"
      52                 : #include "nsIDocShellTreeOwner.h"
      53                 : #include "nsIEditorDocShell.h"
      54                 : #include "nsISimpleEnumerator.h"
      55                 : #include "nsPIDOMWindow.h"
      56                 : #include "nsIDOMNSEvent.h"
      57                 : #include "nsIPrefBranch.h"
      58                 : #include "nsIPrefService.h"
      59                 : #include "nsString.h"
      60                 : #include "nsCRT.h"
      61                 : 
      62                 : #include "nsIDOMNode.h"
      63                 : #include "mozilla/dom/Element.h"
      64                 : #include "nsIFrame.h"
      65                 : #include "nsFrameTraversal.h"
      66                 : #include "nsIDOMDocument.h"
      67                 : #include "nsIImageDocument.h"
      68                 : #include "nsIDOMHTMLDocument.h"
      69                 : #include "nsIDOMHTMLElement.h"
      70                 : #include "nsIDocument.h"
      71                 : #include "nsISelection.h"
      72                 : #include "nsILink.h"
      73                 : #include "nsTextFragment.h"
      74                 : #include "nsIDOMNSEditableElement.h"
      75                 : #include "nsIEditor.h"
      76                 : 
      77                 : #include "nsIDocShellTreeItem.h"
      78                 : #include "nsIWebNavigation.h"
      79                 : #include "nsIInterfaceRequestor.h"
      80                 : #include "nsIInterfaceRequestorUtils.h"
      81                 : #include "nsContentCID.h"
      82                 : #include "nsLayoutCID.h"
      83                 : #include "nsWidgetsCID.h"
      84                 : #include "nsIFormControl.h"
      85                 : #include "nsINameSpaceManager.h"
      86                 : #include "nsIWindowWatcher.h"
      87                 : #include "nsIObserverService.h"
      88                 : #include "nsFocusManager.h"
      89                 : #include "mozilla/dom/Element.h"
      90                 : #include "nsRange.h"
      91                 : 
      92                 : #include "nsTypeAheadFind.h"
      93                 : 
      94               0 : NS_INTERFACE_MAP_BEGIN(nsTypeAheadFind)
      95               0 :   NS_INTERFACE_MAP_ENTRY(nsITypeAheadFind)
      96               0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITypeAheadFind)
      97               0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
      98               0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
      99               0 : NS_INTERFACE_MAP_END
     100                 : 
     101               0 : NS_IMPL_ADDREF(nsTypeAheadFind)
     102               0 : NS_IMPL_RELEASE(nsTypeAheadFind)
     103                 : 
     104                 : static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
     105                 : 
     106                 : #define NS_FIND_CONTRACTID "@mozilla.org/embedcomp/rangefind;1"
     107                 : 
     108               0 : nsTypeAheadFind::nsTypeAheadFind():
     109                 :   mStartLinksOnlyPref(false),
     110                 :   mCaretBrowsingOn(false),
     111                 :   mLastFindLength(0),
     112                 :   mIsSoundInitialized(false),
     113               0 :   mCaseSensitive(false)
     114                 : {
     115               0 : }
     116                 : 
     117               0 : nsTypeAheadFind::~nsTypeAheadFind()
     118                 : {
     119               0 :   nsCOMPtr<nsIPrefBranch> prefInternal(do_GetService(NS_PREFSERVICE_CONTRACTID));
     120               0 :   if (prefInternal) {
     121               0 :     prefInternal->RemoveObserver("accessibility.typeaheadfind", this);
     122               0 :     prefInternal->RemoveObserver("accessibility.browsewithcaret", this);
     123                 :   }
     124               0 : }
     125                 : 
     126                 : nsresult
     127               0 : nsTypeAheadFind::Init(nsIDocShell* aDocShell)
     128                 : {
     129               0 :   nsCOMPtr<nsIPrefBranch> prefInternal(do_GetService(NS_PREFSERVICE_CONTRACTID));
     130               0 :   mSearchRange = new nsRange();
     131               0 :   mStartPointRange = new nsRange();
     132               0 :   mEndPointRange = new nsRange();
     133               0 :   if (!prefInternal || !EnsureFind())
     134               0 :     return NS_ERROR_FAILURE;
     135                 : 
     136               0 :   SetDocShell(aDocShell);
     137                 : 
     138                 :   // ----------- Listen to prefs ------------------
     139               0 :   nsresult rv = prefInternal->AddObserver("accessibility.browsewithcaret", this, true);
     140               0 :   NS_ENSURE_SUCCESS(rv, rv);
     141                 : 
     142                 :   // ----------- Get initial preferences ----------
     143               0 :   PrefsReset();
     144                 : 
     145               0 :   return rv;
     146                 : }
     147                 : 
     148                 : nsresult
     149               0 : nsTypeAheadFind::PrefsReset()
     150                 : {
     151               0 :   nsCOMPtr<nsIPrefBranch> prefBranch(do_GetService(NS_PREFSERVICE_CONTRACTID));
     152               0 :   NS_ENSURE_TRUE(prefBranch, NS_ERROR_FAILURE);
     153                 : 
     154               0 :   prefBranch->GetBoolPref("accessibility.typeaheadfind.startlinksonly",
     155               0 :                           &mStartLinksOnlyPref);
     156                 : 
     157               0 :   bool isSoundEnabled = true;
     158               0 :   prefBranch->GetBoolPref("accessibility.typeaheadfind.enablesound",
     159               0 :                            &isSoundEnabled);
     160               0 :   nsXPIDLCString soundStr;
     161               0 :   if (isSoundEnabled)
     162               0 :     prefBranch->GetCharPref("accessibility.typeaheadfind.soundURL", getter_Copies(soundStr));
     163                 : 
     164               0 :   mNotFoundSoundURL = soundStr;
     165                 : 
     166               0 :   prefBranch->GetBoolPref("accessibility.browsewithcaret",
     167               0 :                           &mCaretBrowsingOn);
     168                 : 
     169               0 :   return NS_OK;
     170                 : }
     171                 : 
     172                 : NS_IMETHODIMP
     173               0 : nsTypeAheadFind::SetCaseSensitive(bool isCaseSensitive)
     174                 : {
     175               0 :   mCaseSensitive = isCaseSensitive;
     176                 : 
     177               0 :   if (mFind) {
     178               0 :     mFind->SetCaseSensitive(mCaseSensitive);
     179                 :   }
     180                 : 
     181               0 :   return NS_OK;
     182                 : }
     183                 : 
     184                 : NS_IMETHODIMP
     185               0 : nsTypeAheadFind::GetCaseSensitive(bool* isCaseSensitive)
     186                 : {
     187               0 :   *isCaseSensitive = mCaseSensitive;
     188                 : 
     189               0 :   return NS_OK;
     190                 : }
     191                 : 
     192                 : NS_IMETHODIMP
     193               0 : nsTypeAheadFind::SetDocShell(nsIDocShell* aDocShell)
     194                 : {
     195               0 :   mDocShell = do_GetWeakReference(aDocShell);
     196                 : 
     197               0 :   mWebBrowserFind = do_GetInterface(aDocShell);
     198               0 :   NS_ENSURE_TRUE(mWebBrowserFind, NS_ERROR_FAILURE);
     199                 : 
     200               0 :   nsCOMPtr<nsIPresShell> presShell;
     201               0 :   aDocShell->GetPresShell(getter_AddRefs(presShell));
     202               0 :   mPresShell = do_GetWeakReference(presShell);      
     203                 : 
     204               0 :   mStartFindRange = nsnull;
     205               0 :   mStartPointRange = new nsRange();
     206               0 :   mSearchRange = new nsRange();
     207               0 :   mEndPointRange = new nsRange();
     208                 : 
     209               0 :   mFoundLink = nsnull;
     210               0 :   mFoundEditable = nsnull;
     211               0 :   mCurrentWindow = nsnull;
     212                 : 
     213               0 :   mSelectionController = nsnull;
     214                 : 
     215               0 :   mFind = nsnull;
     216                 : 
     217               0 :   return NS_OK;
     218                 : }
     219                 : 
     220                 : NS_IMETHODIMP
     221               0 : nsTypeAheadFind::SetSelectionModeAndRepaint(PRInt16 aToggle)
     222                 : {
     223                 :   nsCOMPtr<nsISelectionController> selectionController = 
     224               0 :     do_QueryReferent(mSelectionController);
     225               0 :   if (!selectionController) {
     226               0 :     return NS_OK;
     227                 :   }
     228                 : 
     229               0 :   selectionController->SetDisplaySelection(aToggle);
     230               0 :   selectionController->RepaintSelection(nsISelectionController::SELECTION_NORMAL);
     231                 : 
     232               0 :   return NS_OK;
     233                 : }
     234                 : 
     235                 : NS_IMETHODIMP
     236               0 : nsTypeAheadFind::CollapseSelection()
     237                 : {
     238                 :   nsCOMPtr<nsISelectionController> selectionController = 
     239               0 :     do_QueryReferent(mSelectionController);
     240               0 :   if (!selectionController) {
     241               0 :     return NS_OK;
     242                 :   }
     243                 : 
     244               0 :   nsCOMPtr<nsISelection> selection;
     245               0 :   selectionController->GetSelection(nsISelectionController::SELECTION_NORMAL,
     246               0 :                                      getter_AddRefs(selection));
     247               0 :   if (selection)
     248               0 :     selection->CollapseToStart();
     249                 : 
     250               0 :   return NS_OK;
     251                 : }
     252                 : 
     253                 : NS_IMETHODIMP
     254               0 : nsTypeAheadFind::Observe(nsISupports *aSubject, const char *aTopic,
     255                 :                          const PRUnichar *aData)
     256                 : {
     257               0 :   if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID))
     258               0 :     return PrefsReset();
     259                 : 
     260               0 :   return NS_OK;
     261                 : }
     262                 : 
     263                 : void
     264               0 : nsTypeAheadFind::SaveFind()
     265                 : {
     266               0 :   if (mWebBrowserFind)
     267               0 :     mWebBrowserFind->SetSearchString(mTypeAheadBuffer.get());
     268                 :   
     269                 :   // save the length of this find for "not found" sound
     270               0 :   mLastFindLength = mTypeAheadBuffer.Length();
     271               0 : }
     272                 : 
     273                 : void
     274               0 : nsTypeAheadFind::PlayNotFoundSound()
     275                 : {
     276               0 :   if (mNotFoundSoundURL.IsEmpty())    // no sound
     277               0 :     return;
     278                 : 
     279               0 :   if (!mSoundInterface)
     280               0 :     mSoundInterface = do_CreateInstance("@mozilla.org/sound;1");
     281                 : 
     282               0 :   if (mSoundInterface) {
     283               0 :     mIsSoundInitialized = true;
     284                 : 
     285               0 :     if (mNotFoundSoundURL.Equals("beep")) {
     286               0 :       mSoundInterface->Beep();
     287               0 :       return;
     288                 :     }
     289                 : 
     290               0 :     nsCOMPtr<nsIURI> soundURI;
     291               0 :     if (mNotFoundSoundURL.Equals("default"))
     292               0 :       NS_NewURI(getter_AddRefs(soundURI), NS_LITERAL_CSTRING(TYPEAHEADFIND_NOTFOUND_WAV_URL));
     293                 :     else
     294               0 :       NS_NewURI(getter_AddRefs(soundURI), mNotFoundSoundURL);
     295                 : 
     296               0 :     nsCOMPtr<nsIURL> soundURL(do_QueryInterface(soundURI));
     297               0 :     if (soundURL)
     298               0 :       mSoundInterface->Play(soundURL);
     299                 :   }
     300                 : }
     301                 : 
     302                 : nsresult
     303               0 : nsTypeAheadFind::FindItNow(nsIPresShell *aPresShell, bool aIsLinksOnly,
     304                 :                            bool aIsFirstVisiblePreferred, bool aFindPrev,
     305                 :                            PRUint16* aResult)
     306                 : {
     307               0 :   *aResult = FIND_NOTFOUND;
     308               0 :   mFoundLink = nsnull;
     309               0 :   mFoundEditable = nsnull;
     310               0 :   mCurrentWindow = nsnull;
     311               0 :   nsCOMPtr<nsIPresShell> startingPresShell (GetPresShell());
     312               0 :   if (!startingPresShell) {    
     313               0 :     nsCOMPtr<nsIDocShell> ds = do_QueryReferent(mDocShell);
     314               0 :     NS_ENSURE_TRUE(ds, NS_ERROR_FAILURE);
     315                 : 
     316               0 :     ds->GetPresShell(getter_AddRefs(startingPresShell));
     317               0 :     mPresShell = do_GetWeakReference(startingPresShell);    
     318                 :   }  
     319                 : 
     320               0 :   nsCOMPtr<nsIPresShell> presShell(aPresShell);
     321                 : 
     322               0 :   if (!presShell) {
     323               0 :     presShell = startingPresShell;  // this is the current document
     324                 : 
     325               0 :     if (!presShell)
     326               0 :       return NS_ERROR_FAILURE;
     327                 :   }
     328                 : 
     329               0 :   nsRefPtr<nsPresContext> presContext = presShell->GetPresContext();
     330                 : 
     331               0 :   if (!presContext)
     332               0 :     return NS_ERROR_FAILURE;
     333                 : 
     334               0 :   nsCOMPtr<nsISelection> selection;
     335                 :   nsCOMPtr<nsISelectionController> selectionController = 
     336               0 :     do_QueryReferent(mSelectionController);
     337               0 :   if (!selectionController) {
     338               0 :     GetSelection(presShell, getter_AddRefs(selectionController),
     339               0 :                  getter_AddRefs(selection)); // cache for reuse
     340               0 :     mSelectionController = do_GetWeakReference(selectionController);
     341                 :   } else {
     342               0 :     selectionController->GetSelection(
     343               0 :       nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
     344                 :   }
     345                 :  
     346               0 :   nsCOMPtr<nsISupports> startingContainer = presContext->GetContainer();
     347               0 :   nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(startingContainer));
     348               0 :   NS_ASSERTION(treeItem, "Bug 175321 Crashes with Type Ahead Find [@ nsTypeAheadFind::FindItNow]");
     349               0 :   if (!treeItem)
     350               0 :     return NS_ERROR_FAILURE;
     351                 : 
     352               0 :   nsCOMPtr<nsIDocShellTreeItem> rootContentTreeItem;
     353               0 :   nsCOMPtr<nsIDocShell> currentDocShell;
     354               0 :   nsCOMPtr<nsIDocShell> startingDocShell(do_QueryInterface(startingContainer));
     355                 : 
     356               0 :   treeItem->GetSameTypeRootTreeItem(getter_AddRefs(rootContentTreeItem));
     357                 :   nsCOMPtr<nsIDocShell> rootContentDocShell =
     358               0 :     do_QueryInterface(rootContentTreeItem);
     359                 : 
     360               0 :   if (!rootContentDocShell)
     361               0 :     return NS_ERROR_FAILURE;
     362                 : 
     363               0 :   nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
     364               0 :   rootContentDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
     365                 :                                              nsIDocShell::ENUMERATE_FORWARDS,
     366               0 :                                              getter_AddRefs(docShellEnumerator));
     367                 : 
     368                 :   // Default: can start at the current document
     369                 :   nsCOMPtr<nsISupports> currentContainer = startingContainer =
     370               0 :     do_QueryInterface(rootContentDocShell);
     371                 : 
     372                 :   // Iterate up to current shell, if there's more than 1 that we're
     373                 :   // dealing with
     374                 :   bool hasMoreDocShells;
     375                 : 
     376               0 :   while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells)) && hasMoreDocShells) {
     377               0 :     docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
     378               0 :     currentDocShell = do_QueryInterface(currentContainer);
     379               0 :     if (!currentDocShell || currentDocShell == startingDocShell || aIsFirstVisiblePreferred)
     380               0 :       break;    
     381                 :   }
     382                 : 
     383                 :   // ------------ Get ranges ready ----------------
     384               0 :   nsCOMPtr<nsIDOMRange> returnRange;
     385               0 :   nsCOMPtr<nsIPresShell> focusedPS;
     386               0 :   if (NS_FAILED(GetSearchContainers(currentContainer,
     387                 :                                     (!aIsFirstVisiblePreferred ||
     388                 :                                      mStartFindRange) ?
     389                 :                                     selectionController.get() : nsnull,
     390                 :                                     aIsFirstVisiblePreferred,  aFindPrev,
     391                 :                                     getter_AddRefs(presShell),
     392                 :                                     getter_AddRefs(presContext)))) {
     393               0 :     return NS_ERROR_FAILURE;
     394                 :   }
     395                 : 
     396               0 :   PRInt16 rangeCompareResult = 0;
     397               0 :   mStartPointRange->CompareBoundaryPoints(nsIDOMRange::START_TO_START, mSearchRange, &rangeCompareResult);
     398                 :   // No need to wrap find in doc if starting at beginning
     399               0 :   bool hasWrapped = (rangeCompareResult < 0);
     400                 : 
     401               0 :   if (mTypeAheadBuffer.IsEmpty() || !EnsureFind())
     402               0 :     return NS_ERROR_FAILURE;
     403                 : 
     404               0 :   mFind->SetFindBackwards(aFindPrev);
     405                 : 
     406               0 :   while (true) {    // ----- Outer while loop: go through all docs -----
     407               0 :     while (true) {  // === Inner while loop: go through a single doc ===
     408               0 :       mFind->Find(mTypeAheadBuffer.get(), mSearchRange, mStartPointRange,
     409               0 :                   mEndPointRange, getter_AddRefs(returnRange));
     410                 :       
     411               0 :       if (!returnRange)
     412                 :         break;  // Nothing found in this doc, go to outer loop (try next doc)
     413                 : 
     414                 :       // ------- Test resulting found range for success conditions ------
     415               0 :       bool isInsideLink = false, isStartingLink = false;
     416                 : 
     417               0 :       if (aIsLinksOnly) {
     418                 :         // Don't check if inside link when searching all text
     419                 :         RangeStartsInsideLink(returnRange, presShell, &isInsideLink,
     420               0 :                               &isStartingLink);
     421                 :       }
     422                 : 
     423                 :       bool usesIndependentSelection;
     424               0 :       if (!IsRangeVisible(presShell, presContext, returnRange,
     425                 :                           aIsFirstVisiblePreferred, false,
     426               0 :                           getter_AddRefs(mStartPointRange), 
     427               0 :                           &usesIndependentSelection) ||
     428               0 :           (aIsLinksOnly && !isInsideLink) ||
     429               0 :           (mStartLinksOnlyPref && aIsLinksOnly && !isStartingLink)) {
     430                 :         // ------ Failure ------
     431                 :         // Start find again from here
     432               0 :         returnRange->CloneRange(getter_AddRefs(mStartPointRange));
     433                 : 
     434                 :         // Collapse to end
     435               0 :         mStartPointRange->Collapse(aFindPrev);
     436                 : 
     437               0 :         continue;
     438                 :       }
     439                 : 
     440                 :       // ------ Success! -------
     441                 :       // Hide old selection (new one may be on a different controller)
     442               0 :       if (selection) {
     443               0 :         selection->CollapseToStart();
     444               0 :         SetSelectionModeAndRepaint(nsISelectionController::SELECTION_ON);
     445                 :       }
     446                 : 
     447                 :       // Make sure new document is selected
     448               0 :       if (presShell != startingPresShell) {
     449                 :         // We are in a new document (because of frames/iframes)
     450               0 :         mPresShell = do_GetWeakReference(presShell);
     451                 :       }
     452                 : 
     453                 :       nsCOMPtr<nsIDocument> document =
     454               0 :         do_QueryInterface(presShell->GetDocument());
     455               0 :       NS_ASSERTION(document, "Wow, presShell doesn't have document!");
     456               0 :       if (!document)
     457               0 :         return NS_ERROR_UNEXPECTED;
     458                 : 
     459               0 :       nsCOMPtr<nsPIDOMWindow> window = document->GetWindow();
     460               0 :       NS_ASSERTION(window, "document has no window");
     461               0 :       if (!window)
     462               0 :         return NS_ERROR_UNEXPECTED;
     463                 : 
     464               0 :       nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
     465               0 :       if (usesIndependentSelection) {
     466                 :         /* If a search result is found inside an editable element, we'll focus
     467                 :          * the element only if focus is in our content window, i.e.
     468                 :          * |if (focusedWindow.top == ourWindow.top)| */
     469               0 :         bool shouldFocusEditableElement = false;
     470               0 :         if (fm) {
     471               0 :           nsCOMPtr<nsIDOMWindow> focusedWindow;
     472               0 :           nsresult rv = fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
     473               0 :           if (NS_SUCCEEDED(rv)) {
     474               0 :             nsCOMPtr<nsPIDOMWindow> fwPI(do_QueryInterface(focusedWindow, &rv));
     475               0 :             if (NS_SUCCEEDED(rv)) {
     476                 :               nsCOMPtr<nsIDocShellTreeItem> fwTreeItem
     477               0 :                 (do_QueryInterface(fwPI->GetDocShell(), &rv));
     478               0 :               if (NS_SUCCEEDED(rv)) {
     479               0 :                 nsCOMPtr<nsIDocShellTreeItem> fwRootTreeItem;
     480               0 :                 rv = fwTreeItem->GetSameTypeRootTreeItem(getter_AddRefs(fwRootTreeItem));
     481               0 :                 if (NS_SUCCEEDED(rv) && fwRootTreeItem == rootContentTreeItem)
     482               0 :                   shouldFocusEditableElement = true;
     483                 :               }
     484                 :             }
     485                 :           }
     486                 :         }
     487                 : 
     488                 :         // We may be inside an editable element, and therefore the selection
     489                 :         // may be controlled by a different selection controller.  Walk up the
     490                 :         // chain of parent nodes to see if we find one.
     491               0 :         nsCOMPtr<nsIDOMNode> node;
     492               0 :         returnRange->GetStartContainer(getter_AddRefs(node));
     493               0 :         while (node) {
     494               0 :           nsCOMPtr<nsIDOMNSEditableElement> editable = do_QueryInterface(node);
     495               0 :           if (editable) {
     496                 :             // Inside an editable element.  Get the correct selection 
     497                 :             // controller and selection.
     498               0 :             nsCOMPtr<nsIEditor> editor;
     499               0 :             editable->GetEditor(getter_AddRefs(editor));
     500               0 :             NS_ASSERTION(editor, "Editable element has no editor!");
     501               0 :             if (!editor) {
     502                 :               break;
     503                 :             }
     504               0 :             editor->GetSelectionController(
     505               0 :               getter_AddRefs(selectionController));
     506               0 :             if (selectionController) {
     507               0 :               selectionController->GetSelection(
     508                 :                 nsISelectionController::SELECTION_NORMAL, 
     509               0 :                 getter_AddRefs(selection));
     510                 :             }
     511               0 :             mFoundEditable = do_QueryInterface(node);
     512                 : 
     513               0 :             if (!shouldFocusEditableElement)
     514                 :               break;
     515                 : 
     516                 :             // Otherwise move focus/caret to editable element
     517               0 :             if (fm)
     518               0 :               fm->SetFocus(mFoundEditable, 0);
     519                 :             break;
     520                 :           }
     521               0 :           nsIDOMNode* tmp = node;
     522               0 :           tmp->GetParentNode(getter_AddRefs(node));
     523                 :         }
     524                 : 
     525                 :         // If we reach here without setting mFoundEditable, then something
     526                 :         // besides editable elements can cause us to have an independent
     527                 :         // selection controller.  I don't know whether this is possible.
     528                 :         // Currently, we simply fall back to grabbing the document's selection
     529                 :         // controller in this case.  Perhaps we should reject this find match
     530                 :         // and search again.
     531               0 :         NS_ASSERTION(mFoundEditable, "Independent selection controller on "
     532                 :                      "non-editable element!");
     533                 :       }
     534                 : 
     535               0 :       if (!mFoundEditable) {
     536                 :         // Not using a separate selection controller, so just get the
     537                 :         // document's controller and selection.
     538               0 :         GetSelection(presShell, getter_AddRefs(selectionController), 
     539               0 :                      getter_AddRefs(selection));
     540                 :       }
     541               0 :       mSelectionController = do_GetWeakReference(selectionController);
     542                 : 
     543                 :       // Select the found text
     544               0 :       if (selection) {
     545               0 :         selection->RemoveAllRanges();
     546               0 :         selection->AddRange(returnRange);
     547                 :       }
     548                 : 
     549               0 :       if (!mFoundEditable && fm) {
     550               0 :         nsCOMPtr<nsIDOMWindow> win = do_QueryInterface(window);
     551               0 :         fm->MoveFocus(win, nsnull, nsIFocusManager::MOVEFOCUS_CARET,
     552                 :                       nsIFocusManager::FLAG_NOSCROLL | nsIFocusManager::FLAG_NOSWITCHFRAME,
     553               0 :                       getter_AddRefs(mFoundLink));
     554                 :       }
     555                 : 
     556                 :       // Change selection color to ATTENTION and scroll to it.  Careful: we
     557                 :       // must wait until after we goof with focus above before changing to
     558                 :       // ATTENTION, or when we MoveFocus() and the selection is not on a
     559                 :       // link, we'll blur, which will lose the ATTENTION.
     560               0 :       if (selectionController) {
     561                 :         // Beware! This may flush notifications via synchronous
     562                 :         // ScrollSelectionIntoView.
     563               0 :         SetSelectionModeAndRepaint(nsISelectionController::SELECTION_ATTENTION);
     564               0 :         selectionController->ScrollSelectionIntoView(
     565                 :           nsISelectionController::SELECTION_NORMAL, 
     566                 :           nsISelectionController::SELECTION_WHOLE_SELECTION,
     567                 :           nsISelectionController::SCROLL_CENTER_VERTICALLY |
     568               0 :           nsISelectionController::SCROLL_SYNCHRONOUS);
     569                 :       }
     570                 : 
     571               0 :       mCurrentWindow = window;
     572               0 :       *aResult = hasWrapped ? FIND_WRAPPED : FIND_FOUND;
     573               0 :       return NS_OK;
     574                 :     }
     575                 : 
     576                 :     // ======= end-inner-while (go through a single document) ==========
     577                 : 
     578                 :     // ---------- Nothing found yet, try next document  -------------
     579               0 :     bool hasTriedFirstDoc = false;
     580               0 :     do {
     581                 :       // ==== Second inner loop - get another while  ====
     582               0 :       if (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMoreDocShells))
     583                 :           && hasMoreDocShells) {
     584               0 :         docShellEnumerator->GetNext(getter_AddRefs(currentContainer));
     585               0 :         NS_ASSERTION(currentContainer, "HasMoreElements lied to us!");
     586               0 :         currentDocShell = do_QueryInterface(currentContainer);
     587                 : 
     588               0 :         if (currentDocShell)
     589               0 :           break;
     590                 :       }
     591               0 :       else if (hasTriedFirstDoc)  // Avoid potential infinite loop
     592               0 :         return NS_ERROR_FAILURE;  // No content doc shells
     593                 : 
     594                 :       // Reached last doc shell, loop around back to first doc shell
     595               0 :       rootContentDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeContent,
     596                 :                                                  nsIDocShell::ENUMERATE_FORWARDS,
     597               0 :                                                  getter_AddRefs(docShellEnumerator));
     598               0 :       hasTriedFirstDoc = true;      
     599               0 :     } while (docShellEnumerator);  // ==== end second inner while  ===
     600                 : 
     601               0 :     bool continueLoop = false;
     602               0 :     if (currentDocShell != startingDocShell)
     603               0 :       continueLoop = true;  // Try next document
     604               0 :     else if (!hasWrapped || aIsFirstVisiblePreferred) {
     605                 :       // Finished searching through docshells:
     606                 :       // If aFirstVisiblePreferred == true, we may need to go through all
     607                 :       // docshells twice -once to look for visible matches, the second time
     608                 :       // for any match
     609               0 :       aIsFirstVisiblePreferred = false;
     610               0 :       hasWrapped = true;
     611               0 :       continueLoop = true; // Go through all docs again
     612                 :     }
     613                 : 
     614               0 :     if (continueLoop) {
     615               0 :       if (NS_FAILED(GetSearchContainers(currentContainer, nsnull,
     616                 :                                         aIsFirstVisiblePreferred, aFindPrev,
     617                 :                                         getter_AddRefs(presShell),
     618                 :                                         getter_AddRefs(presContext)))) {
     619               0 :         continue;
     620                 :       }
     621                 : 
     622               0 :       if (aFindPrev) {
     623                 :         // Reverse mode: swap start and end points, so that we start
     624                 :         // at end of document and go to beginning
     625               0 :         nsCOMPtr<nsIDOMRange> tempRange;
     626               0 :         mStartPointRange->CloneRange(getter_AddRefs(tempRange));
     627               0 :         mStartPointRange = mEndPointRange;
     628               0 :         mEndPointRange = tempRange;
     629                 :       }
     630                 : 
     631               0 :       continue;
     632                 :     }
     633                 : 
     634                 :     // ------------- Failed --------------
     635                 :     break;
     636                 :   }   // end-outer-while: go through all docs
     637                 : 
     638               0 :   return NS_ERROR_FAILURE;
     639                 : }
     640                 : 
     641                 : NS_IMETHODIMP
     642               0 : nsTypeAheadFind::GetSearchString(nsAString& aSearchString)
     643                 : {
     644               0 :   aSearchString = mTypeAheadBuffer;
     645               0 :   return NS_OK;
     646                 : }
     647                 : 
     648                 : NS_IMETHODIMP
     649               0 : nsTypeAheadFind::GetFoundLink(nsIDOMElement** aFoundLink)
     650                 : {
     651               0 :   NS_ENSURE_ARG_POINTER(aFoundLink);
     652               0 :   *aFoundLink = mFoundLink;
     653               0 :   NS_IF_ADDREF(*aFoundLink);
     654               0 :   return NS_OK;
     655                 : }
     656                 : 
     657                 : NS_IMETHODIMP
     658               0 : nsTypeAheadFind::GetFoundEditable(nsIDOMElement** aFoundEditable)
     659                 : {
     660               0 :   NS_ENSURE_ARG_POINTER(aFoundEditable);
     661               0 :   *aFoundEditable = mFoundEditable;
     662               0 :   NS_IF_ADDREF(*aFoundEditable);
     663               0 :   return NS_OK;
     664                 : }
     665                 : 
     666                 : NS_IMETHODIMP
     667               0 : nsTypeAheadFind::GetCurrentWindow(nsIDOMWindow** aCurrentWindow)
     668                 : {
     669               0 :   NS_ENSURE_ARG_POINTER(aCurrentWindow);
     670               0 :   *aCurrentWindow = mCurrentWindow;
     671               0 :   NS_IF_ADDREF(*aCurrentWindow);
     672               0 :   return NS_OK;
     673                 : }
     674                 : 
     675                 : nsresult
     676               0 : nsTypeAheadFind::GetSearchContainers(nsISupports *aContainer,
     677                 :                                      nsISelectionController *aSelectionController,
     678                 :                                      bool aIsFirstVisiblePreferred,
     679                 :                                      bool aFindPrev,
     680                 :                                      nsIPresShell **aPresShell,
     681                 :                                      nsPresContext **aPresContext)
     682                 : {
     683               0 :   NS_ENSURE_ARG_POINTER(aContainer);
     684               0 :   NS_ENSURE_ARG_POINTER(aPresShell);
     685               0 :   NS_ENSURE_ARG_POINTER(aPresContext);
     686                 : 
     687               0 :   *aPresShell = nsnull;
     688               0 :   *aPresContext = nsnull;
     689                 : 
     690               0 :   nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aContainer));
     691               0 :   if (!docShell)
     692               0 :     return NS_ERROR_FAILURE;
     693                 : 
     694               0 :   nsCOMPtr<nsIPresShell> presShell;
     695               0 :   docShell->GetPresShell(getter_AddRefs(presShell));
     696                 : 
     697               0 :   nsRefPtr<nsPresContext> presContext;
     698               0 :   docShell->GetPresContext(getter_AddRefs(presContext));
     699                 : 
     700               0 :   if (!presShell || !presContext)
     701               0 :     return NS_ERROR_FAILURE;
     702                 : 
     703               0 :   nsIDocument* doc = presShell->GetDocument();
     704                 : 
     705               0 :   if (!doc)
     706               0 :     return NS_ERROR_FAILURE;
     707                 : 
     708               0 :   nsCOMPtr<nsIContent> rootContent;
     709               0 :   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(doc));
     710               0 :   if (htmlDoc) {
     711               0 :     nsCOMPtr<nsIDOMHTMLElement> bodyEl;
     712               0 :     htmlDoc->GetBody(getter_AddRefs(bodyEl));
     713               0 :     rootContent = do_QueryInterface(bodyEl);
     714                 :   }
     715                 : 
     716               0 :   if (!rootContent)
     717               0 :     rootContent = doc->GetRootElement();
     718                 :  
     719               0 :   nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootContent));
     720                 : 
     721               0 :   if (!rootNode)
     722               0 :     return NS_ERROR_FAILURE;
     723                 : 
     724               0 :   PRUint32 childCount = rootContent->GetChildCount();
     725                 : 
     726               0 :   mSearchRange->SelectNodeContents(rootNode);
     727                 : 
     728               0 :   mEndPointRange->SetEnd(rootNode, childCount);
     729               0 :   mEndPointRange->Collapse(false); // collapse to end
     730                 : 
     731                 :   // Consider current selection as null if
     732                 :   // it's not in the currently focused document
     733               0 :   nsCOMPtr<nsIDOMRange> currentSelectionRange;
     734               0 :   nsCOMPtr<nsIPresShell> selectionPresShell = GetPresShell();
     735               0 :   if (aSelectionController && selectionPresShell && selectionPresShell == presShell) {
     736               0 :     nsCOMPtr<nsISelection> selection;
     737                 :     aSelectionController->GetSelection(
     738               0 :       nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
     739               0 :     if (selection)
     740               0 :       selection->GetRangeAt(0, getter_AddRefs(currentSelectionRange));
     741                 :   }
     742                 : 
     743               0 :   if (!currentSelectionRange) {
     744                 :     // Ensure visible range, move forward if necessary
     745                 :     // This uses ignores the return value, but usese the side effect of
     746                 :     // IsRangeVisible. It returns the first visible range after searchRange
     747                 :     IsRangeVisible(presShell, presContext, mSearchRange, 
     748                 :                    aIsFirstVisiblePreferred, true, 
     749               0 :                    getter_AddRefs(mStartPointRange), nsnull);
     750                 :   }
     751                 :   else {
     752                 :     PRInt32 startOffset;
     753               0 :     nsCOMPtr<nsIDOMNode> startNode;
     754               0 :     if (aFindPrev) {
     755               0 :       currentSelectionRange->GetStartContainer(getter_AddRefs(startNode));
     756               0 :       currentSelectionRange->GetStartOffset(&startOffset);
     757                 :     } else {
     758               0 :       currentSelectionRange->GetEndContainer(getter_AddRefs(startNode));
     759               0 :       currentSelectionRange->GetEndOffset(&startOffset);
     760                 :     }
     761               0 :     if (!startNode)
     762               0 :       startNode = rootNode;    
     763                 : 
     764                 :     // We need to set the start point this way, other methods haven't worked
     765               0 :     mStartPointRange->SelectNode(startNode);
     766               0 :     mStartPointRange->SetStart(startNode, startOffset);
     767                 :   }
     768                 : 
     769               0 :   mStartPointRange->Collapse(true); // collapse to start
     770                 : 
     771               0 :   *aPresShell = presShell;
     772               0 :   NS_ADDREF(*aPresShell);
     773                 : 
     774               0 :   *aPresContext = presContext;
     775               0 :   NS_ADDREF(*aPresContext);
     776                 : 
     777               0 :   return NS_OK;
     778                 : }
     779                 : 
     780                 : void
     781               0 : nsTypeAheadFind::RangeStartsInsideLink(nsIDOMRange *aRange,
     782                 :                                        nsIPresShell *aPresShell,
     783                 :                                        bool *aIsInsideLink,
     784                 :                                        bool *aIsStartingLink)
     785                 : {
     786               0 :   *aIsInsideLink = false;
     787               0 :   *aIsStartingLink = true;
     788                 : 
     789                 :   // ------- Get nsIContent to test -------
     790               0 :   nsCOMPtr<nsIDOMNode> startNode;
     791               0 :   nsCOMPtr<nsIContent> startContent, origContent;
     792               0 :   aRange->GetStartContainer(getter_AddRefs(startNode));
     793                 :   PRInt32 startOffset;
     794               0 :   aRange->GetStartOffset(&startOffset);
     795                 : 
     796               0 :   startContent = do_QueryInterface(startNode);
     797               0 :   if (!startContent) {
     798               0 :     NS_NOTREACHED("startContent should never be null");
     799                 :     return;
     800                 :   }
     801               0 :   origContent = startContent;
     802                 : 
     803               0 :   if (startContent->IsElement()) {
     804               0 :     nsIContent *childContent = startContent->GetChildAt(startOffset);
     805               0 :     if (childContent) {
     806               0 :       startContent = childContent;
     807                 :     }
     808                 :   }
     809               0 :   else if (startOffset > 0) {
     810               0 :     const nsTextFragment *textFrag = startContent->GetText();
     811               0 :     if (textFrag) {
     812                 :       // look for non whitespace character before start offset
     813               0 :       for (PRInt32 index = 0; index < startOffset; index++) {
     814               0 :         if (!XP_IS_SPACE(textFrag->CharAt(index))) {
     815               0 :           *aIsStartingLink = false;  // not at start of a node
     816                 : 
     817               0 :           break;
     818                 :         }
     819                 :       }
     820                 :     }
     821                 :   }
     822                 : 
     823                 :   // ------- Check to see if inside link ---------
     824                 : 
     825                 :   // We now have the correct start node for the range
     826                 :   // Search for links, starting with startNode, and going up parent chain
     827                 : 
     828               0 :   nsCOMPtr<nsIAtom> tag, hrefAtom(do_GetAtom("href"));
     829               0 :   nsCOMPtr<nsIAtom> typeAtom(do_GetAtom("type"));
     830                 : 
     831               0 :   while (true) {
     832                 :     // Keep testing while startContent is equal to something,
     833                 :     // eventually we'll run out of ancestors
     834                 : 
     835               0 :     if (startContent->IsHTML()) {
     836               0 :       nsCOMPtr<nsILink> link(do_QueryInterface(startContent));
     837               0 :       if (link) {
     838                 :         // Check to see if inside HTML link
     839               0 :         *aIsInsideLink = startContent->HasAttr(kNameSpaceID_None, hrefAtom);
     840                 :         return;
     841                 :       }
     842                 :     }
     843                 :     else {
     844                 :       // Any xml element can be an xlink
     845               0 :       *aIsInsideLink = startContent->HasAttr(kNameSpaceID_XLink, hrefAtom);
     846               0 :       if (*aIsInsideLink) {
     847               0 :         if (!startContent->AttrValueIs(kNameSpaceID_XLink, typeAtom,
     848               0 :                                        NS_LITERAL_STRING("simple"),
     849               0 :                                        eCaseMatters)) {
     850               0 :           *aIsInsideLink = false;  // Xlink must be type="simple"
     851                 :         }
     852                 : 
     853                 :         return;
     854                 :       }
     855                 :     }
     856                 : 
     857                 :     // Get the parent
     858               0 :     nsCOMPtr<nsIContent> parent = startContent->GetParent();
     859               0 :     if (!parent)
     860                 :       break;
     861                 : 
     862               0 :     nsIContent* parentsFirstChild = parent->GetFirstChild();
     863                 : 
     864                 :     // We don't want to look at a whitespace-only first child
     865               0 :     if (parentsFirstChild && parentsFirstChild->TextIsOnlyWhitespace()) {
     866               0 :       parentsFirstChild = parentsFirstChild->GetNextSibling();
     867                 :     }
     868                 : 
     869               0 :     if (parentsFirstChild != startContent) {
     870                 :       // startContent wasn't a first child, so we conclude that
     871                 :       // if this is inside a link, it's not at the beginning of it
     872               0 :       *aIsStartingLink = false;
     873                 :     }
     874                 : 
     875               0 :     startContent = parent;
     876                 :   }
     877                 : 
     878               0 :   *aIsStartingLink = false;
     879                 : }
     880                 : 
     881                 : /* Find another match in the page. */
     882                 : NS_IMETHODIMP
     883               0 : nsTypeAheadFind::FindAgain(bool aFindBackwards, bool aLinksOnly,
     884                 :                            PRUint16* aResult)
     885                 : 
     886                 : {
     887               0 :   *aResult = FIND_NOTFOUND;
     888                 : 
     889               0 :   if (!mTypeAheadBuffer.IsEmpty())
     890                 :     // Beware! This may flush notifications via synchronous
     891                 :     // ScrollSelectionIntoView.
     892               0 :     FindItNow(nsnull, aLinksOnly, false, aFindBackwards, aResult);
     893                 : 
     894               0 :   return NS_OK;
     895                 : }
     896                 : 
     897                 : NS_IMETHODIMP
     898               0 : nsTypeAheadFind::Find(const nsAString& aSearchString, bool aLinksOnly,
     899                 :                       PRUint16* aResult)
     900                 : {
     901               0 :   *aResult = FIND_NOTFOUND;
     902                 : 
     903               0 :   nsCOMPtr<nsIPresShell> presShell (GetPresShell());
     904               0 :   if (!presShell) {    
     905               0 :     nsCOMPtr<nsIDocShell> ds (do_QueryReferent(mDocShell));
     906               0 :     NS_ENSURE_TRUE(ds, NS_ERROR_FAILURE);
     907                 : 
     908               0 :     ds->GetPresShell(getter_AddRefs(presShell));
     909               0 :     mPresShell = do_GetWeakReference(presShell);    
     910                 :   }  
     911               0 :   nsCOMPtr<nsISelection> selection;
     912                 :   nsCOMPtr<nsISelectionController> selectionController = 
     913               0 :     do_QueryReferent(mSelectionController);
     914               0 :   if (!selectionController) {
     915               0 :     GetSelection(presShell, getter_AddRefs(selectionController),
     916               0 :                  getter_AddRefs(selection)); // cache for reuse
     917               0 :     mSelectionController = do_GetWeakReference(selectionController);
     918                 :   } else {
     919               0 :     selectionController->GetSelection(
     920               0 :       nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
     921                 :   }
     922                 : 
     923               0 :   if (selection)
     924               0 :     selection->CollapseToStart();
     925                 : 
     926               0 :   if (aSearchString.IsEmpty()) {
     927               0 :     mTypeAheadBuffer.Truncate();
     928                 : 
     929                 :     // These will be initialized to their true values after the first character
     930                 :     // is typed
     931               0 :     mStartFindRange = nsnull;
     932               0 :     mSelectionController = nsnull;
     933                 : 
     934               0 :     *aResult = FIND_FOUND;
     935               0 :     return NS_OK;
     936                 :   }
     937                 : 
     938               0 :   bool atEnd = false;    
     939               0 :   if (mTypeAheadBuffer.Length()) {
     940               0 :     const nsAString& oldStr = Substring(mTypeAheadBuffer, 0, mTypeAheadBuffer.Length());
     941               0 :     const nsAString& newStr = Substring(aSearchString, 0, mTypeAheadBuffer.Length());
     942               0 :     if (oldStr.Equals(newStr))
     943               0 :       atEnd = true;
     944                 :   
     945               0 :     const nsAString& newStr2 = Substring(aSearchString, 0, aSearchString.Length());
     946               0 :     const nsAString& oldStr2 = Substring(mTypeAheadBuffer, 0, aSearchString.Length());
     947               0 :     if (oldStr2.Equals(newStr2))
     948               0 :       atEnd = true;
     949                 :     
     950               0 :     if (!atEnd)
     951               0 :       mStartFindRange = nsnull;
     952                 :   }
     953                 : 
     954               0 :   if (!mIsSoundInitialized && !mNotFoundSoundURL.IsEmpty()) {
     955                 :     // This makes sure system sound library is loaded so that
     956                 :     // there's no lag before the first sound is played
     957                 :     // by waiting for the first keystroke, we still get the startup time benefits.
     958               0 :     mIsSoundInitialized = true;
     959               0 :     mSoundInterface = do_CreateInstance("@mozilla.org/sound;1");
     960               0 :     if (mSoundInterface && !mNotFoundSoundURL.Equals(NS_LITERAL_CSTRING("beep"))) {
     961               0 :       mSoundInterface->Init();
     962                 :     }
     963                 :   }
     964                 : 
     965                 : #ifdef XP_WIN
     966                 :   // After each keystroke, ensure sound object is destroyed, to free up memory 
     967                 :   // allocated for error sound, otherwise Windows' nsISound impl 
     968                 :   // holds onto the last played sound, using up memory.
     969                 :   mSoundInterface = nsnull;
     970                 : #endif
     971                 : 
     972               0 :   PRInt32 bufferLength = mTypeAheadBuffer.Length();
     973                 : 
     974               0 :   mTypeAheadBuffer = aSearchString;
     975                 : 
     976               0 :   bool isFirstVisiblePreferred = false;
     977                 : 
     978                 :   // --------- Initialize find if 1st char ----------
     979               0 :   if (bufferLength == 0) {
     980                 :     // If you can see the selection (not collapsed or thru caret browsing),
     981                 :     // or if already focused on a page element, start there.
     982                 :     // Otherwise we're going to start at the first visible element
     983               0 :     bool isSelectionCollapsed = true;
     984               0 :     if (selection)
     985               0 :       selection->GetIsCollapsed(&isSelectionCollapsed);
     986                 : 
     987                 :     // If true, we will scan from top left of visible area
     988                 :     // If false, we will scan from start of selection
     989               0 :     isFirstVisiblePreferred = !atEnd && !mCaretBrowsingOn && isSelectionCollapsed;
     990               0 :     if (isFirstVisiblePreferred) {
     991                 :       // Get the focused content. If there is a focused node, ensure the
     992                 :       // selection is at that point. Otherwise, we will just want to start
     993                 :       // from the caret position or the beginning of the document.
     994               0 :       nsPresContext* presContext = presShell->GetPresContext();
     995               0 :       NS_ENSURE_TRUE(presContext, NS_OK);
     996                 : 
     997                 :       nsCOMPtr<nsIDocument> document =
     998               0 :         do_QueryInterface(presShell->GetDocument());
     999               0 :       if (!document)
    1000               0 :         return NS_ERROR_UNEXPECTED;
    1001                 : 
    1002               0 :       nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(document->GetWindow());
    1003                 : 
    1004               0 :       nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
    1005               0 :       if (fm) {
    1006               0 :         nsCOMPtr<nsIDOMElement> focusedElement;
    1007               0 :         nsCOMPtr<nsIDOMWindow> focusedWindow;
    1008               0 :         fm->GetFocusedElementForWindow(window, false, getter_AddRefs(focusedWindow),
    1009               0 :                                        getter_AddRefs(focusedElement));
    1010                 :         // If the root element is focused, then it's actually the document
    1011                 :         // that has the focus, so ignore this.
    1012               0 :         if (focusedElement &&
    1013               0 :             !SameCOMIdentity(focusedElement, document->GetRootElement())) {
    1014               0 :           fm->MoveCaretToFocus(window);
    1015               0 :           isFirstVisiblePreferred = false;
    1016                 :         }
    1017                 :       }
    1018                 :     }
    1019                 :   }
    1020                 : 
    1021                 :   // ----------- Find the text! ---------------------
    1022                 :   // Beware! This may flush notifications via synchronous
    1023                 :   // ScrollSelectionIntoView.
    1024                 :   nsresult rv = FindItNow(nsnull, aLinksOnly, isFirstVisiblePreferred,
    1025               0 :                           false, aResult);
    1026                 : 
    1027                 :   // ---------Handle success or failure ---------------
    1028               0 :   if (NS_SUCCEEDED(rv)) {
    1029               0 :     if (mTypeAheadBuffer.Length() == 1) {
    1030                 :       // If first letter, store where the first find succeeded
    1031                 :       // (mStartFindRange)
    1032                 : 
    1033               0 :       mStartFindRange = nsnull;
    1034               0 :       if (selection) {
    1035               0 :         nsCOMPtr<nsIDOMRange> startFindRange;
    1036               0 :         selection->GetRangeAt(0, getter_AddRefs(startFindRange));
    1037               0 :         if (startFindRange)
    1038               0 :           startFindRange->CloneRange(getter_AddRefs(mStartFindRange));
    1039                 :       }
    1040                 :     }
    1041                 :   }
    1042                 :   else {
    1043                 :     // Error sound
    1044               0 :     if (mTypeAheadBuffer.Length() > mLastFindLength)
    1045               0 :       PlayNotFoundSound();
    1046                 :   }
    1047                 : 
    1048               0 :   SaveFind();
    1049               0 :   return NS_OK;
    1050                 : }
    1051                 : 
    1052                 : void
    1053               0 : nsTypeAheadFind::GetSelection(nsIPresShell *aPresShell,
    1054                 :                               nsISelectionController **aSelCon,
    1055                 :                               nsISelection **aDOMSel)
    1056                 : {
    1057               0 :   if (!aPresShell)
    1058               0 :     return;
    1059                 : 
    1060                 :   // if aCurrentNode is nsnull, get selection for document
    1061               0 :   *aDOMSel = nsnull;
    1062                 : 
    1063               0 :   nsPresContext* presContext = aPresShell->GetPresContext();
    1064                 : 
    1065               0 :   nsIFrame *frame = aPresShell->GetRootFrame();
    1066                 : 
    1067               0 :   if (presContext && frame) {
    1068               0 :     frame->GetSelectionController(presContext, aSelCon);
    1069               0 :     if (*aSelCon) {
    1070                 :       (*aSelCon)->GetSelection(nsISelectionController::SELECTION_NORMAL,
    1071               0 :                                aDOMSel);
    1072                 :     }
    1073                 :   }
    1074                 : }
    1075                 : 
    1076                 : 
    1077                 : bool
    1078               0 : nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell,
    1079                 :                                 nsPresContext *aPresContext,
    1080                 :                                 nsIDOMRange *aRange, bool aMustBeInViewPort,
    1081                 :                                 bool aGetTopVisibleLeaf,
    1082                 :                                 nsIDOMRange **aFirstVisibleRange,
    1083                 :                                 bool *aUsesIndependentSelection)
    1084                 : {
    1085               0 :   NS_ASSERTION(aPresShell && aPresContext && aRange && aFirstVisibleRange, 
    1086                 :                "params are invalid");
    1087                 : 
    1088                 :   // We need to know if the range start is visible.
    1089                 :   // Otherwise, return the first visible range start 
    1090                 :   // in aFirstVisibleRange
    1091                 : 
    1092               0 :   aRange->CloneRange(aFirstVisibleRange);
    1093               0 :   nsCOMPtr<nsIDOMNode> node;
    1094               0 :   aRange->GetStartContainer(getter_AddRefs(node));
    1095                 : 
    1096               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
    1097               0 :   if (!content)
    1098               0 :     return false;
    1099                 : 
    1100               0 :   nsIFrame *frame = content->GetPrimaryFrame();
    1101               0 :   if (!frame)    
    1102               0 :     return false;  // No frame! Not visible then.
    1103                 : 
    1104               0 :   if (!frame->GetStyleVisibility()->IsVisible())
    1105               0 :     return false;
    1106                 : 
    1107                 :   // Detect if we are _inside_ a text control, or something else with its own
    1108                 :   // selection controller.
    1109               0 :   if (aUsesIndependentSelection) {
    1110                 :     *aUsesIndependentSelection = 
    1111               0 :       (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
    1112                 :   }
    1113                 : 
    1114                 :   // ---- We have a frame ----
    1115               0 :   if (!aMustBeInViewPort)   
    1116               0 :     return true; //  Don't need it to be on screen, just in rendering tree
    1117                 : 
    1118                 :   // Get the next in flow frame that contains the range start
    1119                 :   PRInt32 startRangeOffset, startFrameOffset, endFrameOffset;
    1120               0 :   aRange->GetStartOffset(&startRangeOffset);
    1121               0 :   while (true) {
    1122               0 :     frame->GetOffsets(startFrameOffset, endFrameOffset);
    1123               0 :     if (startRangeOffset < endFrameOffset)
    1124               0 :       break;
    1125                 : 
    1126               0 :     nsIFrame *nextContinuationFrame = frame->GetNextContinuation();
    1127               0 :     if (nextContinuationFrame)
    1128               0 :       frame = nextContinuationFrame;
    1129                 :     else
    1130               0 :       break;
    1131                 :   }
    1132                 : 
    1133                 :   // Set up the variables we need, return true if we can't get at them all
    1134               0 :   const PRUint16 kMinPixels  = 12;
    1135               0 :   nscoord minDistance = nsPresContext::CSSPixelsToAppUnits(kMinPixels);
    1136                 : 
    1137                 :   // Get the bounds of the current frame, relative to the current view.
    1138                 :   // We don't use the more accurate AccGetBounds, because that is
    1139                 :   // more expensive and the STATE_OFFSCREEN flag that this is used
    1140                 :   // for only needs to be a rough indicator
    1141               0 :   nsRectVisibility rectVisibility = nsRectVisibility_kAboveViewport;
    1142                 : 
    1143               0 :   if (!aGetTopVisibleLeaf && !frame->GetRect().IsEmpty()) {
    1144                 :     rectVisibility =
    1145                 :       aPresShell->GetRectVisibility(frame,
    1146               0 :                                     nsRect(nsPoint(0,0), frame->GetSize()),
    1147               0 :                                     minDistance);
    1148                 : 
    1149               0 :     if (rectVisibility != nsRectVisibility_kAboveViewport) {
    1150               0 :       return true;
    1151                 :     }
    1152                 :   }
    1153                 : 
    1154                 :   // We know that the target range isn't usable because it's not in the
    1155                 :   // view port. Move range forward to first visible point,
    1156                 :   // this speeds us up a lot in long documents
    1157               0 :   nsCOMPtr<nsIFrameEnumerator> frameTraversal;
    1158               0 :   nsCOMPtr<nsIFrameTraversal> trav(do_CreateInstance(kFrameTraversalCID));
    1159               0 :   if (trav)
    1160               0 :     trav->NewFrameTraversal(getter_AddRefs(frameTraversal),
    1161                 :                             aPresContext, frame,
    1162                 :                             eLeaf,
    1163                 :                             false, // aVisual
    1164                 :                             false, // aLockInScrollView
    1165                 :                             false     // aFollowOOFs
    1166               0 :                             );
    1167                 : 
    1168               0 :   if (!frameTraversal)
    1169               0 :     return false;
    1170                 : 
    1171               0 :   while (rectVisibility == nsRectVisibility_kAboveViewport) {
    1172               0 :     frameTraversal->Next();
    1173               0 :     frame = frameTraversal->CurrentItem();
    1174               0 :     if (!frame)
    1175               0 :       return false;
    1176                 : 
    1177               0 :     if (!frame->GetRect().IsEmpty()) {
    1178                 :       rectVisibility =
    1179                 :         aPresShell->GetRectVisibility(frame,
    1180               0 :                                       nsRect(nsPoint(0,0), frame->GetSize()),
    1181               0 :                                       minDistance);
    1182                 :     }
    1183                 :   }
    1184                 : 
    1185               0 :   if (frame) {
    1186               0 :     nsCOMPtr<nsIDOMNode> firstVisibleNode = do_QueryInterface(frame->GetContent());
    1187                 : 
    1188               0 :     if (firstVisibleNode) {
    1189               0 :       (*aFirstVisibleRange)->SelectNode(firstVisibleNode);
    1190               0 :       frame->GetOffsets(startFrameOffset, endFrameOffset);
    1191               0 :       (*aFirstVisibleRange)->SetStart(firstVisibleNode, startFrameOffset);
    1192               0 :       (*aFirstVisibleRange)->Collapse(true);  // Collapse to start
    1193                 :     }
    1194                 :   }
    1195                 : 
    1196               0 :   return false;
    1197                 : }
    1198                 : 
    1199                 : already_AddRefed<nsIPresShell>
    1200               0 : nsTypeAheadFind::GetPresShell()
    1201                 : {
    1202               0 :   if (!mPresShell)
    1203               0 :     return nsnull;
    1204                 : 
    1205               0 :   nsIPresShell *shell = nsnull;
    1206               0 :   CallQueryReferent(mPresShell.get(), &shell);
    1207               0 :   if (shell) {
    1208               0 :     nsPresContext *pc = shell->GetPresContext();
    1209               0 :     if (!pc || !nsCOMPtr<nsISupports>(pc->GetContainer())) {
    1210               0 :       NS_RELEASE(shell);
    1211                 :     }
    1212                 :   }
    1213                 : 
    1214               0 :   return shell;
    1215                 : }

Generated by: LCOV version 1.7