mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 1170894 - Implement nsIFrameLoader::SwitchProcessAndLoadURI. r=smaug
This commit is contained in:
parent
bb3240f4f5
commit
57f614afaf
@ -275,6 +275,42 @@ nsFrameLoader::LoadURI(nsIURI* aURI)
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::SwitchProcessAndLoadURI(nsIURI* aURI)
|
||||
{
|
||||
nsCOMPtr<nsIURI> URIToLoad = aURI;
|
||||
nsRefPtr<TabParent> tp = nullptr;
|
||||
|
||||
MutableTabContext context;
|
||||
nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
|
||||
nsCOMPtr<mozIApplication> containingApp = GetContainingApp();
|
||||
|
||||
bool tabContextUpdated = true;
|
||||
if (ownApp) {
|
||||
tabContextUpdated = context.SetTabContextForAppFrame(ownApp, containingApp);
|
||||
} else if (OwnerIsBrowserFrame()) {
|
||||
// The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp.
|
||||
tabContextUpdated = context.SetTabContextForBrowserFrame(containingApp);
|
||||
} else {
|
||||
tabContextUpdated = context.SetTabContextForNormalFrame();
|
||||
}
|
||||
NS_ENSURE_STATE(tabContextUpdated);
|
||||
|
||||
nsCOMPtr<Element> ownerElement = mOwnerContent;
|
||||
tp = ContentParent::CreateBrowserOrApp(context, ownerElement, nullptr);
|
||||
if (!tp) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mRemoteBrowserShown = false;
|
||||
|
||||
nsresult rv = SwapRemoteBrowser(tp);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
LoadURI(URIToLoad);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameLoader::SetIsPrerendered()
|
||||
{
|
||||
@ -2603,6 +2639,57 @@ nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
|
||||
ShowRemoteFrame(ScreenIntSize(0, 0));
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrameLoader::SwapRemoteBrowser(nsITabParent* aTabParent)
|
||||
{
|
||||
nsRefPtr<TabParent> newParent = TabParent::GetFrom(aTabParent);
|
||||
if (!newParent || !mRemoteBrowser) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
if (!IsRemoteFrame()) {
|
||||
NS_WARNING("Switching from in-process to out-of-process is not supported.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (!OwnerIsBrowserOrAppFrame()) {
|
||||
NS_WARNING("Switching process for non-mozbrowser/app frame is not supported.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (newParent == mRemoteBrowser) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"frameloader-message-manager-will-change", nullptr);
|
||||
}
|
||||
|
||||
mRemoteBrowser->CacheFrameLoader(nullptr);
|
||||
mRemoteBrowser->SetOwnerElement(nullptr);
|
||||
mRemoteBrowser->Detach();
|
||||
mRemoteBrowser->Destroy();
|
||||
|
||||
if (mMessageManager) {
|
||||
mMessageManager->Disconnect();
|
||||
mMessageManager = nullptr;
|
||||
}
|
||||
|
||||
mRemoteBrowser = newParent;
|
||||
mRemoteBrowser->Attach(this);
|
||||
mChildID = mRemoteBrowser->Manager()->ChildID();
|
||||
ReallyLoadFrameScripts();
|
||||
InitializeBrowserAPI();
|
||||
|
||||
if (os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, this),
|
||||
"frameloader-message-manager-changed", nullptr);
|
||||
}
|
||||
if (!mRemoteBrowserShown) {
|
||||
ShowRemoteFrame(ScreenIntSize(0, 0));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews,
|
||||
nsIDocument* aContainerDoc)
|
||||
|
@ -181,6 +181,8 @@ public:
|
||||
*/
|
||||
void SetRemoteBrowser(nsITabParent* aTabParent);
|
||||
|
||||
nsresult SwapRemoteBrowser(nsITabParent* aTabParent);
|
||||
|
||||
/**
|
||||
* Stashes a detached view on the frame loader. We do this when we're
|
||||
* destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
|
||||
|
@ -16,7 +16,7 @@ interface nsIDOMElement;
|
||||
interface nsITabParent;
|
||||
interface nsILoadContext;
|
||||
|
||||
[scriptable, builtinclass, uuid(d24f9330-ae4e-11e4-ab27-0800200c9a66)]
|
||||
[scriptable, builtinclass, uuid(c6e00815-b7a1-4544-b309-a85b86cb1747)]
|
||||
interface nsIFrameLoader : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -49,6 +49,14 @@ interface nsIFrameLoader : nsISupports
|
||||
*/
|
||||
void loadURI(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Loads the specified URI in this frame but using a different process.
|
||||
* Behaves identically to loadURI, except that this method only works
|
||||
* with remote frame.
|
||||
* Throws an exception with non-remote frames.
|
||||
*/
|
||||
void switchProcessAndLoadURI(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Puts the frameloader in prerendering mode.
|
||||
*/
|
||||
|
@ -840,3 +840,5 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
|
||||
[test_postMessages.html]
|
||||
support-files = worker_postMessages.js
|
||||
[test_window_proto.html]
|
||||
[test_frameLoader_switchProcess.html]
|
||||
skip-if = e10s || os != 'linux' || buildapp != 'browser'
|
||||
|
84
dom/base/test/test_frameLoader_switchProcess.html
Normal file
84
dom/base/test/test_frameLoader_switchProcess.html
Normal file
@ -0,0 +1,84 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test frameLoader SwitchProcessAndLoadURI</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var Cc = SpecialPowers.Cc;
|
||||
|
||||
function expectProcessCreated() {
|
||||
return new Promise((resolve, reject) => {
|
||||
var topic = "process-priority-manager:TEST-ONLY:process-created";
|
||||
function observer() {
|
||||
SpecialPowers.removeObserver(observer, topic);
|
||||
ok(true, "Expect process created");
|
||||
resolve();
|
||||
}
|
||||
SpecialPowers.addObserver(observer, topic, /* weak = */ false);
|
||||
});
|
||||
}
|
||||
|
||||
function switchProcessAndLoadURI(iframe, url) {
|
||||
var fl = SpecialPowers.wrap(iframe)
|
||||
.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader;
|
||||
var uri = SpecialPowers.Services.io.newURI(url, null, null);
|
||||
fl.switchProcessAndLoadURI(uri);
|
||||
}
|
||||
|
||||
var messageManager;
|
||||
|
||||
function runTest() {
|
||||
ok(true, "Run Test");
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("mozbrowser", "true");
|
||||
iframe.setAttribute("remote", "true");
|
||||
iframe.setAttribute("src", "http://example.org");
|
||||
|
||||
expectProcessCreated()
|
||||
.then(() => new Promise(next => {
|
||||
iframe.addEventListener("mozbrowserloadend", function loadend(e) {
|
||||
iframe.removeEventListener("mozbrowserloadend", loadend);
|
||||
ok(true, "Got mozbrowserloadend");
|
||||
mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
expectProcessCreated().then(next);
|
||||
switchProcessAndLoadURI(iframe, "data:text/html,%3Cscript%3Ealert(true)%3C/script%3E");
|
||||
});
|
||||
}))
|
||||
.then(() => new Promise(next => {
|
||||
var newMessageManager = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
isnot(messageManager, newMessageManager, "Got a new message manager");
|
||||
messageManager = newMessageManager;
|
||||
iframe.addEventListener("mozbrowsershowmodalprompt", function prompt(e) {
|
||||
iframe.removeEventListener("mozbrowsershowmodalprompt", prompt);
|
||||
ok(true, "Browser API still works after process switch");
|
||||
next();
|
||||
});
|
||||
}))
|
||||
.then(SimpleTest.finish);
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
// XXX Set LRUPoolLevels to 2 to avoid breaking priority tests
|
||||
{ "set": [["dom.ipc.processPriorityManager.BACKGROUND.LRUPoolLevels", 2],
|
||||
["dom.ipc.processPriorityManager.BACKGROUND_PERCEIVABLE.LRUPoolLevels", 2],
|
||||
["dom.ipc.processPriorityManager.testMode", true],
|
||||
["dom.ipc.processPriorityManager.enabled", true],
|
||||
["dom.ipc.tabs.disabled", false],
|
||||
["dom.ipc.processCount", 3],
|
||||
["dom.mozBrowserFramesEnabled", true]] },
|
||||
() => SpecialPowers.pushPermissions([
|
||||
{ "type": "browser", "allow": 1, "context": document }
|
||||
], runTest));
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -77,6 +77,8 @@ function BrowserElementParent() {
|
||||
Services.obs.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true);
|
||||
Services.obs.addObserver(this, 'copypaste-docommand', /* ownsWeak = */ true);
|
||||
Services.obs.addObserver(this, 'ask-children-to-execute-copypaste-command', /* ownsWeak = */ true);
|
||||
Services.obs.addObserver(this, 'frameloader-message-manager-will-change', /* ownsWeak = */ true);
|
||||
Services.obs.addObserver(this, 'frameloader-message-manager-changed', /* ownsWeak = */ true);
|
||||
}
|
||||
|
||||
BrowserElementParent.prototype = {
|
||||
@ -161,10 +163,17 @@ BrowserElementParent.prototype = {
|
||||
|
||||
_setupMessageListener: function() {
|
||||
this._mm = this._frameLoader.messageManager;
|
||||
let self = this;
|
||||
let isWidget = this._frameLoader
|
||||
.QueryInterface(Ci.nsIFrameLoader)
|
||||
.ownerIsWidget;
|
||||
this._isWidget = this._frameLoader
|
||||
.QueryInterface(Ci.nsIFrameLoader)
|
||||
.ownerIsWidget;
|
||||
this._mm.addMessageListener('browser-element-api:call', this);
|
||||
this._mm.loadFrameScript("chrome://global/content/extensions.js", true);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMsg) {
|
||||
if (!this._isAlive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Messages we receive are handed to functions which take a (data) argument,
|
||||
// where |data| is the message manager's data object.
|
||||
@ -222,20 +231,15 @@ BrowserElementParent.prototype = {
|
||||
"opentab": this._fireEventFromMsg
|
||||
};
|
||||
|
||||
this._mm.addMessageListener('browser-element-api:call', function(aMsg) {
|
||||
if (!self._isAlive()) {
|
||||
return;
|
||||
}
|
||||
if (aMsg.data.msg_name in mmCalls) {
|
||||
return mmCalls[aMsg.data.msg_name].apply(this, arguments);
|
||||
} else if (!this._isWidget && aMsg.data.msg_name in mmSecuritySensitiveCalls) {
|
||||
return mmSecuritySensitiveCalls[aMsg.data.msg_name].apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
if (aMsg.data.msg_name in mmCalls) {
|
||||
return mmCalls[aMsg.data.msg_name].apply(self, arguments);
|
||||
} else if (!isWidget && aMsg.data.msg_name in mmSecuritySensitiveCalls) {
|
||||
return mmSecuritySensitiveCalls[aMsg.data.msg_name]
|
||||
.apply(self, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
this._mm.loadFrameScript("chrome://global/content/extensions.js", true);
|
||||
_removeMessageListener: function() {
|
||||
this._mm.removeMessageListener('browser-element-api:call', this);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1105,6 +1109,16 @@ BrowserElementParent.prototype = {
|
||||
this._sendAsyncMsg('copypaste-do-command', { command: data });
|
||||
}
|
||||
break;
|
||||
case 'frameloader-message-manager-will-change':
|
||||
if (this._isAlive() && subject == this._frameLoader) {
|
||||
this._removeMessageListener();
|
||||
}
|
||||
break;
|
||||
case 'frameloader-message-manager-changed':
|
||||
if (this._isAlive() && subject == this._frameLoader) {
|
||||
this._setupMessageListener();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug('Unknown topic: ' + topic);
|
||||
break;
|
||||
|
@ -66,10 +66,13 @@ nsBrowserElement::InitBrowserElementAPI()
|
||||
return;
|
||||
}
|
||||
|
||||
mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
|
||||
if (mBrowserElementAPI) {
|
||||
mBrowserElementAPI->SetFrameLoader(frameLoader);
|
||||
if (!mBrowserElementAPI) {
|
||||
mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
|
||||
if (NS_WARN_IF(!mBrowserElementAPI)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mBrowserElementAPI->SetFrameLoader(frameLoader);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -278,6 +278,7 @@ TabParent::TabParent(nsIContentParent* aManager,
|
||||
, mManager(aManager)
|
||||
, mMarkedDestroying(false)
|
||||
, mIsDestroyed(false)
|
||||
, mIsDetached(true)
|
||||
, mAppPackageFileDescriptorSent(false)
|
||||
, mSendOfflineStatus(true)
|
||||
, mChromeFlags(aChromeFlags)
|
||||
@ -481,6 +482,35 @@ TabParent::Destroy()
|
||||
mMarkedDestroying = true;
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Detach()
|
||||
{
|
||||
if (mIsDetached) {
|
||||
return;
|
||||
}
|
||||
RemoveWindowListeners();
|
||||
if (RenderFrameParent* frame = GetRenderFrame()) {
|
||||
RemoveTabParentFromTable(frame->GetLayersId());
|
||||
}
|
||||
mIsDetached = true;
|
||||
}
|
||||
|
||||
void
|
||||
TabParent::Attach(nsFrameLoader* aFrameLoader)
|
||||
{
|
||||
MOZ_ASSERT(mIsDetached);
|
||||
if (!mIsDetached) {
|
||||
return;
|
||||
}
|
||||
Element* ownerElement = aFrameLoader->GetOwnerContent();
|
||||
SetOwnerElement(ownerElement);
|
||||
if (RenderFrameParent* frame = GetRenderFrame()) {
|
||||
AddTabParentToTable(frame->GetLayersId(), this);
|
||||
frame->OwnerContentChanged(ownerElement);
|
||||
}
|
||||
mIsDetached = false;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::Recv__delete__()
|
||||
{
|
||||
|
@ -122,6 +122,8 @@ public:
|
||||
nsIXULBrowserWindow* GetXULBrowserWindow();
|
||||
|
||||
void Destroy();
|
||||
void Detach();
|
||||
void Attach(nsFrameLoader* aFrameLoader);
|
||||
|
||||
void RemoveWindowListeners();
|
||||
void AddWindowListeners();
|
||||
@ -516,6 +518,8 @@ private:
|
||||
bool mMarkedDestroying;
|
||||
// When true, the TabParent is invalid and we should not send IPC messages anymore.
|
||||
bool mIsDestroyed;
|
||||
// When true, the TabParent is detached from the frame loader.
|
||||
bool mIsDetached;
|
||||
// Whether we have already sent a FileDescriptor for the app package.
|
||||
bool mAppPackageFileDescriptorSent;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user