Bug 559993. Scroll the whole selection into view, not just the focus point when finding on a page. r=roc a=blocking-final+
authorTimothy Nikkel <tnikkel@gmail.com>
Wed, 24 Nov 2010 19:35:02 -0600
changeset 58206 015f5aa6ede2db5e8c376255c8686617f1668aaa
parent 58205 c6a2526886f959b6923e93aa5578945140dca1f9
child 58207 0a29ac059eb580261f1b9401161a4c095d0c1bec
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersroc, blocking-final
bugs559993
milestone2.0b8pre
Bug 559993. Scroll the whole selection into view, not just the focus point when finding on a page. r=roc a=blocking-final+
browser/base/content/test/Makefile.in
browser/base/content/test/browser_visibleFindSelection.js
content/base/public/nsISelectionController.idl
embedding/components/find/src/nsWebBrowserFind.cpp
layout/generic/nsSelection.cpp
toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -194,16 +194,17 @@ endif
                  browser_sanitize-timespans.js \
                  browser_sanitizeDialog.js \
                  browser_scope.js \
                  browser_selectTabAtIndex.js \
                  browser_tab_dragdrop2.js \
                  browser_tab_dragdrop2_frame1.xul \
                  browser_tabfocus.js \
                  browser_tabs_owner.js \
+                 browser_visibleFindSelection.js \
                  browser_visibleTabs.js \
                  browser_visibleTabs_contextMenu.js \
                  browser_visibleTabs_bookmarkAllPages.js \
                  browser_visibleTabs_bookmarkAllTabs.js \
                  browser_visibleTabs_tabPreview.js \
                  bug592338.html \
                  discovery.html \
                  domplate_test.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_visibleFindSelection.js
@@ -0,0 +1,39 @@
+
+function test() {
+  waitForExplicitFinish();
+
+  let tab = gBrowser.addTab();
+  gBrowser.selectedTab = tab;
+  tab.linkedBrowser.addEventListener("load", function(aEvent) {
+    tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
+
+    ok(true, "Load listener called");
+    waitForFocus(onFocus, content);
+  }, true);
+
+  content.location = "data:text/html,<div style='position: absolute; left: 2200px; background: green; width: 200px; height: 200px;'>div</div><div style='position: absolute; left: 0px; background: red; width: 200px; height: 200px;'><span id='s'>div</span></div>";
+}
+
+function onFocus() {
+  EventUtils.synthesizeKey("f", { accelKey: true });
+  ok(gFindBarInitialized, "find bar is now initialized");
+
+  EventUtils.synthesizeKey("d", {});
+  EventUtils.synthesizeKey("i", {});
+  EventUtils.synthesizeKey("v", {});
+  // finds the div in the green box
+
+  EventUtils.synthesizeKey("g", { accelKey: true });
+  // finds the div in the red box
+
+  var rect = content.document.getElementById("s").getBoundingClientRect();
+  ok(rect.left >= 0, "scroll should include find result");
+
+  // clear the find bar
+  EventUtils.synthesizeKey("a", { accelKey: true });
+  EventUtils.synthesizeKey("VK_DELETE", { });
+
+  gFindBar.close();
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/content/base/public/nsISelectionController.idl
+++ b/content/base/public/nsISelectionController.idl
@@ -62,17 +62,18 @@ interface nsISelectionController : nsISe
    const short SELECTION_IME_CONVERTEDTEXT=16;
    const short SELECTION_IME_SELECTEDCONVERTEDTEXT=32;
    const short SELECTION_ACCESSIBILITY=64; // For accessibility API usage
    const short SELECTION_FIND=128;
    const short NUM_SELECTIONTYPES=9;
 
    const short SELECTION_ANCHOR_REGION = 0;
    const short SELECTION_FOCUS_REGION = 1;
-   const short NUM_SELECTION_REGIONS = 2;
+   const short SELECTION_WHOLE_SELECTION = 2;
+   const short NUM_SELECTION_REGIONS = 3;
 
    const short SELECTION_OFF = 0;
    const short SELECTION_HIDDEN =1;//>HIDDEN displays selection
    const short SELECTION_ON = 2;
    const short SELECTION_DISABLED = 3;
    const short SELECTION_ATTENTION = 4;
 
    /**
--- a/embedding/components/find/src/nsWebBrowserFind.cpp
+++ b/embedding/components/find/src/nsWebBrowserFind.cpp
@@ -446,17 +446,17 @@ void nsWebBrowserFind::SetSelectionAndSc
 
     // Scroll if necessary to make the selection visible:
     // Must be the last thing to do - bug 242056
 
     // After ScrollSelectionIntoView(), the pending notifications might be
     // flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
     selCon->ScrollSelectionIntoView
       (nsISelectionController::SELECTION_NORMAL,
-       nsISelectionController::SELECTION_FOCUS_REGION,
+       nsISelectionController::SELECTION_WHOLE_SELECTION,
        nsISelectionController::SCROLL_SYNCHRONOUS);
   }
 }
 
 // Adapted from nsTextServicesDocument::GetDocumentContentRootNode
 nsresult nsWebBrowserFind::GetRootNode(nsIDOMDocument* aDomDoc,
                                        nsIDOMNode **aNode)
 {
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -193,19 +193,26 @@ public:
   NS_DECL_NSISELECTION
   NS_DECL_NSISELECTION2
   NS_DECL_NSISELECTION3
   NS_DECL_NSISELECTIONPRIVATE
 
   // utility methods for scrolling the selection into view
   nsresult      GetPresContext(nsPresContext **aPresContext);
   nsresult      GetPresShell(nsIPresShell **aPresShell);
-  // Returns the position of the region, and frame that that position is relative
-  // to. The 'position' is a zero-width rectangle.
+  // Returns a rect containing the selection region, and frame that that
+  // position is relative to. For SELECTION_ANCHOR_REGION or
+  // SELECTION_FOCUS_REGION the rect is a zero-width rectangle. For
+  // SELECTION_WHOLE_SELECTION the rect contains both the anchor and focus
+  // region rects.
   nsIFrame*     GetSelectionAnchorGeometry(SelectionRegion aRegion, nsRect *aRect);
+  // Returns the position of the region (SELECTION_ANCHOR_REGION or
+  // SELECTION_FOCUS_REGION only), and frame that that position is relative to.
+  // The 'position' is a zero-width rectangle.
+  nsIFrame*     GetSelectionEndPointGeometry(SelectionRegion aRegion, nsRect *aRect);
 
   nsresult      PostScrollSelectionIntoViewEvent(SelectionRegion aRegion, PRBool aFirstAncestorOnly);
   enum {
     SCROLL_SYNCHRONOUS = 1<<1,
     SCROLL_FIRST_ANCESTOR_ONLY = 1<<2,
     SCROLL_DO_FLUSH = 1<<3
   };
   // aDoFlush only matters if aIsSynchronous is true.  If not, we'll just flush
@@ -5504,16 +5511,62 @@ nsTypedSelection::GetSelectionAnchorGeom
 {
   if (!mFrameSelection)
     return nsnull;  // nothing to do
 
   NS_ENSURE_TRUE(aRect, nsnull);
 
   aRect->SetRect(0, 0, 0, 0);
 
+  switch (aRegion) {
+    case nsISelectionController::SELECTION_ANCHOR_REGION:
+    case nsISelectionController::SELECTION_FOCUS_REGION:
+      return GetSelectionEndPointGeometry(aRegion, aRect);
+      break;
+    case nsISelectionController::SELECTION_WHOLE_SELECTION:
+      break;
+    default:
+      return nsnull;
+  }
+
+  NS_ASSERTION(aRegion == nsISelectionController::SELECTION_WHOLE_SELECTION,
+    "should only be SELECTION_WHOLE_SELECTION here");
+
+  nsRect anchorRect;
+  nsIFrame* anchorFrame = GetSelectionEndPointGeometry(
+    nsISelectionController::SELECTION_ANCHOR_REGION, &anchorRect);
+  if (!anchorFrame)
+    return nsnull;
+
+  nsRect focusRect;
+  nsIFrame* focusFrame = GetSelectionEndPointGeometry(
+    nsISelectionController::SELECTION_FOCUS_REGION, &focusRect);
+  if (!focusFrame)
+    return nsnull;
+
+  NS_ASSERTION(anchorFrame->PresContext() == focusFrame->PresContext(),
+    "points of selection in different documents?");
+  // make focusRect relative to anchorFrame
+  focusRect += focusFrame->GetOffsetTo(anchorFrame);
+
+  aRect->UnionRectIncludeEmpty(anchorRect, focusRect);
+  return anchorFrame;
+}
+
+nsIFrame *
+nsTypedSelection::GetSelectionEndPointGeometry(SelectionRegion aRegion,
+                                               nsRect *aRect)
+{
+  if (!mFrameSelection)
+    return nsnull;  // nothing to do
+
+  NS_ENSURE_TRUE(aRect, nsnull);
+
+  aRect->SetRect(0, 0, 0, 0);
+
   nsINode    *node       = nsnull;
   PRInt32     nodeOffset = 0;
   nsIFrame   *frame      = nsnull;
 
   switch (aRegion) {
     case nsISelectionController::SELECTION_ANCHOR_REGION:
       node       = GetAnchorNode();
       nodeOffset = GetAnchorOffset();
--- a/toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp
+++ b/toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp
@@ -557,17 +557,17 @@ nsTypeAheadFind::FindItNow(nsIPresShell 
       // ATTENTION, or when we MoveFocus() and the selection is not on a
       // link, we'll blur, which will lose the ATTENTION.
       if (selectionController) {
         // Beware! This may flush notifications via synchronous
         // ScrollSelectionIntoView.
         SetSelectionModeAndRepaint(nsISelectionController::SELECTION_ATTENTION);
         selectionController->ScrollSelectionIntoView(
           nsISelectionController::SELECTION_NORMAL, 
-          nsISelectionController::SELECTION_FOCUS_REGION,
+          nsISelectionController::SELECTION_WHOLE_SELECTION,
           nsISelectionController::SCROLL_SYNCHRONOUS);
       }
 
       mCurrentWindow = window;
       *aResult = hasWrapped ? FIND_WRAPPED : FIND_FOUND;
       return NS_OK;
     }