Bug 1698663 - Make Document::RemoveFromBFCacheSync() work with SHIP+BFCache, r=peterv

Depends on D108487

Differential Revision: https://phabricator.services.mozilla.com/D108851
This commit is contained in:
Olli Pettay 2021-03-21 21:46:25 +00:00
Родитель dd5347ded5
Коммит b535d5b970
7 изменённых файлов: 158 добавлений и 0 удалений

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

@ -0,0 +1,29 @@
<html>
<head>
<script>
onpageshow = function(pageShowEvent) {
var bc = new BroadcastChannel("evict_from_bfcache");
bc.onmessage = function(event) {
if (event.data == "nextpage") {
bc.close();
location.href += "?nextpage";
} else if (event.data == "back") {
bc.close();
history.back();
} else if (event.data == "forward") {
// Note, we don't close BroadcastChannel
history.forward();
} else if (event.data == "close") {
bc.postMessage("closed");
bc.close();
window.close();
}
}
bc.postMessage({ type: "pageshow", persisted: pageShowEvent.persisted});
};
</script>
</head>
<body>
</body>
</html>

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

@ -100,6 +100,8 @@ support-files = file_bug1536471.html
[test_child.html]
[test_docshell_gotoindex.html]
support-files = file_docshell_gotoindex.html
[test_evict_from_bfcache.html]
support-files = file_evict_from_bfcache.html
[test_grandchild.html]
[test_load_history_entry.html]
[test_meta_refresh.html]

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

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Evict a page from bfcache</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
<script>
/*
* This test checks that a page can be evicted from bfcache. Sending a
* message to an open BroadcastChannel is used for this.
*
* First the test opens a window and loads a page there. Another page is then
* loaded and then session history is navigated back to check if bfcache is
* enabled. If not, close message is sent to close the opened window and this
* controller page will finish the test.
* If bfcache is enabled, session history goes forward, but the
* BroadcastChannel in the page isn't closed. Then sending the message to go
* back again should evict the bfcached page.
* Close message is sent and window closed and test finishes.
*/
SimpleTest.waitForExplicitFinish();
var bc = new BroadcastChannel("evict_from_bfcache");
var pageshowCount = 0;
bc.onmessage = function(event) {
if (event.data.type == "pageshow") {
++pageshowCount;
info("pageshow " + pageshowCount);
if (pageshowCount == 1) {
bc.postMessage("nextpage");
} else if (pageshowCount == 2) {
bc.postMessage("back");
} else if (pageshowCount == 3) {
if (!event.data.persisted) {
ok(true, "BFCache isn't enabled.");
bc.postMessage("close");
} else {
bc.postMessage("forward");
}
} else if (pageshowCount == 4) {
bc.postMessage("back");
} else if (pageshowCount == 5) {
ok(!event.data.persisted,
"The page should have been evicted from BFCache");
bc.postMessage("close");
}
} else if (event.data == "closed") {
SimpleTest.finish();
}
}
function runTest() {
window.open("file_evict_from_bfcache.html", "", "noopener");
}
</script>
</head>
<body onload="runTest()">
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</html>

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

@ -6632,6 +6632,22 @@ bool Document::RemoveFromBFCacheSync() {
entry->RemoveFromBFCacheSync();
return true;
}
if (XRE_IsContentProcess()) {
if (BrowsingContext* bc = GetBrowsingContext()) {
BrowsingContext* top = bc->Top();
if (top->GetIsInBFCache()) {
ContentChild* cc = ContentChild::GetSingleton();
// IPC is asynchronous but the caller is supposed to check the return
// value. The reason for 'Sync' in the method name is that the old
// implementation may run scripts. There is Async variant in
// the old session history implementation for the cases where
// synchronous operation isn't safe.
cc->SendRemoveFromBFCache(top);
return true;
}
}
}
return false;
}

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

@ -7368,6 +7368,49 @@ ContentParent::RecvGetLoadingSessionHistoryInfoFromParent(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvRemoveFromBFCache(
const MaybeDiscarded<BrowsingContext>& aContext) {
if (aContext.IsNullOrDiscarded()) {
return IPC_OK();
}
nsCOMPtr<nsFrameLoaderOwner> owner =
do_QueryInterface(aContext.get_canonical()->GetEmbedderElement());
if (!owner) {
return IPC_OK();
}
RefPtr<nsFrameLoader> frameLoader = owner->GetFrameLoader();
if (!frameLoader || !frameLoader->GetMaybePendingBrowsingContext()) {
return IPC_OK();
}
nsCOMPtr<nsISHistory> shistory = frameLoader->GetMaybePendingBrowsingContext()
->Canonical()
->GetSessionHistory();
if (!shistory) {
return IPC_OK();
}
uint32_t count = shistory->GetCount();
for (uint32_t i = 0; i < count; ++i) {
nsCOMPtr<nsISHEntry> entry;
shistory->GetEntryAtIndex(i, getter_AddRefs(entry));
nsCOMPtr<SessionHistoryEntry> she = do_QueryInterface(entry);
if (she) {
if (RefPtr<nsFrameLoader> frameLoader = she->GetFrameLoader()) {
if (frameLoader->GetMaybePendingBrowsingContext() == aContext.get()) {
she->SetFrameLoader(nullptr);
frameLoader->Destroy();
break;
}
}
}
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntry(
const MaybeDiscarded<BrowsingContext>& aContext,
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,

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

@ -1384,6 +1384,9 @@ class ContentParent final
const MaybeDiscarded<BrowsingContext>& aContext,
GetLoadingSessionHistoryInfoFromParentResolver&& aResolver);
mozilla::ipc::IPCResult RecvRemoveFromBFCache(
const MaybeDiscarded<BrowsingContext>& aContext);
mozilla::ipc::IPCResult RecvSetActiveSessionHistoryEntry(
const MaybeDiscarded<BrowsingContext>& aContext,
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,

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

@ -958,6 +958,8 @@ parent:
async GetLoadingSessionHistoryInfoFromParent(MaybeDiscardedBrowsingContext aContext)
returns (LoadingSessionHistoryInfo? aLoadingInfo, int32_t aRequestedIndex, int32_t aLength);
async RemoveFromBFCache(MaybeDiscardedBrowsingContext aContext);
async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
async CreateGMPService();