Bug 685779 - Add -moz-full-screen-ancestor pseudo class. r=bz

This commit is contained in:
Chris Pearce 2011-11-01 18:11:09 +13:00
parent 8afb06de79
commit 427807cc7c
15 changed files with 452 additions and 274 deletions

View File

@ -126,8 +126,8 @@ class Element;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0xb52356d4, 0xe191, 0x4cf8, \
{ 0xb8, 0x58, 0xc0, 0xf1, 0xe1, 0x98, 0x09, 0xdf } }
{ 0xc3e40e8e, 0x8b91, 0x424c, \
{ 0xbe, 0x9c, 0x9c, 0xc1, 0x76, 0xa7, 0xf7, 0x24 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -737,14 +737,10 @@ public:
virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0;
/**
* Resets the current full-screen element to nsnull.
*/
virtual void ResetFullScreenElement() = 0;
/**
* Returns the element which either is the full-screen element, or
* contains the full-screen element if a child of this document contains
* the fullscreen element.
* Returns the element which either requested DOM full-screen mode, or
* contains the element which requested DOM full-screen mode if the
* requestee is in a subdocument. Note this element must be *in*
* this document.
*/
virtual Element* GetFullScreenElement() = 0;
@ -760,14 +756,6 @@ public:
*/
virtual void CancelFullScreen() = 0;
/**
* Updates the full-screen status on this document, setting the full-screen
* mode to aIsFullScreen. This doesn't affect the window's full-screen mode,
* this updates the document's internal state which determines whether the
* document reports as being in full-screen mode.
*/
virtual void UpdateFullScreenStatus(bool aIsFullScreen) = 0;
/**
* Returns true if this document is in full-screen mode.
*/

View File

@ -214,6 +214,7 @@ using namespace mozilla::dom;
typedef nsTArray<Link*> LinkArray;
nsWeakPtr nsDocument::sFullScreenDoc = nsnull;
#ifdef PR_LOGGING
static PRLogModuleInfo* gDocumentLeakPRLog;
@ -6011,7 +6012,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
// Scope firing mutation events so that we don't carry any state that
// might be stale
{
@ -8358,39 +8359,12 @@ nsIDocument::SizeOf() const
return size;
}
// Returns the root document in a document hierarchy.
static nsIDocument*
GetRootDocument(nsIDocument* aDoc)
{
if (!aDoc) {
return nsnull;
}
nsCOMPtr<nsIPresShell> shell = aDoc->GetShell();
if (!shell) {
return nsnull;
}
nsPresContext* ctx = shell->GetPresContext();
if (!ctx) {
return nsnull;
}
nsRootPresContext* rpc = ctx->GetRootPresContext();
if (!rpc) {
return nsnull;
}
return rpc->Document();
}
class nsDispatchFullScreenChange : public nsRunnable
{
public:
nsDispatchFullScreenChange(nsIDocument *aDoc)
: mDoc(aDoc)
{
mTarget = aDoc->GetFullScreenElement();
if (!mTarget) {
mTarget = aDoc;
}
}
nsDispatchFullScreenChange(nsIDocument *aDoc, nsINode* aElement)
: mDoc(aDoc),
mTarget(aElement ? aElement : aDoc) {}
NS_IMETHOD Run()
{
@ -8406,63 +8380,41 @@ public:
nsCOMPtr<nsISupports> mTarget;
};
void
nsDocument::UpdateFullScreenStatus(bool aIsFullScreen)
static void DispatchFullScreenChange(nsIDocument* aDocument, Element* aElement)
{
if (mIsFullScreen != aIsFullScreen) {
nsCOMPtr<nsIRunnable> event(new nsDispatchFullScreenChange(this));
NS_DispatchToCurrentThread(event);
}
mIsFullScreen = aIsFullScreen;
if (!mIsFullScreen) {
// Full-screen is being turned off. Reset the full-screen element, to
// save us from having to traverse the document hierarchy again in
// MozCancelFullScreen().
ResetFullScreenElement();
}
nsCOMPtr<nsIRunnable> event(
new nsDispatchFullScreenChange(aDocument, aElement));
NS_DispatchToCurrentThread(event);
}
static bool
UpdateFullScreenStatus(nsIDocument* aDocument, void* aData)
{
aDocument->UpdateFullScreenStatus(*static_cast<bool*>(aData));
aDocument->EnumerateSubDocuments(UpdateFullScreenStatus, aData);
return true;
}
static void
UpdateFullScreenStatusInDocTree(nsIDocument* aDoc, bool aIsFullScreen)
{
nsIDocument* root = GetRootDocument(aDoc);
if (root) {
UpdateFullScreenStatus(root, static_cast<void*>(&aIsFullScreen));
}
}
void
nsDocument::ResetFullScreenElement()
bool
nsDocument::SetFullScreenState(Element* aElement, bool aIsFullScreen)
{
if (mFullScreenElement) {
// Reset the ancestor and full-screen styles on the outgoing full-screen
// element in the current document.
nsEventStateManager::SetFullScreenState(mFullScreenElement, false);
mFullScreenElement = nsnull;
}
mFullScreenElement = nsnull;
}
if (aElement) {
nsEventStateManager::SetFullScreenState(aElement, aIsFullScreen);
}
mFullScreenElement = aElement;
static bool
ResetFullScreenElement(nsIDocument* aDocument, void* aData)
{
aDocument->ResetFullScreenElement();
aDocument->EnumerateSubDocuments(ResetFullScreenElement, aData);
if (mIsFullScreen == aIsFullScreen) {
return false;
}
mIsFullScreen = aIsFullScreen;
return true;
}
static void
ResetFullScreenElementInDocTree(nsIDocument* aDoc)
// Wrapper for the nsIDocument -> nsDocument cast required to call
// nsDocument::SetFullScreenState().
static bool
SetFullScreenState(nsIDocument* aDoc, Element* aElement, bool aIsFullScreen)
{
nsIDocument* root = GetRootDocument(aDoc);
if (root) {
ResetFullScreenElement(root, nsnull);
}
return static_cast<nsDocument*>(aDoc)->
SetFullScreenState(aElement, aIsFullScreen);
}
NS_IMETHODIMP
@ -8475,20 +8427,57 @@ nsDocument::MozCancelFullScreen()
return NS_OK;
}
// Runnable to set window full-screen mode. Used as a script runner
// to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to
// run script. nsGlobalWindow::SetFullScreen() dispatches a synchronous event
// (handled in chome code) which is unsafe to run if this is called in
// nsGenericElement::UnbindFromTree().
class nsSetWindowFullScreen : public nsRunnable {
public:
nsSetWindowFullScreen(nsIDocument* aDoc, bool aValue)
: mDoc(aDoc), mValue(aValue) {}
NS_IMETHOD Run()
{
if (mDoc->GetWindow()) {
mDoc->GetWindow()->SetFullScreen(mValue);
}
return NS_OK;
}
private:
nsCOMPtr<nsIDocument> mDoc;
bool mValue;
};
static void
SetWindowFullScreen(nsIDocument* aDoc, bool aValue)
{
nsContentUtils::AddScriptRunner(new nsSetWindowFullScreen(aDoc, aValue));
}
void
nsDocument::CancelFullScreen()
{
if (!nsContentUtils::IsFullScreenApiEnabled() ||
!IsFullScreenDoc() ||
!GetWindow()) {
NS_ASSERTION(!IsFullScreenDoc() || sFullScreenDoc != nsnull,
"Should have a full-screen doc when full-screen!");
if (!IsFullScreenDoc() || !GetWindow() || !sFullScreenDoc) {
return;
}
// Disable full-screen mode in all documents in this hierarchy.
UpdateFullScreenStatusInDocTree(this, false);
// Reset full-screen state in all full-screen documents.
nsCOMPtr<nsIDocument> doc(do_QueryReferent(sFullScreenDoc));
while (doc != nsnull) {
if (::SetFullScreenState(doc, nsnull, false)) {
DispatchFullScreenChange(doc, nsnull);
}
doc = doc->GetParentDocument();
}
sFullScreenDoc = nsnull;
// Move the window out of full-screen mode.
GetWindow()->SetFullScreen(false);
SetWindowFullScreen(this, false);
return;
}
@ -8496,7 +8485,38 @@ nsDocument::CancelFullScreen()
bool
nsDocument::IsFullScreenDoc()
{
return nsContentUtils::IsFullScreenApiEnabled() && mIsFullScreen;
return mIsFullScreen;
}
static nsIDocument*
GetCommonAncestor(nsIDocument* aDoc1, nsIDocument* aDoc2)
{
nsIDocument* doc1 = aDoc1;
nsIDocument* doc2 = aDoc2;
nsAutoTArray<nsIDocument*, 30> parents1, parents2;
do {
parents1.AppendElement(doc1);
doc1 = doc1->GetParentDocument();
} while (doc1);
do {
parents2.AppendElement(doc2);
doc2 = doc2->GetParentDocument();
} while (doc2);
PRUint32 pos1 = parents1.Length();
PRUint32 pos2 = parents2.Length();
nsIDocument* parent = nsnull;
PRUint32 len;
for (len = NS_MIN(pos1, pos2); len > 0; --len) {
nsIDocument* child1 = parents1.ElementAt(--pos1);
nsIDocument* child2 = parents2.ElementAt(--pos2);
if (child1 != child2) {
break;
}
parent = child1;
}
return parent;
}
void
@ -8506,61 +8526,78 @@ nsDocument::RequestFullScreen(Element* aElement)
return;
}
// Reset the full-screen elements of every document in this document
// hierarchy.
ResetFullScreenElementInDocTree(this);
if (aElement->IsInDoc()) {
// Propagate up the document hierarchy, setting the full-screen element as
// the element's container in ancestor documents. Note we don't propagate
// down the document hierarchy, the full-screen element (or its container)
// is not visible there.
mFullScreenElement = aElement;
// Set the full-screen state on the element, so the css-pseudo class
// applies to the element.
nsEventStateManager::SetFullScreenState(mFullScreenElement, true);
nsIDocument* child = this;
nsIDocument* parent;
while (parent = child->GetParentDocument()) {
Element* element = parent->FindContentForSubDocument(child);
// Containing frames also need the css-pseudo class applied.
nsEventStateManager::SetFullScreenState(element, true);
static_cast<nsDocument*>(parent)->mFullScreenElement = element;
child = parent;
// Turn off full-screen state in all documents which were previously
// full-screen but which shouldn't be after this request is granted.
// Note commonAncestor will be null when in a separate browser window
// to the requesting document.
nsIDocument* commonAncestor = nsnull;
nsCOMPtr<nsIDocument> fullScreenDoc(do_QueryReferent(sFullScreenDoc));
if (fullScreenDoc) {
commonAncestor = GetCommonAncestor(fullScreenDoc, this);
}
nsIDocument* doc = fullScreenDoc;
while (doc != commonAncestor) {
if (::SetFullScreenState(doc, nsnull, false)) {
DispatchFullScreenChange(doc, nsnull);
}
doc = doc->GetParentDocument();
}
if (!commonAncestor && fullScreenDoc) {
// Other doc is in another browser window. Move it out of full-screen.
// Note that nsGlobalWindow::SetFullScreen() proxies to the root window
// in its hierarchy, and does not operate on the a per-nsIDOMWindow basis.
SetWindowFullScreen(fullScreenDoc, false);
}
// Set all documents in hierarchy to full-screen mode.
UpdateFullScreenStatusInDocTree(this, true);
// Set the full-screen element. This sets the full-screen style on the
// element, and the full-screen-ancestor styles on ancestors of the element
// in this document.
if (SetFullScreenState(aElement, true)) {
DispatchFullScreenChange(this, aElement);
}
// Propagate up the document hierarchy, setting the full-screen element as
// the element's container in ancestor documents. This also sets the
// appropriate css styles as well. Note we don't propagate down the
// document hierarchy, the full-screen element (or its container) is not
// visible there.
nsIDocument* child = this;
nsIDocument* parent;
while ((parent = child->GetParentDocument())) {
Element* element = parent->FindContentForSubDocument(child)->AsElement();
if (::SetFullScreenState(parent, element, true)) {
DispatchFullScreenChange(parent, element);
}
child = parent;
}
// Make the window full-screen. Note we must make the state changes above
// before making the window full-screen, as then the document reports as
// being in full-screen mode when the Chrome "fullscreen" event fires,
// enabling browser.js to distinguish between browser and dom full-screen
// being in full-screen mode when the chrome "fullscreen" event fires,
// enabling chrome to distinguish between browser and dom full-screen
// modes.
GetWindow()->SetFullScreen(true);
SetWindowFullScreen(this, true);
// Remember this is the requesting full-screen document.
sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
}
NS_IMETHODIMP
nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement)
{
NS_ENSURE_ARG_POINTER(aFullScreenElement);
if (!nsContentUtils::IsFullScreenApiEnabled() || !IsFullScreenDoc()) {
*aFullScreenElement = nsnull;
return NS_OK;
*aFullScreenElement = nsnull;
if (IsFullScreenDoc()) {
// Must have a full-screen element while in full-screen mode.
NS_ENSURE_STATE(GetFullScreenElement());
CallQueryInterface(GetFullScreenElement(), aFullScreenElement);
}
nsCOMPtr<nsIDOMHTMLElement> e(do_QueryInterface(GetFullScreenElement()));
NS_IF_ADDREF(*aFullScreenElement = e);
return NS_OK;
}
Element*
nsDocument::GetFullScreenElement()
{
if (!nsContentUtils::IsFullScreenApiEnabled() ||
(mFullScreenElement && !mFullScreenElement->IsInDoc())) {
return nsnull;
}
return mFullScreenElement;
}
@ -8568,7 +8605,7 @@ NS_IMETHODIMP
nsDocument::GetMozFullScreen(bool *aFullScreen)
{
NS_ENSURE_ARG_POINTER(aFullScreen);
*aFullScreen = nsContentUtils::IsFullScreenApiEnabled() && IsFullScreenDoc();
*aFullScreen = IsFullScreenDoc();
return NS_OK;
}

View File

@ -947,13 +947,15 @@ public:
virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
virtual void ResetFullScreenElement();
virtual Element* GetFullScreenElement();
virtual void RequestFullScreen(Element* aElement);
virtual void CancelFullScreen();
virtual void UpdateFullScreenStatus(bool aIsFullScreen);
virtual bool IsFullScreenDoc();
// Returns true if making this change results in a change in the full-screen
// state of this document.
bool SetFullScreenState(Element* aElement, bool aIsFullScreen);
// This method may fire a DOM event; if it does so it will happen
// synchronously.
void UpdateVisibilityState();
@ -1073,6 +1075,10 @@ protected:
// is a weak reference to avoid leaks due to circular references.
nsWeakPtr mScopeObject;
// The document which requested (and was granted) full-screen. All ancestors
// of this document will also be full-screen.
static nsWeakPtr sFullScreenDoc;
nsRefPtr<nsEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;

View File

@ -3056,6 +3056,14 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
return NS_OK;
}
static bool
IsFullScreenAncestor(Element* aElement)
{
nsEventStates state = aElement->State();
return state.HasAtLeastOneOfStates(NS_EVENT_STATE_FULL_SCREEN_ANCESTOR |
NS_EVENT_STATE_FULL_SCREEN);
}
void
nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
@ -3067,6 +3075,11 @@ nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
if (aNullParent) {
if (IsFullScreenAncestor(this)) {
// The element being removed is an ancestor of the full-screen element,
// exit full-screen state.
OwnerDoc()->CancelFullScreen();
}
if (GetParent()) {
NS_RELEASE(mParent);
} else {

View File

@ -264,8 +264,10 @@ private:
// Content is the full screen element, or a frame containing the
// current full-screen element.
#define NS_EVENT_STATE_FULL_SCREEN NS_DEFINE_EVENT_STATE_MACRO(34)
// Content is an ancestor of the DOM full-screen element.
#define NS_EVENT_STATE_FULL_SCREEN_ANCESTOR NS_DEFINE_EVENT_STATE_MACRO(35)
// Handler for click to play plugin
#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(35)
#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(36)
/**
* NOTE: do not go over 63 without updating nsEventStates::InternalType!
@ -274,7 +276,7 @@ private:
#define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \
NS_EVENT_STATE_FULL_SCREEN)
NS_EVENT_STATE_FULL_SCREEN | NS_EVENT_STATE_FULL_SCREEN_ANCESTOR)
#define INTRINSIC_STATES (~ESM_MANAGED_STATES)

View File

@ -4445,12 +4445,22 @@ static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2)
return nsnull;
}
static Element*
GetParentElement(Element* aElement)
{
nsIContent* p = aElement->GetParent();
return (p && p->IsElement()) ? p->AsElement() : nsnull;
}
/* static */
void
nsEventStateManager::SetFullScreenState(Element* aElement,
bool aIsFullScreen)
nsEventStateManager::SetFullScreenState(Element* aElement, bool aIsFullScreen)
{
DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen);
Element* ancestor = aElement;
while ((ancestor = GetParentElement(ancestor))) {
DoStateChange(ancestor, NS_EVENT_STATE_FULL_SCREEN_ANCESTOR, aIsFullScreen);
}
}
/* static */

View File

@ -3403,7 +3403,8 @@ 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.
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
if (!nsContentUtils::IsRequestFullScreenAllowed() ||
!IsInDoc()) {
return NS_OK;
}
@ -3418,11 +3419,7 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
doc->RequestFullScreen(this);
#ifdef DEBUG
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(doc->GetWindow());
NS_ENSURE_STATE(window);
bool fullscreen;
window->GetFullScreen(&fullscreen);
NS_ASSERTION(fullscreen, "Windows should report fullscreen");
domDocument->GetMozFullScreen(&fullscreen);
NS_ASSERTION(fullscreen, "Document should report fullscreen");
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");

View File

@ -282,6 +282,7 @@ _TEST_FILES = \
file_fullscreen-api-keys.html \
test_fullscreen-api.html \
file_fullscreen-plugins.html \
file_fullscreen-denied.html \
test_li_attributes_reflection.html \
test_ol_attributes_reflection.html \
test_bug651956.html \

View File

@ -9,6 +9,11 @@ Test that restricted key pressed drop documents out of DOM full-screen mode.
<head>
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body {
background-color: black;
}
</style>
</head>
<body onload="document.body.mozRequestFullScreen();">
@ -186,7 +191,8 @@ function checkKeyEffect() {
if (gKeyTestIndex < keyList.length) {
setTimeout(testNextKey, 0);
} else {
opener.keysTestFinished();
document.mozCancelFullScreen();
opener.nextTest();
}
}

View File

@ -1,4 +1,4 @@
<!DOCTYPE HTML>
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=545812
@ -10,12 +10,12 @@ Test DOM full-screen API.
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body:-moz-full-screen, div:-moz-full-screen {
background-color: red;
body {
background-color: black;
}
</style>
</head>
<body onload="document.body.mozRequestFullScreen();">
<body onload="fullScreenElement().mozRequestFullScreen();">
<script type="application/javascript">
@ -32,14 +32,16 @@ function is(a, b, msg) {
/*
<html>
<body onload='document.body.mozRequestFullScreen();'>
<iframe id='inner-frame'></iframe>
</body>
</html>
*/
var iframeContents = "data:text/html;charset=utf-8,<html>%0D%0A <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A <%2Fbody>%0D%0A<%2Fhtml>";
var iframeContents = "data:text/html;charset=utf-8,<html><body onload%3D'document.body.mozRequestFullScreen()%3B'><iframe id%3D'inner-frame'><%2Fiframe><%2Fbody><%2Fhtml>";
var iframe = null;
var outOfDocElement = null;
var inDocElement = null;
var container = null;
var button = null;
var fullScreenChangeCount = 0;
@ -52,19 +54,33 @@ function setRequireTrustedContext(value) {
opener.SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", value);
}
function fullScreenElement() {
return document.getElementById('full-screen-element');
}
function fullScreenChange(event) {
switch (fullScreenChangeCount) {
case 0: {
ok(document.mozFullScreen, "Should be in full-screen mode (first time)");
is(event.target, document.body, "Event target should be full-screen element");
is(document.mozFullScreenElement, document.body,
"Full-screen element should be body element.");
document.mozCancelFullScreen();
is(event.target, fullScreenElement(), "Event target should be full-screen element");
is(document.mozFullScreenElement, fullScreenElement(),
"Full-screen element should be div element.");
ok(document.mozFullScreenElement.mozMatchesSelector(":-moz-full-screen"),
"FSE should match :-moz-full-screen");
var fse = fullScreenElement();
fse.parentNode.removeChild(fse);
is(document.mozFullScreenElement, null,
"Full-screen element should be null after removing.");
ok(!document.mozFullScreen, "Should have left full-screen mode when we remove full-screen element");
document.body.appendChild(fse);
ok(!document.mozFullScreen, "Should not return to full-screen mode when re-adding former FSE");
is(document.mozFullScreenElement, null,
"Full-screen element should still be null after re-adding former FSE.");
break;
}
case 1: {
ok(!document.mozFullScreen, "Should have left full-screen mode (first time)");
is(event.target, document.body, "Event target should be full-screen element");
is(event.target, document, "Event target should be document when we exit via removing from doc");
is(document.mozFullScreenElement, null, "Full-screen element should be null.");
iframe = document.createElement("iframe");
iframe.mozAllowFullScreen = true;
@ -78,55 +94,71 @@ function fullScreenChange(event) {
"Event target should be full-screen element container");
is(document.mozFullScreenElement, iframe,
"Full-screen element should be iframe element.");
document.mozCancelFullScreen();
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);
break;
}
case 3: {
ok(!document.mozFullScreen, "Should be back in non-full-screen mode (second time)");
is(event.target, iframe,
is(event.target, document,
"Event target should be full-screen element container");
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)");
break;
}
case 4: {
ok(document.mozFullScreen, "Should be back in full-screen mode (third time)");
is(event.target, document, "Event target should be document");
is(document.mozFullScreenElement, null,
"Should not have a full-screen element when element not in document requests full-screen.");
// Set another element to be the full-screen element. It should immediately
// become the current full-screen element.
inDocElement = document.createElement("div");
document.body.appendChild(inDocElement);
inDocElement.mozRequestFullScreen();
ok(document.mozFullScreen, "Should remain in full-screen mode (third and a half time)");
ok(document.mozFullScreen, "Should still be in full-screen mode (third time)");
is(event.target, inDocElement, "Event target should be inDocElement");
is(document.mozFullScreenElement, inDocElement,
"Full-screen element should be in doc again.");
// Remove full-screen element from document before exiting full screen.
document.body.removeChild(inDocElement);
ok(document.mozFullScreen,
"Should remain in full-screen mode after removing full-screen element from document");
"FSE should be inDocElement.");
var n = container;
do {
ok(n.mozMatchesSelector(":-moz-full-screen-ancestor"), "Ancestor " + n + " should match :-moz-full-screen-ancestor")
n = n.parentNode;
} while (n && n.mozMatchesSelector);
// Remove full-screen ancestor element from document, verify it stops being reported as current FSE.
container.parentNode.removeChild(container);
ok(!document.mozFullScreen,
"Should exit full-screen mode after removing full-screen element ancestor from document");
is(document.mozFullScreenElement, null,
"Should not have a full-screen element again.");
document.mozCancelFullScreen();
break;
}
case 5: {
ok(!document.mozFullScreen, "Should be back in non-full-screen mode (third time)");
setRequireTrustedContext(true);
document.body.mozRequestFullScreen();
fullScreenElement().mozRequestFullScreen();
ok(!document.mozFullScreen, "Should still be in normal mode, because calling context isn't trusted.");
button = document.createElement("button");
button.onclick = function(){document.body.mozRequestFullScreen();}
document.body.appendChild(button);
button.onclick = function(){fullScreenElement().mozRequestFullScreen();}
fullScreenElement().appendChild(button);
sendMouseClick(button);
break;
}
@ -144,22 +176,22 @@ function fullScreenChange(event) {
SpecialPowers.setBoolPref("full-screen-api.enabled", false);
is(document.mozFullScreenEnabled, false, "document.mozFullScreenEnabled should be false if full-screen-api.enabled is false");
document.body.mozRequestFullScreen();
fullScreenElement().mozRequestFullScreen();
ok(!document.mozFullScreen, "Should still be in normal mode, because pref is not enabled.");
SpecialPowers.setBoolPref("full-screen-api.enabled", true);
is(document.mozFullScreenEnabled, true, "document.mozFullScreenEnabled should be true if full-screen-api.enabled is true");
iframe = document.createElement("iframe");
document.body.appendChild(iframe);
fullScreenElement().appendChild(iframe);
iframe.src = iframeContents;
ok(!document.mozFullScreen, "Should still be in normal mode, because iframe did not have mozallowfullscreen attribute.");
document.body.removeChild(iframe);
fullScreenElement().removeChild(iframe);
iframe = null;
// Set timeout for calling finish(), so that any pending "mozfullscreenchange" events
// would have a chance to fire.
setTimeout(function(){opener.apiTestFinished();}, 0);
setTimeout(function(){opener.nextTest();}, 0);
break;
}
default: {
@ -173,5 +205,6 @@ document.addEventListener("mozfullscreenchange", fullScreenChange, false);
</script>
</pre>
<div id="full-screen-element"></div>
</body>
</html>

View File

@ -0,0 +1,96 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=545812
Test DOM full-screen API.
-->
<head>
<title>Test for Bug 545812</title>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body {
background-color: black;
}
</style>
</head>
<body onload="run();">
<script type="application/javascript">
/** Test for Bug 545812 **/
function ok(condition, msg) {
opener.ok(condition, msg);
}
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 gotFullScreenChange = false;
function run() {
document.addEventListener("mozfullscreenchange",
function() {
ok(false, "Should never receive a mozfullscreenchange event in the main window.");
gotFullScreenChange = true;
},
false);
// 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();
ok(!document.mozFullScreen, "Should not grant request in non-truested context");
// Test requesting full-screen mode in a long-running user-generated event handler.
// The request in the key handler should not be granted.
window.addEventListener("keypress", keyHandler, false);
synthesizeKey("VK_A", {});
}
function keyHandler(event) {
window.removeEventListener("keypress", keyHandler, false);
// Busy loop until 2s has passed. We should then be past the 1 second threshold, and so
// our request for full-screen mode should be rejected.
var end = (new Date()).getTime() + 2000;
while ((new Date()).getTime() < end) {
; // Wait...
}
document.body.mozRequestFullScreen();
ok(!document.mozFullScreen, "Should not grant request in long-running event handler.");
// Disable the requirement for trusted contexts only, so the tests are easier
// to write.
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
// Create an iframe without a mozallowfullscreen sttribute, whose contents requests
// full-screen. The request should be denied.
var iframe = document.createElement("iframe");
iframe.src = requestFullScreenContents;
document.body.appendChild(iframe);
setTimeout(
function() {
ok(!gotFullScreenChange, "Should not ever grant a fullscreen request in this doc.");
opener.nextTest();
}, 0);
}
</script>
</pre>
<div id="full-screen-element"></div>
</body>
</html>

View File

@ -119,7 +119,7 @@ function macFullScreenChange(event) {
}
case 1: {
ok(!document.mozFullScreen, "Should have left full-screen mode after calling document.mozCancelFullScreen().");
opener.pluginTestFinished();
opener.nextTest();
break;
}
default: {
@ -164,7 +164,7 @@ function fullScreenChange(event) {
}
case 5: {
ok(!document.mozFullScreen, "Should have left full-screen mode after adding windowed plugin created before going full-screen to document");
opener.pluginTestFinished();
opener.nextTest();
break;
}
default: {

View File

@ -6,6 +6,11 @@
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body {
background-color: black;
}
</style>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
@ -16,88 +21,45 @@
<pre id="test">
<script type="application/javascript">
/** Test for Bug 545812 **/
/** Tests for Bug 545812 **/
// Ensure the full-screen api is enabled, and will be disabled on test exit.
var prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
SpecialPowers.setBoolPref("full-screen-api.enabled", true);
// Disable the requirement for trusted contexts only, so the tests are easier
// to write.
var prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
// Run the tests which go full-screen in new windows, as mochitests normally
// run in an iframe, which by default will not have the mozallowfullscreen
// attribute set, so full-screen won't work.
var gTestWindows = [
"file_fullscreen-denied.html",
"file_fullscreen-api.html",
"file_fullscreen-api-keys.html",
"file_fullscreen-plugins.html"
];
var testWindow = null;
var gTestIndex = 0;
/*
<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 prevTrusted = false;
var prevEnabled = false;
function run() {
document.addEventListener("mozfullscreenchange",
function(){ok(false, "Should never receive a mozfullscreenchange event in the main window.");},
false);
// Ensure the full-screen api is enabled, and will be disabled on test exit.
prevEnabled = SpecialPowers.getBoolPref("full-screen-api.enabled");
SpecialPowers.setBoolPref("full-screen-api.enabled", true);
// Test requesting full-screen mode in a long-running user-generated event handler.
// The request in the key handler should not be granted.
window.addEventListener("keypress", keyHandler, false);
synthesizeKey("VK_A", {});
}
function keyHandler(event) {
window.removeEventListener("keypress", keyHandler, false);
// Busy loop until 2s has passed. We should then be past the 1 second threshold, and so
// our request for full-screen mode should be rejected.
var end = (new Date()).getTime() + 2000;
while ((new Date()).getTime() < end) {
; // Wait...
function nextTest() {
if (testWindow) {
testWindow.close();
}
if (gTestIndex < gTestWindows.length) {
testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500");
gTestIndex++;
} else {
SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);
SimpleTest.finish();
}
document.body.mozRequestFullScreen();
prevTrusted = SpecialPowers.getBoolPref("full-screen-api.allow-trusted-requests-only");
// Request full-screen from a non trusted context (this script isn't a user
// generated event!). We should not receive a "mozfullscreenchange" event.
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", true);
document.body.mozRequestFullScreen();
// Disable the requirement for trusted contexts only, so the tests are easier
// to write.
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", false);
// Load an iframe whose contents requests full-screen. This request should
// fail, and we should never receive a "mozfullscreenchange" event, because the
// iframe doesn't have a mozallowfullscreen attribute.
var iframe = document.createElement("iframe");
iframe.src = requestFullScreenContents;
document.body.appendChild(iframe);
// Run the tests which go full-screen in a new window, as mochitests normally
// run in an iframe, which by default will not have the mozallowfullscreen
// attribute set, so full-screen won't work.
testWindow = window.open("file_fullscreen-api.html", "", "width=500,height=500");
}
function apiTestFinished() {
testWindow.close();
testWindow = window.open("file_fullscreen-api-keys.html", "", "width=500,height=500");
}
function keysTestFinished() {
testWindow.close();
testWindow = window.open("file_fullscreen-plugins.html", "", "width=500,height=500");
}
function pluginTestFinished() {
testWindow.close();
SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);
SimpleTest.finish();
}
addLoadEvent(run);
addLoadEvent(nextTest);
SimpleTest.waitForExplicitFinish();
</script>

View File

@ -144,6 +144,10 @@ CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate",
// any containing frames.
CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", NS_EVENT_STATE_FULL_SCREEN)
// Matches any element which is an ancestor of the DOM full-screen element,
// or an ancestor of a containing frame of the full-screen element.
CSS_STATE_PSEUDO_CLASS(mozFullScreenAncestor, ":-moz-full-screen-ancestor", NS_EVENT_STATE_FULL_SCREEN_ANCESTOR)
// Matches if the element is focused and should show a focus ring
CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", NS_EVENT_STATE_FOCUSRING)

View File

@ -241,17 +241,40 @@
}
*|*:-moz-full-screen {
position:fixed;
top:0;
left:0;
right:0;
bottom:0;
z-index:2147483647;
background:black;
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
z-index: 2147483647 !important;
background: black;
width: 100% !important;
height: 100% !important;
}
/* If there is a full-screen element that is not the root then
we should hide the viewport scrollbar. */
*|*:root:-moz-full-screen-ancestor {
overflow: hidden !important;
}
*|*:-moz-full-screen-ancestor {
/* Ancestors of a full-screen element should not induce stacking contexts
that would prevent the full-screen element from being on top. */
z-index:auto !important;
/* Ancestors of a full-screen element should not be partially transparent,
since that would apply to the full-screen element and make the page visible
behind it. It would also create a pseudo-stacking-context that would let content
draw on top of the full-screen element. */
opacity:1 !important;
/* Ancestors of a full-screen element should not apply SVG masking, clipping, or
filtering, since that would affect the full-screen element and create a pseudo-
stacking context. */
mask:none !important;
clip:none !important;
filter:none !important;
}
/* XML parse error reporting */
parsererror|parsererror {