Bug 125282 Webpage-JS can steal focus from URLbar / chrome r=enndeakin

This commit is contained in:
Masayuki Nakano 2009-12-12 14:17:40 +09:00
Родитель 4bf3154454
Коммит 73f9a129d8
7 изменённых файлов: 264 добавлений и 8 удалений

Просмотреть файл

@ -20,4 +20,7 @@ function test()
var dt = EventUtils.synthesizeDragStart(proxyicon, expected);
is(dt, null, "drag on proxy icon");
proxyicon.setAttribute("pageproxystate", oldstate);
// Now, the identity information panel is opened by the proxy icon click.
// We need to close it for next tests.
EventUtils.synthesizeKey("VK_ESCAPE", {}, window);
}

Просмотреть файл

@ -16,6 +16,13 @@ function nextRightElement() elementFromPoint(right(scrollbox) + 1);
function test() {
waitForExplicitFinish();
// If the previous (or more) test finished with cleaning up the tabs,
// there may be some pending animations. That can cause a failure of
// this tests, so, we should test this in another stack.
setTimeout(doTest, 0);
}
function doTest() {
tabstrip.smoothScroll = false;
var tabMinWidth = gPrefService.getIntPref("browser.tabs.tabMinWidth");

Просмотреть файл

@ -1075,7 +1075,24 @@ nsFocusManager::SetFocusInner(nsIContent* aNewContent, PRInt32 aFlags,
// 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)) {
PRBool sendFocusEvent =
isElementInActiveWindow && allowFrameSwitch && IsWindowVisible(newWindow);
// When the following conditions are true:
// * an element has focus
// * isn't called by trusted event (i.e., called by untrusted event or by js)
// * the focus is moved to another document's element
// we need to check the permission.
if (sendFocusEvent && mFocusedContent &&
mFocusedContent->GetOwnerDoc() != aNewContent->GetOwnerDoc()) {
// 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.
nsCOMPtr<nsIDOMNode> domNode(do_QueryInterface(mFocusedContent));
sendFocusEvent = nsContentUtils::CanCallerAccess(domNode);
}
if (sendFocusEvent) {
// 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,
@ -1109,10 +1126,10 @@ nsFocusManager::SetFocusInner(nsIContent* aNewContent, PRInt32 aFlags,
aFocusChanged, PR_FALSE);
}
else {
// otherwise, for inactive windows, update the node in the window, and
// raise the window if desired.
// otherwise, for inactive windows and when the caller cannot steal the
// focus, update the node in the window, and raise the window if desired.
if (allowFrameSwitch)
AdjustWindowFocus(newWindow);
AdjustWindowFocus(newWindow, PR_TRUE);
// set the focus node and method as needed
PRUint32 focusMethod = aFocusChanged ? aFlags & FOCUSMETHOD_MASK :
@ -1201,7 +1218,8 @@ nsFocusManager::GetCommonAncestor(nsPIDOMWindow* aWindow1,
}
void
nsFocusManager::AdjustWindowFocus(nsPIDOMWindow* aWindow)
nsFocusManager::AdjustWindowFocus(nsPIDOMWindow* aWindow,
PRBool aCheckPermission)
{
PRBool isVisible = IsWindowVisible(aWindow);
@ -1227,6 +1245,12 @@ nsFocusManager::AdjustWindowFocus(nsPIDOMWindow* aWindow)
if (IsWindowVisible(window) != isVisible)
break;
// When aCheckPermission is true, we should check whether the caller can
// access the window or not. If it cannot access, we should stop the
// adjusting.
if (aCheckPermission && !nsContentUtils::CanCallerAccess(window))
break;
window->SetFocusedNode(frameContent);
}
}
@ -1528,7 +1552,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
// focus can be traversed from the top level down to the newly focused
// window.
if (aIsNewDocument)
AdjustWindowFocus(aWindow);
AdjustWindowFocus(aWindow, PR_FALSE);
// indicate that the window has taken focus.
if (aWindow->TakeFocus(PR_TRUE, focusMethod))

Просмотреть файл

@ -150,7 +150,7 @@ protected:
* the active top-level window and navigate down the currently focused
* elements for each frame in the tree to get to aNewWindow.
*/
void AdjustWindowFocus(nsPIDOMWindow* aNewWindow);
void AdjustWindowFocus(nsPIDOMWindow* aNewWindow, PRBool aCheckPermission);
/**
* Returns true if aWindow is visible.

Просмотреть файл

@ -44,7 +44,9 @@ include $(DEPTH)/config/autoconf.mk
MODULE = test_dom
DIRS += mochitest
DIRS += mochitest \
browser \
$(NULL)
XPCSHELL_TESTS = unit
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,51 @@
#
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
relativesrcdir = dom/tests/browser
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_focus_steal_from_chrome.js \
libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

Просмотреть файл

@ -0,0 +1,169 @@
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 testingList = [
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><input id='target'></body>",
tagName: "INPUT", methodName: "focus" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').select(); }, 10);\"><input id='target'></body>",
tagName: "INPUT", methodName: "select" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><a href='about:blank' id='target'>anchor</a></body>",
tagName: "A", methodName: "focus" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><button id='target'>button</button></body>",
tagName: "BUTTON", methodName: "focus" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><select id='target'><option>item1</option></select></body>",
tagName: "SELECT", methodName: "focus" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><textarea id='target'>textarea</textarea></body>",
tagName: "TEXTAREA", methodName: "focus" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').select(); }, 10);\"><textarea id='target'>textarea</textarea></body>",
tagName: "TEXTAREA", methodName: "select" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><label id='target'><input></label></body>",
tagName: "INPUT", methodName: "focus of label element" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () { document.getElementById('target').focus(); }, 10);\"><fieldset><legend id='target'>legend</legend><input></fieldset></body>",
tagName: "INPUT", methodName: "focus of legend element" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () {" +
" var element = document.getElementById('target');" +
" var event = document.createEvent('MouseEvent');" +
" event.initMouseEvent('mousedown', true, true, window," +
" 0, 0, 0, 0, 0, false, false, false, false, 0, element);" +
" element.dispatchEvent(event); }, 10);\">" +
"<button id='target'>button</button></body>",
tagName: "BUTTON", methodName: "mousedown event on the button element" },
{ uri: "data:text/html,<body onload=\"setTimeout(function () {" +
" var element = document.getElementById('target');" +
" var event = document.createEvent('MouseEvent');" +
" event.initMouseEvent('click', true, true, window," +
" 1, 0, 0, 0, 0, false, false, false, false, 0, element);" +
" element.dispatchEvent(event); }, 10);\">" +
"<label id='target'><input></label></body>",
tagName: "INPUT", methodName: "click event on the label element" },
];
let testingIndex = -1;
let canRetry;
let callback;
let loadedCount;
function runNextTest() {
if (++testingIndex >= testingList.length) {
// cleaning-up...
let cleanTab = gBrowser.addTab();
gBrowser.selectedTab = cleanTab;
for (let i = 0; i < tabs.length; i++) {
gBrowser.removeTab(tabs[i]);
}
finish();
return;
}
callback = doTest1;
loadTestPage();
}
function loadTestPage() {
loadedCount = 0;
canRetry = 10;
// Set the focus to the contents.
tabs[0].linkedBrowser.focus();
for (let i = 0; i < tabs.length; i++) {
tabs[i].linkedBrowser.addEventListener("load", onLoad, true);
tabs[i].linkedBrowser.loadURI(testingList[testingIndex].uri);
}
}
function onLoad() {
if (++loadedCount == tabs.length) {
for (let i = 0; i < tabs.length; i++) {
tabs[i].linkedBrowser.removeEventListener("load", onLoad, true);
}
setTimeout(callback, 20);
}
}
function isPrepared() {
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].linkedBrowser.contentDocument.activeElement.tagName !=
testingList[testingIndex].tagName) {
return false;
}
}
return true;
}
function doTest1() {
if (canRetry-- > 0 && !isPrepared()) {
setTimeout(callback, 10); // retry
return;
}
// The contents should be able to steal the focus from content.
// in foreground tab
let e = tabs[0].linkedBrowser.contentDocument.activeElement;
is(e.tagName, testingList[testingIndex].tagName,
"the foreground tab's " + testingList[testingIndex].tagName +
" element is not active by the " + testingList[testingIndex].methodName +
" (Test1: content can steal focus)");
is(fm.focusedElement, e,
"the " + testingList[testingIndex].tagName +
" element isn't focused by the " + testingList[testingIndex].methodName +
" (Test1: content can steal focus)");
// in background tab
e = tabs[1].linkedBrowser.contentDocument.activeElement;
is(e.tagName, testingList[testingIndex].tagName,
"the background tab's " + testingList[testingIndex].tagName +
" element is not active by the " + testingList[testingIndex].methodName +
" (Test1: content can steal focus)");
isnot(fm.focusedElement, e,
"the " + testingList[testingIndex].tagName +
" element is focused by the " + testingList[testingIndex].methodName +
" (Test1: content can steal focus)");
callback = doTest2;
loadTestPage();
// Set focus to chrome element before onload events of the loading contents.
BrowserSearch.searchBar.focus();
}
function doTest2() {
if (canRetry-- > 0 && !isPrepared()) {
setTimeout(callback, 10); // retry
return;
}
// The contents shouldn't be able to steal the focus from chrome.
// in foreground tab
let e = tabs[0].linkedBrowser.contentDocument.activeElement;
is(e.tagName, testingList[testingIndex].tagName,
"the foreground tab's " + testingList[testingIndex].tagName +
" element is not active by the " + testingList[testingIndex].methodName +
" (Test2: content can NOT steal focus)");
isnot(fm.focusedElement, e,
"the " + testingList[testingIndex].tagName +
" element is focused by the " + testingList[testingIndex].methodName +
" (Test2: content can NOT steal focus)");
// in background tab
e = tabs[1].linkedBrowser.contentDocument.activeElement;
is(e.tagName, testingList[testingIndex].tagName,
"the background tab's " + testingList[testingIndex].tagName +
" element is not active by the " + testingList[testingIndex].methodName +
" (Test2: content can NOT steal focus)");
isnot(fm.focusedElement, e,
"the " + testingList[testingIndex].tagName +
" element is focused by the " + testingList[testingIndex].methodName +
" (Test2: content can NOT steal focus)");
runNextTest();
}
runNextTest();
}