зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1268688 - Start browser API for frames swapping to HTML. r=bz
MozReview-Commit-ID: 56lMg0b86Bp
This commit is contained in:
Родитель
184c33c9c4
Коммит
a899dd1d54
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче