File: web_contents_based_canceller.cc

package info (click to toggle)
chromium 145.0.7632.159-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,976,224 kB
  • sloc: cpp: 36,198,469; ansic: 7,634,080; javascript: 3,564,060; python: 1,649,622; xml: 838,470; asm: 717,087; pascal: 185,708; sh: 88,786; perl: 88,718; objc: 79,984; sql: 59,811; cs: 42,452; fortran: 24,101; makefile: 21,144; tcl: 15,277; php: 14,022; yacc: 9,066; ruby: 7,553; awk: 3,720; lisp: 3,233; lex: 1,328; ada: 727; jsp: 228; sed: 36
file content (133 lines) | stat: -rw-r--r-- 4,617 bytes parent folder | download | duplicates (3)
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2025 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/web_contents_based_canceller.h"

#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "content/common/features.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"

namespace content {

// static
std::unique_ptr<WebContentsBasedCanceller> WebContentsBasedCanceller::Create(
    RenderFrameHost* rfh,
    CancelCondition condition) {
  // `make_unique` would force the constructor to be public.
  auto canceller =
      base::WrapUnique(new WebContentsBasedCanceller(rfh, condition));
  if (canceller->CanShow()) {
    return canceller;
  }
  return nullptr;
}

WebContentsBasedCanceller::WebContentsBasedCanceller(
    RenderFrameHost* render_frame_host,
    CancelCondition condition)
    : WebContentsObserver(WebContents::FromRenderFrameHost(render_frame_host)),
      condition_(condition),
      document_(render_frame_host->GetWeakDocumentPtr()) {}

WebContentsBasedCanceller::~WebContentsBasedCanceller() = default;

bool WebContentsBasedCanceller::CanShow() {
  RenderFrameHost* render_frame_host = document_.AsRenderFrameHostIfValid();
  if (!render_frame_host) {
    return false;
  }
  return CanShowForVisibility(web_contents()->GetVisibility()) &&
         CanShowForRFHActiveState() && CanShowForTabState();
}

bool WebContentsBasedCanceller::CanShowForVisibility(Visibility visibility) {
  return condition_ != CancelCondition::kVisibility ||
         visibility != Visibility::HIDDEN;
}

bool WebContentsBasedCanceller::CanShowForRFHActiveState() {
  RenderFrameHost* render_frame_host = document_.AsRenderFrameHostIfValid();
  return render_frame_host && render_frame_host->IsActive();
}

bool WebContentsBasedCanceller::CanShowForTabState() {
  if (!base::FeatureList::IsEnabled(
          features::kSideBySideFilePickerCancelling)) {
    return true;
  }
  // Within Split View, it is possible for the tab containing a WebContents to
  // be visible but not active. This scenario is considered a cancel condition
  // for kVisibility rather than kActiveState because kActiveState is determined
  // by the RenderFrameHost state, while kVisibility is determined by the
  // WebContents state.
  WebContentsDelegate* web_contents_delegate = web_contents()->GetDelegate();
  return condition_ != CancelCondition::kVisibility || !web_contents_delegate ||
         web_contents_delegate->IsContentsActive(web_contents());
}

void WebContentsBasedCanceller::SetCancelCallback(
    CancelCallback cancel_callback) {
  CHECK(cancel_callback_.is_null());
  // Check all conditions immediately. This ensures that even if
  // SetCancelCallback is called later (in a different task), we are not leaving
  // a window for a race.
  if (!CanShow()) {
    std::move(cancel_callback).Run();
    return;
  }
  cancel_callback_ = std::move(cancel_callback);
}

void WebContentsBasedCanceller::OnVisibilityChanged(Visibility visibility) {
  // TODO(https://crbug.com/446032849): Remove this.
  VLOG(1) << "Visibility changed: " << static_cast<int>(visibility);
#if BUILDFLAG(IS_ANDROID)
  // TODO(crbug.com/457495639): We need a different way to detect when a
  // WebContents is no longer displayed to the user for android since the
  // intent to select a file always causes a HIDDEN event as the whole app
  // receives onStop().
  return;
#else
  if (cancel_callback_.is_null()) {
    return;
  }
  if (!CanShowForVisibility(visibility)) {
    // TODO(https://crbug.com/446032849): Remove this.
    VLOG(1) << "Cancelling";
    std::move(cancel_callback_).Run();
  }
#endif
}

void WebContentsBasedCanceller::RenderFrameHostStateChanged(
    RenderFrameHost* changed_render_frame_host,
    RenderFrameHost::LifecycleState old_state,
    RenderFrameHost::LifecycleState new_state) {
  // TODO(https://crbug.com/446032849): Remove this.
  VLOG(1) << "State changed: " << static_cast<int>(new_state);
  if (cancel_callback_.is_null()) {
    return;
  }

  if (!CanShowForRFHActiveState()) {
    VLOG(1) << "Cancelling.";
    std::move(cancel_callback_).Run();
    return;
  }
}

void WebContentsBasedCanceller::DidFinishNavigation(
    NavigationHandle* navigation_handle) {
  VLOG(1) << "Finished navigation";
  if (!document_.AsRenderFrameHostIfValid()) {
    // TODO(https://crbug.com/446032849): Remove this.
    VLOG(1) << "Cancelling";
    std::move(cancel_callback_).Run();
  }
}

}  // namespace content