embedding/components/find/src/nsWebBrowserFind.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "nsWebBrowserFind.h"
     9 // Only need this for NS_FIND_CONTRACTID,
    10 // else we could use nsIDOMRange.h and nsIFind.h.
    11 #include "nsFind.h"
    13 #include "nsIComponentManager.h"
    14 #include "nsIScriptSecurityManager.h"
    15 #include "nsIInterfaceRequestor.h"
    16 #include "nsIInterfaceRequestorUtils.h"
    17 #include "nsPIDOMWindow.h"
    18 #include "nsIURI.h"
    19 #include "nsIDocShell.h"
    20 #include "nsIPresShell.h"
    21 #include "nsPresContext.h"
    22 #include "nsIDocument.h"
    23 #include "nsIDOMDocument.h"
    24 #include "nsISelectionController.h"
    25 #include "nsISelection.h"
    26 #include "nsIFrame.h"
    27 #include "nsITextControlFrame.h"
    28 #include "nsReadableUtils.h"
    29 #include "nsIDOMHTMLElement.h"
    30 #include "nsIDOMHTMLDocument.h"
    31 #include "nsIContent.h"
    32 #include "nsContentCID.h"
    33 #include "nsIServiceManager.h"
    34 #include "nsIObserverService.h"
    35 #include "nsISupportsPrimitives.h"
    36 #include "nsFind.h"
    37 #include "nsError.h"
    38 #include "nsFocusManager.h"
    39 #include "mozilla/Services.h"
    40 #include "mozilla/dom/Element.h"
    41 #include "nsISimpleEnumerator.h"
    43 #if DEBUG
    44 #include "nsIWebNavigation.h"
    45 #include "nsXPIDLString.h"
    46 #endif
    48 //*****************************************************************************
    49 // nsWebBrowserFind
    50 //*****************************************************************************
    52 nsWebBrowserFind::nsWebBrowserFind() :
    53     mFindBackwards(false),
    54     mWrapFind(false),
    55     mEntireWord(false),
    56     mMatchCase(false),
    57     mSearchSubFrames(true),
    58     mSearchParentFrames(true)
    59 {
    60 }
    62 nsWebBrowserFind::~nsWebBrowserFind()
    63 {
    64 }
    66 NS_IMPL_ISUPPORTS(nsWebBrowserFind, nsIWebBrowserFind, nsIWebBrowserFindInFrames)
    69 /* boolean findNext (); */
    70 NS_IMETHODIMP nsWebBrowserFind::FindNext(bool *outDidFind)
    71 {
    72     NS_ENSURE_ARG_POINTER(outDidFind);
    73     *outDidFind = false;
    75     NS_ENSURE_TRUE(CanFindNext(), NS_ERROR_NOT_INITIALIZED);
    77     nsresult rv = NS_OK;
    78     nsCOMPtr<nsIDOMWindow> searchFrame = do_QueryReferent(mCurrentSearchFrame);
    79     NS_ENSURE_TRUE(searchFrame, NS_ERROR_NOT_INITIALIZED);
    81     nsCOMPtr<nsIDOMWindow> rootFrame = do_QueryReferent(mRootSearchFrame);
    82     NS_ENSURE_TRUE(rootFrame, NS_ERROR_NOT_INITIALIZED);
    84     // first, if there's a "cmd_findagain" observer around, check to see if it
    85     // wants to perform the find again command . If it performs the find again
    86     // it will return true, in which case we exit ::FindNext() early.
    87     // Otherwise, nsWebBrowserFind needs to perform the find again command itself
    88     // this is used by nsTypeAheadFind, which controls find again when it was
    89     // the last executed find in the current window.
    90     nsCOMPtr<nsIObserverService> observerSvc =
    91       mozilla::services::GetObserverService();
    92     if (observerSvc) {
    93         nsCOMPtr<nsISupportsInterfacePointer> windowSupportsData = 
    94           do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
    95         NS_ENSURE_SUCCESS(rv, rv);
    96         nsCOMPtr<nsISupports> searchWindowSupports =
    97           do_QueryInterface(rootFrame);
    98         windowSupportsData->SetData(searchWindowSupports);
    99         NS_NAMED_LITERAL_STRING(dnStr, "down");
   100         NS_NAMED_LITERAL_STRING(upStr, "up");
   101         observerSvc->NotifyObservers(windowSupportsData, 
   102                                      "nsWebBrowserFind_FindAgain", 
   103                                      mFindBackwards? upStr.get(): dnStr.get());
   104         windowSupportsData->GetData(getter_AddRefs(searchWindowSupports));
   105         // findnext performed if search window data cleared out
   106         *outDidFind = searchWindowSupports == nullptr;
   107         if (*outDidFind)
   108             return NS_OK;
   109     }
   111     // next, look in the current frame. If found, return.
   113     // Beware! This may flush notifications via synchronous
   114     // ScrollSelectionIntoView.
   115     rv = SearchInFrame(searchFrame, false, outDidFind);
   116     if (NS_FAILED(rv)) return rv;
   117     if (*outDidFind)
   118         return OnFind(searchFrame);     // we are done
   120     // if we are not searching other frames, return
   121     if (!mSearchSubFrames && !mSearchParentFrames)
   122         return NS_OK;
   124     nsIDocShell *rootDocShell = GetDocShellFromWindow(rootFrame);
   125     if (!rootDocShell) return NS_ERROR_FAILURE;
   127     int32_t enumDirection;
   128     if (mFindBackwards)
   129         enumDirection = nsIDocShell::ENUMERATE_BACKWARDS;
   130     else
   131         enumDirection = nsIDocShell::ENUMERATE_FORWARDS;
   133     nsCOMPtr<nsISimpleEnumerator> docShellEnumerator;
   134     rv = rootDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeAll,
   135             enumDirection, getter_AddRefs(docShellEnumerator));    
   136     if (NS_FAILED(rv)) return rv;
   138     // remember where we started
   139     nsCOMPtr<nsIDocShellTreeItem> startingItem =
   140         do_QueryInterface(GetDocShellFromWindow(searchFrame), &rv);
   141     if (NS_FAILED(rv)) return rv;
   143     nsCOMPtr<nsIDocShellTreeItem> curItem;
   145     // XXX We should avoid searching in frameset documents here.
   146     // We also need to honour mSearchSubFrames and mSearchParentFrames.
   147     bool hasMore, doFind = false;
   148     while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMore)) && hasMore)
   149     {
   150         nsCOMPtr<nsISupports> curSupports;
   151         rv = docShellEnumerator->GetNext(getter_AddRefs(curSupports));
   152         if (NS_FAILED(rv)) break;
   153         curItem = do_QueryInterface(curSupports, &rv);
   154         if (NS_FAILED(rv)) break;
   156         if (doFind)
   157         {
   158             searchFrame = do_GetInterface(curItem, &rv);
   159             if (NS_FAILED(rv)) break;
   161             OnStartSearchFrame(searchFrame);
   163             // Beware! This may flush notifications via synchronous
   164             // ScrollSelectionIntoView.
   165             rv = SearchInFrame(searchFrame, false, outDidFind);
   166             if (NS_FAILED(rv)) return rv;
   167             if (*outDidFind)
   168                 return OnFind(searchFrame);     // we are done
   170             OnEndSearchFrame(searchFrame);
   171         }
   173         if (curItem.get() == startingItem.get())
   174             doFind = true;       // start looking in frames after this one
   175     };
   177     if (!mWrapFind)
   178     {
   179         // remember where we left off
   180         SetCurrentSearchFrame(searchFrame);
   181         return NS_OK;
   182     }
   184     // From here on, we're wrapping, first through the other frames,
   185     // then finally from the beginning of the starting frame back to
   186     // the starting point.
   188     // because nsISimpleEnumerator is totally lame and isn't resettable, I
   189     // have to make a new one
   190     docShellEnumerator = nullptr;
   191     rv = rootDocShell->GetDocShellEnumerator(nsIDocShellTreeItem::typeAll,
   192             enumDirection, getter_AddRefs(docShellEnumerator));    
   193     if (NS_FAILED(rv)) return rv;
   195     while (NS_SUCCEEDED(docShellEnumerator->HasMoreElements(&hasMore)) && hasMore)
   196     {
   197         nsCOMPtr<nsISupports> curSupports;
   198         rv = docShellEnumerator->GetNext(getter_AddRefs(curSupports));
   199         if (NS_FAILED(rv)) break;
   200         curItem = do_QueryInterface(curSupports, &rv);
   201         if (NS_FAILED(rv)) break;
   203         searchFrame = do_GetInterface(curItem, &rv);
   204         if (NS_FAILED(rv)) break;
   206         if (curItem.get() == startingItem.get())
   207         {
   208             // Beware! This may flush notifications via synchronous
   209             // ScrollSelectionIntoView.
   210             rv = SearchInFrame(searchFrame, true, outDidFind);
   211             if (NS_FAILED(rv)) return rv;
   212             if (*outDidFind)
   213                 return OnFind(searchFrame);        // we are done
   214             break;
   215         }
   217         OnStartSearchFrame(searchFrame);
   219         // Beware! This may flush notifications via synchronous
   220         // ScrollSelectionIntoView.
   221         rv = SearchInFrame(searchFrame, false, outDidFind);
   222         if (NS_FAILED(rv)) return rv;
   223         if (*outDidFind)
   224             return OnFind(searchFrame);        // we are done
   226         OnEndSearchFrame(searchFrame);
   227     }
   229     // remember where we left off
   230     SetCurrentSearchFrame(searchFrame);
   232     NS_ASSERTION(NS_SUCCEEDED(rv), "Something failed");
   233     return rv;
   234 }
   237 /* attribute wstring searchString; */
   238 NS_IMETHODIMP nsWebBrowserFind::GetSearchString(char16_t * *aSearchString)
   239 {
   240     NS_ENSURE_ARG_POINTER(aSearchString);
   241     *aSearchString = ToNewUnicode(mSearchString);
   242     return NS_OK;
   243 }
   245 NS_IMETHODIMP nsWebBrowserFind::SetSearchString(const char16_t * aSearchString)
   246 {
   247     mSearchString.Assign(aSearchString);
   248     return NS_OK;
   249 }
   251 /* attribute boolean findBackwards; */
   252 NS_IMETHODIMP nsWebBrowserFind::GetFindBackwards(bool *aFindBackwards)
   253 {
   254     NS_ENSURE_ARG_POINTER(aFindBackwards);
   255     *aFindBackwards = mFindBackwards;
   256     return NS_OK;
   257 }
   259 NS_IMETHODIMP nsWebBrowserFind::SetFindBackwards(bool aFindBackwards)
   260 {
   261     mFindBackwards = aFindBackwards;
   262     return NS_OK;
   263 }
   265 /* attribute boolean wrapFind; */
   266 NS_IMETHODIMP nsWebBrowserFind::GetWrapFind(bool *aWrapFind)
   267 {
   268     NS_ENSURE_ARG_POINTER(aWrapFind);
   269     *aWrapFind = mWrapFind;
   270     return NS_OK;
   271 }
   272 NS_IMETHODIMP nsWebBrowserFind::SetWrapFind(bool aWrapFind)
   273 {
   274     mWrapFind = aWrapFind;
   275     return NS_OK;
   276 }
   278 /* attribute boolean entireWord; */
   279 NS_IMETHODIMP nsWebBrowserFind::GetEntireWord(bool *aEntireWord)
   280 {
   281     NS_ENSURE_ARG_POINTER(aEntireWord);
   282     *aEntireWord = mEntireWord;
   283     return NS_OK;
   284 }
   285 NS_IMETHODIMP nsWebBrowserFind::SetEntireWord(bool aEntireWord)
   286 {
   287     mEntireWord = aEntireWord;
   288     return NS_OK;
   289 }
   291 /* attribute boolean matchCase; */
   292 NS_IMETHODIMP nsWebBrowserFind::GetMatchCase(bool *aMatchCase)
   293 {
   294     NS_ENSURE_ARG_POINTER(aMatchCase);
   295     *aMatchCase = mMatchCase;
   296     return NS_OK;
   297 }
   298 NS_IMETHODIMP nsWebBrowserFind::SetMatchCase(bool aMatchCase)
   299 {
   300     mMatchCase = aMatchCase;
   301     return NS_OK;
   302 }
   304 static bool
   305 IsInNativeAnonymousSubtree(nsIContent* aContent)
   306 {
   307     while (aContent) {
   308         nsIContent* bindingParent = aContent->GetBindingParent();
   309         if (bindingParent == aContent) {
   310             return true;
   311         }
   313         aContent = bindingParent;
   314     }
   316     return false;
   317 }
   319 void nsWebBrowserFind::SetSelectionAndScroll(nsIDOMWindow* aWindow,
   320                                              nsIDOMRange*  aRange)
   321 {
   322   nsCOMPtr<nsIDOMDocument> domDoc;    
   323   aWindow->GetDocument(getter_AddRefs(domDoc));
   324   if (!domDoc) return;
   326   nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
   327   nsIPresShell* presShell = doc->GetShell();
   328   if (!presShell) return;
   330   nsCOMPtr<nsIDOMNode> node;
   331   aRange->GetStartContainer(getter_AddRefs(node));
   332   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
   333   nsIFrame* frame = content->GetPrimaryFrame();
   334   if (!frame)
   335       return;
   336   nsCOMPtr<nsISelectionController> selCon;
   337   frame->GetSelectionController(presShell->GetPresContext(),
   338                                 getter_AddRefs(selCon));
   340   // since the match could be an anonymous textnode inside a
   341   // <textarea> or text <input>, we need to get the outer frame
   342   nsITextControlFrame *tcFrame = nullptr;
   343   for ( ; content; content = content->GetParent()) {
   344     if (!IsInNativeAnonymousSubtree(content)) {
   345       nsIFrame* f = content->GetPrimaryFrame();
   346       if (!f)
   347         return;
   348       tcFrame = do_QueryFrame(f);
   349       break;
   350     }
   351   }
   353   nsCOMPtr<nsISelection> selection;
   355   selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
   356   selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
   357     getter_AddRefs(selection));
   358   if (selection) {
   359     selection->RemoveAllRanges();
   360     selection->AddRange(aRange);
   362     nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   363     if (fm) {
   364       if (tcFrame) {
   365         nsCOMPtr<nsIDOMElement> newFocusedElement(do_QueryInterface(content));
   366         fm->SetFocus(newFocusedElement, nsIFocusManager::FLAG_NOSCROLL);
   367       }
   368       else  {
   369         nsCOMPtr<nsIDOMElement> result;
   370         fm->MoveFocus(aWindow, nullptr, nsIFocusManager::MOVEFOCUS_CARET,
   371                       nsIFocusManager::FLAG_NOSCROLL,
   372                       getter_AddRefs(result));
   373       }
   374     }
   376     // Scroll if necessary to make the selection visible:
   377     // Must be the last thing to do - bug 242056
   379     // After ScrollSelectionIntoView(), the pending notifications might be
   380     // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
   381     selCon->ScrollSelectionIntoView
   382       (nsISelectionController::SELECTION_NORMAL,
   383        nsISelectionController::SELECTION_WHOLE_SELECTION,
   384        nsISelectionController::SCROLL_CENTER_VERTICALLY |
   385        nsISelectionController::SCROLL_SYNCHRONOUS);
   386   }
   387 }
   389 // Adapted from nsTextServicesDocument::GetDocumentContentRootNode
   390 nsresult nsWebBrowserFind::GetRootNode(nsIDOMDocument* aDomDoc,
   391                                        nsIDOMNode **aNode)
   392 {
   393   nsresult rv;
   395   NS_ENSURE_ARG_POINTER(aNode);
   396   *aNode = 0;
   398   nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(aDomDoc);
   399   if (htmlDoc)
   400   {
   401     // For HTML documents, the content root node is the body.
   402     nsCOMPtr<nsIDOMHTMLElement> bodyElement;
   403     rv = htmlDoc->GetBody(getter_AddRefs(bodyElement));
   404     NS_ENSURE_SUCCESS(rv, rv);
   405     NS_ENSURE_ARG_POINTER(bodyElement);
   406     return bodyElement->QueryInterface(NS_GET_IID(nsIDOMNode),
   407                                        (void **)aNode);
   408   }
   410   // For non-HTML documents, the content root node will be the doc element.
   411   nsCOMPtr<nsIDOMElement> docElement;
   412   rv = aDomDoc->GetDocumentElement(getter_AddRefs(docElement));
   413   NS_ENSURE_SUCCESS(rv, rv);
   414   NS_ENSURE_ARG_POINTER(docElement);
   415   return docElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode);
   416 }
   418 nsresult nsWebBrowserFind::SetRangeAroundDocument(nsIDOMRange* aSearchRange,
   419                                                   nsIDOMRange* aStartPt,
   420                                                   nsIDOMRange* aEndPt,
   421                                                   nsIDOMDocument* aDoc)
   422 {
   423     nsCOMPtr<nsIDOMNode> bodyNode;
   424     nsresult rv = GetRootNode(aDoc, getter_AddRefs(bodyNode));
   425     nsCOMPtr<nsIContent> bodyContent (do_QueryInterface(bodyNode));
   426     NS_ENSURE_SUCCESS(rv, rv);
   427     NS_ENSURE_ARG_POINTER(bodyContent);
   429     uint32_t childCount = bodyContent->GetChildCount();
   431     aSearchRange->SetStart(bodyNode, 0);
   432     aSearchRange->SetEnd(bodyNode, childCount);
   434     if (mFindBackwards)
   435     {
   436         aStartPt->SetStart(bodyNode, childCount);
   437         aStartPt->SetEnd(bodyNode, childCount);
   438         aEndPt->SetStart(bodyNode, 0);
   439         aEndPt->SetEnd(bodyNode, 0);
   440     }
   441     else
   442     {
   443         aStartPt->SetStart(bodyNode, 0);
   444         aStartPt->SetEnd(bodyNode, 0);
   445         aEndPt->SetStart(bodyNode, childCount);
   446         aEndPt->SetEnd(bodyNode, childCount);
   447     }
   449     return NS_OK;
   450 }
   452 // Set the range to go from the end of the current selection to the
   453 // end of the document (forward), or beginning to beginning (reverse).
   454 // or around the whole document if there's no selection.
   455 nsresult
   456 nsWebBrowserFind::GetSearchLimits(nsIDOMRange* aSearchRange,
   457                                   nsIDOMRange* aStartPt,
   458                                   nsIDOMRange* aEndPt,
   459                                   nsIDOMDocument* aDoc,
   460                                   nsISelection* aSel,
   461                                   bool aWrap)
   462 {
   463     NS_ENSURE_ARG_POINTER(aSel);
   465     // There is a selection.
   466     int32_t count = -1;
   467     nsresult rv = aSel->GetRangeCount(&count);
   468     NS_ENSURE_SUCCESS(rv, rv);
   469     if (count < 1)
   470         return SetRangeAroundDocument(aSearchRange, aStartPt, aEndPt, aDoc);
   472     // Need bodyNode, for the start/end of the document
   473     nsCOMPtr<nsIDOMNode> bodyNode;
   474     rv = GetRootNode(aDoc, getter_AddRefs(bodyNode));
   475     NS_ENSURE_SUCCESS(rv, rv);
   477     nsCOMPtr<nsIContent> bodyContent (do_QueryInterface(bodyNode));
   478     NS_ENSURE_ARG_POINTER(bodyContent);
   480     uint32_t childCount = bodyContent->GetChildCount();
   482     // There are four possible range endpoints we might use:
   483     // DocumentStart, SelectionStart, SelectionEnd, DocumentEnd.
   485     nsCOMPtr<nsIDOMRange> range;
   486     nsCOMPtr<nsIDOMNode> node;
   487     int32_t offset;
   489     // Forward, not wrapping: SelEnd to DocEnd
   490     if (!mFindBackwards && !aWrap)
   491     {
   492         // This isn't quite right, since the selection's ranges aren't
   493         // necessarily in order; but they usually will be.
   494         aSel->GetRangeAt(count-1, getter_AddRefs(range));
   495         if (!range) return NS_ERROR_UNEXPECTED;
   496         range->GetEndContainer(getter_AddRefs(node));
   497         if (!node) return NS_ERROR_UNEXPECTED;
   498         range->GetEndOffset(&offset);
   500         aSearchRange->SetStart(node, offset);
   501         aSearchRange->SetEnd(bodyNode, childCount);
   502         aStartPt->SetStart(node, offset);
   503         aStartPt->SetEnd(node, offset);
   504         aEndPt->SetStart(bodyNode, childCount);
   505         aEndPt->SetEnd(bodyNode, childCount);
   506     }
   507     // Backward, not wrapping: DocStart to SelStart
   508     else if (mFindBackwards && !aWrap)
   509     {
   510         aSel->GetRangeAt(0, getter_AddRefs(range));
   511         if (!range) return NS_ERROR_UNEXPECTED;
   512         range->GetStartContainer(getter_AddRefs(node));
   513         if (!node) return NS_ERROR_UNEXPECTED;
   514         range->GetStartOffset(&offset);
   516         aSearchRange->SetStart(bodyNode, 0);
   517         aSearchRange->SetEnd(bodyNode, childCount);
   518         aStartPt->SetStart(node, offset);
   519         aStartPt->SetEnd(node, offset);
   520         aEndPt->SetStart(bodyNode, 0);
   521         aEndPt->SetEnd(bodyNode, 0);
   522     }
   523     // Forward, wrapping: DocStart to SelEnd
   524     else if (!mFindBackwards && aWrap)
   525     {
   526         aSel->GetRangeAt(count-1, getter_AddRefs(range));
   527         if (!range) return NS_ERROR_UNEXPECTED;
   528         range->GetEndContainer(getter_AddRefs(node));
   529         if (!node) return NS_ERROR_UNEXPECTED;
   530         range->GetEndOffset(&offset);
   532         aSearchRange->SetStart(bodyNode, 0);
   533         aSearchRange->SetEnd(bodyNode, childCount);
   534         aStartPt->SetStart(bodyNode, 0);
   535         aStartPt->SetEnd(bodyNode, 0);
   536         aEndPt->SetStart(node, offset);
   537         aEndPt->SetEnd(node, offset);
   538     }
   539     // Backward, wrapping: SelStart to DocEnd
   540     else if (mFindBackwards && aWrap)
   541     {
   542         aSel->GetRangeAt(0, getter_AddRefs(range));
   543         if (!range) return NS_ERROR_UNEXPECTED;
   544         range->GetStartContainer(getter_AddRefs(node));
   545         if (!node) return NS_ERROR_UNEXPECTED;
   546         range->GetStartOffset(&offset);
   548         aSearchRange->SetStart(bodyNode, 0);
   549         aSearchRange->SetEnd(bodyNode, childCount);
   550         aStartPt->SetStart(bodyNode, childCount);
   551         aStartPt->SetEnd(bodyNode, childCount);
   552         aEndPt->SetStart(node, offset);
   553         aEndPt->SetEnd(node, offset);
   554     }
   555     return NS_OK;
   556 }
   558 /* attribute boolean searchFrames; */
   559 NS_IMETHODIMP nsWebBrowserFind::GetSearchFrames(bool *aSearchFrames)
   560 {
   561     NS_ENSURE_ARG_POINTER(aSearchFrames);
   562     // this only returns true if we are searching both sub and parent
   563     // frames. There is ambiguity if the caller has previously set
   564     // one, but not both of these.
   565     *aSearchFrames = mSearchSubFrames && mSearchParentFrames;
   566     return NS_OK;
   567 }
   569 NS_IMETHODIMP nsWebBrowserFind::SetSearchFrames(bool aSearchFrames)
   570 {
   571     mSearchSubFrames = aSearchFrames;
   572     mSearchParentFrames = aSearchFrames;
   573     return NS_OK;
   574 }
   576 /* attribute nsIDOMWindow currentSearchFrame; */
   577 NS_IMETHODIMP nsWebBrowserFind::GetCurrentSearchFrame(nsIDOMWindow * *aCurrentSearchFrame)
   578 {
   579     NS_ENSURE_ARG_POINTER(aCurrentSearchFrame);
   580     nsCOMPtr<nsIDOMWindow> searchFrame = do_QueryReferent(mCurrentSearchFrame);
   581     NS_IF_ADDREF(*aCurrentSearchFrame = searchFrame);
   582     return (*aCurrentSearchFrame) ? NS_OK : NS_ERROR_NOT_INITIALIZED;
   583 }
   585 NS_IMETHODIMP nsWebBrowserFind::SetCurrentSearchFrame(nsIDOMWindow * aCurrentSearchFrame)
   586 {
   587     // is it ever valid to set this to null?
   588     NS_ENSURE_ARG(aCurrentSearchFrame);
   589     mCurrentSearchFrame = do_GetWeakReference(aCurrentSearchFrame);
   590     return NS_OK;
   591 }
   593 /* attribute nsIDOMWindow rootSearchFrame; */
   594 NS_IMETHODIMP nsWebBrowserFind::GetRootSearchFrame(nsIDOMWindow * *aRootSearchFrame)
   595 {
   596     NS_ENSURE_ARG_POINTER(aRootSearchFrame);
   597     nsCOMPtr<nsIDOMWindow> searchFrame = do_QueryReferent(mRootSearchFrame);
   598     NS_IF_ADDREF(*aRootSearchFrame = searchFrame);
   599     return (*aRootSearchFrame) ? NS_OK : NS_ERROR_NOT_INITIALIZED;
   600 }
   602 NS_IMETHODIMP nsWebBrowserFind::SetRootSearchFrame(nsIDOMWindow * aRootSearchFrame)
   603 {
   604     // is it ever valid to set this to null?
   605     NS_ENSURE_ARG(aRootSearchFrame);
   606     mRootSearchFrame = do_GetWeakReference(aRootSearchFrame);
   607     return NS_OK;
   608 }
   610 /* attribute boolean searchSubframes; */
   611 NS_IMETHODIMP nsWebBrowserFind::GetSearchSubframes(bool *aSearchSubframes)
   612 {
   613     NS_ENSURE_ARG_POINTER(aSearchSubframes);
   614     *aSearchSubframes = mSearchSubFrames;
   615     return NS_OK;
   616 }
   618 NS_IMETHODIMP nsWebBrowserFind::SetSearchSubframes(bool aSearchSubframes)
   619 {
   620     mSearchSubFrames = aSearchSubframes;
   621     return NS_OK;
   622 }
   624 /* attribute boolean searchParentFrames; */
   625 NS_IMETHODIMP nsWebBrowserFind::GetSearchParentFrames(bool *aSearchParentFrames)
   626 {
   627     NS_ENSURE_ARG_POINTER(aSearchParentFrames);
   628     *aSearchParentFrames = mSearchParentFrames;
   629     return NS_OK;
   630 }
   632 NS_IMETHODIMP nsWebBrowserFind::SetSearchParentFrames(bool aSearchParentFrames)
   633 {
   634     mSearchParentFrames = aSearchParentFrames;
   635     return NS_OK;
   636 }
   638 /*
   639     This method handles finding in a single window (aka frame).
   641 */
   642 nsresult nsWebBrowserFind::SearchInFrame(nsIDOMWindow* aWindow,
   643                                          bool aWrapping,
   644                                          bool* aDidFind)
   645 {
   646     NS_ENSURE_ARG(aWindow);
   647     NS_ENSURE_ARG_POINTER(aDidFind);
   649     *aDidFind = false;
   651     nsCOMPtr<nsIDOMDocument> domDoc;    
   652     nsresult rv = aWindow->GetDocument(getter_AddRefs(domDoc));
   653     NS_ENSURE_SUCCESS(rv, rv);
   654     if (!domDoc) return NS_ERROR_FAILURE;
   656     // Do security check, to ensure that the frame we're searching is
   657     // acccessible from the frame where the Find is being run.
   659     // get a uri for the window
   660     nsCOMPtr<nsIDocument> theDoc = do_QueryInterface(domDoc);
   661     if (!theDoc) return NS_ERROR_FAILURE;
   663     nsCOMPtr<nsIScriptSecurityManager> secMan =
   664       do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
   665     NS_ENSURE_SUCCESS(rv, rv);
   667     nsCOMPtr<nsIPrincipal> subject;
   668     rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
   669     NS_ENSURE_SUCCESS(rv, rv);
   671     if (subject) {
   672         bool subsumes;
   673         rv = subject->Subsumes(theDoc->NodePrincipal(), &subsumes);
   674         NS_ENSURE_SUCCESS(rv, rv);
   675         if (!subsumes) {
   676             return NS_ERROR_DOM_PROP_ACCESS_DENIED;
   677         }
   678     }
   680     nsCOMPtr<nsIFind> find = do_CreateInstance(NS_FIND_CONTRACTID, &rv);
   681     NS_ENSURE_SUCCESS(rv, rv);
   683     (void) find->SetCaseSensitive(mMatchCase);
   684     (void) find->SetFindBackwards(mFindBackwards);
   686     // XXX Make and set a line breaker here, once that's implemented.
   687     (void) find->SetWordBreaker(0);
   689     // Now make sure the content (for actual finding) and frame (for
   690     // selection) models are up to date.
   691     theDoc->FlushPendingNotifications(Flush_Frames);
   693     nsCOMPtr<nsISelection> sel;
   694     GetFrameSelection(aWindow, getter_AddRefs(sel));
   695     NS_ENSURE_ARG_POINTER(sel);
   697     nsCOMPtr<nsIDOMRange> searchRange = nsFind::CreateRange(theDoc);
   698     NS_ENSURE_ARG_POINTER(searchRange);
   699     nsCOMPtr<nsIDOMRange> startPt  = nsFind::CreateRange(theDoc);
   700     NS_ENSURE_ARG_POINTER(startPt);
   701     nsCOMPtr<nsIDOMRange> endPt  = nsFind::CreateRange(theDoc);
   702     NS_ENSURE_ARG_POINTER(endPt);
   704     nsCOMPtr<nsIDOMRange> foundRange;
   706     // If !aWrapping, search from selection to end
   707     if (!aWrapping)
   708         rv = GetSearchLimits(searchRange, startPt, endPt, domDoc, sel,
   709                              false);
   711     // If aWrapping, search the part of the starting frame
   712     // up to the point where we left off.
   713     else
   714         rv = GetSearchLimits(searchRange, startPt, endPt, domDoc, sel,
   715                              true);
   717     NS_ENSURE_SUCCESS(rv, rv);
   719     rv =  find->Find(mSearchString.get(), searchRange, startPt, endPt,
   720                      getter_AddRefs(foundRange));
   722     if (NS_SUCCEEDED(rv) && foundRange)
   723     {
   724         *aDidFind = true;
   725         sel->RemoveAllRanges();
   726         // Beware! This may flush notifications via synchronous
   727         // ScrollSelectionIntoView.
   728         SetSelectionAndScroll(aWindow, foundRange);
   729     }
   731     return rv;
   732 }
   735 // called when we start searching a frame that is not the initial
   736 // focussed frame. Prepare the frame to be searched.
   737 // we clear the selection, so that the search starts from the top
   738 // of the frame.
   739 nsresult nsWebBrowserFind::OnStartSearchFrame(nsIDOMWindow *aWindow)
   740 {
   741     return ClearFrameSelection(aWindow);
   742 }
   744 // called when we are done searching a frame and didn't find anything,
   745 // and about about to start searching the next frame.
   746 nsresult nsWebBrowserFind::OnEndSearchFrame(nsIDOMWindow *aWindow)
   747 {
   748     return NS_OK;
   749 }
   751 void
   752 nsWebBrowserFind::GetFrameSelection(nsIDOMWindow* aWindow, 
   753                                     nsISelection** aSel)
   754 {
   755     *aSel = nullptr;
   757     nsCOMPtr<nsIDOMDocument> domDoc;    
   758     aWindow->GetDocument(getter_AddRefs(domDoc));
   759     if (!domDoc) return;
   761     nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
   762     nsIPresShell* presShell = doc->GetShell();
   763     if (!presShell) return;
   765     // text input controls have their independent selection controllers
   766     // that we must use when they have focus.
   767     nsPresContext *presContext = presShell->GetPresContext();
   769     nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aWindow));
   771     nsCOMPtr<nsPIDOMWindow> focusedWindow;
   772     nsCOMPtr<nsIContent> focusedContent =
   773       nsFocusManager::GetFocusedDescendant(window, false, getter_AddRefs(focusedWindow));
   775     nsIFrame *frame = focusedContent ? focusedContent->GetPrimaryFrame() : nullptr;
   777     nsCOMPtr<nsISelectionController> selCon;
   778     if (frame) {
   779         frame->GetSelectionController(presContext, getter_AddRefs(selCon));
   780         selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSel);
   781         if (*aSel) {
   782             int32_t count = -1;
   783             (*aSel)->GetRangeCount(&count);
   784             if (count > 0) {
   785                 return;
   786             }
   787             NS_RELEASE(*aSel);
   788         }
   789     }
   791     selCon = do_QueryInterface(presShell);
   792     selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSel);
   793 }
   795 nsresult nsWebBrowserFind::ClearFrameSelection(nsIDOMWindow *aWindow)
   796 {
   797     NS_ENSURE_ARG(aWindow);
   798     nsCOMPtr<nsISelection> selection;
   799     GetFrameSelection(aWindow, getter_AddRefs(selection));
   800     if (selection)
   801         selection->RemoveAllRanges();
   803     return NS_OK;
   804 }
   806 nsresult nsWebBrowserFind::OnFind(nsIDOMWindow *aFoundWindow)
   807 {
   808     SetCurrentSearchFrame(aFoundWindow);
   810     // We don't want a selection to appear in two frames simultaneously
   811     nsCOMPtr<nsIDOMWindow> lastFocusedWindow = do_QueryReferent(mLastFocusedWindow);
   812     if (lastFocusedWindow && lastFocusedWindow != aFoundWindow)
   813         ClearFrameSelection(lastFocusedWindow);
   815     nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
   816     if (fm) {
   817       // get the containing frame and focus it. For top-level windows,
   818       // the right window should already be focused.
   819       nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(aFoundWindow));
   820       NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
   822       nsCOMPtr<nsIDOMElement> frameElement =
   823         do_QueryInterface(window->GetFrameElementInternal());
   824       if (frameElement)
   825         fm->SetFocus(frameElement, 0);
   827       mLastFocusedWindow = do_GetWeakReference(aFoundWindow);
   828     }
   830     return NS_OK;
   831 }
   833 /*---------------------------------------------------------------------------
   835   GetDocShellFromWindow
   837   Utility method. This will always return nullptr if no docShell
   838   is returned. Oh why isn't there a better way to do this?
   839 ----------------------------------------------------------------------------*/
   840 nsIDocShell *
   841 nsWebBrowserFind::GetDocShellFromWindow(nsIDOMWindow *inWindow)
   842 {
   843     nsCOMPtr<nsPIDOMWindow> window(do_QueryInterface(inWindow));
   844     if (!window) return nullptr;
   846     return window->GetDocShell();
   847 }

mercurial