File: webui_bubble_manager.h

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (243 lines) | stat: -rw-r--r-- 9,140 bytes parent folder | download | duplicates (5)
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_VIEWS_BUBBLE_WEBUI_BUBBLE_MANAGER_H_
#define CHROME_BROWSER_UI_VIEWS_BUBBLE_WEBUI_BUBBLE_MANAGER_H_

#include <memory>
#include <optional>
#include <string>
#include <utility>

#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/browser/ui/views/bubble/webui_bubble_dialog_view.h"
#include "chrome/browser/ui/views/bubble/webui_bubble_manager_observer.h"
#include "chrome/browser/ui/views/close_bubble_on_tab_activation_helper.h"
#include "chrome/browser/ui/webui/top_chrome/webui_contents_warmup_level.h"
#include "chrome/browser/ui/webui/webui_embedding_context.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_observer.h"

class GURL;
class WebUIBubbleDialogView;

// WebUIBubbleManager handles the creation / destruction of the WebUI bubble.
// This is needed to deal with the asynchronous presentation of WebUI.
class WebUIBubbleManager : public views::WidgetObserver {
 public:
  template <typename Controller>
  static std::unique_ptr<WebUIBubbleManager> Create(
      views::View* anchor_view,
      BrowserWindowInterface* browser_window_interface,
      const GURL& webui_url,
      int task_manager_string_id,
      bool force_load_on_create = false);

  WebUIBubbleManager(const WebUIBubbleManager&) = delete;
  const WebUIBubbleManager& operator=(const WebUIBubbleManager&) = delete;
  ~WebUIBubbleManager() override;

  // Show the bubble. The widget is created synchronously. If the contents is
  // preloaded, the bubble will show immediately. Otherwise, the widget is
  // hidden and will be made visible at a later time when the page invokes
  // `MojoBubbleWebUIController::Embedder::ShowUI()`.
  bool ShowBubble(
      const std::optional<gfx::Rect>& anchor = std::nullopt,
      views::BubbleBorder::Arrow arrow = views::BubbleBorder::TOP_RIGHT,
      ui::ElementIdentifier identifier = ui::ElementIdentifier());

  void CloseBubble();

  views::Widget* GetBubbleWidget() const;

  void AddObserver(WebUIBubbleManagerObserver* observer);
  void RemoveObserver(WebUIBubbleManagerObserver* observer);

  // Register a callback that will be invoked when the bubble widget is
  // initialized. This is used for metrics collections.
  void set_widget_initialization_callback(base::OnceClosure callback) {
    widget_initialization_callback_ = std::move(callback);
  }

  bool bubble_using_cached_web_contents() const {
    return bubble_using_cached_web_contents_;
  }

  WebUIContentsWarmupLevel contents_warmup_level() const {
    CHECK(contents_warmup_level_.has_value());
    return *contents_warmup_level_;
  }

  // views::WidgetObserver:
  void OnWidgetDestroying(views::Widget* widget) override;

  base::WeakPtr<WebUIBubbleDialogView> bubble_view_for_testing() {
    return bubble_view_;
  }
  void ResetContentsWrapperForTesting();
  void DisableCloseBubbleHelperForTesting();
  WebUIContentsWrapper* GetContentsWrapperForTesting();

 protected:
  WebUIBubbleManager();

  virtual base::WeakPtr<WebUIBubbleDialogView> CreateWebUIBubbleDialog(
      const std::optional<gfx::Rect>& anchor,
      views::BubbleBorder::Arrow arrow) = 0;

  // Gets the WebUIContentsWrapper. This is available after calling
  // ShowBubble().
  virtual WebUIContentsWrapper* GetContentsWrapper() = 0;

  WebUIContentsWrapper* cached_contents_wrapper() {
    return cached_contents_wrapper_.get();
  }
  void set_cached_contents_wrapper(
      std::unique_ptr<WebUIContentsWrapper> cached_contents_wrapper) {
    cached_contents_wrapper_ = std::move(cached_contents_wrapper);
  }
  void set_bubble_using_cached_web_contents(bool is_cached) {
    bubble_using_cached_web_contents_ = is_cached;
  }

  // A callback that will be invoked when the bubble widget is initialized.
  base::OnceClosure widget_initialization_callback_;

  base::ObserverList<WebUIBubbleManagerObserver> observers_;

 private:
  void ResetContentsWrapper();

  base::WeakPtr<WebUIBubbleDialogView> bubble_view_;

  // Stores a cached WebUIContentsWrapper for reuse in the WebUIBubbleDialog.
  std::unique_ptr<WebUIContentsWrapper> cached_contents_wrapper_;

  // Tracks whether the current bubble was created by reusing a preloaded web
  // contents.
  bool bubble_using_cached_web_contents_ = false;

  // The readiness of the browser when it is about to show this
  // bubble. See WebUIContentsWarmupLevel.
  std::optional<WebUIContentsWarmupLevel> contents_warmup_level_;

  // A timer controlling how long the |cached_web_view_| is cached for.
  std::unique_ptr<base::RetainingOneShotTimer> cache_timer_;

  base::ScopedObservation<views::Widget, views::WidgetObserver>
      bubble_widget_observation_{this};

  // This is necessary to prevent a bug closing the active tab in the bubble.
  // See https://crbug.com/1139028.
  std::unique_ptr<CloseBubbleOnTabActivationHelper> close_bubble_helper_;

  // Controls whether `close_bubble_helper_` is set when ShowBubble() is called.
  bool disable_close_bubble_helper_ = false;
};

template <typename T>
class WebUIBubbleManagerImpl : public WebUIBubbleManager {
 public:
  WebUIBubbleManagerImpl(views::View* anchor_view,
                         BrowserWindowInterface* browser_window_interface,
                         const GURL& webui_url,
                         int task_manager_string_id,
                         bool force_load_on_create)
      : anchor_view_(anchor_view),
        browser_window_interface_(browser_window_interface),
        webui_url_(webui_url),
        task_manager_string_id_(task_manager_string_id),
        force_load_on_create_(force_load_on_create) {}
  ~WebUIBubbleManagerImpl() override = default;

 private:
  // WebUIBubbleManager:
  base::WeakPtr<WebUIBubbleDialogView> CreateWebUIBubbleDialog(
      const std::optional<gfx::Rect>& anchor,
      views::BubbleBorder::Arrow arrow) override;
  WebUIContentsWrapper* GetContentsWrapper() override;

  const raw_ptr<views::View> anchor_view_;
  const raw_ptr<BrowserWindowInterface> browser_window_interface_;
  const GURL webui_url_;
  const int task_manager_string_id_;

  // Forces the WebUI through the page load lifecycle when a bubble is created,
  // if necessary. If set page load is forced regardless of the caching status
  // of the contents.
  const bool force_load_on_create_;
};

template <typename Controller>
std::unique_ptr<WebUIBubbleManager> WebUIBubbleManager::Create(
    views::View* anchor_view,
    BrowserWindowInterface* browser_window_interface,
    const GURL& webui_url,
    int task_manager_string_id,
    bool force_load_on_create) {
  return std::make_unique<WebUIBubbleManagerImpl<Controller>>(
      anchor_view, browser_window_interface, webui_url, task_manager_string_id,
      force_load_on_create);
}

template <typename T>
base::WeakPtr<WebUIBubbleDialogView>
WebUIBubbleManagerImpl<T>::CreateWebUIBubbleDialog(
    const std::optional<gfx::Rect>& anchor,
    views::BubbleBorder::Arrow arrow) {
  WebUIContentsWrapper* contents_wrapper = nullptr;

  set_bubble_using_cached_web_contents(!!cached_contents_wrapper());

  if (!cached_contents_wrapper()) {
    set_cached_contents_wrapper(std::make_unique<WebUIContentsWrapperT<T>>(
        webui_url_, browser_window_interface_->GetProfile(),
        task_manager_string_id_));
  }

  contents_wrapper = cached_contents_wrapper();

  // Set the browser context for the chosen WebUIContentsWrapper.
  webui::SetBrowserWindowInterface(contents_wrapper->web_contents(),
                                   browser_window_interface_.get());

  // If the contents has already navigated to the current WebUI page force a
  // reload. This will force the contents back through the page load lifecycle.
  if (force_load_on_create_ &&
      !contents_wrapper->web_contents()
           ->HasUncommittedNavigationInPrimaryMainFrame()) {
    contents_wrapper->ReloadWebContents();
  }

  auto bubble_view = std::make_unique<WebUIBubbleDialogView>(
      anchor_view_, contents_wrapper->GetWeakPtr(), anchor, arrow);

  if (!widget_initialization_callback_.is_null()) {
    bubble_view->RegisterWidgetInitializedCallback(
        std::move(widget_initialization_callback_));
  }

  auto weak_ptr = bubble_view->GetWeakPtr();
  views::BubbleDialogDelegateView::CreateBubble(std::move(bubble_view));

  return weak_ptr;
}

template <typename T>
WebUIContentsWrapper* WebUIBubbleManagerImpl<T>::GetContentsWrapper() {
  return cached_contents_wrapper();
}

#endif  // CHROME_BROWSER_UI_VIEWS_BUBBLE_WEBUI_BUBBLE_MANAGER_H_