Commit 0362e8d0 authored by Lingqi Chi's avatar Lingqi Chi Committed by Chromium LUCI CQ

Prerender: Set Prerendering State for Sub-Frame Navigations

https://chromium-review.googlesource.com/c/chromium/src/+/2583677 only
set the prerendering state for main-frame navigation.
This CL shares parents' prerendering states with their children, so that
sub-frames can also know the correct prerendering state.

Bug: 1142658
Change-Id: I70552d4dc6380f91536e062ad2ea3ec8d0719b45
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2603660Reviewed-by: default avatarTakashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842936}
parent 779b630b
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/thread_annotations.h" #include "base/thread_annotations.h"
#include "content/browser/prerender/prerender_host.h" #include "content/browser/prerender/prerender_host.h"
#include "content/browser/prerender/prerender_host_registry.h" #include "content/browser/prerender/prerender_host_registry.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/storage_partition_impl.h" #include "content/browser/storage_partition_impl.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
...@@ -133,6 +134,49 @@ class PrerenderBrowserTest : public ContentBrowserTest, ...@@ -133,6 +134,49 @@ class PrerenderBrowserTest : public ContentBrowserTest,
bool IsActivationDisabled() const { return GetParam(); } bool IsActivationDisabled() const { return GetParam(); }
void TestRenderFrameHostPrerenderingState(const GURL& prerender_url) {
const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
// Navigate to an initial page.
ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
// The initial page should not be for prerendering.
RenderFrameHostImpl* initiator_render_frame_host =
static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetMainFrame());
EXPECT_FALSE(initiator_render_frame_host->IsPrerendering());
// Start a prerender.
AddPrerender(prerender_url);
PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
PrerenderHost* prerender_host =
registry.FindHostByUrlForTesting(prerender_url);
// Verify all RenderFrameHostImpl in the prerendered page know the
// prerendering state.
RenderFrameHostImpl* prerendered_render_frame_host =
prerender_host->GetPrerenderedMainFrameHostForTesting();
std::vector<RenderFrameHost*> frames =
prerendered_render_frame_host->GetFramesInSubtree();
for (auto* frame : frames) {
auto* rfhi = static_cast<RenderFrameHostImpl*>(frame);
EXPECT_TRUE(rfhi->IsPrerendering());
}
// Activate the prerendered page.
NavigateWithLocation(prerender_url);
// The activated page should no longer be in the prerendering state.
RenderFrameHostImpl* navigated_render_frame_host =
static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetMainFrame());
// The new page shouldn't be in the prerendering state.
frames = navigated_render_frame_host->GetFramesInSubtree();
for (auto* frame : frames) {
auto* rfhi = static_cast<RenderFrameHostImpl*>(frame);
EXPECT_FALSE(rfhi->IsPrerendering());
}
}
private: private:
net::test_server::EmbeddedTestServer ssl_server_{ net::test_server::EmbeddedTestServer ssl_server_{
net::test_server::EmbeddedTestServer::TYPE_HTTPS}; net::test_server::EmbeddedTestServer::TYPE_HTTPS};
...@@ -274,56 +318,6 @@ IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, LinkRelPrerender_Duplicate) { ...@@ -274,56 +318,6 @@ IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, LinkRelPrerender_Duplicate) {
} }
} }
IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, InformedRenderFrameHost) {
const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
const GURL kPrerenderingUrl = GetUrl("/empty.html");
// Navigate to an initial page.
ASSERT_TRUE(NavigateToURL(shell(), kInitialUrl));
ASSERT_EQ(shell()->web_contents()->GetURL(), kInitialUrl);
// The initial page should not be for prerendering.
RenderFrameHostImpl* initiator_render_frame_host =
static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetMainFrame());
EXPECT_FALSE(initiator_render_frame_host->IsPrerendering());
// Add <link rel=prerender> that will prerender `kPrerenderingUrl`.
ASSERT_EQ(GetRequestCount(kPrerenderingUrl), 0);
AddPrerender(kPrerenderingUrl);
EXPECT_EQ(GetRequestCount(kPrerenderingUrl), 1);
// A prerender host for the URL should be registered.
PrerenderHostRegistry& registry = GetPrerenderHostRegistry();
PrerenderHost* prerender_host =
registry.FindHostByUrlForTesting(kPrerenderingUrl);
EXPECT_NE(prerender_host, nullptr);
// Verify the corresponding RenderFrameHostImpl knows the prerendering state.
RenderFrameHostImpl* prerendered_render_frame_host =
prerender_host->GetPrerenderedMainFrameHostForTesting();
EXPECT_TRUE(prerendered_render_frame_host->IsPrerendering());
// Activate the prerendered page.
NavigateWithLocation(kPrerenderingUrl);
if (IsActivationDisabled()) {
// Activation is disabled, so the page should newly be rendered instead
// of the prerendered page.
RenderFrameHostImpl* new_render_frame_host =
static_cast<RenderFrameHostImpl*>(
shell()->web_contents()->GetMainFrame());
EXPECT_NE(prerendered_render_frame_host, new_render_frame_host);
// The new page shouldn't be in the prerendering state.
EXPECT_FALSE(new_render_frame_host->IsPrerendering());
} else {
// The prerendered page is activated. The page should no longer be in
// the prerendering state.
ASSERT_EQ(prerendered_render_frame_host,
shell()->web_contents()->GetMainFrame());
EXPECT_FALSE(prerendered_render_frame_host->IsPrerendering());
}
}
// Makes sure that activations on navigations for iframes don't happen. // Makes sure that activations on navigations for iframes don't happen.
IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, Activation_iFrame) { IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, Activation_iFrame) {
const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html"); const GURL kInitialUrl = GetUrl("/prerender/add_prerender.html");
...@@ -410,6 +404,18 @@ IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, HistoryAfterActivation) { ...@@ -410,6 +404,18 @@ IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, HistoryAfterActivation) {
EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kInitialUrl); EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), kInitialUrl);
} }
// Tests that all RenderFrameHostImpls in the prerendering page know the
// prerendering state.
IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, PrerenderIframe) {
TestRenderFrameHostPrerenderingState(GetUrl("/page_with_iframe.html"));
}
// Blank <iframe> is a special case. Tests that the blank iframe knows the
// prerendering state as well.
IN_PROC_BROWSER_TEST_P(PrerenderBrowserTest, PrerenderBlankIframe) {
TestRenderFrameHostPrerenderingState(GetUrl("/page_with_blank_iframe.html"));
}
// TODO(https://crbug.com/1132746): Test canceling prerendering. // TODO(https://crbug.com/1132746): Test canceling prerendering.
// TODO(https://crbug.com/1132746): Test prerendering for 404 page, redirection, // TODO(https://crbug.com/1132746): Test prerendering for 404 page, redirection,
......
...@@ -766,6 +766,12 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated( ...@@ -766,6 +766,12 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
} }
} }
// The prerendering state of a sub-frame is decided by its parent.
if (base::FeatureList::IsEnabled(blink::features::kPrerender2) &&
frame_tree_node->parent()) {
is_prerendering = frame_tree_node->parent()->IsPrerendering();
}
std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest( std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
frame_tree_node, std::move(common_params), std::move(navigation_params), frame_tree_node, std::move(common_params), std::move(navigation_params),
std::move(commit_params), browser_initiated, std::move(commit_params), browser_initiated,
...@@ -880,6 +886,13 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated( ...@@ -880,6 +886,13 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
int initiator_process_id = int initiator_process_id =
frame_tree_node->current_frame_host()->GetProcess()->GetID(); frame_tree_node->current_frame_host()->GetProcess()->GetID();
// For sub-frame navigations, inherit the prerendering state from the parent.
bool is_prerendering = false;
if (base::FeatureList::IsEnabled(blink::features::kPrerender2) &&
frame_tree_node->parent()) {
is_prerendering = frame_tree_node->parent()->IsPrerendering();
}
// `was_opener_suppressed` can be true for renderer initiated navigations, but // `was_opener_suppressed` can be true for renderer initiated navigations, but
// only in cases which get routed through `CreateBrowserInitiated()` instead. // only in cases which get routed through `CreateBrowserInitiated()` instead.
std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest( std::unique_ptr<NavigationRequest> navigation_request(new NavigationRequest(
...@@ -888,8 +901,9 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated( ...@@ -888,8 +901,9 @@ std::unique_ptr<NavigationRequest> NavigationRequest::CreateRendererInitiated(
false, // browser_initiated false, // browser_initiated
true, // from_begin_navigation true, // from_begin_navigation
false, // is_for_commit false, // is_for_commit
false, // is_prerendering is_prerendering,
nullptr, entry, nullptr, // frame_entry
entry,
nullptr, // navigation_ui_data nullptr, // navigation_ui_data
std::move(navigation_client), std::move(navigation_initiator), std::move(navigation_client), std::move(navigation_initiator),
nullptr, // rfh_restored_from_back_forward_cache nullptr, // rfh_restored_from_back_forward_cache
......
...@@ -7812,6 +7812,9 @@ void RenderFrameHostImpl::OnPrerenderedPageActivated() { ...@@ -7812,6 +7812,9 @@ void RenderFrameHostImpl::OnPrerenderedPageActivated() {
DCHECK(is_prerendering_); DCHECK(is_prerendering_);
is_prerendering_ = false; is_prerendering_ = false;
for (auto& child : children_)
child->current_frame_host()->OnPrerenderedPageActivated();
// TODO(https://crbug.com/1132752): Inform `broker_` that the prerendered // TODO(https://crbug.com/1132752): Inform `broker_` that the prerendered
// frame is activated. // frame is activated.
} }
...@@ -8781,6 +8784,14 @@ bool RenderFrameHostImpl::DidCommitNavigationInternal( ...@@ -8781,6 +8784,14 @@ bool RenderFrameHostImpl::DidCommitNavigationInternal(
// create one in order to properly issue DidFinishNavigation calls to // create one in order to properly issue DidFinishNavigation calls to
// WebContentsObservers. // WebContentsObservers.
DCHECK(is_initial_empty_commit || is_same_document_navigation); DCHECK(is_initial_empty_commit || is_same_document_navigation);
// Handle src-less <iframe> for prerendering.
// This is a special case that does not go through CommitNavigation path.
if (base::FeatureList::IsEnabled(blink::features::kPrerender2) &&
is_initial_empty_commit && !is_main_frame()) {
is_prerendering_ = parent_->IsPrerendering();
}
// TODO(https://crbug.com/1131832): Do not use |params| to get the values, // TODO(https://crbug.com/1131832): Do not use |params| to get the values,
// depend on values known at commit time instead. // depend on values known at commit time instead.
navigation_request = CreateNavigationRequestForCommit( navigation_request = CreateNavigationRequestForCommit(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment