зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1599773 - [remote] Implement Page.frameDetached. r=remote-protocol-reviewers,maja_zf
Differential Revision: https://phabricator.services.mozilla.com/D71293
This commit is contained in:
Родитель
4a22ea5bfe
Коммит
d854295e0d
|
@ -38,6 +38,7 @@ class Page extends ContentProcessDomain {
|
||||||
this.worldsToEvaluateOnLoad = new Set();
|
this.worldsToEvaluateOnLoad = new Set();
|
||||||
|
|
||||||
this._onFrameAttached = this._onFrameAttached.bind(this);
|
this._onFrameAttached = this._onFrameAttached.bind(this);
|
||||||
|
this._onFrameDetached = this._onFrameDetached.bind(this);
|
||||||
this._onFrameNavigated = this._onFrameNavigated.bind(this);
|
this._onFrameNavigated = this._onFrameNavigated.bind(this);
|
||||||
this._onScriptLoaded = this._onScriptLoaded.bind(this);
|
this._onScriptLoaded = this._onScriptLoaded.bind(this);
|
||||||
|
|
||||||
|
@ -57,6 +58,7 @@ class Page extends ContentProcessDomain {
|
||||||
async enable() {
|
async enable() {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
this.session.contextObserver.on("frame-attached", this._onFrameAttached);
|
this.session.contextObserver.on("frame-attached", this._onFrameAttached);
|
||||||
|
this.session.contextObserver.on("frame-detached", this._onFrameDetached);
|
||||||
this.session.contextObserver.on(
|
this.session.contextObserver.on(
|
||||||
"frame-navigated",
|
"frame-navigated",
|
||||||
this._onFrameNavigated
|
this._onFrameNavigated
|
||||||
|
@ -91,6 +93,7 @@ class Page extends ContentProcessDomain {
|
||||||
disable() {
|
disable() {
|
||||||
if (this.enabled) {
|
if (this.enabled) {
|
||||||
this.session.contextObserver.off("frame-attached", this._onFrameAttached);
|
this.session.contextObserver.off("frame-attached", this._onFrameAttached);
|
||||||
|
this.session.contextObserver.off("frame-detached", this._onFrameDetached);
|
||||||
this.session.contextObserver.off(
|
this.session.contextObserver.off(
|
||||||
"frame-navigated",
|
"frame-navigated",
|
||||||
this._onFrameNavigated
|
this._onFrameNavigated
|
||||||
|
@ -254,6 +257,10 @@ class Page extends ContentProcessDomain {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onFrameDetached(name, { frameId }) {
|
||||||
|
this.emit("Page.frameDetached", { frameId });
|
||||||
|
}
|
||||||
|
|
||||||
_onFrameNavigated(name, { frameId, window }) {
|
_onFrameNavigated(name, { frameId, window }) {
|
||||||
const url = window.location.href;
|
const url = window.location.href;
|
||||||
this.emit("Page.frameNavigated", {
|
this.emit("Page.frameNavigated", {
|
||||||
|
|
|
@ -60,6 +60,7 @@ class ContextObserver {
|
||||||
|
|
||||||
if (FRAMES_ENABLED) {
|
if (FRAMES_ENABLED) {
|
||||||
Services.obs.addObserver(this, "webnavigation-create");
|
Services.obs.addObserver(this, "webnavigation-create");
|
||||||
|
Services.obs.addObserver(this, "webnavigation-destroy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@ class ContextObserver {
|
||||||
|
|
||||||
if (FRAMES_ENABLED) {
|
if (FRAMES_ENABLED) {
|
||||||
Services.obs.removeObserver(this, "webnavigation-create");
|
Services.obs.removeObserver(this, "webnavigation-create");
|
||||||
|
Services.obs.removeObserver(this, "webnavigation-destroy");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +137,10 @@ class ContextObserver {
|
||||||
subject.QueryInterface(Ci.nsIDocShell);
|
subject.QueryInterface(Ci.nsIDocShell);
|
||||||
this.onDocShellCreated(subject);
|
this.onDocShellCreated(subject);
|
||||||
break;
|
break;
|
||||||
|
case "webnavigation-destroy":
|
||||||
|
subject.QueryInterface(Ci.nsIDocShell);
|
||||||
|
this.onDocShellDestroyed(subject);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,4 +153,11 @@ class ContextObserver {
|
||||||
parentFrameId: parent ? parent.id.toString() : null,
|
parentFrameId: parent ? parent.id.toString() : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDocShellDestroyed(docShell) {
|
||||||
|
// TODO: Use a unique identifier for frames (bug 1605359)
|
||||||
|
this.emit("frame-detached", {
|
||||||
|
frameId: docShell.browsingContext.id.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ support-files =
|
||||||
[browser_captureScreenshot.js]
|
[browser_captureScreenshot.js]
|
||||||
[browser_createIsolatedWorld.js]
|
[browser_createIsolatedWorld.js]
|
||||||
[browser_frameAttached.js]
|
[browser_frameAttached.js]
|
||||||
|
[browser_frameDetached.js]
|
||||||
[browser_frameNavigated.js]
|
[browser_frameNavigated.js]
|
||||||
[browser_getFrameTree.js]
|
[browser_getFrameTree.js]
|
||||||
[browser_getLayoutMetrics.js]
|
[browser_getLayoutMetrics.js]
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const DOC = toDataURL("<div>foo</div>");
|
||||||
|
const DOC_IFRAME_MULTI = toDataURL(`
|
||||||
|
<iframe src='data:text/html,foo'></iframe>
|
||||||
|
<iframe src='data:text/html,bar'></iframe>
|
||||||
|
`);
|
||||||
|
const DOC_IFRAME_NESTED = toDataURL(`
|
||||||
|
<iframe src="data:text/html,<iframe src='data:text/html,foo'></iframe>">
|
||||||
|
</iframe>
|
||||||
|
`);
|
||||||
|
|
||||||
|
// Disable bfcache to force documents to be destroyed on navigation
|
||||||
|
Services.prefs.setIntPref("browser.sessionhistory.max_total_viewers", 0);
|
||||||
|
registerCleanupFunction(() => {
|
||||||
|
Services.prefs.clearUserPref("browser.sessionhistory.max_total_viewers");
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function noEventWhenPageDomainDisabled({ client }) {
|
||||||
|
await loadURL(DOC_IFRAME_MULTI);
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 0, async () => {
|
||||||
|
info("Navigate away from a page with an iframe");
|
||||||
|
await loadURL(DOC);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function noEventAfterPageDomainDisabled({ client }) {
|
||||||
|
const { Page } = client;
|
||||||
|
|
||||||
|
await Page.enable();
|
||||||
|
|
||||||
|
await loadURL(DOC_IFRAME_MULTI);
|
||||||
|
|
||||||
|
await Page.disable();
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 0, async () => {
|
||||||
|
info("Navigate away from a page with an iframe");
|
||||||
|
await loadURL(DOC);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function noEventWhenNavigatingWithNoFrames({ client }) {
|
||||||
|
const { Page } = client;
|
||||||
|
|
||||||
|
await Page.enable();
|
||||||
|
|
||||||
|
await loadURL(DOC);
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 0, async () => {
|
||||||
|
info("Navigate away from a page with no iframes");
|
||||||
|
await loadURL(DOC);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function eventWhenNavigatingWithFrames({ client }) {
|
||||||
|
const { Page } = client;
|
||||||
|
|
||||||
|
await Page.enable();
|
||||||
|
|
||||||
|
await loadURL(DOC_IFRAME_MULTI);
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 2, async () => {
|
||||||
|
info("Navigate away from a page with an iframe");
|
||||||
|
await loadURL(DOC);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function eventWhenNavigatingWithNestedFrames({ client }) {
|
||||||
|
const { Page } = client;
|
||||||
|
|
||||||
|
await Page.enable();
|
||||||
|
|
||||||
|
await loadURL(DOC_IFRAME_NESTED);
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 2, async () => {
|
||||||
|
info("Navigate away from a page with nested iframes");
|
||||||
|
await loadURL(DOC);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function eventWhenDetachingFrame({ client }) {
|
||||||
|
const { Page } = client;
|
||||||
|
|
||||||
|
await Page.enable();
|
||||||
|
|
||||||
|
await loadURL(DOC_IFRAME_MULTI);
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 1, async () => {
|
||||||
|
// Remove the single frame from the page
|
||||||
|
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
|
||||||
|
const frame = content.document.getElementsByTagName("iframe")[0];
|
||||||
|
frame.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function eventWhenDetachingNestedFrames({ client }) {
|
||||||
|
const { Page, Runtime } = client;
|
||||||
|
|
||||||
|
await Page.enable();
|
||||||
|
|
||||||
|
await loadURL(DOC_IFRAME_NESTED);
|
||||||
|
|
||||||
|
await Runtime.enable();
|
||||||
|
const { context } = await Runtime.executionContextCreated();
|
||||||
|
|
||||||
|
await runFrameDetachedTest(client, 2, async () => {
|
||||||
|
// Remove top-frame, which also removes any nested frames
|
||||||
|
await evaluate(client, context.id, async () => {
|
||||||
|
const frame = document.getElementsByTagName("iframe")[0];
|
||||||
|
frame.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
async function runFrameDetachedTest(client, expectedEventCount, callback) {
|
||||||
|
const { Page } = client;
|
||||||
|
|
||||||
|
const frameDetachedEvents = [];
|
||||||
|
Page.frameDetached(frame => frameDetachedEvents.push(frame));
|
||||||
|
|
||||||
|
const framesBefore = await getFlattendFrameList();
|
||||||
|
await callback();
|
||||||
|
const framesAfter = await getFlattendFrameList();
|
||||||
|
|
||||||
|
// check how many frames were added or removed
|
||||||
|
const count = Math.abs(framesBefore.size - framesAfter.size);
|
||||||
|
|
||||||
|
if (expectedEventCount == 0) {
|
||||||
|
is(frameDetachedEvents.length, 0, "Got no frame detached event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
is(count, expectedEventCount, "Expected amount of frames removed");
|
||||||
|
is(
|
||||||
|
frameDetachedEvents.length,
|
||||||
|
count,
|
||||||
|
"Received the expected amount of frameDetached events"
|
||||||
|
);
|
||||||
|
|
||||||
|
// extract the new or removed frames
|
||||||
|
const framesAll = new Map([...framesBefore, ...framesAfter]);
|
||||||
|
const expectedFrames = new Map(
|
||||||
|
[...framesAll].filter(([key, _value]) => {
|
||||||
|
return framesBefore.has(key) && !framesAfter.has(key);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
frameDetachedEvents.forEach(event => {
|
||||||
|
const expectedFrame = expectedFrames.get(event.frameId);
|
||||||
|
|
||||||
|
is(
|
||||||
|
event.frameId,
|
||||||
|
expectedFrame.id,
|
||||||
|
"Got expected frame id for frameDetached event"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче