From d74ecdd91a177827cc950f84e55caa0e0ff4e3ca Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Sun, 2 Aug 2009 10:51:17 +0900 Subject: [PATCH] Bug 125282 Webpage-JS can steal focus from URLbar / chrome r=enn, sr=smaug --- browser/base/content/test/Makefile.in | 1 + .../base/content/test/browser_bug125282.js | 77 +++++++++++++++++++ dom/base/nsFocusManager.cpp | 15 +++- 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 browser/base/content/test/browser_bug125282.js diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 14b9ae15d649..a2b2b4758ddb 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -126,6 +126,7 @@ _BROWSER_FILES = \ browser_bug491431.js \ browser_bug304198.js \ browser_drag.js \ + browser_bug125282.js \ $(NULL) ifeq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT))) diff --git a/browser/base/content/test/browser_bug125282.js b/browser/base/content/test/browser_bug125282.js new file mode 100644 index 000000000000..ee3a18055ea5 --- /dev/null +++ b/browser/base/content/test/browser_bug125282.js @@ -0,0 +1,77 @@ +function test() { + waitForExplicitFinish(); + + let fm = Components.classes["@mozilla.org/focus-manager;1"] + .getService(Components.interfaces.nsIFocusManager); + + let tabs = [ gBrowser.mCurrentTab, gBrowser.addTab() ]; + gBrowser.selectedTab = tabs[0]; + + let loadedCount; + + // The first test set is checking the nsIDOMElement.focus can move focus at + // onload event. + let callback = doTest1; + load("data:text/html,"); + + function load(aURI) { + loadedCount = 0; + for (let i = 0; i < tabs.length; i++) { + tabs[i].linkedBrowser.addEventListener("load", onLoad, true); + tabs[i].linkedBrowser.loadURI(aURI); + } + } + + function onLoad() { + if (++loadedCount == tabs.length) { + setTimeout(callback, 10); + } + } + + function doTest1() { + tabs[0].linkedBrowser.removeEventListener("load", onLoad, true); + tabs[1].linkedBrowser.removeEventListener("load", onLoad, true); + + let e = tabs[0].linkedBrowser.contentDocument.activeElement; + is(e.tagName, "INPUT", "the foreground tab's input element is not active"); + is(fm.focusedElement, e, "the input element isn't focused"); + e = tabs[1].linkedBrowser.contentDocument.activeElement; + is(e.tagName, "INPUT", "the background tab's input element is not active"); + isnot(fm.focusedElement, e, "the input element is focused"); + + // The second test set is checking the nsIDOMElement.focus can NOT move + // if an element of chrome has focus. + callback = doTest2; + load("data:text/html,"); + + BrowserSearch.searchBar.focus(); + } + + let canRetry = 10; + + function doTest2() { + if (canRetry-- > 0 && + (tabs[0].linkedBrowser.contentDocument.activeElement.tagName != "INPUT" || + tabs[1].linkedBrowser.contentDocument.activeElement.tagName != "INPUT")) { + setTimeout(doTest2, 10); // retry + return; + } + + tabs[0].linkedBrowser.removeEventListener("load", onLoad, true); + tabs[1].linkedBrowser.removeEventListener("load", onLoad, true); + + let e = tabs[0].linkedBrowser.contentDocument.activeElement; + is(e.tagName, "INPUT", "the foreground tab's input element is not active"); + isnot(fm.focusedElement, e, "the input element is focused"); + e = tabs[1].linkedBrowser.contentDocument.activeElement; + is(e.tagName, "INPUT", "the background tab's input element is not active"); + isnot(fm.focusedElement, e, "the input element is focused"); + + // cleaning-up... + tabs[0].linkedBrowser.loadURI("about:blank"); + gBrowser.selectedTab = tabs[1]; + gBrowser.removeCurrentTab(); + + finish(); + } +} \ No newline at end of file diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 4d8f59ab9f51..e388f99afa3e 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1041,9 +1041,22 @@ nsFocusManager::SetFocusInner(nsIContent* aNewContent, PRInt32 aFlags, PRBool allowFrameSwitch = !(aFlags & FLAG_NOSWITCHFRAME) || IsSameOrAncestor(newWindow, mFocusedWindow); + PRBool canStealFocus = PR_TRUE; + // When an element already has focus but this focus changing isn't by the + // user input, we should check the permission. + if (mFocusedContent && !(aFlags & (FLAG_BYMOUSE | FLAG_BYKEY))) { + nsCOMPtr currentFocusedNode = + do_QueryInterface(mFocusedContent); + // If the caller cannot access the current focused node, the caller should + // not be able to steal focus from it. E.g., When the current focused node + // is in chrome, any web contents should not be able to steal the focus. + canStealFocus = nsContentUtils::CanCallerAccess(currentFocusedNode); + } + // if the element is in the active window, frame switching is allowed and // the content is in a visible window, fire blur and focus events. - if (isElementInActiveWindow && allowFrameSwitch && IsWindowVisible(newWindow)) { + if (isElementInActiveWindow && allowFrameSwitch && + IsWindowVisible(newWindow) && canStealFocus) { // return if blurring fails or the focus changes during the blur if (mFocusedWindow) { // if the focus is being moved to another element in the same document,