mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +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;
|
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
|
NS_IMETHODIMP
|
||||||
nsFrameLoader::SetIsPrerendered()
|
nsFrameLoader::SetIsPrerendered()
|
||||||
{
|
{
|
||||||
@ -2603,6 +2639,57 @@ nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
|
|||||||
ShowRemoteFrame(ScreenIntSize(0, 0));
|
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
|
void
|
||||||
nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews,
|
nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews,
|
||||||
nsIDocument* aContainerDoc)
|
nsIDocument* aContainerDoc)
|
||||||
|
@ -181,6 +181,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetRemoteBrowser(nsITabParent* aTabParent);
|
void SetRemoteBrowser(nsITabParent* aTabParent);
|
||||||
|
|
||||||
|
nsresult SwapRemoteBrowser(nsITabParent* aTabParent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stashes a detached view on the frame loader. We do this when we're
|
* Stashes a detached view on the frame loader. We do this when we're
|
||||||
* destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
|
* destroying the nsSubDocumentFrame. If the nsSubdocumentFrame is
|
||||||
|
@ -16,7 +16,7 @@ interface nsIDOMElement;
|
|||||||
interface nsITabParent;
|
interface nsITabParent;
|
||||||
interface nsILoadContext;
|
interface nsILoadContext;
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(d24f9330-ae4e-11e4-ab27-0800200c9a66)]
|
[scriptable, builtinclass, uuid(c6e00815-b7a1-4544-b309-a85b86cb1747)]
|
||||||
interface nsIFrameLoader : nsISupports
|
interface nsIFrameLoader : nsISupports
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -49,6 +49,14 @@ interface nsIFrameLoader : nsISupports
|
|||||||
*/
|
*/
|
||||||
void loadURI(in nsIURI aURI);
|
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.
|
* Puts the frameloader in prerendering mode.
|
||||||
*/
|
*/
|
||||||
|
@ -840,3 +840,5 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g'
|
|||||||
[test_postMessages.html]
|
[test_postMessages.html]
|
||||||
support-files = worker_postMessages.js
|
support-files = worker_postMessages.js
|
||||||
[test_window_proto.html]
|
[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, 'oop-frameloader-crashed', /* ownsWeak = */ true);
|
||||||
Services.obs.addObserver(this, 'copypaste-docommand', /* 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, '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 = {
|
BrowserElementParent.prototype = {
|
||||||
@ -161,10 +163,17 @@ BrowserElementParent.prototype = {
|
|||||||
|
|
||||||
_setupMessageListener: function() {
|
_setupMessageListener: function() {
|
||||||
this._mm = this._frameLoader.messageManager;
|
this._mm = this._frameLoader.messageManager;
|
||||||
let self = this;
|
this._isWidget = this._frameLoader
|
||||||
let isWidget = this._frameLoader
|
.QueryInterface(Ci.nsIFrameLoader)
|
||||||
.QueryInterface(Ci.nsIFrameLoader)
|
.ownerIsWidget;
|
||||||
.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,
|
// Messages we receive are handed to functions which take a (data) argument,
|
||||||
// where |data| is the message manager's data object.
|
// where |data| is the message manager's data object.
|
||||||
@ -222,20 +231,15 @@ BrowserElementParent.prototype = {
|
|||||||
"opentab": this._fireEventFromMsg
|
"opentab": this._fireEventFromMsg
|
||||||
};
|
};
|
||||||
|
|
||||||
this._mm.addMessageListener('browser-element-api:call', function(aMsg) {
|
if (aMsg.data.msg_name in mmCalls) {
|
||||||
if (!self._isAlive()) {
|
return mmCalls[aMsg.data.msg_name].apply(this, arguments);
|
||||||
return;
|
} 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) {
|
_removeMessageListener: function() {
|
||||||
return mmCalls[aMsg.data.msg_name].apply(self, arguments);
|
this._mm.removeMessageListener('browser-element-api:call', this);
|
||||||
} 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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1105,6 +1109,16 @@ BrowserElementParent.prototype = {
|
|||||||
this._sendAsyncMsg('copypaste-do-command', { command: data });
|
this._sendAsyncMsg('copypaste-do-command', { command: data });
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
debug('Unknown topic: ' + topic);
|
debug('Unknown topic: ' + topic);
|
||||||
break;
|
break;
|
||||||
|
@ -66,10 +66,13 @@ nsBrowserElement::InitBrowserElementAPI()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
|
if (!mBrowserElementAPI) {
|
||||||
if (mBrowserElementAPI) {
|
mBrowserElementAPI = do_CreateInstance("@mozilla.org/dom/browser-element-api;1");
|
||||||
mBrowserElementAPI->SetFrameLoader(frameLoader);
|
if (NS_WARN_IF(!mBrowserElementAPI)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
mBrowserElementAPI->SetFrameLoader(frameLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -278,6 +278,7 @@ TabParent::TabParent(nsIContentParent* aManager,
|
|||||||
, mManager(aManager)
|
, mManager(aManager)
|
||||||
, mMarkedDestroying(false)
|
, mMarkedDestroying(false)
|
||||||
, mIsDestroyed(false)
|
, mIsDestroyed(false)
|
||||||
|
, mIsDetached(true)
|
||||||
, mAppPackageFileDescriptorSent(false)
|
, mAppPackageFileDescriptorSent(false)
|
||||||
, mSendOfflineStatus(true)
|
, mSendOfflineStatus(true)
|
||||||
, mChromeFlags(aChromeFlags)
|
, mChromeFlags(aChromeFlags)
|
||||||
@ -481,6 +482,35 @@ TabParent::Destroy()
|
|||||||
mMarkedDestroying = true;
|
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
|
bool
|
||||||
TabParent::Recv__delete__()
|
TabParent::Recv__delete__()
|
||||||
{
|
{
|
||||||
|
@ -122,6 +122,8 @@ public:
|
|||||||
nsIXULBrowserWindow* GetXULBrowserWindow();
|
nsIXULBrowserWindow* GetXULBrowserWindow();
|
||||||
|
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
void Detach();
|
||||||
|
void Attach(nsFrameLoader* aFrameLoader);
|
||||||
|
|
||||||
void RemoveWindowListeners();
|
void RemoveWindowListeners();
|
||||||
void AddWindowListeners();
|
void AddWindowListeners();
|
||||||
@ -516,6 +518,8 @@ private:
|
|||||||
bool mMarkedDestroying;
|
bool mMarkedDestroying;
|
||||||
// When true, the TabParent is invalid and we should not send IPC messages anymore.
|
// When true, the TabParent is invalid and we should not send IPC messages anymore.
|
||||||
bool mIsDestroyed;
|
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.
|
// Whether we have already sent a FileDescriptor for the app package.
|
||||||
bool mAppPackageFileDescriptorSent;
|
bool mAppPackageFileDescriptorSent;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user