blob: 47872210db8d2388dfcb03e9ad26600092661ae8 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/renderer_host/view_transition_commit_deferring_condition.h"
#include "base/memory/ptr_util.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/view_transition_opt_in_state.h"
#include "content/public/common/content_features.h"
#include "third_party/blink/public/common/features_generated.h"
#include "third_party/blink/public/common/frame/view_transition_state.h"
namespace content {
namespace {
void OnSnapshotAck(base::OnceClosure closure,
base::WeakPtr<NavigationRequest> navigation_request,
const blink::ViewTransitionState& view_transition_state) {
if (navigation_request && !view_transition_state.elements.empty()) {
navigation_request->SetViewTransitionState(
std::move(view_transition_state));
}
std::move(closure).Run();
}
} // namespace
// static
std::unique_ptr<CommitDeferringCondition>
ViewTransitionCommitDeferringCondition::MaybeCreate(
NavigationRequest& navigation_request) {
// TODO(khushalsagar): This shouldn't be done for every navigation. We'll need
// a meta tag (or another way) in the API to know whether this Document is
// interested in enabling transitions for same-origin navigations.
if (!base::FeatureList::IsEnabled(
blink::features::kViewTransitionOnNavigation)) {
return nullptr;
}
if (!navigation_request.IsInPrimaryMainFrame())
return nullptr;
RenderFrameHostImpl* rfh =
navigation_request.frame_tree_node()->current_frame_host();
if (ViewTransitionOptInState::GetOrCreateForCurrentDocument(rfh)
->same_origin_opt_in() ==
blink::mojom::ViewTransitionSameOriginOptIn::kDisabled) {
return nullptr;
}
const url::Origin& current_request_origin = rfh->GetLastCommittedOrigin();
const url::Origin& new_request_origin =
navigation_request.state() >= NavigationRequest::WILL_PROCESS_RESPONSE
? navigation_request.GetOriginToCommit().value_or(url::Origin())
: navigation_request.GetTentativeOriginAtRequestTime();
// Only support same origin.
// TODO(khushalsagar): We need to be able to deal with redirects.
// https://github.com/WICG/view-transitions/issues/200
if (current_request_origin != new_request_origin) {
return nullptr;
}
return base::WrapUnique(
new ViewTransitionCommitDeferringCondition(navigation_request));
}
ViewTransitionCommitDeferringCondition::ViewTransitionCommitDeferringCondition(
NavigationRequest& navigation_request)
: CommitDeferringCondition(navigation_request) {}
ViewTransitionCommitDeferringCondition::
~ViewTransitionCommitDeferringCondition() = default;
CommitDeferringCondition::Result
ViewTransitionCommitDeferringCondition::WillCommitNavigation(
base::OnceClosure resume) {
auto* navigation_request = NavigationRequest::From(&GetNavigationHandle());
auto* render_frame_host =
navigation_request->frame_tree_node()->current_frame_host();
// TODO(crbug.com/1372584): Implement a timeout, to avoid blocking the
// navigation for too long.
render_frame_host->SnapshotDocumentForViewTransition(base::BindOnce(
&OnSnapshotAck, std::move(resume), navigation_request->GetWeakPtr()));
return Result::kDefer;
}
} // namespace content