mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 22:32:46 +00:00
Bug 684620 - Implement cross process fullscreen API for B2G apps and web content. r=jlebar
* * * Bug 684620 - Fix in-process fullscreen in B2G. r=?
This commit is contained in:
parent
e3bcda27f0
commit
cd61327986
@ -383,6 +383,12 @@ Services.obs.addObserver(function onSystemMessage(subject, topic, data) {
|
||||
});
|
||||
}, 'system-messages-open-app', false);
|
||||
|
||||
Services.obs.addObserver(function(aSubject, aTopic, aData) {
|
||||
shell.sendEvent(shell.contentBrowser.contentWindow,
|
||||
"mozChromeEvent", { type: "fullscreenoriginchange",
|
||||
fullscreenorigin: aData } );
|
||||
}, "fullscreen-origin-change", false);
|
||||
|
||||
(function Repl() {
|
||||
if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
|
||||
return;
|
||||
|
@ -92,8 +92,8 @@ class Element;
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0x8c6a1e62, 0xd5ad, 0x4297, \
|
||||
{ 0xb9, 0x41, 0x64, 0x49, 0x22, 0x2e, 0xc4, 0xf0 } }
|
||||
{ 0xbd70ee06, 0x2a7d, 0x4258, \
|
||||
{ 0x86, 0x4b, 0xbd, 0x28, 0xad, 0x9f, 0xd1, 0x41 } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
@ -723,6 +723,27 @@ public:
|
||||
*/
|
||||
virtual void AsyncRequestFullScreen(Element* aElement) = 0;
|
||||
|
||||
/**
|
||||
* Called when a frame in a child process has entered fullscreen or when a
|
||||
* fullscreen frame in a child process changes to another origin.
|
||||
* aFrameElement is the frame element which contains the child-process
|
||||
* fullscreen document, and aNewOrigin is the origin of the new fullscreen
|
||||
* document.
|
||||
*/
|
||||
virtual nsresult RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
|
||||
const nsAString& aNewOrigin) = 0;
|
||||
|
||||
/**
|
||||
* Called when a frame in a remote child document has rolled back fullscreen
|
||||
* so that all its fullscreen element stacks are empty; we must continue the
|
||||
* rollback in this parent process' doc tree branch which is fullscreen.
|
||||
* Note that only one branch of the document tree can have its documents in
|
||||
* fullscreen state at one time. We're in inconsistent state if the a
|
||||
* fullscreen document has a parent and that parent isn't fullscreen. We
|
||||
* preserve this property across process boundaries.
|
||||
*/
|
||||
virtual nsresult RemoteFrameFullscreenReverted() = 0;
|
||||
|
||||
/**
|
||||
* Restores the previous full-screen element to full-screen status. If there
|
||||
* is no former full-screen element, this exits full-screen, moving the
|
||||
|
@ -8499,7 +8499,7 @@ nsDocument::MozCancelFullScreen()
|
||||
}
|
||||
|
||||
// Runnable to set window full-screen mode. Used as a script runner
|
||||
// to ensure we only call nsGlobalWindow::SetFullScreen() when it's safe to
|
||||
// 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().
|
||||
@ -8547,13 +8547,54 @@ nsIDocument::ExitFullScreen(bool aRunAsync)
|
||||
nsDocument::ExitFullScreen();
|
||||
}
|
||||
|
||||
// Returns true if the document is a direct child of a cross process parent
|
||||
// mozbrowser iframe. This is the case when the document has a null parent,
|
||||
// and its DocShell reports that it is a browser frame.
|
||||
static bool
|
||||
ResetFullScreen(nsIDocument* aDocument, void* aData) {
|
||||
HasCrossProcessParent(nsIDocument* aDocument)
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Content) {
|
||||
return false;
|
||||
}
|
||||
if (aDocument->GetParentDocument() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
nsPIDOMWindow* win = aDocument->GetWindow();
|
||||
if (!win) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIDocShell> docShell = win->GetDocShell();
|
||||
if (!docShell) {
|
||||
return false;
|
||||
}
|
||||
bool isBrowserElement = false;
|
||||
docShell->GetIsBrowserElement(&isBrowserElement);
|
||||
return isBrowserElement;
|
||||
}
|
||||
|
||||
static bool
|
||||
ResetFullScreen(nsIDocument* aDocument, void* aData)
|
||||
{
|
||||
if (aDocument->IsFullScreenDoc()) {
|
||||
static_cast<nsDocument*>(aDocument)->CleanupFullscreenState();
|
||||
NS_ASSERTION(!aDocument->IsFullScreenDoc(), "Should reset full-screen");
|
||||
nsTArray<nsIDocument*>* changed = reinterpret_cast<nsTArray<nsIDocument*>*>(aData);
|
||||
changed->AppendElement(aDocument);
|
||||
|
||||
if (HasCrossProcessParent(aDocument)) {
|
||||
// We're at the top of the content-process side doc tree. Ask the parent
|
||||
// process to exit fullscreen.
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
os->NotifyObservers(aDocument, "ask-parent-to-exit-fullscreen", nullptr);
|
||||
}
|
||||
|
||||
// Dispatch a notification so that if this document has any
|
||||
// cross-process subdocuments, they'll be notified to exit fullscreen.
|
||||
// The BrowserElementParent listens for this event and performs the
|
||||
// cross process notification if it has a remote child process.
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
os->NotifyObservers(aDocument, "ask-children-to-exit-fullscreen", nullptr);
|
||||
|
||||
aDocument->EnumerateSubDocuments(ResetFullScreen, aData);
|
||||
}
|
||||
return true;
|
||||
@ -8623,8 +8664,15 @@ nsDocument::RestorePreviousFullScreenState()
|
||||
UnlockPointer();
|
||||
}
|
||||
|
||||
// Clear full-screen stacks in all descendant documents, bottom up.
|
||||
nsCOMPtr<nsIDocument> fullScreenDoc(do_QueryReferent(sFullScreenDoc));
|
||||
|
||||
// The fullscreen document may contain a <iframe mozbrowser> element which
|
||||
// has a cross process child. So send a notification so that its browser
|
||||
// parent will send a message to its child process to also exit fullscreen.
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
os->NotifyObservers(fullScreenDoc, "ask-children-to-exit-fullscreen", nullptr);
|
||||
|
||||
// Clear full-screen stacks in all descendant in process documents, bottom up.
|
||||
nsIDocument* doc = fullScreenDoc;
|
||||
while (doc != this) {
|
||||
NS_ASSERTION(doc->IsFullScreenDoc(), "Should be full-screen doc");
|
||||
@ -8641,6 +8689,12 @@ nsDocument::RestorePreviousFullScreenState()
|
||||
UnlockPointer();
|
||||
DispatchFullScreenChange(doc);
|
||||
if (static_cast<nsDocument*>(doc)->mFullScreenStack.IsEmpty()) {
|
||||
if (HasCrossProcessParent(doc)) {
|
||||
// Send notification to the parent process to tell it to rollback to
|
||||
// the previous fullscreen elements in its fullscreen element stacks.
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
os->NotifyObservers(doc, "ask-parent-to-rollback-fullscreen", nullptr);
|
||||
}
|
||||
// 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.
|
||||
@ -8665,6 +8719,18 @@ nsDocument::RestorePreviousFullScreenState()
|
||||
e->PostDOMEvent();
|
||||
}
|
||||
}
|
||||
|
||||
if (!nsContentUtils::HaveEqualPrincipals(doc, fullScreenDoc)) {
|
||||
// The origin which is fullscreen changed. Send a notification to
|
||||
// the root process so that a warning or approval UI can be shown
|
||||
// as necessary.
|
||||
nsAutoString origin;
|
||||
nsContentUtils::GetUTFOrigin(doc->NodePrincipal(), origin);
|
||||
nsIDocument* root = nsContentUtils::GetRootDocument(doc);
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
os->NotifyObservers(root, "fullscreen-origin-change", origin.get());
|
||||
}
|
||||
|
||||
sFullScreenDoc = do_GetWeakReference(doc);
|
||||
break;
|
||||
}
|
||||
@ -8700,7 +8766,9 @@ public:
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsDocument* doc = static_cast<nsDocument*>(mDoc.get());
|
||||
doc->RequestFullScreen(mElement, mWasCallerChrome);
|
||||
doc->RequestFullScreen(mElement,
|
||||
mWasCallerChrome,
|
||||
/* aNotifyOnOriginChange */ true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -8867,7 +8935,7 @@ IsInActiveTab(nsIDocument* aDoc)
|
||||
if (!isActive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> dsti = do_QueryInterface(container);
|
||||
if (!dsti) {
|
||||
return false;
|
||||
@ -8896,8 +8964,43 @@ IsInActiveTab(nsIDocument* aDoc)
|
||||
return activeWindow == rootWin;
|
||||
}
|
||||
|
||||
nsresult nsDocument::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
|
||||
const nsAString& aOrigin)
|
||||
{
|
||||
// Ensure the frame element is the fullscreen element in this document.
|
||||
// If the frame element is already the fullscreen element in this document,
|
||||
// this has no effect.
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aFrameElement));
|
||||
RequestFullScreen(content->AsElement(),
|
||||
/* aWasCallerChrome */ false,
|
||||
/* aNotifyOnOriginChange */ false);
|
||||
|
||||
// Origin changed in child process, send notifiction, so that chrome can
|
||||
// update the UI to reflect the fullscreen origin change if necessary.
|
||||
// The BrowserElementChild listens on this, and forwards it over its
|
||||
// parent process, where it is redispatched. Chrome (in the root process,
|
||||
// which could be *this* process) listens for this notification so that
|
||||
// it can show a warning or approval UI.
|
||||
if (!aOrigin.IsEmpty()) {
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
os->NotifyObservers(nsContentUtils::GetRootDocument(this),
|
||||
"fullscreen-origin-change",
|
||||
PromiseFlatString(aOrigin).get());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsDocument::RemoteFrameFullscreenReverted()
|
||||
{
|
||||
RestorePreviousFullScreenState();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
nsDocument::RequestFullScreen(Element* aElement,
|
||||
bool aWasCallerChrome,
|
||||
bool aNotifyOnOriginChange)
|
||||
{
|
||||
NS_ASSERTION(aElement,
|
||||
"Must pass non-null element to nsDocument::RequestFullScreen");
|
||||
@ -8922,7 +9025,7 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
}
|
||||
if (GetFullScreenElement() &&
|
||||
!nsContentUtils::ContentIsDescendantOf(aElement, GetFullScreenElement())) {
|
||||
// If this document is full-screen, only grant full-screen requests from
|
||||
// If this document is full-screen, only grant full-screen requests from
|
||||
// a descendent of the current full-screen element.
|
||||
LogFullScreenDenied(true, "FullScreenDeniedNotDescendant", this);
|
||||
return;
|
||||
@ -8958,12 +9061,12 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
|
||||
// Remember the root document, so that if a full-screen document is hidden
|
||||
// we can reset full-screen state in the remaining visible full-screen documents.
|
||||
nsIDocument* fullScreenDoc = nsContentUtils::GetRootDocument(this);
|
||||
sFullScreenRootDoc = do_GetWeakReference(fullScreenDoc);
|
||||
nsIDocument* fullScreenRootDoc = nsContentUtils::GetRootDocument(this);
|
||||
sFullScreenRootDoc = do_GetWeakReference(fullScreenRootDoc);
|
||||
|
||||
// If a document is already in fullscreen, then unlock the mouse pointer
|
||||
// before setting a new document to fullscreen
|
||||
if (fullScreenDoc) {
|
||||
if (sFullScreenDoc) {
|
||||
UnlockPointer();
|
||||
}
|
||||
|
||||
@ -8981,15 +9084,18 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
DebugOnly<bool> x = FullScreenStackPush(aElement);
|
||||
NS_ASSERTION(x, "Full-screen state of requesting doc should always change!");
|
||||
changed.AppendElement(this);
|
||||
|
||||
|
||||
// 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.
|
||||
// visible there. Stop when we reach the root document.
|
||||
nsIDocument* child = this;
|
||||
nsIDocument* parent;
|
||||
while ((parent = child->GetParentDocument())) {
|
||||
while (true) {
|
||||
nsIDocument* parent = child->GetParentDocument();
|
||||
if (!parent) {
|
||||
break;
|
||||
}
|
||||
Element* element = parent->FindContentForSubDocument(child)->AsElement();
|
||||
if (static_cast<nsDocument*>(parent)->FullScreenStackPush(element)) {
|
||||
changed.AppendElement(parent);
|
||||
@ -9012,10 +9118,12 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
|
||||
// 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.
|
||||
// to the document's principal's host, if it has one. Note that documents
|
||||
// in web apps which are the same origin as the web app are considered
|
||||
// trusted and so are automatically approved.
|
||||
if (!mIsApprovedForFullscreen) {
|
||||
mIsApprovedForFullscreen =
|
||||
GetWindow()->IsPartOfApp() ||
|
||||
GetWindow()->IsInAppOrigin() ||
|
||||
nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
|
||||
}
|
||||
|
||||
@ -9052,6 +9160,21 @@ nsDocument::RequestFullScreen(Element* aElement, bool aWasCallerChrome)
|
||||
"GetMozFullScreenElement should match GetFullScreenElement()");
|
||||
#endif
|
||||
|
||||
// The origin which is fullscreen changed, send a notifiction so that the
|
||||
// root document knows the origin of the document which requested fullscreen.
|
||||
// This is used for the fullscreen approval UI. If we're in a child
|
||||
// process, the root BrowserElementChild listens for this notification,
|
||||
// and forwards it across to its BrowserElementParent, which
|
||||
// re-broadcasts the message for the root document in its process.
|
||||
if (aNotifyOnOriginChange &&
|
||||
!nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
nsIDocument* root = nsContentUtils::GetRootDocument(this);
|
||||
nsAutoString origin;
|
||||
nsContentUtils::GetUTFOrigin(NodePrincipal(), origin);
|
||||
os->NotifyObservers(root, "fullscreen-origin-change", origin.get());
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
@ -937,14 +937,26 @@ public:
|
||||
virtual void RestorePreviousFullScreenState();
|
||||
virtual bool IsFullScreenDoc();
|
||||
virtual void SetApprovedForFullscreen(bool aIsApproved);
|
||||
virtual nsresult RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
|
||||
const nsAString& aNewOrigin);
|
||||
|
||||
virtual nsresult RemoteFrameFullscreenReverted();
|
||||
|
||||
static void ExitFullScreen();
|
||||
|
||||
// This is called asynchronously by nsIDocument::AsyncRequestFullScreen()
|
||||
// to move document into full-screen mode if allowed. aWasCallerChrome
|
||||
// to move this 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);
|
||||
// by chrome code. aNotifyOnOriginChange denotes whether we should send a
|
||||
// fullscreen-origin-change notification if requesting fullscreen in this
|
||||
// document causes the origin which is fullscreen to change. We may want to
|
||||
// *not* send this notification if we're calling RequestFullscreen() as part
|
||||
// of a continuation of a request in a subdocument, whereupon the caller will
|
||||
// need to send the notification with the origin of the document which
|
||||
// originally requested fullscreen, not *this* document's origin.
|
||||
void RequestFullScreen(Element* aElement,
|
||||
bool aWasCallerChrome,
|
||||
bool aNotifyOnOriginChange);
|
||||
|
||||
// Removes all elements from the full-screen stack, removing full-scren
|
||||
// styles from the top element in the stack.
|
||||
|
@ -2342,3 +2342,4 @@ nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
|
||||
"remote-browser-frame-shown", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4762,14 +4762,18 @@ static const char*
|
||||
GetFullScreenError(nsIDocument* aDoc)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = aDoc->GetWindow();
|
||||
if (win && win->IsPartOfApp()) {
|
||||
if (win && win->IsInAppOrigin()) {
|
||||
// Request is in a web app and in the same origin as the web app.
|
||||
// Don't enforce as strict security checks for web apps, the user
|
||||
// is supposed to have trust in them. However documents cross-origin
|
||||
// to the web app must still confirm to the normal security checks.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!nsContentUtils::IsRequestFullScreenAllowed()) {
|
||||
return "FullScreenDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
|
||||
if (nsContentUtils::IsSitePermDeny(aDoc->NodePrincipal(), "fullscreen")) {
|
||||
return "FullScreenDeniedBlocked";
|
||||
}
|
||||
@ -4784,6 +4788,8 @@ nsresult nsGenericElement::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.
|
||||
// Note that requests for fullscreen inside a web app's origin are exempt
|
||||
// from this restriction.
|
||||
const char* error = GetFullScreenError(OwnerDoc());
|
||||
if (error) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
@ -4803,3 +4809,4 @@ nsresult nsGenericElement::MozRequestFullScreen()
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2593,3 +2593,37 @@ nsDOMWindowUtils::GetApp(mozIDOMApplication** aApplication)
|
||||
|
||||
return static_cast<nsGlobalWindow*>(window.get())->GetApp(aApplication);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMWindowUtils::RemoteFrameFullscreenChanged(nsIDOMElement* aFrameElement,
|
||||
const nsAString& aNewOrigin)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_STATE(window);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
|
||||
NS_ENSURE_STATE(doc);
|
||||
|
||||
doc->RemoteFrameFullscreenChanged(aFrameElement, aNewOrigin);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMWindowUtils::RemoteFrameFullscreenReverted()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_STATE(window);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc(do_QueryInterface(window->GetExtantDocument()));
|
||||
NS_ENSURE_STATE(doc);
|
||||
|
||||
doc->RemoteFrameFullscreenReverted();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDOMWindowUtils::ExitFullscreen()
|
||||
{
|
||||
nsIDocument::ExitFullScreen(/* async = */ false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -10661,6 +10661,34 @@ nsGlobalWindow::SetIsApp(bool aValue)
|
||||
mIsApp = aValue ? TriState_True : TriState_False;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindow::IsInAppOrigin()
|
||||
{
|
||||
FORWARD_TO_OUTER(IsInAppOrigin, (), false);
|
||||
|
||||
nsIPrincipal* principal = GetPrincipal();
|
||||
NS_ENSURE_TRUE(principal != nullptr, false);
|
||||
|
||||
// We go trough all window parents until we find one with |mIsApp| set to
|
||||
// something. If none is found, we are not part of an application.
|
||||
for (nsGlobalWindow* w = static_cast<nsGlobalWindow*>(this); w;
|
||||
w = static_cast<nsGlobalWindow*>(w->GetParentInternal())) {
|
||||
if (w->mIsApp == TriState_True) {
|
||||
// The window should be part of an application.
|
||||
MOZ_ASSERT(w->mApp);
|
||||
bool sameOrigin = false;
|
||||
return w->mAppPrincipal &&
|
||||
principal &&
|
||||
NS_SUCCEEDED(principal->Equals(w->mAppPrincipal, &sameOrigin)) &&
|
||||
sameOrigin;
|
||||
} else if (w->mIsApp == TriState_False) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsGlobalWindow::IsPartOfApp()
|
||||
{
|
||||
@ -10691,6 +10719,14 @@ nsGlobalWindow::SetApp(const nsAString& aManifestURL)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult res = NS_NewURI(getter_AddRefs(uri), aManifestURL);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
res = ssm->GetSimpleCodebasePrincipal(uri, getter_AddRefs(mAppPrincipal));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
mApp = app.forget();
|
||||
|
||||
return NS_OK;
|
||||
|
@ -385,6 +385,7 @@ public:
|
||||
virtual NS_HIDDEN_(void) RefreshCompartmentPrincipal();
|
||||
virtual NS_HIDDEN_(nsresult) SetFullScreenInternal(bool aIsFullScreen, bool aRequireTrust);
|
||||
virtual NS_HIDDEN_(bool) IsPartOfApp();
|
||||
virtual NS_HIDDEN_(bool) IsInAppOrigin();
|
||||
|
||||
// nsIDOMStorageIndexedDB
|
||||
NS_DECL_NSIDOMSTORAGEINDEXEDDB
|
||||
@ -978,6 +979,9 @@ protected:
|
||||
// iframe which is neither mozBrowser nor mozApp.
|
||||
TriState mIsApp : 2;
|
||||
|
||||
// Principal of the web app running in this window, if any.
|
||||
nsCOMPtr<nsIPrincipal> mAppPrincipal;
|
||||
|
||||
nsCOMPtr<nsIScriptContext> mContext;
|
||||
nsWeakPtr mOpener;
|
||||
nsCOMPtr<nsIControllers> mControllers;
|
||||
|
@ -602,6 +602,12 @@ public:
|
||||
*/
|
||||
virtual bool IsPartOfApp() = 0;
|
||||
|
||||
/**
|
||||
* Returns true of this window is part of an we app, and this window has
|
||||
* the same origin (principal) as the web app.
|
||||
*/
|
||||
virtual bool IsInAppOrigin() = 0;
|
||||
|
||||
protected:
|
||||
// The nsPIDOMWindow constructor. The aOuterWindow argument should
|
||||
// be null if and only if the created window itself is an outer
|
||||
|
@ -62,6 +62,10 @@ function BrowserElementChild() {
|
||||
};
|
||||
|
||||
BrowserElementChild.prototype = {
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
_init: function() {
|
||||
debug("Starting up.");
|
||||
sendAsyncMsg("hello");
|
||||
@ -137,6 +141,7 @@ BrowserElementChild.prototype = {
|
||||
addMsgListener("unblock-modal-prompt", this._recvStopWaiting);
|
||||
addMsgListener("fire-ctx-callback", this._recvFireCtxCallback);
|
||||
addMsgListener("owner-visibility-change", this._recvOwnerVisibilityChange);
|
||||
addMsgListener("exit-fullscreen", this._recvExitFullscreen.bind(this));
|
||||
|
||||
let els = Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Ci.nsIEventListenerService);
|
||||
@ -161,6 +166,35 @@ BrowserElementChild.prototype = {
|
||||
els.addSystemEventListener(global, 'scroll',
|
||||
this._scrollEventHandler.bind(this),
|
||||
/* useCapture = */ false);
|
||||
|
||||
Services.obs.addObserver(this,
|
||||
"fullscreen-origin-change",
|
||||
/* ownsWeak = */ true);
|
||||
|
||||
Services.obs.addObserver(this,
|
||||
'ask-parent-to-exit-fullscreen',
|
||||
/* ownsWeak = */ true);
|
||||
|
||||
Services.obs.addObserver(this,
|
||||
'ask-parent-to-rollback-fullscreen',
|
||||
/* ownsWeak = */ true);
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
// Ignore notifications not about our document.
|
||||
if (subject != content.document)
|
||||
return;
|
||||
switch (topic) {
|
||||
case 'fullscreen-origin-change':
|
||||
sendAsyncMsg('fullscreen-origin-change', data);
|
||||
break;
|
||||
case 'ask-parent-to-exit-fullscreen':
|
||||
sendAsyncMsg('exit-fullscreen');
|
||||
break;
|
||||
case 'ask-parent-to-rollback-fullscreen':
|
||||
sendAsyncMsg('rollback-fullscreen');
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_tryGetInnerWindowID: function(win) {
|
||||
@ -293,6 +327,13 @@ BrowserElementChild.prototype = {
|
||||
win.modalDepth--;
|
||||
},
|
||||
|
||||
_recvExitFullscreen: function() {
|
||||
var utils = content.document.defaultView
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
utils.exitFullscreen();
|
||||
},
|
||||
|
||||
_titleChangedHandler: function(e) {
|
||||
debug("Got titlechanged: (" + e.target.title + ")");
|
||||
var win = e.target.defaultView;
|
||||
|
@ -83,17 +83,17 @@ BrowserElementParentFactory.prototype = {
|
||||
|
||||
_observeInProcessBrowserFrameShown: function(frameLoader) {
|
||||
debug("In-process browser frame shown " + frameLoader);
|
||||
this._createBrowserElementParent(frameLoader);
|
||||
this._createBrowserElementParent(frameLoader, /* hasRemoteFrame = */ false);
|
||||
},
|
||||
|
||||
_observeRemoteBrowserFrameShown: function(frameLoader) {
|
||||
debug("Remote browser frame shown " + frameLoader);
|
||||
this._createBrowserElementParent(frameLoader);
|
||||
this._createBrowserElementParent(frameLoader, /* hasRemoteFrame = */ true);
|
||||
},
|
||||
|
||||
_createBrowserElementParent: function(frameLoader) {
|
||||
_createBrowserElementParent: function(frameLoader, hasRemoteFrame) {
|
||||
let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
|
||||
this._bepMap.set(frameElement, new BrowserElementParent(frameLoader));
|
||||
this._bepMap.set(frameElement, new BrowserElementParent(frameLoader, hasRemoteFrame));
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
@ -119,10 +119,11 @@ BrowserElementParentFactory.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
function BrowserElementParent(frameLoader) {
|
||||
function BrowserElementParent(frameLoader, hasRemoteFrame) {
|
||||
debug("Creating new BrowserElementParent object for " + frameLoader);
|
||||
this._domRequestCounter = 0;
|
||||
this._pendingDOMRequests = {};
|
||||
this._hasRemoteFrame = hasRemoteFrame;
|
||||
|
||||
this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
|
||||
if (!this._frameElement) {
|
||||
@ -162,6 +163,12 @@ function BrowserElementParent(frameLoader) {
|
||||
addMessageListener('got-screenshot', this._gotDOMRequestResult);
|
||||
addMessageListener('got-can-go-back', this._gotDOMRequestResult);
|
||||
addMessageListener('got-can-go-forward', this._gotDOMRequestResult);
|
||||
addMessageListener('fullscreen-origin-change', this._remoteFullscreenOriginChange);
|
||||
addMessageListener('rollback-fullscreen', this._remoteFrameFullscreenReverted);
|
||||
addMessageListener('exit-fullscreen', this._exitFullscreen);
|
||||
|
||||
let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
os.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true);
|
||||
|
||||
function defineMethod(name, fn) {
|
||||
XPCNativeWrapper.unwrap(self._frameElement)[name] = function() {
|
||||
@ -202,6 +209,10 @@ function BrowserElementParent(frameLoader) {
|
||||
}
|
||||
|
||||
BrowserElementParent.prototype = {
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
/**
|
||||
* You shouldn't touch this._frameElement or this._window if _isAlive is
|
||||
* false. (You'll likely get an exception if you do.)
|
||||
@ -216,6 +227,11 @@ BrowserElementParent.prototype = {
|
||||
return this._frameElement.ownerDocument.defaultView;
|
||||
},
|
||||
|
||||
get _windowUtils() {
|
||||
return this._window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
},
|
||||
|
||||
_sendAsyncMsg: function(msg, data) {
|
||||
this._frameElement.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader
|
||||
@ -435,6 +451,27 @@ BrowserElementParent.prototype = {
|
||||
this._sendAsyncMsg('owner-visibility-change',
|
||||
{visible: !this._window.document.mozHidden});
|
||||
},
|
||||
|
||||
_exitFullscreen: function() {
|
||||
this._windowUtils.exitFullscreen();
|
||||
},
|
||||
|
||||
_remoteFullscreenOriginChange: function(data) {
|
||||
let origin = data.json;
|
||||
this._windowUtils.remoteFrameFullscreenChanged(this._frameElement, origin);
|
||||
},
|
||||
|
||||
_remoteFrameFullscreenReverted: function(data) {
|
||||
this._windowUtils.remoteFrameFullscreenReverted();
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic == 'ask-children-to-exit-fullscreen' &&
|
||||
this._isAlive() &&
|
||||
this._frameElement.ownerDocument == subject &&
|
||||
this._hasRemoteFrame)
|
||||
this._sendAsyncMsg('exit-fullscreen');
|
||||
},
|
||||
};
|
||||
|
||||
var NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParentFactory]);
|
||||
|
@ -40,7 +40,7 @@ interface nsIDOMTouch;
|
||||
interface nsIDOMClientRect;
|
||||
interface mozIDOMApplication;
|
||||
|
||||
[scriptable, uuid(858578f1-9653-4d5c-821a-07479bf2d9b2)]
|
||||
[scriptable, uuid(b276a71e-21ee-4be6-894d-4039523e1ad8)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -761,6 +761,29 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
in long aX,
|
||||
in long aY);
|
||||
|
||||
|
||||
/**
|
||||
* Called when the remote child frame has changed its fullscreen state,
|
||||
* when entering fullscreen, and when the origin which is fullscreen changes.
|
||||
* aFrameElement is the iframe element which contains the child-process
|
||||
* fullscreen document, and aNewOrigin is the origin of the new fullscreen
|
||||
* document.
|
||||
*/
|
||||
void remoteFrameFullscreenChanged(in nsIDOMElement aFrameElement,
|
||||
in AString aNewOrigin);
|
||||
|
||||
/**
|
||||
* Called when the remote frame has popped all fullscreen elements off its
|
||||
* stack, so that the operation can complete on the parent side.
|
||||
*/
|
||||
void remoteFrameFullscreenReverted();
|
||||
|
||||
/**
|
||||
* Called when the child frame has fully exit fullscreen, so that the parent
|
||||
* process can also fully exit.
|
||||
*/
|
||||
void exitFullscreen();
|
||||
|
||||
// NOTE: following values are same as NS_QUERY_* in nsGUIEvent.h
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user