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
Родитель 4faa25c5fa
Коммит c205ec6d86
15 изменённых файлов: 452 добавлений и 274 удалений

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

@ -126,8 +126,8 @@ class Element;
} // namespace mozilla } // namespace mozilla
#define NS_IDOCUMENT_IID \ #define NS_IDOCUMENT_IID \
{ 0xb52356d4, 0xe191, 0x4cf8, \ { 0xc3e40e8e, 0x8b91, 0x424c, \
{ 0xb8, 0x58, 0xc0, 0xf1, 0xe1, 0x98, 0x09, 0xdf } } { 0xbe, 0x9c, 0x9c, 0xc1, 0x76, 0xa7, 0xf7, 0x24 } }
// Flag for AddStyleSheet(). // Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0) #define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -737,14 +737,10 @@ public:
virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0; virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0;
/** /**
* Resets the current full-screen element to nsnull. * Returns the element which either requested DOM full-screen mode, or
*/ * contains the element which requested DOM full-screen mode if the
virtual void ResetFullScreenElement() = 0; * requestee is in a subdocument. Note this element must be *in*
* this document.
/**
* 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.
*/ */
virtual Element* GetFullScreenElement() = 0; virtual Element* GetFullScreenElement() = 0;
@ -760,14 +756,6 @@ public:
*/ */
virtual void CancelFullScreen() = 0; 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. * Returns true if this document is in full-screen mode.
*/ */

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

@ -214,6 +214,7 @@ using namespace mozilla::dom;
typedef nsTArray<Link*> LinkArray; typedef nsTArray<Link*> LinkArray;
nsWeakPtr nsDocument::sFullScreenDoc = nsnull;
#ifdef PR_LOGGING #ifdef PR_LOGGING
static PRLogModuleInfo* gDocumentLeakPRLog; static PRLogModuleInfo* gDocumentLeakPRLog;
@ -6011,7 +6012,7 @@ nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode); nsCOMPtr<nsINode> adoptedNode = do_QueryInterface(aAdoptedNode);
// Scope firing mutation events so that we don't carry any state that // Scope firing mutation events so that we don't carry any state that
// might be stale // might be stale
{ {
@ -8358,39 +8359,12 @@ nsIDocument::SizeOf() const
return size; 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 class nsDispatchFullScreenChange : public nsRunnable
{ {
public: public:
nsDispatchFullScreenChange(nsIDocument *aDoc) nsDispatchFullScreenChange(nsIDocument *aDoc, nsINode* aElement)
: mDoc(aDoc) : mDoc(aDoc),
{ mTarget(aElement ? aElement : aDoc) {}
mTarget = aDoc->GetFullScreenElement();
if (!mTarget) {
mTarget = aDoc;
}
}
NS_IMETHOD Run() NS_IMETHOD Run()
{ {
@ -8406,63 +8380,41 @@ public:
nsCOMPtr<nsISupports> mTarget; nsCOMPtr<nsISupports> mTarget;
}; };
void static void DispatchFullScreenChange(nsIDocument* aDocument, Element* aElement)
nsDocument::UpdateFullScreenStatus(bool aIsFullScreen)
{ {
if (mIsFullScreen != aIsFullScreen) { nsCOMPtr<nsIRunnable> event(
nsCOMPtr<nsIRunnable> event(new nsDispatchFullScreenChange(this)); new nsDispatchFullScreenChange(aDocument, aElement));
NS_DispatchToCurrentThread(event); 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();
}
} }
static bool bool
UpdateFullScreenStatus(nsIDocument* aDocument, void* aData) nsDocument::SetFullScreenState(Element* aElement, bool aIsFullScreen)
{
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()
{ {
if (mFullScreenElement) { if (mFullScreenElement) {
// Reset the ancestor and full-screen styles on the outgoing full-screen
// element in the current document.
nsEventStateManager::SetFullScreenState(mFullScreenElement, false); nsEventStateManager::SetFullScreenState(mFullScreenElement, false);
mFullScreenElement = nsnull;
} }
mFullScreenElement = nsnull; if (aElement) {
} nsEventStateManager::SetFullScreenState(aElement, aIsFullScreen);
}
mFullScreenElement = aElement;
static bool if (mIsFullScreen == aIsFullScreen) {
ResetFullScreenElement(nsIDocument* aDocument, void* aData) return false;
{ }
aDocument->ResetFullScreenElement(); mIsFullScreen = aIsFullScreen;
aDocument->EnumerateSubDocuments(ResetFullScreenElement, aData);
return true; return true;
} }
static void // Wrapper for the nsIDocument -> nsDocument cast required to call
ResetFullScreenElementInDocTree(nsIDocument* aDoc) // nsDocument::SetFullScreenState().
static bool
SetFullScreenState(nsIDocument* aDoc, Element* aElement, bool aIsFullScreen)
{ {
nsIDocument* root = GetRootDocument(aDoc); return static_cast<nsDocument*>(aDoc)->
if (root) { SetFullScreenState(aElement, aIsFullScreen);
ResetFullScreenElement(root, nsnull);
}
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -8475,20 +8427,57 @@ nsDocument::MozCancelFullScreen()
return NS_OK; 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 void
nsDocument::CancelFullScreen() nsDocument::CancelFullScreen()
{ {
if (!nsContentUtils::IsFullScreenApiEnabled() || NS_ASSERTION(!IsFullScreenDoc() || sFullScreenDoc != nsnull,
!IsFullScreenDoc() || "Should have a full-screen doc when full-screen!");
!GetWindow()) {
if (!IsFullScreenDoc() || !GetWindow() || !sFullScreenDoc) {
return; return;
} }
// Disable full-screen mode in all documents in this hierarchy. // Reset full-screen state in all full-screen documents.
UpdateFullScreenStatusInDocTree(this, false); 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. // Move the window out of full-screen mode.
GetWindow()->SetFullScreen(false); SetWindowFullScreen(this, false);
return; return;
} }
@ -8496,7 +8485,38 @@ nsDocument::CancelFullScreen()
bool bool
nsDocument::IsFullScreenDoc() 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 void
@ -8506,61 +8526,78 @@ nsDocument::RequestFullScreen(Element* aElement)
return; return;
} }
// Reset the full-screen elements of every document in this document // Turn off full-screen state in all documents which were previously
// hierarchy. // full-screen but which shouldn't be after this request is granted.
ResetFullScreenElementInDocTree(this); // Note commonAncestor will be null when in a separate browser window
// to the requesting document.
if (aElement->IsInDoc()) { nsIDocument* commonAncestor = nsnull;
// Propagate up the document hierarchy, setting the full-screen element as nsCOMPtr<nsIDocument> fullScreenDoc(do_QueryReferent(sFullScreenDoc));
// the element's container in ancestor documents. Note we don't propagate if (fullScreenDoc) {
// down the document hierarchy, the full-screen element (or its container) commonAncestor = GetCommonAncestor(fullScreenDoc, this);
// is not visible there. }
mFullScreenElement = aElement; nsIDocument* doc = fullScreenDoc;
// Set the full-screen state on the element, so the css-pseudo class while (doc != commonAncestor) {
// applies to the element. if (::SetFullScreenState(doc, nsnull, false)) {
nsEventStateManager::SetFullScreenState(mFullScreenElement, true); DispatchFullScreenChange(doc, nsnull);
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;
} }
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. // Set the full-screen element. This sets the full-screen style on the
UpdateFullScreenStatusInDocTree(this, true); // 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 // 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 // before making the window full-screen, as then the document reports as
// being in full-screen mode when the Chrome "fullscreen" event fires, // being in full-screen mode when the chrome "fullscreen" event fires,
// enabling browser.js to distinguish between browser and dom full-screen // enabling chrome to distinguish between browser and dom full-screen
// modes. // modes.
GetWindow()->SetFullScreen(true); SetWindowFullScreen(this, true);
// Remember this is the requesting full-screen document.
sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
} }
NS_IMETHODIMP NS_IMETHODIMP
nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement) nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement)
{ {
NS_ENSURE_ARG_POINTER(aFullScreenElement); NS_ENSURE_ARG_POINTER(aFullScreenElement);
if (!nsContentUtils::IsFullScreenApiEnabled() || !IsFullScreenDoc()) { *aFullScreenElement = nsnull;
*aFullScreenElement = nsnull; if (IsFullScreenDoc()) {
return NS_OK; // 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; return NS_OK;
} }
Element* Element*
nsDocument::GetFullScreenElement() nsDocument::GetFullScreenElement()
{ {
if (!nsContentUtils::IsFullScreenApiEnabled() ||
(mFullScreenElement && !mFullScreenElement->IsInDoc())) {
return nsnull;
}
return mFullScreenElement; return mFullScreenElement;
} }
@ -8568,7 +8605,7 @@ NS_IMETHODIMP
nsDocument::GetMozFullScreen(bool *aFullScreen) nsDocument::GetMozFullScreen(bool *aFullScreen)
{ {
NS_ENSURE_ARG_POINTER(aFullScreen); NS_ENSURE_ARG_POINTER(aFullScreen);
*aFullScreen = nsContentUtils::IsFullScreenApiEnabled() && IsFullScreenDoc(); *aFullScreen = IsFullScreenDoc();
return NS_OK; return NS_OK;
} }

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

@ -947,13 +947,15 @@ public:
virtual Element* FindImageMap(const nsAString& aNormalizedMapName); virtual Element* FindImageMap(const nsAString& aNormalizedMapName);
virtual void ResetFullScreenElement();
virtual Element* GetFullScreenElement(); virtual Element* GetFullScreenElement();
virtual void RequestFullScreen(Element* aElement); virtual void RequestFullScreen(Element* aElement);
virtual void CancelFullScreen(); virtual void CancelFullScreen();
virtual void UpdateFullScreenStatus(bool aIsFullScreen);
virtual bool IsFullScreenDoc(); 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 // This method may fire a DOM event; if it does so it will happen
// synchronously. // synchronously.
void UpdateVisibilityState(); void UpdateVisibilityState();
@ -1073,6 +1075,10 @@ protected:
// is a weak reference to avoid leaks due to circular references. // is a weak reference to avoid leaks due to circular references.
nsWeakPtr mScopeObject; 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; nsRefPtr<nsEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets; nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;
nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList; nsRefPtr<nsDOMStyleSheetSetList> mStyleSheetSetList;

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

@ -3056,6 +3056,14 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
return NS_OK; 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 void
nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent) nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
{ {
@ -3067,6 +3075,11 @@ nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc(); HasFlag(NODE_FORCE_XBL_BINDINGS) ? OwnerDoc() : GetCurrentDoc();
if (aNullParent) { 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()) { if (GetParent()) {
NS_RELEASE(mParent); NS_RELEASE(mParent);
} else { } else {

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

@ -264,8 +264,10 @@ private:
// Content is the full screen element, or a frame containing the // Content is the full screen element, or a frame containing the
// current full-screen element. // current full-screen element.
#define NS_EVENT_STATE_FULL_SCREEN NS_DEFINE_EVENT_STATE_MACRO(34) #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 // 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! * 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 | \ #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \ NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \
NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \ 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) #define INTRINSIC_STATES (~ESM_MANAGED_STATES)

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

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

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

@ -3403,7 +3403,8 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
// This stops the full-screen from being abused similar to the popups of old, // 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 // and it also makes it harder for bad guys' script to go full-screen and
// spoof the browser chrome/window and phish logins etc. // spoof the browser chrome/window and phish logins etc.
if (!nsContentUtils::IsRequestFullScreenAllowed()) { if (!nsContentUtils::IsRequestFullScreenAllowed() ||
!IsInDoc()) {
return NS_OK; return NS_OK;
} }
@ -3418,11 +3419,7 @@ nsresult nsGenericHTMLElement::MozRequestFullScreen()
doc->RequestFullScreen(this); doc->RequestFullScreen(this);
#ifdef DEBUG #ifdef DEBUG
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(doc->GetWindow());
NS_ENSURE_STATE(window);
bool fullscreen; bool fullscreen;
window->GetFullScreen(&fullscreen);
NS_ASSERTION(fullscreen, "Windows should report fullscreen");
domDocument->GetMozFullScreen(&fullscreen); domDocument->GetMozFullScreen(&fullscreen);
NS_ASSERTION(fullscreen, "Document should report fullscreen"); NS_ASSERTION(fullscreen, "Document should report fullscreen");
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!"); NS_ASSERTION(doc->IsFullScreenDoc(), "Should be in full screen state!");

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

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

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

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

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

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

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

@ -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>

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

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

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

@ -6,6 +6,11 @@
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<style>
body {
background-color: black;
}
</style>
</head> </head>
<body> <body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=545812">Mozilla Bug 545812</a>
@ -16,88 +21,45 @@
<pre id="test"> <pre id="test">
<script type="application/javascript"> <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 testWindow = null;
var gTestIndex = 0;
/* function nextTest() {
<html> if (testWindow) {
<body onload='document.body.mozRequestFullScreen();'> testWindow.close();
</body> }
</html> if (gTestIndex < gTestWindows.length) {
*/ testWindow = window.open(gTestWindows[gTestIndex], "", "width=500,height=500");
var requestFullScreenContents = "data:text/html;charset=utf-8,<html>%0D%0A <body onload%3D'document.body.mozRequestFullScreen()%3B'>%0D%0A <%2Fbody>%0D%0A<%2Fhtml>"; gTestIndex++;
} else {
var prevTrusted = false; SpecialPowers.setBoolPref("full-screen-api.enabled", prevEnabled);
var prevEnabled = false; SpecialPowers.setBoolPref("full-screen-api.allow-trusted-requests-only", prevTrusted);
SimpleTest.finish();
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...
} }
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() { addLoadEvent(nextTest);
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);
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
</script> </script>

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

@ -144,6 +144,10 @@ CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate",
// any containing frames. // any containing frames.
CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", NS_EVENT_STATE_FULL_SCREEN) 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 // Matches if the element is focused and should show a focus ring
CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", NS_EVENT_STATE_FOCUSRING) CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", NS_EVENT_STATE_FOCUSRING)

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

@ -241,17 +241,40 @@
} }
*|*:-moz-full-screen { *|*:-moz-full-screen {
position:fixed; position: fixed !important;
top:0; top: 0 !important;
left:0; left: 0 !important;
right:0; right: 0 !important;
bottom:0; bottom: 0 !important;
z-index:2147483647; z-index: 2147483647 !important;
background:black; background: black;
width: 100% !important; width: 100% !important;
height: 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 */ /* XML parse error reporting */
parsererror|parsererror { parsererror|parsererror {