Bug 695935 - Make document.mozRequestFullScreen() asynchronous. r=bz

This commit is contained in:
Chris Pearce 2011-11-05 08:05:16 +13:00
Родитель b64e5ed638
Коммит cd58c1d983
10 изменённых файлов: 168 добавлений и 95 удалений

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

@ -745,10 +745,10 @@ public:
virtual Element* GetFullScreenElement() = 0;
/**
* Requests that the document make aElement the full-screen element,
* and move into full-screen mode.
* Asynchronously requests that the document make aElement the full-screen
* element, and move into full-screen mode.
*/
virtual void RequestFullScreen(Element* aElement) = 0;
virtual void AsyncRequestFullScreen(Element* aElement) = 0;
/**
* Requests that the document, and all documents in its hierarchy exit

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

@ -8557,18 +8557,53 @@ GetRootDocument(nsIDocument* aDoc)
return doc;
}
void
nsDocument::RequestFullScreen(Element* aElement)
class nsCallRequestFullScreen : public nsRunnable
{
if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) {
if (aElement) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(aElement,
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
e->PostDOMEvent();
}
public:
nsCallRequestFullScreen(Element* aElement)
: mElement(aElement),
mDoc(aElement->OwnerDoc()),
mWasCallerChrome(nsContentUtils::IsCallerChrome())
{
}
NS_IMETHOD Run()
{
nsDocument* doc = static_cast<nsDocument*>(mDoc.get());
doc->RequestFullScreen(mElement, mWasCallerChrome);
return NS_OK;
}
nsRefPtr<Element> mElement;
nsCOMPtr<nsIDocument> mDoc;
bool mWasCallerChrome;
};
void
nsDocument::AsyncRequestFullScreen(Element* aElement)
{
if (!aElement) {
return;
}
// Request full-screen asynchronously.
nsCOMPtr<nsIRunnable> event(new nsCallRequestFullScreen(aElement));
NS_DispatchToCurrentThread(event);
}
void
nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
{
if (!aElement ||
!aElement->IsInDoc() ||
aElement->OwnerDoc() != this ||
!IsFullScreenEnabled(aWasCallerChrome) ||
!GetWindow()) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(this,
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
e->PostDOMEvent();
return;
}
@ -8663,20 +8698,25 @@ NS_IMETHODIMP
nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
{
NS_ENSURE_ARG_POINTER(aFullScreen);
*aFullScreen = false;
*aFullScreen = IsFullScreenEnabled(nsContentUtils::IsCallerChrome());
return NS_OK;
}
if (nsContentUtils::IsCallerChrome() &&
nsContentUtils::IsFullScreenApiEnabled()) {
bool
nsDocument::IsFullScreenEnabled(bool aCallerIsChrome)
{
if (nsContentUtils::IsFullScreenApiEnabled() && aCallerIsChrome) {
// Chrome code can always use the full-screen API, provided it's not
// explicitly disabled.
*aFullScreen = true;
return NS_OK;
// explicitly disabled. Note IsCallerChrome() returns true when running
// in an nsRunnable, so don't use GetMozFullScreenEnabled() from an
// nsRunnable!
return true;
}
if (!nsContentUtils::IsFullScreenApiEnabled() ||
nsContentUtils::HasPluginWithUncontrolledEventDispatch(this) ||
!IsVisible()) {
return NS_OK;
return false;
}
// Ensure that all ancestor <iframe> elements have the mozallowfullscreen
@ -8689,13 +8729,12 @@ nsDocument::GetMozFullScreenEnabled(bool *aFullScreen)
// The node requesting fullscreen, or one of its crossdoc ancestors,
// is an iframe which doesn't have the "mozalllowfullscreen" attribute.
// This request is not authorized by the parent document.
return NS_OK;
return false;
}
node = nsContentUtils::GetCrossDocParentNode(node);
} while (node);
*aFullScreen = true;
return NS_OK;
return true;
}
PRInt64

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

@ -952,10 +952,16 @@ public:
virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
virtual Element* GetFullScreenElement();
virtual void RequestFullScreen(Element* aElement);
virtual void AsyncRequestFullScreen(Element* aElement);
virtual void CancelFullScreen();
virtual bool IsFullScreenDoc();
// This is called asynchronously by nsIDocument::AsyncRequestFullScreen()
// to move document into full-screen mode if allowed. aWasCallerChrome
// should be true when nsIDocument::AsyncRequestFullScreen() was called
// by chrome code.
void RequestFullScreen(Element* aElement, bool aWasCallerChrome);
// Returns true if making this change results in a change in the full-screen
// state of this document.
bool SetFullScreenState(Element* aElement, bool aIsFullScreen);
@ -969,6 +975,13 @@ public:
protected:
friend class nsNodeUtils;
// Returns true if a request for DOM full-screen is currently enabled in
// this document. This returns true if there are no windowed plugins in this
// doc tree, and if the document is visible, and if the api is not
// disabled by pref. aIsCallerChrome must contain the return value of
// nsContentUtils::IsCallerChrome() from the context we're checking.
bool IsFullScreenEnabled(bool aIsCallerChrome);
/**
* Check that aId is not empty and log a message to the console
* service if it is.

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

@ -3404,11 +3404,9 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
// This stops the full-screen from being abused similar to the popups of old,
// and it also makes it harder for bad guys' script to go full-screen and
// spoof the browser chrome/window and phish logins etc.
nsIDocument* doc = OwnerDoc();
if (!nsContentUtils::IsRequestFullScreenAllowed() ||
!IsInDoc()) {
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(this,
new nsPLDOMEvent(OwnerDoc(),
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
@ -3416,27 +3414,8 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
return NS_OK;
}
nsCOMPtr<nsIDOMDocument> domDocument(do_QueryInterface(doc));
NS_ENSURE_STATE(domDocument);
bool fullScreenEnabled;
domDocument->GetMozFullScreenEnabled(&fullScreenEnabled);
if (!fullScreenEnabled) {
nsRefPtr<nsPLDOMEvent> e =
new nsPLDOMEvent(this,
NS_LITERAL_STRING("mozfullscreenerror"),
true,
false);
e->PostDOMEvent();
return NS_OK;
}
OwnerDoc()->AsyncRequestFullScreen(this);
doc->RequestFullScreen(this);
#ifdef DEBUG
bool fullscreen;
domDocument->GetMozFullScreen(&fullscreen);
NS_ASSERTION(fullscreen, "Document should report fullscreen");
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");
#endif
return NS_OK;
}

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

@ -283,6 +283,7 @@ _TEST_FILES = \
test_fullscreen-api.html \
file_fullscreen-plugins.html \
file_fullscreen-denied.html \
file_fullscreen-denied-inner.html \
file_fullscreen-hidden.html \
file_fullscreen-navigation.html \
test_li_attributes_reflection.html \

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

@ -94,15 +94,19 @@ function testNextKey() {
if (!document.mozFullScreen) {
document.body.mozRequestFullScreen();
}
ok(document.mozFullScreen, "Must be in full-screen mode");
// mozRequestFullScreen() is async...
setTimeout(
function() {
ok(document.mozFullScreen, "Must be in full-screen mode");
gKeyName = keyList[gKeyTestIndex].code;
gKeyCode = KeyEvent["DOM_" + gKeyName];
gKeySuppressed = keyList[gKeyTestIndex].suppressed;
gKeyTestIndex++;
gKeyName = keyList[gKeyTestIndex].code;
gKeyCode = KeyEvent["DOM_" + gKeyName];
gKeySuppressed = keyList[gKeyTestIndex].suppressed;
gKeyTestIndex++;
testScriptInitiatedKeyEvents();
testTrustedKeyEvents();
testScriptInitiatedKeyEvents();
testTrustedKeyEvents();
}, 0);
}
window.addEventListener("keydown", keyHandler, true);

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

@ -98,18 +98,23 @@ function fullScreenChange(event) {
"Full-screen element should be iframe element.");
var fse = fullScreenElement();
fse.mozRequestFullScreen();
ok(document.mozFullScreen, "Should still be full-screen mode after re-requesting.");
is(document.mozFullScreenElement, fse, "Full-screen element should have switched to requestee.");
var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
_innerFrame.contentDocument.body.appendChild(fse);
ok(!document.mozFullScreen, "Should exit full-screen after transplanting FSE");
is(document.mozFullScreenElement, null, "Full-screen element transplanted, should be null.");
is(iframe.contentDocument.mozFullScreenElement, null, "Full-screen element in outer frame should be null.");
is(_innerFrame.contentDocument.mozFullScreenElement, null, "Full-screen element in inner frame should be null.");
ok(!iframe.contentDocument.mozFullScreen, "Outer frame should not acquire full-screen status.");
ok(!_innerFrame.contentDocument.mozFullScreen, "Inner frame should not acquire full-screen status.");
document.body.appendChild(fse);
setTimeout(
function() {
ok(document.mozFullScreen, "Should still be full-screen mode after re-requesting.");
is(document.mozFullScreenElement, fse, "Full-screen element should have switched to requestee.");
var _innerFrame = iframe.contentDocument.getElementById("inner-frame");
_innerFrame.contentDocument.body.appendChild(fse);
ok(!document.mozFullScreen, "Should exit full-screen after transplanting FSE");
is(document.mozFullScreenElement, null, "Full-screen element transplanted, should be null.");
is(iframe.contentDocument.mozFullScreenElement, null, "Full-screen element in outer frame should be null.");
is(_innerFrame.contentDocument.mozFullScreenElement, null, "Full-screen element in inner frame should be null.");
ok(!iframe.contentDocument.mozFullScreen, "Outer frame should not acquire full-screen status.");
ok(!_innerFrame.contentDocument.mozFullScreen, "Inner frame should not acquire full-screen status.");
document.body.appendChild(fse);
}, 0);
break;
}
case 3: {
@ -119,17 +124,25 @@ function fullScreenChange(event) {
is(document.mozFullScreenElement, null, "Full-screen element should be null.");
document.body.removeChild(iframe);
iframe = null;
outOfDocElement = document.createElement("div");
outOfDocElement.mozRequestFullScreen();
ok(!document.mozFullScreen, "Requests for full-screen from not-in-doc elements should fail.");
container = document.createElement("div");
inDocElement = document.createElement("div");
container.appendChild(inDocElement);
fullScreenElement().appendChild(container);
inDocElement.mozRequestFullScreen();
ok(document.mozFullScreen, "Should grant request to return to full-screen mode (third time)");
// Do a request out of document. It should be denied.
// Continue test in the following mozfullscreenerror handler.
outOfDocElement = document.createElement("div");
var f =
function(e) {
document.removeEventListener("mozfullscreenerror", f, false);
ok(!document.mozFullScreen, "Requests for full-screen from not-in-doc elements should fail.");
container = document.createElement("div");
inDocElement = document.createElement("div");
container.appendChild(inDocElement);
fullScreenElement().appendChild(container);
inDocElement.mozRequestFullScreen();
};
document.addEventListener("mozfullscreenerror", f, false);
outOfDocElement.mozRequestFullScreen();
break;
}
case 4: {
@ -157,11 +170,11 @@ function fullScreenChange(event) {
setRequireTrustedContext(true);
fullscreendenied = false;
fullScreenElement().mozRequestFullScreen();
ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
setTimeout(
function() {
ok(fullscreendenied, "Request for fullscreen should have been denied because calling context isn't trusted");
ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
button = document.createElement("button");
button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
fullScreenElement().appendChild(button);

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

@ -0,0 +1,22 @@
<html>
<body onload='foo();'>
<script>
function foo() {
document.addEventListener('mozfullscreenerror',
function() {
parent.ok(true, "Request from an iframe without mozallowfullscreen should be denied");
parent.finish();
},
false);
document.addEventListener('mozfullscreenchange',
function() {
parent.ok(false, "Request from an iframe without mozallowfullscreen should be denied, but was granted!");
parent.finish();
},
false);
parent.is(document.mozFullScreenEnabled, false, "Full-screen should not be enabled, coz mozallowfullscreen isn't present.");
document.body.mozRequestFullScreen();
}
</script>
</body>
</html>

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

@ -29,14 +29,6 @@ function is(a, b, msg) {
opener.is(a, b, msg);
}
/*
<html>
<body onload='document.body.mozRequestFullScreen();'>
</body>
</html>
*/
var requestFullScreenContents = "data:text/html;charset=utf-8,<html>%0D%0A <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A <%2Fbody>%0D%0A<%2Fhtml>";
var fullscreendenied = false;
document.addEventListener("mozfullscreenerror", function(){fullscreendenied=true;}, false);
@ -54,8 +46,8 @@ function run() {
// Request full-screen from a non trusted context (this script isn't a user
// generated event!).
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
document.body.mozRequestFullScreen();
fullscreendenied = false;
document.body.mozRequestFullScreen();
setTimeout(
function() {
ok(!document.mozFullScreen, "Should not grant request in non-truested context");
@ -87,21 +79,20 @@ function keyHandler(event) {
// to write.
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
// Create an iframe without a mozallowfullscreen sttribute, whose contents requests
// Create an iframe without a mozallowfullscreen attribute, whose contents requests
// full-screen. The request should be denied, and we should not receive a fullscreenchange
// event in this document.
var iframe = document.createElement("iframe");
iframe.src = requestFullScreenContents;
iframe.src = "file_fullscreen-denied-inner.html";
document.body.appendChild(iframe);
setTimeout(
function() {
ok(!gotFullScreenChange, "Should not ever grant a fullscreen request in this doc.");
opener.nextTest();
}, 0);
}, 0);
}
function finish() {
ok(!gotFullScreenChange, "Should not ever grant a fullscreen request in this doc.");
opener.nextTest();
}
</script>
</pre>
<div id="full-screen-element"></div>

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

@ -74,15 +74,26 @@ function startTest() {
// Running on MacOS, all plugins are effectively windowless, request for full-screen should be granted.
// Continue test in the (mac-specific) "mozfullscreenchange" handler.
return;
} else {
// Non-MacOS, request should be denied, carry on the test after receiving error event.
document.addEventListener("mozfullscreenerror", nonMacTest, false);
}
}
function nonMacTest() {
document.removeEventListener("mozfullscreenerror", nonMacTest, false);
ok(!document.mozFullScreen, "Request for full-screen from a document containing windowed plugin should be denied.");
// Remove plugin in this document. Should still be a windowed plugin in sub-document.
windowedPlugin = document.getElementById("windowed-plugin");
windowedPlugin.parentNode.removeChild(windowedPlugin);
document.addEventListener("mozfullscreenerror", nonMacTest2, false);
document.body.mozRequestFullScreen();
}
function nonMacTest2() {
document.removeEventListener("mozfullscreenerror", nonMacTest2, false);
ok(!document.mozFullScreen, "Request for full-screen from a document with subdocument containing windowed plugin should be denied.");
// Remove subdoc which contains windowed plugin, request full-screen, request should be granted.
// Continue test in "mozfullscreenchange" handler.