Bug 753978 - Be able to know if a window is part of an application. r=jlebar

This commit is contained in:
Mounir Lamouri 2012-05-10 17:56:21 -07:00
parent ac7264c069
commit 18041509b8
9 changed files with 103 additions and 10 deletions

View File

@ -937,7 +937,10 @@ nsFrameLoader::ShowRemoteFrame(const nsIntSize& size)
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (OwnerIsBrowserFrame() && os) {
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
"remote-browser-frame-shown", NULL);
"remote-browser-frame-shown",
mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)
? NS_LITERAL_STRING("is-moz-app:true").get()
: NS_LITERAL_STRING("is-moz-app:false").get());
}
} else {
nsRect dimensions;
@ -1522,7 +1525,10 @@ nsFrameLoader::MaybeCreateDocShell()
if (OwnerIsBrowserFrame() && os) {
mDocShell->SetIsBrowserFrame(true);
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
"in-process-browser-frame-shown", NULL);
"in-process-browser-frame-shown",
mOwnerContent->HasAttr(kNameSpaceID_None, nsGkAtoms::mozapp)
? NS_LITERAL_STRING("is-moz-app:true").get()
: NS_LITERAL_STRING("is-moz-app:false").get());
}
// This is nasty, this code (the do_GetInterface(mDocShell) below)

View File

@ -108,6 +108,7 @@ GK_ATOM(ancestor, "ancestor")
GK_ATOM(ancestorOrSelf, "ancestor-or-self")
GK_ATOM(_and, "and")
GK_ATOM(any, "any")
GK_ATOM(mozapp, "mozapp")
GK_ATOM(applet, "applet")
GK_ATOM(applyImports, "apply-imports")
GK_ATOM(applyTemplates, "apply-templates")

View File

@ -284,6 +284,7 @@ nsGenericHTMLFrameElement::GetReallyIsBrowser(bool *aOut)
}
// Fail if the node principal isn't trusted.
// TODO: check properly for mozApps rights when mozApps will be less hacky.
nsIPrincipal *principal = NodePrincipal();
nsCOMPtr<nsIURI> principalURI;
principal->GetURI(getter_AddRefs(principalURI));

View File

@ -41,6 +41,17 @@ BrowserElementChild.prototype = {
Ci.nsIWebProgress.NOTIFY_LOCATION |
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW);
// A mozbrowser iframe contained inside a mozapp iframe should return false
// for nsWindowUtils::IsPartOfApp (unless the mozbrowser iframe is itself
// also mozapp). That is, mozapp is transitive down to its children, but
// mozbrowser serves as a barrier.
//
// This is because mozapp iframes have some privileges which we don't want
// to extend to untrusted mozbrowser content.
content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.setIsApp(false);
addEventListener('DOMTitleChanged',
this._titleChangedHandler.bind(this),
/* useCapture = */ true,

View File

@ -67,17 +67,17 @@ BrowserElementParent.prototype = {
}
},
_observeInProcessBrowserFrameShown: function(frameLoader) {
_observeInProcessBrowserFrameShown: function(frameLoader, isMozApp) {
debug("In-process browser frame shown " + frameLoader);
this._setUpMessageManagerListeners(frameLoader);
this._setUpMessageManagerListeners(frameLoader, isMozApp);
},
_observeRemoteBrowserFrameShown: function(frameLoader) {
_observeRemoteBrowserFrameShown: function(frameLoader, isMozApp) {
debug("Remote browser frame shown " + frameLoader);
this._setUpMessageManagerListeners(frameLoader);
this._setUpMessageManagerListeners(frameLoader, isMozApp);
},
_setUpMessageManagerListeners: function(frameLoader) {
_setUpMessageManagerListeners: function(frameLoader, isMozApp) {
let frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
if (!frameElement) {
debug("No frame element?");
@ -102,6 +102,12 @@ BrowserElementParent.prototype = {
mm.loadFrameScript("chrome://global/content/BrowserElementChild.js",
/* allowDelayedLoad = */ true);
if (isMozApp) {
mm.loadFrameScript("data:,content.QueryInterface(Ci.nsIInterfaceRequestor)" +
" .getInterface(Components.interfaces.nsIDOMWindowUtils)" +
" .setIsApp(true);",
/* allowDelayedLoad = */ true);
}
},
_recvHello: function(frameElement, data) {
@ -144,10 +150,10 @@ BrowserElementParent.prototype = {
}
break;
case 'remote-browser-frame-shown':
this._observeRemoteBrowserFrameShown(subject);
this._observeRemoteBrowserFrameShown(subject, data == "is-moz-app:true");
break;
case 'in-process-browser-frame-shown':
this._observeInProcessBrowserFrameShown(subject);
this._observeInProcessBrowserFrameShown(subject, data == "is-moz-app:true");
break;
case 'content-document-global-created':
this._observeContentGlobalCreated(subject);

View File

@ -2453,3 +2453,14 @@ nsDOMWindowUtils::SetScrollPositionClampingScrollPortSize(float aWidth, float aH
return NS_OK;
}
NS_IMETHODIMP
nsDOMWindowUtils::SetIsApp(bool aValue)
{
nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
static_cast<nsGlobalWindow*>(window.get())->SetIsApp(aValue);
return NS_OK;
}

View File

@ -692,6 +692,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
mShowFocusRingForContent(false),
mFocusByKeyOccurred(false),
mNotifiedIDDestroyed(false),
mIsApp(TriState_Unknown),
mTimeoutInsertionPoint(nsnull),
mTimeoutPublicIdCounter(1),
mTimeoutFiringDepth(0),
@ -10015,6 +10016,33 @@ nsGlobalWindow::SizeOfIncludingThis(nsWindowSizes* aWindowSizes) const
mNavigator->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf) : 0;
}
void
nsGlobalWindow::SetIsApp(bool aValue)
{
FORWARD_TO_OUTER_VOID(SetIsApp, (aValue));
mIsApp = aValue ? TriState_True : TriState_False;
}
bool
nsGlobalWindow::IsPartOfApp()
{
FORWARD_TO_OUTER(IsPartOfApp, (), TriState_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 = this; w;
w = static_cast<nsGlobalWindow*>(w->GetParentInternal())) {
if (w->mIsApp == TriState_True) {
return true;
} else if (w->mIsApp == TriState_False) {
return false;
}
}
return false;
}
// nsGlobalChromeWindow implementation
NS_IMPL_CYCLE_COLLECTION_CLASS(nsGlobalChromeWindow)

View File

@ -558,10 +558,23 @@ public:
void AddEventTargetObject(nsDOMEventTargetHelper* aObject);
void RemoveEventTargetObject(nsDOMEventTargetHelper* aObject);
/**
* Returns if the window is part of an application.
* It will check for the window app state and its parents until a window has
* an app state different from |TriState_Unknown|.
*/
bool IsPartOfApp();
protected:
friend class HashchangeCallback;
friend class nsBarProp;
enum TriState {
TriState_Unknown = -1,
TriState_False,
TriState_True
};
// Object Management
virtual ~nsGlobalWindow();
void CleanUp(bool aIgnoreModalDialog);
@ -811,6 +824,8 @@ protected:
nsresult CloneStorageEvent(const nsAString& aType,
nsCOMPtr<nsIDOMStorageEvent>& aEvent);
void SetIsApp(bool aValue);
// When adding new member variables, be careful not to create cycles
// through JavaScript. If there is any chance that a member variable
// could own objects that are implemented in JavaScript, then those
@ -878,6 +893,11 @@ protected:
// whether we've sent the destroy notification for our window id
bool mNotifiedIDDestroyed : 1;
// Whether the window is the window of an application frame.
// This is TriState_Unknown if the object is the content window of an
// iframe which is neither mozBrowser nor mozApp.
TriState mIsApp : 2;
nsCOMPtr<nsIScriptContext> mContext;
nsWeakPtr mOpener;
nsCOMPtr<nsIControllers> mControllers;

View File

@ -70,7 +70,7 @@ interface nsIDOMFile;
interface nsIFile;
interface nsIDOMTouch;
[scriptable, uuid(f75d0a14-e278-4716-a151-637862451a2f)]
[scriptable, uuid(2e5a1f37-786b-4a52-b0e3-f711ee2268a8)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -1149,4 +1149,13 @@ interface nsIDOMWindowUtils : nsISupports {
* The caller of this method must have UniversalXPConnect privileges.
*/
void setScrollPositionClampingScrollPortSize(in float aWidth, in float aHeight);
/**
* Mark if the window is an application window or not.
* This should only be set for top-level mozApp or mozBrowser frames.
* It should not be set for other frames unless you want a frame (and its
* children) to have a different value for IsPartOfApp than the frame's
* parent.
*/
void setIsApp(in boolean value);
};