Bug 753546 part 3 - Record fullscreen approval in nsDocument flag. r=smaug

This commit is contained in:
Chris Pearce 2012-05-22 08:43:36 +12:00
parent b8d01f2593
commit a462b79857
3 changed files with 104 additions and 47 deletions

View File

@ -92,9 +92,8 @@ class Element;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0x8e51e6d9, 0x914d, 0x46ba, \
{ 0xb3, 0x11, 0x2f, 0x27, 0x3d, 0xe6, 0x0d, 0x19 } }
{ 0x88d887da, 0xd228, 0x41c2, \
{ 0xb8, 0x0a, 0x42, 0xec, 0xf0, 0xcb, 0xce, 0x37 } }
// Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -744,6 +743,14 @@ public:
*/
virtual bool IsFullScreenDoc() = 0;
/**
* Sets whether this document is approved for fullscreen mode.
* Documents aren't approved for fullscreen until chrome has sent a
* "fullscreen-approved" notification with a subject which is a pointer
* to the approved document.
*/
virtual void SetApprovedForFullscreen(bool aIsApproved) = 0;
/**
* Exits all documents from DOM full-screen mode, and moves the top-level
* browser window out of full-screen mode. If aRunAsync is true, this runs

View File

@ -7391,7 +7391,7 @@ nsDocument::OnPageHide(bool aPersisted,
// document to reset its state, so reset full-screen state in *this*
// document. OnPageHide() is called in every hidden document, so doing
// this ensures all hidden documents have their full-screen state reset.
ClearFullScreenStack();
CleanupFullscreenState();
// Next reset full-screen state in all visible documents in the doctree.
nsIDocument::ExitFullScreen(false);
@ -8581,7 +8581,7 @@ nsIDocument::ExitFullScreen(bool aRunAsync)
static bool
ResetFullScreen(nsIDocument* aDocument, void* aData) {
if (aDocument->IsFullScreenDoc()) {
static_cast<nsDocument*>(aDocument)->ClearFullScreenStack();
static_cast<nsDocument*>(aDocument)->CleanupFullscreenState();
NS_ASSERTION(!aDocument->IsFullScreenDoc(), "Should reset full-screen");
nsTArray<nsIDocument*>* changed = reinterpret_cast<nsTArray<nsIDocument*>*>(aData);
changed->AppendElement(aDocument);
@ -8659,7 +8659,7 @@ nsDocument::RestorePreviousFullScreenState()
nsIDocument* doc = fullScreenDoc;
while (doc != this) {
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc");
static_cast<nsDocument*>(doc)->ClearFullScreenStack();
static_cast<nsDocument*>(doc)->CleanupFullscreenState();
UnlockPointer();
DispatchFullScreenChange(doc);
doc = doc->GetParentDocument();
@ -8675,6 +8675,7 @@ nsDocument::RestorePreviousFullScreenState()
// Full-screen stack in document is empty. Go back up to the parent
// document. We'll pop the containing element off its stack, and use
// its next full-screen element as the full-screen element.
static_cast<nsDocument*>(doc)->CleanupFullscreenState();
doc = doc->GetParentDocument();
} else {
// Else we popped the top of the stack, and there's still another
@ -8768,21 +8769,46 @@ LogFullScreenDenied(bool aLogFailure, const char* aMessage, nsIDocument* aDoc)
aMessage);
}
void
nsDocument::ClearFullScreenStack()
nsresult
nsDocument::AddFullscreenApprovedObserver()
{
if (mFullScreenStack.IsEmpty()) {
return;
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
nsresult res = os->AddObserver(this, "fullscreen-approved", true);
NS_ENSURE_SUCCESS(res, res);
return NS_OK;
}
nsresult
nsDocument::RemoveFullscreenApprovedObserver()
{
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
NS_ENSURE_TRUE(os, NS_ERROR_FAILURE);
nsresult res = os->RemoveObserver(this, "fullscreen-approved");
NS_ENSURE_SUCCESS(res, res);
return NS_OK;
}
void
nsDocument::CleanupFullscreenState()
{
if (!mFullScreenStack.IsEmpty()) {
// The top element in the full-screen stack will have full-screen
// style bits set on it and its ancestors. Remove the style bits.
// Note the non-top elements won't have the style bits set.
Element* top = FullScreenStackTop();
NS_ASSERTION(top, "Should have a top when full-screen stack isn't empty");
if (top) {
nsEventStateManager::SetFullScreenState(top, false);
}
mFullScreenStack.Clear();
}
// The top element in the full-screen stack will have full-screen
// style bits set on it and its ancestors. Remove the style bits.
// Note the non-top elements won't have the style bits set.
Element* top = FullScreenStackTop();
NS_ASSERTION(top, "Should have a top when full-screen stack isn't empty");
if (top) {
nsEventStateManager::SetFullScreenState(top, false);
}
mFullScreenStack.Clear();
SetApprovedForFullscreen(false);
RemoveFullscreenApprovedObserver();
}
bool
@ -8950,6 +8976,8 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
}
}
AddFullscreenApprovedObserver();
// Stores a list of documents which we must dispatch "mozfullscreenchange"
// too. We're required by the spec to dispatch the events in root-to-leaf
// order, but we traverse the doctree in a leaf-to-root order, so we save
@ -9018,6 +9046,14 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
true);
e->PostDOMEvent();
// If this document hasn't already been approved in this session,
// check to see if the user has granted the fullscreen access
// to the document's principal's host, if it has one.
if (!mIsApprovedForFullscreen) {
mIsApprovedForFullscreen =
nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
}
// Remember this is the requesting full-screen document.
sFullScreenDoc = do_GetWeakReference(static_cast<nsIDocument*>(this));
@ -9246,19 +9282,6 @@ nsDocument::ClearPendingPointerLockRequest(bool aDispatchErrorEvents)
return;
}
nsCOMPtr<nsIDocument> doc(do_QueryReferent(sPendingPointerLockDoc));
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
if (!os) {
NS_WARNING("Lost observer service in ClearPendingPointerLockRequest()!");
return;
}
nsCOMPtr<nsIObserver> obs(do_QueryInterface(doc));
if (!os) {
NS_WARNING("Document must implement nsIObserver");
return;
}
os->RemoveObserver(obs, "fullscreen-approved");
if (aDispatchErrorEvents) {
DispatchPointerLockError(doc);
}
@ -9283,16 +9306,7 @@ nsDocument::SetPendingPointerLockRequest(Element* aElement)
// If there's an existing pending pointer lock request, deny it.
ClearPendingPointerLockRequest(true);
NS_ENSURE_TRUE(aElement != nsnull, NS_ERROR_FAILURE);
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
NS_ENSURE_TRUE(os != nsnull, NS_ERROR_FAILURE);
nsCOMPtr<nsIObserver> obs(do_QueryInterface(aElement->OwnerDoc()));
NS_ENSURE_TRUE(obs != nsnull, NS_ERROR_FAILURE);
nsresult res = os->AddObserver(obs, "fullscreen-approved", true);
NS_ENSURE_SUCCESS(res, res);
NS_ENSURE_TRUE(aElement != nsnull, NS_ERROR_FAILURE);
sPendingPointerLockDoc = do_GetWeakReference(aElement->OwnerDoc());
sPendingPointerLockElement = do_GetWeakReference(aElement);
@ -9303,6 +9317,12 @@ nsDocument::SetPendingPointerLockRequest(Element* aElement)
return NS_OK;
}
void
nsDocument::SetApprovedForFullscreen(bool aIsApproved)
{
mIsApprovedForFullscreen = aIsApproved;
}
nsresult
nsDocument::Observe(nsISupports *aSubject,
@ -9311,11 +9331,17 @@ nsDocument::Observe(nsISupports *aSubject,
{
if (strcmp("fullscreen-approved", aTopic) == 0) {
nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
if (subject != this) {
return NS_OK;
}
SetApprovedForFullscreen(true);
nsCOMPtr<nsIDocument> doc(do_QueryReferent(sPendingPointerLockDoc));
if (subject == doc) {
if (this == doc) {
// This doc has a pointer lock request, waiting for fullscreen to be
// approved before it can be granted. Process the pointer lock request.
nsCOMPtr<Element> element(do_QueryReferent(sPendingPointerLockElement));
nsDocument::ClearPendingPointerLockRequest(false);
nsAsyncPointerLockRequest::Request(element, doc);
nsAsyncPointerLockRequest::Request(element, this);
}
}
return NS_OK;
@ -9339,8 +9365,8 @@ nsDocument::RequestPointerLock(Element* aElement)
return;
}
if (!nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen")) {
// Domain isn't yet approved for fullscreen, so we must wait until
if (!mIsApprovedForFullscreen) {
// Document isn't yet approved for fullscreen, so we must wait until
// it's been approved.
if (NS_FAILED(SetPendingPointerLockRequest(aElement))) {
NS_WARNING("Failed to make pointer lock request pending!");

View File

@ -929,6 +929,8 @@ public:
virtual void AsyncRequestFullScreen(Element* aElement);
virtual void RestorePreviousFullScreenState();
virtual bool IsFullScreenDoc();
virtual void SetApprovedForFullscreen(bool aIsApproved);
static void ExitFullScreen();
// This is called asynchronously by nsIDocument::AsyncRequestFullScreen()
@ -939,7 +941,14 @@ public:
// Removes all elements from the full-screen stack, removing full-scren
// styles from the top element in the stack.
void ClearFullScreenStack();
void CleanupFullscreenState();
// Add/remove "fullscreen-approved" observer service notification listener.
// Chrome sends us a notification when fullscreen is approved for a
// document, with the notification subject as the document that was approved.
// We maintain this listener while in fullscreen mode.
nsresult AddFullscreenApprovedObserver();
nsresult RemoveFullscreenApprovedObserver();
// Pushes aElement onto the full-screen stack, and removes full-screen styles
// from the former full-screen stack top, and its ancestors, and applies the
@ -1180,6 +1189,21 @@ protected:
// terminated instead of letting it finish at its own pace.
bool mParserAborted:1;
// Whether this document has been approved for fullscreen, either by explicit
// approval via the fullscreen-approval UI, or because it received
// approval because its document's host already had the "fullscreen"
// permission granted when the document requested fullscreen.
//
// Note if a document's principal doesn't have a host, the permission manager
// can't store permissions for it, so we can only manage approval using this
// flag.
//
// Note we must track this separately from the "fullscreen" permission,
// so that pending pointer lock requests can determine whether documents
// whose principal doesn't have a host (i.e. those which can't store
// permissions in the permission manager) have been approved for fullscreen.
bool mIsApprovedForFullscreen:1;
PRUint8 mXMLDeclarationBits;
nsInterfaceHashtable<nsPtrHashKey<nsIContent>, nsPIBoxObject> *mBoxObjectTable;