LCOV - code coverage report
Current view: top level - toolkit/components/typeaheadfind - nsTypeAheadFind.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 654 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13