1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65

content / browser / renderer_host / concurrent_navigations_commit_deferring_condition.cc [blame]

// Copyright 2023 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/concurrent_navigations_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"

namespace content {

// static
std::unique_ptr<CommitDeferringCondition>
ConcurrentNavigationsCommitDeferringCondition::MaybeCreate(
    NavigationRequest& navigation_request,
    NavigationType navigation_type) {
  // Only defer back/forward cache or prerender activations here. Non-activation
  // navigations are handled by code in NavigationRequest instead.
  if (!navigation_request.IsServedFromBackForwardCache() &&
      navigation_type != NavigationType::kPrerenderedPageActivation) {
    return nullptr;
  }

  // Currently only navigations in the primary main frame can restore pages
  // from BFCache or activate prerendered pages.
  DCHECK(navigation_request.IsInPrimaryMainFrame());

  return base::WrapUnique(
      new ConcurrentNavigationsCommitDeferringCondition(navigation_request));
}

ConcurrentNavigationsCommitDeferringCondition::
    ConcurrentNavigationsCommitDeferringCondition(
        NavigationRequest& navigation_request)
    : CommitDeferringCondition(navigation_request) {}

ConcurrentNavigationsCommitDeferringCondition::
    ~ConcurrentNavigationsCommitDeferringCondition() = default;

CommitDeferringCondition::Result
ConcurrentNavigationsCommitDeferringCondition::WillCommitNavigation(
    base::OnceClosure resume) {
  auto* request = NavigationRequest::From(&GetNavigationHandle());

  // See if there is a speculative RFH that has a pending commit cross-document
  // navigation. It's possible for a speculative RenderFrameHost to exist for
  // another navigation as we don't delete existing speculative RFHs that have
  // in-flight commits when we start a new navigation. We need to defer our
  // navigation while the older commit continues, to avoid deleting a pending
  // commit RFH.
  if (request->ShouldQueueDueToExistingPendingCommitRFH()) {
    DCHECK(!request->IsQueued());
    request->set_resume_commit_closure(std::move(resume));
    return Result::kDefer;
  }
  return Result::kProceed;
}

const char* ConcurrentNavigationsCommitDeferringCondition::TraceEventName()
    const {
  return "ConcurrentNavigationsCommitDeferringCondition";
}

}  // namespace content