blob: 6691603b66071863f812a22c9585438f5d77ab01 [file] [log] [blame]
// Copyright 2021 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/renderer_host/commit_deferring_condition_runner.h"
#include "content/browser/renderer_host/back_forward_cache_commit_deferring_condition.h"
#include "content/browser/renderer_host/commit_deferring_condition.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/navigator_delegate.h"
namespace content {
// static
std::unique_ptr<CommitDeferringConditionRunner>
CommitDeferringConditionRunner::Create(NavigationRequest& navigation_request) {
auto runner =
base::WrapUnique(new CommitDeferringConditionRunner(navigation_request));
runner->RegisterDeferringConditions(navigation_request);
return runner;
}
CommitDeferringConditionRunner::CommitDeferringConditionRunner(
Delegate& delegate)
: delegate_(delegate) {}
CommitDeferringConditionRunner::~CommitDeferringConditionRunner() = default;
void CommitDeferringConditionRunner::ProcessChecks() {
ProcessConditions();
}
void CommitDeferringConditionRunner::AddConditionForTesting(
std::unique_ptr<CommitDeferringCondition> condition) {
AddCondition(std::move(condition));
}
void CommitDeferringConditionRunner::ResumeProcessing() {
DCHECK(is_deferred_);
is_deferred_ = false;
// This is resuming from a check that resolved asynchronously. The current
// check is always at the front of the vector so pop it and then proceed with
// the next one.
DCHECK(!conditions_.empty());
conditions_.erase(conditions_.begin());
ProcessConditions();
}
void CommitDeferringConditionRunner::RegisterDeferringConditions(
NavigationRequest& navigation_request) {
// Let WebContents add deferring conditions.
std::vector<std::unique_ptr<CommitDeferringCondition>> delegate_conditions =
navigation_request.GetDelegate()
->CreateDeferringConditionsForNavigationCommit(navigation_request);
for (auto& condition : delegate_conditions) {
DCHECK(condition);
AddCondition(std::move(condition));
}
// The BFCache deferring condition should run after all other conditions
// since it'll disable eviction on a cached renderer.
AddCondition(BackForwardCacheCommitDeferringCondition::MaybeCreate(
navigation_request));
}
void CommitDeferringConditionRunner::ProcessConditions() {
while (!conditions_.empty()) {
// If the condition isn't yet ready to commit, it'll be resolved
// asynchronously. The loop will continue from ResumeProcessing();
auto resume_closure =
base::BindOnce(&CommitDeferringConditionRunner::ResumeProcessing,
weak_factory_.GetWeakPtr());
if (!(*conditions_.begin())
->WillCommitNavigation(std::move(resume_closure))) {
is_deferred_ = true;
return;
}
// Otherwise, the condition is resolved synchronously so remove it and move
// on to the next one.
conditions_.erase(conditions_.begin());
}
// All checks are completed, proceed with the commit in the
// NavigationRequest.
delegate_.OnCommitDeferringConditionChecksComplete();
}
void CommitDeferringConditionRunner::AddCondition(
std::unique_ptr<CommitDeferringCondition> condition) {
if (!condition)
return;
conditions_.push_back(std::move(condition));
}
} // namespace content