Bug 617872 - Focus manager allows F6 to focus elements inside non-focusable iframes/browsers. r=smaug, a=blocking
authorNeil Deakin <enndeakin@gmail.com>
Thu, 09 Dec 2010 13:20:00 -0800
changeset 60230 310cfcff5588ff5abc2d09ada42f8a084511530a
parent 60229 5e8b96f85355488871c18597d38635801dc2f8c8
child 60231 906f834203ffaae888029972aa28fbfc0c839f54
push idunknown
push userunknown
push dateunknown
reviewerssmaug, blocking
bugs617872
milestone2.0b9pre
Bug 617872 - Focus manager allows F6 to focus elements inside non-focusable iframes/browsers. r=smaug, a=blocking
browser/base/content/test/browser_tabfocus.js
dom/base/nsFocusManager.cpp
--- a/browser/base/content/test/browser_tabfocus.js
+++ b/browser/base/content/test/browser_tabfocus.js
@@ -118,16 +118,32 @@ function test() {
                      window, null, true,
                      "focusedWindow after switch to chrome with no focused element");
 
     // switch focus to another tab when neither have an active focus
     expectFocusShift(function () gBrowser.selectedTab = tab1,
                      browser1.contentWindow, null, true,
                      "focusedWindow after tab switch from no focus to no focus");
 
+    gURLBar.focus();
+    _browser_tabfocus_test_events = "";
+    _browser_tabfocus_test_lastfocus = gURLBar;
+    _browser_tabfocus_test_lastfocuswindow = window;
+
+    expectFocusShift(function () EventUtils.synthesizeKey("VK_F6", { }),
+                     browser1.contentWindow, browser1.contentDocument.documentElement,
+                     true, "switch document forward with f6");
+    EventUtils.synthesizeKey("VK_F6", { });
+    is(fm.focusedWindow, window, "switch document forward again with f6");
+
+    browser1.style.MozUserFocus = "ignore";
+    browser1.clientWidth;
+    EventUtils.synthesizeKey("VK_F6", { });
+    is(fm.focusedWindow, window, "switch document forward again with f6 when browser non-focusable");
+
     window.addEventListener("focus", _browser_tabfocus_test_eventOccured, true);
     window.addEventListener("blur", _browser_tabfocus_test_eventOccured, true);
 
     // next, check whether navigating forward, focusing the urlbar and then
     // navigating back maintains the focus in the urlbar.
     browser1.addEventListener("pageshow", _browser_tabfocus_navigation_test_eventOccured, true);
     button1.focus();
     browser1.contentWindow.location = testPage3;
@@ -202,17 +218,17 @@ function expectFocusShift(callback, expe
     if (expectedWindow && _browser_tabfocus_test_lastfocuswindow != expectedWindow) {
       if (expectedEvents)
         expectedEvents += " ";
       var windowid = expectedWindow.document.documentElement.id;
       expectedEvents += "focus: " + windowid + "-document " +
                         "focus: " + windowid + "-window";
     }
 
-    if (expectedElement) {
+    if (expectedElement && expectedElement != expectedElement.ownerDocument.documentElement) {
       if (expectedEvents)
         expectedEvents += " ";
       expectedEvents += "focus: " + getId(expectedElement);
     }
 
     _browser_tabfocus_test_lastfocus = expectedElement;
     _browser_tabfocus_test_lastfocuswindow = expectedWindow;
   }
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2873,18 +2873,25 @@ nsFocusManager::GetRootForFocus(nsPIDOMW
                                 PRBool aIsForDocNavigation,
                                 PRBool aCheckVisibility)
 {
   // the root element's canvas may be focused as long as the document is in a
   // a non-chrome shell and does not contain a frameset.
   if (aIsForDocNavigation) {
     nsCOMPtr<nsIContent> docContent =
       do_QueryInterface(aWindow->GetFrameElementInternal());
-    if (docContent && docContent->Tag() == nsGkAtoms::iframe)
-      return nsnull;
+    // document navigation skips iframes and frames that are specifically non-focusable
+    if (docContent) {
+      if (docContent->Tag() == nsGkAtoms::iframe)
+        return nsnull;
+
+      nsIFrame* frame = docContent->GetPrimaryFrame();
+      if (!frame || !frame->IsFocusable(nsnull, 0))
+        return nsnull;
+    }
   }
   else  {
     PRInt32 itemType;
     nsCOMPtr<nsIDocShellTreeItem> shellItem = do_QueryInterface(aWindow->GetDocShell());
     shellItem->GetItemType(&itemType);
 
     if (itemType == nsIDocShellTreeItem::typeChrome)
       return nsnull;