зеркало из https://github.com/mozilla/gecko-dev.git
Bug 125282 Webpage-JS can steal focus from URLbar / chrome r=enndeakin
This commit is contained in:
Родитель
4bf3154454
Коммит
73f9a129d8
|
@ -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();
|
||||
}
|
Загрузка…
Ссылка в новой задаче