blob: aad841f50ee19d3f25cebe8ffc9403418c08c13e [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/prerender/prerender_host.h"
#include "base/feature_list.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "third_party/blink/public/common/features.h"
namespace content {
PrerenderHost::PrerenderHost(
blink::mojom::PrerenderAttributesPtr attributes,
const GlobalFrameRoutingId& initiator_render_frame_host_id,
const url::Origin& initiator_origin)
: attributes_(std::move(attributes)),
initiator_render_frame_host_id_(initiator_render_frame_host_id),
initiator_origin_(initiator_origin) {
DCHECK(base::FeatureList::IsEnabled(blink::features::kPrerender2));
}
// TODO(https://crbug.com/1132746): Abort ongoing prerendering and notify the
// mojo capability controller in the destructor.
PrerenderHost::~PrerenderHost() = default;
// TODO(https://crbug.com/1132746): Inspect diffs from the current
// no-state-prefetch implementation. See PrerenderContents::StartPrerendering()
// for example.
void PrerenderHost::StartPrerendering() {
// The initiator render frame host may have already been closed. In that case,
// abort the prerendering request.
auto* initiator_render_frame_host =
RenderFrameHostImpl::FromID(initiator_render_frame_host_id_);
if (!initiator_render_frame_host)
return;
// TODO(https://crbug.com/1138711, https://crbug.com/1138723): Abort if the
// initiator frame is not the main frame (i.e., iframe or pop-up window).
// Create a new WebContents for prerendering.
WebContents::CreateParams web_contents_params(
initiator_render_frame_host->GetBrowserContext());
// TODO(https://crbug.com/1132746): Set up other fields of
// `web_contents_params` as well, and add tests for them.
prerendered_contents_ = WebContents::Create(web_contents_params);
// Observe events about the prerendering contents.
Observe(prerendered_contents_.get());
// Start prerendering navigation.
NavigationController::LoadURLParams load_url_params(attributes_->url);
load_url_params.initiator_origin = initiator_origin_;
load_url_params.is_prerendering = true;
// TODO(https://crbug.com/1132746): Set up other fields of `load_url_params`
// as well, and add tests for them.
prerendered_contents_->GetController().LoadURLWithParams(load_url_params);
}
void PrerenderHost::DidFinishNavigation(NavigationHandle* navigation_handle) {
// The prerendered contents are considered ready for activation when it
// reaches DidFinishNavigation.
DCHECK(!is_ready_for_activation_);
is_ready_for_activation_ = true;
// Stop observing the events about the prerendered contents.
Observe(nullptr);
}
bool PrerenderHost::ActivatePrerenderedContents(
RenderFrameHostImpl& current_render_frame_host) {
DCHECK_EQ(blink::features::kPrerender2Param.Get(),
blink::features::Prerender2ActivationMode::kEnabled);
DCHECK(is_ready_for_activation_);
is_ready_for_activation_ = false;
auto* current_web_contents =
WebContents::FromRenderFrameHost(&current_render_frame_host);
if (!current_web_contents)
return false;
// Activate the prerendered contents.
WebContentsDelegate* delegate = current_web_contents->GetDelegate();
DCHECK(delegate);
DCHECK(prerendered_contents_);
static_cast<RenderFrameHostImpl*>(prerendered_contents_->GetMainFrame())
->OnPrerenderedPageActivated();
// Tentatively use Portal's activation function.
// TODO(https://crbug.com/1132746): Replace this with the MPArch.
std::unique_ptr<WebContents> predecessor_web_contents =
delegate->ActivatePortalWebContents(current_web_contents,
std::move(prerendered_contents_));
// Stop loading on the predecessor WebContents.
predecessor_web_contents->Stop();
// TODO(https://crbug.com/1142658): Notify renderer processes that the
// contents get activated.
// TODO(https://crbug.com/1132752): Notify the mojo capability controller that
// the prerendered contents get activated.
return true;
}
RenderFrameHostImpl* PrerenderHost::GetPrerenderedMainFrameHostForTesting() {
DCHECK(prerendered_contents_);
return static_cast<RenderFrameHostImpl*>(
prerendered_contents_->GetMainFrame());
}
} // namespace content