LCOV - code coverage report
Current view: directory - embedding/components/find/src - nsWebBrowserFind.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 418 0 0.0 %
Date: 2012-06-02 Functions: 39 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  *
       3                 :  * ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is the Mozilla browser.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * Netscape Communications, Inc.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Conrad Carlen <ccarlen@netscape.com>
      25                 :  *   Simon Fraser  <sfraser@netscape.com>
      26                 :  *   Akkana Peck  <akkana@netscape.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 "nsWebBrowserFind.h"
      43                 : 
      44                 : // Only need this for NS_FIND_CONTRACTID,
      45                 : // else we could use nsIDOMRange.h and nsIFind.h.
      46                 : #include "nsFind.h"
      47                 : 
      48                 : #include "nsIComponentManager.h"
      49                 : #include "nsIScriptSecurityManager.h"
      50                 : #include "nsIInterfaceRequestor.h"
      51                 : #include "nsIInterfaceRequestorUtils.h"
      52                 : #include "nsPIDOMWindow.h"
      53                 : #include "nsIURI.h"
      54                 : #include "nsIDocShell.h"
      55                 : #include "nsIEnumerator.h"
      56                 : #include "nsIDocShellTreeItem.h"
      57                 : #include "nsIPresShell.h"
      58                 : #include "nsPresContext.h"
      59                 : #include "nsIDocument.h"
      60                 : #include "nsIDOMDocument.h"
      61                 : #include "nsISelectionController.h"
      62                 : #include "nsISelection.h"
      63                 : #include "nsIFrame.h"
      64                 : #include "nsITextControlFrame.h"
      65                 : #include "nsReadableUtils.h"
      66                 : #include "nsIDOMHTMLElement.h"
      67                 : #include "nsIDOMHTMLDocument.h"
      68                 : #include "nsIContent.h"
      69                 : #include "nsContentCID.h"
      70                 : #include "nsIServiceManager.h"
      71                 : #include "nsIObserverService.h"
      72                 : #include "nsISupportsPrimitives.h"
      73                 : #include "nsFind.h"
      74                 : #include "nsDOMError.h"
      75                 : #include "nsFocusManager.h"
      76                 : #include "mozilla/Services.h"
      77                 : 
      78                 : #if DEBUG
      79                 : #include "nsIWebNavigation.h"
      80                 : #include "nsXPIDLString.h"
      81                 : #endif
      82                 : 
      83                 : #if defined(XP_MACOSX) && !defined(__LP64__)
      84                 : #include "nsAutoPtr.h"
      85                 : #include <Carbon/Carbon.h>
      86                 : #endif
      87                 : 
      88                 : 
      89                 : //*****************************************************************************
      90                 : // nsWebBrowserFind
      91                 : //*****************************************************************************
      92                 : 
      93               0 : nsWebBrowserFind::nsWebBrowserFind() :
      94                 :     mFindBackwards(false),
      95                 :     mWrapFind(false),
      96                 :     mEntireWord(false),
      97                 :     mMatchCase(false),
      98                 :     mSearchSubFrames(true),
      99               0 :     mSearchParentFrames(true)
     100                 : {
     101               0 : }
     102                 : 
     103               0 : nsWebBrowserFind::~nsWebBrowserFind()
     104                 : {
     105               0 : }
     106                 : 
     107               0 : NS_IMPL_ISUPPORTS2(nsWebBrowserFind, nsIWebBrowserFind, nsIWebBrowserFindInFrames)
     108                 : 
     109                 : 
     110                 : /* boolean findNext (); */
     111               0 : NS_IMETHODIMP nsWebBrowserFind::FindNext(bool *outDidFind)
     112                 : {
     113               0 :     NS_ENSURE_ARG_POINTER(outDidFind);
     114               0 :     *outDidFind = false;
     115                 : 
     116               0 :     NS_ENSURE_TRUE(CanFindNext(), NS_ERROR_NOT_INITIALIZED);
     117                 : 
     118               0 :     nsresult rv = NS_OK;
     119               0 :     nsCOMPtr<nsIDOMWindow> searchFrame = do_QueryReferent(mCurrentSearchFrame);
     120               0 :     NS_ENSURE_TRUE(searchFrame, NS_ERROR_NOT_INITIALIZED);
     121                 : 
     122               0 :     nsCOMPtr<nsIDOMWindow> rootFrame = do_QueryReferent(mRootSearchFrame);
     123               0 :     NS_ENSURE_TRUE(rootFrame, NS_ERROR_NOT_INITIALIZED);
     124                 :     
     125                 :     // first, if there's a "cmd_findagain" observer around, check to see if it
     126                 :     // wants to perform the find again command . If it performs the find again
     127                 :     // it will return true, in which case we exit ::FindNext() early.
     128                 :     // Otherwise, nsWebBrowserFind needs to perform the find again command itself
     129                 :     // this is used by nsTypeAheadFind, which controls find again when it was
     130                 :     // the last executed find in the current window.
     131                 :     nsCOMPtr<nsIObserverService> observerSvc =
     132               0 :       mozilla::services::GetObserverService();
     133               0 :     if (observerSvc) {
     134                 :         nsCOMPtr<nsISupportsInterfacePointer> windowSupportsData = 
     135               0 :           do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
     136               0 :         NS_ENSURE_SUCCESS(rv, rv);
     137                 :         nsCOMPtr<nsISupports> searchWindowSupports =
     138               0 :           do_QueryInterface(rootFrame);
     139               0 :         windowSupportsData->SetData(searchWindowSupports);
     140               0 :         NS_NAMED_LITERAL_STRING(dnStr, "down");
     141               0 :         NS_NAMED_LITERAL_STRING(upStr, "up");
     142               0 :         observerSvc->NotifyObservers(windowSupportsData, 
     143                 :                                      "nsWebBrowserFind_FindAgain", 
     144               0 :                                      mFindBackwards? upStr.get(): dnStr.get());
     145               0 :         windowSupportsData->GetData(getter_AddRefs(searchWindowSupports));
     146                 :         // findnext performed if search window data cleared out
     147               0 :         *outDidFind = searchWindowSupports == nsnull;
     148               0 :         if (*outDidFind)
     149               0 :             return NS_OK;
     150                 :     }
     151                 : 
     152                 :     // next, look in the current frame. If found, return.
     153                 : 
     154                 :     // Beware! This may flush notifications via synchronous
     155                 :     // ScrollSelectionIntoView.
     156               0 :     rv = SearchInFrame(searchFrame, false, outDidFind);
     157               0 :     if (NS_FAILED(rv)) return rv;
     158               0 :     if (*outDidFind)
     159               0 :         return OnFind(searchFrame);     // we are done
     160                 : 
     161                 :     // if we are not searching other frames, return
     162               0 :     if (!mSearchSubFrames && !mSearchParentFrames)
     163               0 :         return NS_OK;
     164                 : 
     165               0 :     nsIDocShell *rootDocShell = GetDocShellFromWindow(rootFrame);
     166               0 :     if (!rootDocShell) return NS_ERROR_FAILURE;
     167                 :     
     168                 :     PRInt32 enumDirection;
     169               0 :     if (mFindBackwards)
     170               0 :         enumDirection = nsIDocShell::ENUMERATE_BACKWARDS;
     171                 :     else
     172               0 :         enumDirection = nsIDocShell::ENUMERATE_FORWARDS;
     173                 :         
     174               0 :     nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
     175                 :     rv = rootDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeAll,
     176               0 :             enumDirection, getter_AddRefs(docShellEnumerator));    
     177               0 :     if (NS_FAILED(rv)) return rv;
     178                 :         
     179                 :     // remember where we started
     180                 :     nsCOMPtr<nsIDocShellTreeItem> startingItem =
     181               0 :         do_QueryInterface(GetDocShellFromWindow(searchFrame), &rv);
     182               0 :     if (NS_FAILED(rv)) return rv;
     183                 : 
     184               0 :     nsCOMPtr<nsIDocShellTreeItem> curItem;
     185                 : 
     186                 :     // XXX We should avoid searching in frameset documents here.
     187                 :     // We also need to honour mSearchSubFrames and mSearchParentFrames.
     188               0 :     bool hasMore, doFind = false;
     189               0 :     while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMore)) && hasMore)
     190                 :     {
     191               0 :         nsCOMPtr<nsISupports> curSupports;
     192               0 :         rv = docShellEnumerator->GetNext(getter_AddRefs(curSupports));
     193               0 :         if (NS_FAILED(rv)) break;
     194               0 :         curItem = do_QueryInterface(curSupports, &rv);
     195               0 :         if (NS_FAILED(rv)) break;
     196                 : 
     197               0 :         if (doFind)
     198                 :         {
     199               0 :             searchFrame = do_GetInterface(curItem, &rv);
     200               0 :             if (NS_FAILED(rv)) break;
     201                 : 
     202               0 :             OnStartSearchFrame(searchFrame);
     203                 : 
     204                 :             // Beware! This may flush notifications via synchronous
     205                 :             // ScrollSelectionIntoView.
     206               0 :             rv = SearchInFrame(searchFrame, false, outDidFind);
     207               0 :             if (NS_FAILED(rv)) return rv;
     208               0 :             if (*outDidFind)
     209               0 :                 return OnFind(searchFrame);     // we are done
     210                 : 
     211               0 :             OnEndSearchFrame(searchFrame);
     212                 :         }
     213                 : 
     214               0 :         if (curItem.get() == startingItem.get())
     215               0 :             doFind = true;       // start looking in frames after this one
     216                 :     };
     217                 : 
     218               0 :     if (!mWrapFind)
     219                 :     {
     220                 :         // remember where we left off
     221               0 :         SetCurrentSearchFrame(searchFrame);
     222               0 :         return NS_OK;
     223                 :     }
     224                 : 
     225                 :     // From here on, we're wrapping, first through the other frames,
     226                 :     // then finally from the beginning of the starting frame back to
     227                 :     // the starting point.
     228                 : 
     229                 :     // because nsISimpleEnumerator is totally lame and isn't resettable, I
     230                 :     // have to make a new one
     231               0 :     docShellEnumerator = nsnull;
     232                 :     rv = rootDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeAll,
     233               0 :             enumDirection, getter_AddRefs(docShellEnumerator));    
     234               0 :     if (NS_FAILED(rv)) return rv;
     235                 :     
     236               0 :     while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMore)) && hasMore)
     237                 :     {
     238               0 :         nsCOMPtr<nsISupports> curSupports;
     239               0 :         rv = docShellEnumerator->GetNext(getter_AddRefs(curSupports));
     240               0 :         if (NS_FAILED(rv)) break;
     241               0 :         curItem = do_QueryInterface(curSupports, &rv);
     242               0 :         if (NS_FAILED(rv)) break;
     243                 : 
     244               0 :         if (curItem.get() == startingItem.get())
     245                 :         {
     246                 :             // Beware! This may flush notifications via synchronous
     247                 :             // ScrollSelectionIntoView.
     248               0 :             rv = SearchInFrame(searchFrame, true, outDidFind);
     249               0 :             if (NS_FAILED(rv)) return rv;
     250               0 :             if (*outDidFind)
     251               0 :                 return OnFind(searchFrame);        // we are done
     252                 :             break;
     253                 :         }
     254                 : 
     255               0 :         searchFrame = do_GetInterface(curItem, &rv);
     256               0 :         if (NS_FAILED(rv)) break;
     257                 : 
     258               0 :         OnStartSearchFrame(searchFrame);
     259                 : 
     260                 :         // Beware! This may flush notifications via synchronous
     261                 :         // ScrollSelectionIntoView.
     262               0 :         rv = SearchInFrame(searchFrame, false, outDidFind);
     263               0 :         if (NS_FAILED(rv)) return rv;
     264               0 :         if (*outDidFind)
     265               0 :             return OnFind(searchFrame);        // we are done
     266                 :         
     267               0 :         OnEndSearchFrame(searchFrame);
     268                 :     }
     269                 : 
     270                 :     // remember where we left off
     271               0 :     SetCurrentSearchFrame(searchFrame);
     272                 :     
     273               0 :     NS_ASSERTION(NS_SUCCEEDED(rv), "Something failed");
     274               0 :     return rv;
     275                 : }
     276                 : 
     277                 : 
     278                 : /* attribute wstring searchString; */
     279               0 : NS_IMETHODIMP nsWebBrowserFind::GetSearchString(PRUnichar * *aSearchString)
     280                 : {
     281               0 :     NS_ENSURE_ARG_POINTER(aSearchString);
     282                 : #if defined(XP_MACOSX) && !defined(__LP64__)
     283                 :     OSStatus err;
     284                 :     ScrapRef scrap;
     285                 :     err = ::GetScrapByName(kScrapFindScrap, kScrapGetNamedScrap, &scrap);
     286                 :     if (err == noErr) {
     287                 :         Size byteCount;
     288                 :         err = ::GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &byteCount);
     289                 :         if (err == noErr) {
     290                 :             NS_ASSERTION(byteCount%2 == 0, "byteCount not a multiple of 2");
     291                 :             nsAutoArrayPtr<PRUnichar> buffer(new PRUnichar[byteCount/2 + 1]);
     292                 :             NS_ENSURE_TRUE(buffer, NS_ERROR_OUT_OF_MEMORY);
     293                 :             err = ::GetScrapFlavorData(scrap, kScrapFlavorTypeUnicode, &byteCount, buffer.get());
     294                 :             if (err == noErr) {
     295                 :                 buffer[byteCount/2] = PRUnichar('\0');
     296                 :                 mSearchString.Assign(buffer);
     297                 :             }
     298                 :         }
     299                 :     }    
     300                 : #endif
     301               0 :     *aSearchString = ToNewUnicode(mSearchString);
     302               0 :     return NS_OK;
     303                 : }
     304                 : 
     305               0 : NS_IMETHODIMP nsWebBrowserFind::SetSearchString(const PRUnichar * aSearchString)
     306                 : {
     307               0 :     mSearchString.Assign(aSearchString);
     308                 : #if defined(XP_MACOSX) && !defined(__LP64__)
     309                 :     OSStatus err;
     310                 :     ScrapRef scrap;
     311                 :     err = ::GetScrapByName(kScrapFindScrap, kScrapClearNamedScrap, &scrap);
     312                 :     if (err == noErr) {
     313                 :         ::PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone,
     314                 :         (mSearchString.Length()*2), aSearchString);
     315                 :     }
     316                 : #endif
     317               0 :     return NS_OK;
     318                 : }
     319                 : 
     320                 : /* attribute boolean findBackwards; */
     321               0 : NS_IMETHODIMP nsWebBrowserFind::GetFindBackwards(bool *aFindBackwards)
     322                 : {
     323               0 :     NS_ENSURE_ARG_POINTER(aFindBackwards);
     324               0 :     *aFindBackwards = mFindBackwards;
     325               0 :     return NS_OK;
     326                 : }
     327                 : 
     328               0 : NS_IMETHODIMP nsWebBrowserFind::SetFindBackwards(bool aFindBackwards)
     329                 : {
     330               0 :     mFindBackwards = aFindBackwards;
     331               0 :     return NS_OK;
     332                 : }
     333                 : 
     334                 : /* attribute boolean wrapFind; */
     335               0 : NS_IMETHODIMP nsWebBrowserFind::GetWrapFind(bool *aWrapFind)
     336                 : {
     337               0 :     NS_ENSURE_ARG_POINTER(aWrapFind);
     338               0 :     *aWrapFind = mWrapFind;
     339               0 :     return NS_OK;
     340                 : }
     341               0 : NS_IMETHODIMP nsWebBrowserFind::SetWrapFind(bool aWrapFind)
     342                 : {
     343               0 :     mWrapFind = aWrapFind;
     344               0 :     return NS_OK;
     345                 : }
     346                 : 
     347                 : /* attribute boolean entireWord; */
     348               0 : NS_IMETHODIMP nsWebBrowserFind::GetEntireWord(bool *aEntireWord)
     349                 : {
     350               0 :     NS_ENSURE_ARG_POINTER(aEntireWord);
     351               0 :     *aEntireWord = mEntireWord;
     352               0 :     return NS_OK;
     353                 : }
     354               0 : NS_IMETHODIMP nsWebBrowserFind::SetEntireWord(bool aEntireWord)
     355                 : {
     356               0 :     mEntireWord = aEntireWord;
     357               0 :     return NS_OK;
     358                 : }
     359                 : 
     360                 : /* attribute boolean matchCase; */
     361               0 : NS_IMETHODIMP nsWebBrowserFind::GetMatchCase(bool *aMatchCase)
     362                 : {
     363               0 :     NS_ENSURE_ARG_POINTER(aMatchCase);
     364               0 :     *aMatchCase = mMatchCase;
     365               0 :     return NS_OK;
     366                 : }
     367               0 : NS_IMETHODIMP nsWebBrowserFind::SetMatchCase(bool aMatchCase)
     368                 : {
     369               0 :     mMatchCase = aMatchCase;
     370               0 :     return NS_OK;
     371                 : }
     372                 : 
     373                 : static bool
     374               0 : IsInNativeAnonymousSubtree(nsIContent* aContent)
     375                 : {
     376               0 :     while (aContent) {
     377               0 :         nsIContent* bindingParent = aContent->GetBindingParent();
     378               0 :         if (bindingParent == aContent) {
     379               0 :             return true;
     380                 :         }
     381                 : 
     382               0 :         aContent = bindingParent;
     383                 :     }
     384                 : 
     385               0 :     return false;
     386                 : }
     387                 : 
     388               0 : void nsWebBrowserFind::SetSelectionAndScroll(nsIDOMWindow* aWindow,
     389                 :                                              nsIDOMRange*  aRange)
     390                 : {
     391               0 :   nsCOMPtr<nsIDOMDocument> domDoc;    
     392               0 :   aWindow->GetDocument(getter_AddRefs(domDoc));
     393               0 :   if (!domDoc) return;
     394                 : 
     395               0 :   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
     396               0 :   nsIPresShell* presShell = doc->GetShell();
     397               0 :   if (!presShell) return;
     398                 : 
     399               0 :   nsCOMPtr<nsIDOMNode> node;
     400               0 :   aRange->GetStartContainer(getter_AddRefs(node));
     401               0 :   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
     402               0 :   nsIFrame* frame = content->GetPrimaryFrame();
     403               0 :   if (!frame)
     404                 :       return;
     405               0 :   nsCOMPtr<nsISelectionController> selCon;
     406                 :   frame->GetSelectionController(presShell->GetPresContext(),
     407               0 :                                 getter_AddRefs(selCon));
     408                 :   
     409                 :   // since the match could be an anonymous textnode inside a
     410                 :   // <textarea> or text <input>, we need to get the outer frame
     411               0 :   nsITextControlFrame *tcFrame = nsnull;
     412               0 :   for ( ; content; content = content->GetParent()) {
     413               0 :     if (!IsInNativeAnonymousSubtree(content)) {
     414               0 :       nsIFrame* f = content->GetPrimaryFrame();
     415               0 :       if (!f)
     416                 :         return;
     417               0 :       tcFrame = do_QueryFrame(f);
     418               0 :       break;
     419                 :     }
     420                 :   }
     421                 : 
     422               0 :   nsCOMPtr<nsISelection> selection;
     423                 : 
     424               0 :   selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
     425               0 :   selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
     426               0 :     getter_AddRefs(selection));
     427               0 :   if (selection) {
     428               0 :     selection->RemoveAllRanges();
     429               0 :     selection->AddRange(aRange);
     430                 : 
     431               0 :     nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
     432               0 :     if (fm) {
     433               0 :       if (tcFrame) {
     434               0 :         nsCOMPtr<nsIDOMElement> newFocusedElement(do_QueryInterface(content));
     435               0 :         fm->SetFocus(newFocusedElement, nsIFocusManager::FLAG_NOSCROLL);
     436                 :       }
     437                 :       else  {
     438               0 :         nsCOMPtr<nsIDOMElement> result;
     439               0 :         fm->MoveFocus(aWindow, nsnull, nsIFocusManager::MOVEFOCUS_CARET,
     440                 :                       nsIFocusManager::FLAG_NOSCROLL,
     441               0 :                       getter_AddRefs(result));
     442                 :       }
     443                 :     }
     444                 : 
     445                 :     // Scroll if necessary to make the selection visible:
     446                 :     // Must be the last thing to do - bug 242056
     447                 : 
     448                 :     // After ScrollSelectionIntoView(), the pending notifications might be
     449                 :     // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
     450               0 :     selCon->ScrollSelectionIntoView
     451                 :       (nsISelectionController::SELECTION_NORMAL,
     452                 :        nsISelectionController::SELECTION_WHOLE_SELECTION,
     453               0 :        nsISelectionController::SCROLL_SYNCHRONOUS);
     454                 :   }
     455                 : }
     456                 : 
     457                 : // Adapted from nsTextServicesDocument::GetDocumentContentRootNode
     458               0 : nsresult nsWebBrowserFind::GetRootNode(nsIDOMDocument* aDomDoc,
     459                 :                                        nsIDOMNode **aNode)
     460                 : {
     461                 :   nsresult rv;
     462                 : 
     463               0 :   NS_ENSURE_ARG_POINTER(aNode);
     464               0 :   *aNode = 0;
     465                 : 
     466               0 :   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(aDomDoc);
     467               0 :   if (htmlDoc)
     468                 :   {
     469                 :     // For HTML documents, the content root node is the body.
     470               0 :     nsCOMPtr<nsIDOMHTMLElement> bodyElement;
     471               0 :     rv = htmlDoc->GetBody(getter_AddRefs(bodyElement));
     472               0 :     NS_ENSURE_SUCCESS(rv, rv);
     473               0 :     NS_ENSURE_ARG_POINTER(bodyElement);
     474               0 :     return bodyElement->QueryInterface(NS_GET_IID(nsIDOMNode),
     475               0 :                                        (void **)aNode);
     476                 :   }
     477                 : 
     478                 :   // For non-HTML documents, the content root node will be the doc element.
     479               0 :   nsCOMPtr<nsIDOMElement> docElement;
     480               0 :   rv = aDomDoc->GetDocumentElement(getter_AddRefs(docElement));
     481               0 :   NS_ENSURE_SUCCESS(rv, rv);
     482               0 :   NS_ENSURE_ARG_POINTER(docElement);
     483               0 :   return docElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
     484                 : }
     485                 : 
     486               0 : nsresult nsWebBrowserFind::SetRangeAroundDocument(nsIDOMRange* aSearchRange,
     487                 :                                                   nsIDOMRange* aStartPt,
     488                 :                                                   nsIDOMRange* aEndPt,
     489                 :                                                   nsIDOMDocument* aDoc)
     490                 : {
     491               0 :     nsCOMPtr<nsIDOMNode> bodyNode;
     492               0 :     nsresult rv = GetRootNode(aDoc, getter_AddRefs(bodyNode));
     493               0 :     nsCOMPtr<nsIContent> bodyContent (do_QueryInterface(bodyNode));
     494               0 :     NS_ENSURE_SUCCESS(rv, rv);
     495               0 :     NS_ENSURE_ARG_POINTER(bodyContent);
     496                 : 
     497               0 :     PRUint32 childCount = bodyContent->GetChildCount();
     498                 : 
     499               0 :     aSearchRange->SetStart(bodyNode, 0);
     500               0 :     aSearchRange->SetEnd(bodyNode, childCount);
     501                 : 
     502               0 :     if (mFindBackwards)
     503                 :     {
     504               0 :         aStartPt->SetStart(bodyNode, childCount);
     505               0 :         aStartPt->SetEnd(bodyNode, childCount);
     506               0 :         aEndPt->SetStart(bodyNode, 0);
     507               0 :         aEndPt->SetEnd(bodyNode, 0);
     508                 :     }
     509                 :     else
     510                 :     {
     511               0 :         aStartPt->SetStart(bodyNode, 0);
     512               0 :         aStartPt->SetEnd(bodyNode, 0);
     513               0 :         aEndPt->SetStart(bodyNode, childCount);
     514               0 :         aEndPt->SetEnd(bodyNode, childCount);
     515                 :     }
     516                 : 
     517               0 :     return NS_OK;
     518                 : }
     519                 : 
     520                 : // Set the range to go from the end of the current selection to the
     521                 : // end of the document (forward), or beginning to beginning (reverse).
     522                 : // or around the whole document if there's no selection.
     523                 : nsresult
     524               0 : nsWebBrowserFind::GetSearchLimits(nsIDOMRange* aSearchRange,
     525                 :                                   nsIDOMRange* aStartPt,
     526                 :                                   nsIDOMRange* aEndPt,
     527                 :                                   nsIDOMDocument* aDoc,
     528                 :                                   nsISelection* aSel,
     529                 :                                   bool aWrap)
     530                 : {
     531               0 :     NS_ENSURE_ARG_POINTER(aSel);
     532                 : 
     533                 :     // There is a selection.
     534               0 :     PRInt32 count = -1;
     535               0 :     nsresult rv = aSel->GetRangeCount(&count);
     536               0 :     if (count < 1)
     537               0 :         return SetRangeAroundDocument(aSearchRange, aStartPt, aEndPt, aDoc);
     538                 : 
     539                 :     // Need bodyNode, for the start/end of the document
     540               0 :     nsCOMPtr<nsIDOMNode> bodyNode;
     541               0 :     rv = GetRootNode(aDoc, getter_AddRefs(bodyNode));
     542               0 :     nsCOMPtr<nsIContent> bodyContent (do_QueryInterface(bodyNode));
     543               0 :     NS_ENSURE_ARG_POINTER(bodyContent);
     544                 : 
     545               0 :     PRUint32 childCount = bodyContent->GetChildCount();
     546                 : 
     547                 :     // There are four possible range endpoints we might use:
     548                 :     // DocumentStart, SelectionStart, SelectionEnd, DocumentEnd.
     549                 : 
     550               0 :     nsCOMPtr<nsIDOMRange> range;
     551               0 :     nsCOMPtr<nsIDOMNode> node;
     552                 :     PRInt32 offset;
     553                 : 
     554                 :     // Forward, not wrapping: SelEnd to DocEnd
     555               0 :     if (!mFindBackwards && !aWrap)
     556                 :     {
     557                 :         // This isn't quite right, since the selection's ranges aren't
     558                 :         // necessarily in order; but they usually will be.
     559               0 :         aSel->GetRangeAt(count-1, getter_AddRefs(range));
     560               0 :         if (!range) return NS_ERROR_UNEXPECTED;
     561               0 :         range->GetEndContainer(getter_AddRefs(node));
     562               0 :         if (!node) return NS_ERROR_UNEXPECTED;
     563               0 :         range->GetEndOffset(&offset);
     564                 : 
     565               0 :         aSearchRange->SetStart(node, offset);
     566               0 :         aSearchRange->SetEnd(bodyNode, childCount);
     567               0 :         aStartPt->SetStart(node, offset);
     568               0 :         aStartPt->SetEnd(node, offset);
     569               0 :         aEndPt->SetStart(bodyNode, childCount);
     570               0 :         aEndPt->SetEnd(bodyNode, childCount);
     571                 :     }
     572                 :     // Backward, not wrapping: DocStart to SelStart
     573               0 :     else if (mFindBackwards && !aWrap)
     574                 :     {
     575               0 :         aSel->GetRangeAt(0, getter_AddRefs(range));
     576               0 :         if (!range) return NS_ERROR_UNEXPECTED;
     577               0 :         range->GetStartContainer(getter_AddRefs(node));
     578               0 :         if (!node) return NS_ERROR_UNEXPECTED;
     579               0 :         range->GetStartOffset(&offset);
     580                 : 
     581               0 :         aSearchRange->SetStart(bodyNode, 0);
     582               0 :         aSearchRange->SetEnd(bodyNode, childCount);
     583               0 :         aStartPt->SetStart(node, offset);
     584               0 :         aStartPt->SetEnd(node, offset);
     585               0 :         aEndPt->SetStart(bodyNode, 0);
     586               0 :         aEndPt->SetEnd(bodyNode, 0);
     587                 :     }
     588                 :     // Forward, wrapping: DocStart to SelEnd
     589               0 :     else if (!mFindBackwards && aWrap)
     590                 :     {
     591               0 :         aSel->GetRangeAt(count-1, getter_AddRefs(range));
     592               0 :         if (!range) return NS_ERROR_UNEXPECTED;
     593               0 :         range->GetEndContainer(getter_AddRefs(node));
     594               0 :         if (!node) return NS_ERROR_UNEXPECTED;
     595               0 :         range->GetEndOffset(&offset);
     596                 : 
     597               0 :         aSearchRange->SetStart(bodyNode, 0);
     598               0 :         aSearchRange->SetEnd(bodyNode, childCount);
     599               0 :         aStartPt->SetStart(bodyNode, 0);
     600               0 :         aStartPt->SetEnd(bodyNode, 0);
     601               0 :         aEndPt->SetStart(node, offset);
     602               0 :         aEndPt->SetEnd(node, offset);
     603                 :     }
     604                 :     // Backward, wrapping: SelStart to DocEnd
     605               0 :     else if (mFindBackwards && aWrap)
     606                 :     {
     607               0 :         aSel->GetRangeAt(0, getter_AddRefs(range));
     608               0 :         if (!range) return NS_ERROR_UNEXPECTED;
     609               0 :         range->GetStartContainer(getter_AddRefs(node));
     610               0 :         if (!node) return NS_ERROR_UNEXPECTED;
     611               0 :         range->GetStartOffset(&offset);
     612                 : 
     613               0 :         aSearchRange->SetStart(bodyNode, 0);
     614               0 :         aSearchRange->SetEnd(bodyNode, childCount);
     615               0 :         aStartPt->SetStart(bodyNode, childCount);
     616               0 :         aStartPt->SetEnd(bodyNode, childCount);
     617               0 :         aEndPt->SetStart(node, offset);
     618               0 :         aEndPt->SetEnd(node, offset);
     619                 :     }
     620               0 :     return NS_OK;
     621                 : }
     622                 : 
     623                 : /* attribute boolean searchFrames; */
     624               0 : NS_IMETHODIMP nsWebBrowserFind::GetSearchFrames(bool *aSearchFrames)
     625                 : {
     626               0 :     NS_ENSURE_ARG_POINTER(aSearchFrames);
     627                 :     // this only returns true if we are searching both sub and parent
     628                 :     // frames. There is ambiguity if the caller has previously set
     629                 :     // one, but not both of these.
     630               0 :     *aSearchFrames = mSearchSubFrames && mSearchParentFrames;
     631               0 :     return NS_OK;
     632                 : }
     633                 : 
     634               0 : NS_IMETHODIMP nsWebBrowserFind::SetSearchFrames(bool aSearchFrames)
     635                 : {
     636               0 :     mSearchSubFrames = aSearchFrames;
     637               0 :     mSearchParentFrames = aSearchFrames;
     638               0 :     return NS_OK;
     639                 : }
     640                 : 
     641                 : /* attribute nsIDOMWindow currentSearchFrame; */
     642               0 : NS_IMETHODIMP nsWebBrowserFind::GetCurrentSearchFrame(nsIDOMWindow * *aCurrentSearchFrame)
     643                 : {
     644               0 :     NS_ENSURE_ARG_POINTER(aCurrentSearchFrame);
     645               0 :     nsCOMPtr<nsIDOMWindow> searchFrame = do_QueryReferent(mCurrentSearchFrame);
     646               0 :     NS_IF_ADDREF(*aCurrentSearchFrame = searchFrame);
     647               0 :     return (*aCurrentSearchFrame) ? NS_OK : NS_ERROR_NOT_INITIALIZED;
     648                 : }
     649                 : 
     650               0 : NS_IMETHODIMP nsWebBrowserFind::SetCurrentSearchFrame(nsIDOMWindow * aCurrentSearchFrame)
     651                 : {
     652                 :     // is it ever valid to set this to null?
     653               0 :     NS_ENSURE_ARG(aCurrentSearchFrame);
     654               0 :     mCurrentSearchFrame = do_GetWeakReference(aCurrentSearchFrame);
     655               0 :     return NS_OK;
     656                 : }
     657                 : 
     658                 : /* attribute nsIDOMWindow rootSearchFrame; */
     659               0 : NS_IMETHODIMP nsWebBrowserFind::GetRootSearchFrame(nsIDOMWindow * *aRootSearchFrame)
     660                 : {
     661               0 :     NS_ENSURE_ARG_POINTER(aRootSearchFrame);
     662               0 :     nsCOMPtr<nsIDOMWindow> searchFrame = do_QueryReferent(mRootSearchFrame);
     663               0 :     NS_IF_ADDREF(*aRootSearchFrame = searchFrame);
     664               0 :     return (*aRootSearchFrame) ? NS_OK : NS_ERROR_NOT_INITIALIZED;
     665                 : }
     666                 : 
     667               0 : NS_IMETHODIMP nsWebBrowserFind::SetRootSearchFrame(nsIDOMWindow * aRootSearchFrame)
     668                 : {
     669                 :     // is it ever valid to set this to null?
     670               0 :     NS_ENSURE_ARG(aRootSearchFrame);
     671               0 :     mRootSearchFrame = do_GetWeakReference(aRootSearchFrame);
     672               0 :     return NS_OK;
     673                 : }
     674                 : 
     675                 : /* attribute boolean searchSubframes; */
     676               0 : NS_IMETHODIMP nsWebBrowserFind::GetSearchSubframes(bool *aSearchSubframes)
     677                 : {
     678               0 :     NS_ENSURE_ARG_POINTER(aSearchSubframes);
     679               0 :     *aSearchSubframes = mSearchSubFrames;
     680               0 :     return NS_OK;
     681                 : }
     682                 : 
     683               0 : NS_IMETHODIMP nsWebBrowserFind::SetSearchSubframes(bool aSearchSubframes)
     684                 : {
     685               0 :     mSearchSubFrames = aSearchSubframes;
     686               0 :     return NS_OK;
     687                 : }
     688                 : 
     689                 : /* attribute boolean searchParentFrames; */
     690               0 : NS_IMETHODIMP nsWebBrowserFind::GetSearchParentFrames(bool *aSearchParentFrames)
     691                 : {
     692               0 :     NS_ENSURE_ARG_POINTER(aSearchParentFrames);
     693               0 :     *aSearchParentFrames = mSearchParentFrames;
     694               0 :     return NS_OK;
     695                 : }
     696                 : 
     697               0 : NS_IMETHODIMP nsWebBrowserFind::SetSearchParentFrames(bool aSearchParentFrames)
     698                 : {
     699               0 :     mSearchParentFrames = aSearchParentFrames;
     700               0 :     return NS_OK;
     701                 : }
     702                 : 
     703                 : /*
     704                 :     This method handles finding in a single window (aka frame).
     705                 : 
     706                 : */
     707               0 : nsresult nsWebBrowserFind::SearchInFrame(nsIDOMWindow* aWindow,
     708                 :                                          bool aWrapping,
     709                 :                                          bool* aDidFind)
     710                 : {
     711               0 :     NS_ENSURE_ARG(aWindow);
     712               0 :     NS_ENSURE_ARG_POINTER(aDidFind);
     713                 : 
     714               0 :     *aDidFind = false;
     715                 : 
     716               0 :     nsCOMPtr<nsIDOMDocument> domDoc;    
     717               0 :     nsresult rv = aWindow->GetDocument(getter_AddRefs(domDoc));
     718               0 :     NS_ENSURE_SUCCESS(rv, rv);
     719               0 :     if (!domDoc) return NS_ERROR_FAILURE;
     720                 : 
     721                 :     // Do security check, to ensure that the frame we're searching is
     722                 :     // acccessible from the frame where the Find is being run.
     723                 : 
     724                 :     // get a uri for the window
     725               0 :     nsCOMPtr<nsIDocument> theDoc = do_QueryInterface(domDoc);
     726               0 :     if (!theDoc) return NS_ERROR_FAILURE;
     727                 : 
     728                 :     nsCOMPtr<nsIScriptSecurityManager> secMan =
     729               0 :       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     730               0 :     NS_ENSURE_SUCCESS(rv, rv);
     731                 :   
     732               0 :     nsCOMPtr<nsIPrincipal> subject;
     733               0 :     rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
     734               0 :     NS_ENSURE_SUCCESS(rv, rv);
     735                 : 
     736               0 :     if (subject) {
     737                 :         bool subsumes;
     738               0 :         rv = subject->Subsumes(theDoc->NodePrincipal(), &subsumes);
     739               0 :         NS_ENSURE_SUCCESS(rv, rv);
     740               0 :         if (!subsumes) {
     741               0 :             bool hasCap = false;
     742               0 :             secMan->IsCapabilityEnabled("UniversalXPConnect", &hasCap);
     743               0 :             if (!hasCap) {
     744               0 :                 return NS_ERROR_DOM_PROP_ACCESS_DENIED;
     745                 :             }
     746                 :         }
     747                 :     }
     748                 : 
     749               0 :     nsCOMPtr<nsIFind> find = do_CreateInstance(NS_FIND_CONTRACTID, &rv);
     750               0 :     NS_ENSURE_SUCCESS(rv, rv);
     751                 : 
     752               0 :     (void) find->SetCaseSensitive(mMatchCase);
     753               0 :     (void) find->SetFindBackwards(mFindBackwards);
     754                 : 
     755                 :     // XXX Make and set a line breaker here, once that's implemented.
     756               0 :     (void) find->SetWordBreaker(0);
     757                 : 
     758                 :     // Now make sure the content (for actual finding) and frame (for
     759                 :     // selection) models are up to date.
     760               0 :     theDoc->FlushPendingNotifications(Flush_Frames);
     761                 : 
     762               0 :     nsCOMPtr<nsISelection> sel;
     763               0 :     GetFrameSelection(aWindow, getter_AddRefs(sel));
     764               0 :     NS_ENSURE_ARG_POINTER(sel);
     765                 : 
     766               0 :     nsCOMPtr<nsIDOMRange> searchRange = nsFind::CreateRange();
     767               0 :     NS_ENSURE_ARG_POINTER(searchRange);
     768               0 :     nsCOMPtr<nsIDOMRange> startPt  = nsFind::CreateRange();
     769               0 :     NS_ENSURE_ARG_POINTER(startPt);
     770               0 :     nsCOMPtr<nsIDOMRange> endPt  = nsFind::CreateRange();
     771               0 :     NS_ENSURE_ARG_POINTER(endPt);
     772                 : 
     773               0 :     nsCOMPtr<nsIDOMRange> foundRange;
     774                 : 
     775                 :     // If !aWrapping, search from selection to end
     776               0 :     if (!aWrapping)
     777                 :         rv = GetSearchLimits(searchRange, startPt, endPt, domDoc, sel,
     778               0 :                              false);
     779                 : 
     780                 :     // If aWrapping, search the part of the starting frame
     781                 :     // up to the point where we left off.
     782                 :     else
     783                 :         rv = GetSearchLimits(searchRange, startPt, endPt, domDoc, sel,
     784               0 :                              true);
     785                 : 
     786               0 :     NS_ENSURE_SUCCESS(rv, rv);
     787                 : 
     788               0 :     rv =  find->Find(mSearchString.get(), searchRange, startPt, endPt,
     789               0 :                      getter_AddRefs(foundRange));
     790                 : 
     791               0 :     if (NS_SUCCEEDED(rv) && foundRange)
     792                 :     {
     793               0 :         *aDidFind = true;
     794               0 :         sel->RemoveAllRanges();
     795                 :         // Beware! This may flush notifications via synchronous
     796                 :         // ScrollSelectionIntoView.
     797               0 :         SetSelectionAndScroll(aWindow, foundRange);
     798                 :     }
     799                 : 
     800               0 :     return rv;
     801                 : }
     802                 : 
     803                 : 
     804                 : // called when we start searching a frame that is not the initial
     805                 : // focussed frame. Prepare the frame to be searched.
     806                 : // we clear the selection, so that the search starts from the top
     807                 : // of the frame.
     808               0 : nsresult nsWebBrowserFind::OnStartSearchFrame(nsIDOMWindow *aWindow)
     809                 : {
     810               0 :     return ClearFrameSelection(aWindow);
     811                 : }
     812                 : 
     813                 : // called when we are done searching a frame and didn't find anything,
     814                 : // and about about to start searching the next frame.
     815               0 : nsresult nsWebBrowserFind::OnEndSearchFrame(nsIDOMWindow *aWindow)
     816                 : {
     817               0 :     return NS_OK;
     818                 : }
     819                 : 
     820                 : void
     821               0 : nsWebBrowserFind::GetFrameSelection(nsIDOMWindow* aWindow, 
     822                 :                                     nsISelection** aSel)
     823                 : {
     824               0 :     *aSel = nsnull;
     825                 : 
     826               0 :     nsCOMPtr<nsIDOMDocument> domDoc;    
     827               0 :     aWindow->GetDocument(getter_AddRefs(domDoc));
     828               0 :     if (!domDoc) return;
     829                 : 
     830               0 :     nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
     831               0 :     nsIPresShell* presShell = doc->GetShell();
     832               0 :     if (!presShell) return;
     833                 : 
     834                 :     // text input controls have their independent selection controllers
     835                 :     // that we must use when they have focus.
     836               0 :     nsPresContext *presContext = presShell->GetPresContext();
     837                 : 
     838               0 :     nsIFrame *frame = nsnull;
     839               0 :     nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
     840               0 :     if (fm) {
     841               0 :       nsCOMPtr<nsIDOMElement> focusedElement;
     842               0 :       fm->GetFocusedElement(getter_AddRefs(focusedElement));
     843               0 :       nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(focusedElement));
     844               0 :       if (focusedContent) {
     845               0 :         frame = focusedContent->GetPrimaryFrame();
     846               0 :         if (frame && frame->PresContext() != presContext)
     847               0 :           frame = nsnull;
     848                 :       }
     849                 :     }
     850                 : 
     851               0 :     nsCOMPtr<nsISelectionController> selCon;
     852               0 :     if (frame) {
     853               0 :         frame->GetSelectionController(presContext, getter_AddRefs(selCon));
     854               0 :         selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSel);
     855               0 :         if (*aSel) {
     856               0 :             PRInt32 count = -1;
     857               0 :             (*aSel)->GetRangeCount(&count);
     858               0 :             if (count > 0) {
     859                 :                 return;
     860                 :             }
     861               0 :             NS_RELEASE(*aSel);
     862                 :         }
     863                 :     }
     864                 : 
     865               0 :     selCon = do_QueryInterface(presShell);
     866               0 :     selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSel);
     867                 : }
     868                 : 
     869               0 : nsresult nsWebBrowserFind::ClearFrameSelection(nsIDOMWindow *aWindow)
     870                 : {
     871               0 :     NS_ENSURE_ARG(aWindow);
     872               0 :     nsCOMPtr<nsISelection> selection;
     873               0 :     GetFrameSelection(aWindow, getter_AddRefs(selection));
     874               0 :     if (selection)
     875               0 :         selection->RemoveAllRanges();
     876                 :     
     877               0 :     return NS_OK;
     878                 : }
     879                 : 
     880               0 : nsresult nsWebBrowserFind::OnFind(nsIDOMWindow *aFoundWindow)
     881                 : {
     882               0 :     SetCurrentSearchFrame(aFoundWindow);
     883                 : 
     884                 :     // We don't want a selection to appear in two frames simultaneously
     885               0 :     nsCOMPtr<nsIDOMWindow> lastFocusedWindow = do_QueryReferent(mLastFocusedWindow);
     886               0 :     if (lastFocusedWindow && lastFocusedWindow != aFoundWindow)
     887               0 :         ClearFrameSelection(lastFocusedWindow);
     888                 : 
     889               0 :     nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
     890               0 :     if (fm) {
     891                 :       // get the containing frame and focus it. For top-level windows,
     892                 :       // the right window should already be focused.
     893               0 :       nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aFoundWindow));
     894               0 :       NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
     895                 : 
     896               0 :       nsCOMPtr<nsIDOMElement> frameElement = window->GetFrameElementInternal();
     897               0 :       if (frameElement)
     898               0 :         fm->SetFocus(frameElement, 0);
     899                 : 
     900               0 :       mLastFocusedWindow = do_GetWeakReference(aFoundWindow);
     901                 :     }
     902                 : 
     903               0 :     return NS_OK;
     904                 : }
     905                 : 
     906                 : /*---------------------------------------------------------------------------
     907                 : 
     908                 :   GetDocShellFromWindow
     909                 : 
     910                 :   Utility method. This will always return nsnull if no docShell
     911                 :   is returned. Oh why isn't there a better way to do this?
     912                 : ----------------------------------------------------------------------------*/
     913                 : nsIDocShell *
     914               0 : nsWebBrowserFind::GetDocShellFromWindow(nsIDOMWindow *inWindow)
     915                 : {
     916               0 :     nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(inWindow));
     917               0 :     if (!window) return nsnull;
     918                 : 
     919               0 :     return window->GetDocShell();
     920                 : }
     921                 : 

Generated by: LCOV version 1.7