Bug 1268688 - Start browser API for frames swapping to HTML. r=bz

MozReview-Commit-ID: 56lMg0b86Bp
This commit is contained in:
J. Ryan Stinnett 2016-04-28 17:04:52 -05:00
Родитель 184c33c9c4
Коммит a899dd1d54
9 изменённых файлов: 164 добавлений и 43 удалений

Просмотреть файл

@ -1020,10 +1020,28 @@ nsFrameLoader::SwapWithOtherRemoteLoader(nsFrameLoader* aOther,
ourDoc->FlushPendingNotifications(Flush_Layout);
otherDoc->FlushPendingNotifications(Flush_Layout);
// Initialize browser API if needed now that owner content has changed.
InitializeBrowserAPI();
aOther->InitializeBrowserAPI();
mInSwap = aOther->mInSwap = false;
Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader();
Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader();
// Send an updated tab context since owner content type may have changed.
MutableTabContext ourContext;
rv = GetNewTabContext(&ourContext);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MutableTabContext otherContext;
rv = aOther->GetNewTabContext(&otherContext);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
Unused << mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
ourContext.AsIPCTabContext());
Unused << aOther->mRemoteBrowser->SendSwappedWithOtherRemoteLoader(
otherContext.AsIPCTabContext());
return NS_OK;
}
@ -1429,6 +1447,10 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
ourParentDocument->FlushPendingNotifications(Flush_Layout);
otherParentDocument->FlushPendingNotifications(Flush_Layout);
// Initialize browser API if needed now that owner content has changed
InitializeBrowserAPI();
aOther->InitializeBrowserAPI();
return NS_OK;
}

Просмотреть файл

@ -18,7 +18,6 @@ Test swapFrameLoaders with different frame types and remoteness
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
SimpleTest.requestLongerTimeout(100);
window.open("window_swapFrameLoaders.xul", "bug1242644",
"chrome,width=600,height=600");

Просмотреть файл

@ -36,6 +36,20 @@ Test swapFrameLoaders with different frame types and remoteness
["html", "html", "remote"],
];
const HEIGHTS = [
200,
400
];
function frameScript() {
addEventListener("load", function onLoad() {
sendAsyncMessage("test:load");
}, true);
}
// Watch for loads in new frames
window.messageManager.loadFrameScript(`data:,(${frameScript})();`, true);
function once(target, eventName, useCapture = false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
@ -56,7 +70,7 @@ Test swapFrameLoaders with different frame types and remoteness
});
}
function* addFrame(type, remote) {
function* addFrame(type, remote, height) {
let frame = document.createElementNS(NS[type], TAG[type]);
frame.setAttribute("remote", remote);
if (remote && type == "xul") {
@ -69,8 +83,12 @@ Test swapFrameLoaders with different frame types and remoteness
} else if (type == "xul") {
frame.setAttribute("type", "content");
}
frame.setAttribute("src", "about:blank");
let src = `data:text/html,<!doctype html>` +
`<body style="height:${height}px"/>`;
frame.setAttribute("src", src);
document.documentElement.appendChild(frame);
let mm = frame.frameLoader.messageManager;
yield once(mm, "test:load");
return frame;
}
@ -86,11 +104,13 @@ Test swapFrameLoaders with different frame types and remoteness
for (let scenario of SCENARIOS) {
let [ typeA, typeB, remote ] = scenario;
remote = !!remote;
info(`Adding frame A, type ${typeA}, remote ${remote}`);
let frameA = yield addFrame(typeA, remote);
let heightA = HEIGHTS[0];
info(`Adding frame A, type ${typeA}, remote ${remote}, height ${heightA}`);
let frameA = yield addFrame(typeA, remote, heightA);
info(`Adding frame B, type ${typeB}, remote ${remote}`);
let frameB = yield addFrame(typeB, remote);
let heightB = HEIGHTS[1];
info(`Adding frame B, type ${typeB}, remote ${remote}, height ${heightB}`);
let frameB = yield addFrame(typeB, remote, heightB);
let frameScriptFactory = function(name) {
return `function() {
@ -128,6 +148,18 @@ Test swapFrameLoaders with different frame types and remoteness
is(pongB, "B", "Frame B message manager gets reply B before swap");
}
// Check height before swap
{
if (frameA.getContentDimensions) {
let { height } = yield frameA.getContentDimensions();
is(height, heightA, "Frame A's content height is 200px before swap");
}
if (frameB.getContentDimensions) {
let { height } = yield frameB.getContentDimensions();
is(height, heightB, "Frame B's content height is 400px before swap");
}
}
// Ping after swap using message managers acquired before
{
let mmA = frameA.frameLoader.messageManager;
@ -150,6 +182,18 @@ Test swapFrameLoaders with different frame types and remoteness
is(pongB, "A", "Frame B message manager acquired before swap gets reply A after swap");
}
// Check height after swap
{
if (frameA.getContentDimensions) {
let { height } = yield frameA.getContentDimensions();
is(height, heightB, "Frame A's content height is 400px after swap");
}
if (frameB.getContentDimensions) {
let { height } = yield frameB.getContentDimensions();
is(height, heightA, "Frame B's content height is 200px after swap");
}
}
// Ping after swap using message managers acquired after
{
let mmA = frameA.frameLoader.messageManager;

Просмотреть файл

@ -33,47 +33,48 @@ function isTopBrowserElement(docShell) {
return true;
}
if (!('BrowserElementIsPreloaded' in this)) {
if (isTopBrowserElement(docShell)) {
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
try {
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
} catch (e) {
if (!BrowserElementIsReady) {
if (!('BrowserElementIsPreloaded' in this)) {
if (isTopBrowserElement(docShell)) {
if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
try {
Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
} catch (e) {
}
}
}
}
if(Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
// general content apps
if (isTopBrowserElement(docShell)) {
if(Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
// general content apps
if (isTopBrowserElement(docShell)) {
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
}
} else {
// rocketbar in system app and other in-process case (ex. B2G desktop client)
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
}
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
if (docShell.asyncPanZoomEnabled === false) {
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js");
ContentPanningAPZDisabled.init();
}
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
ContentPanning.init();
}
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
} else {
// rocketbar in system app and other in-process case (ex. B2G desktop client)
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementCopyPaste.js");
}
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
if (docShell.asyncPanZoomEnabled === false) {
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js");
ContentPanningAPZDisabled.init();
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
if (docShell.asyncPanZoomEnabled === false) {
ContentPanningAPZDisabled.init();
}
ContentPanning.init();
}
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
ContentPanning.init();
}
Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
} else {
if (Services.prefs.getIntPref("dom.w3c_touch_events.enabled") != 0) {
if (docShell.asyncPanZoomEnabled === false) {
ContentPanningAPZDisabled.init();
}
ContentPanning.init();
}
}
var BrowserElementIsReady = true;
sendAsyncMessage('browser-element-api:call', { 'msg_name': 'hello' });

Просмотреть файл

@ -19,6 +19,7 @@ include DOMTypes;
include JavaScriptTypes;
include URIParams;
include BrowserConfiguration;
include PTabContext;
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
@ -724,7 +725,7 @@ child:
* Tell the browser that its frame loader has been swapped
* with another.
*/
async SwappedWithOtherRemoteLoader();
async SwappedWithOtherRemoteLoader(IPCTabContext context);
/**
* A potential accesskey was just pressed. Look for accesskey targets

Просмотреть файл

@ -2287,7 +2287,7 @@ TabChild::RecvAppOfflineStatus(const uint32_t& aId, const bool& aOffline)
}
bool
TabChild::RecvSwappedWithOtherRemoteLoader()
TabChild::RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext)
{
nsCOMPtr<nsIDocShell> ourDocShell = do_GetInterface(WebNavigation());
if (NS_WARN_IF(!ourDocShell)) {
@ -2307,6 +2307,29 @@ TabChild::RecvSwappedWithOtherRemoteLoader()
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, false);
nsContentUtils::FirePageHideEvent(ourDocShell, ourEventTarget);
// Owner content type may have changed, so store the possibly updated context
// and notify others.
MaybeInvalidTabContext maybeContext(aContext);
if (!maybeContext.IsValid()) {
NS_ERROR(nsPrintfCString("Received an invalid TabContext from "
"the parent process. (%s)",
maybeContext.GetInvalidReason()).get());
MOZ_CRASH("Invalid TabContext received from the parent process.");
}
if (!UpdateTabContextAfterSwap(maybeContext.GetTabContext())) {
MOZ_CRASH("Update to TabContext after swap was denied.");
}
NotifyTabContextUpdated();
// Ignore previous value of mTriedBrowserInit since owner content has changed.
mTriedBrowserInit = true;
// Initialize the child side of the browser element machinery, if appropriate.
if (IsMozBrowserOrApp()) {
RecvLoadRemoteScript(BROWSER_ELEMENT_CHILD_SCRIPT, true);
}
nsContentUtils::FirePageShowEvent(ourDocShell, ourEventTarget, true);
docShell->SetInFrameSwap(false);

Просмотреть файл

@ -417,7 +417,8 @@ public:
virtual bool RecvAppOfflineStatus(const uint32_t& aId,
const bool& aOffline) override;
virtual bool RecvSwappedWithOtherRemoteLoader() override;
virtual bool
RecvSwappedWithOtherRemoteLoader(const IPCTabContext& aContext) override;
virtual PDocAccessibleChild*
AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&) override;

Просмотреть файл

@ -159,6 +159,25 @@ TabContext::SetTabContext(const TabContext& aContext)
return true;
}
bool
TabContext::UpdateTabContextAfterSwap(const TabContext& aContext)
{
// This is only used after already initialized.
MOZ_ASSERT(mInitialized);
// The only permissable change is to `mIsMozBrowserElement`. All other fields
// must match for the change to be accepted.
if (aContext.OwnAppId() != OwnAppId() ||
aContext.mContainingAppId != mContainingAppId ||
aContext.mOriginAttributes != mOriginAttributes ||
aContext.mSignedPkgOriginNoSuffix != mSignedPkgOriginNoSuffix) {
return false;
}
mIsMozBrowserElement = aContext.mIsMozBrowserElement;
return true;
}
const DocShellOriginAttributes&
TabContext::OriginAttributesRef() const
{

Просмотреть файл

@ -160,6 +160,17 @@ protected:
const DocShellOriginAttributes& aOriginAttributes,
const nsACString& aSignedPkgOriginNoSuffix);
/**
* Modify this TabContext to match the given TabContext. This is a special
* case triggered by nsFrameLoader::SwapWithOtherRemoteLoader which may have
* caused the owner content to change.
*
* This special case only allows the field `mIsMozBrowserElement` to be
* changed. If any other fields have changed, the update is ignored and
* returns false.
*/
bool UpdateTabContextAfterSwap(const TabContext& aContext);
private:
/**
* Has this TabContext been initialized? If so, mutator methods will fail.