• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <memory>
6 
7 #include "libcef/browser/chrome/chrome_browser_delegate.h"
8 
9 #include "libcef/browser/browser_contents_delegate.h"
10 #include "libcef/browser/browser_host_base.h"
11 #include "libcef/browser/browser_info_manager.h"
12 #include "libcef/browser/browser_platform_delegate.h"
13 #include "libcef/browser/chrome/chrome_browser_host_impl.h"
14 #include "libcef/browser/request_context_impl.h"
15 #include "libcef/common/app_manager.h"
16 #include "libcef/common/frame_util.h"
17 
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_tabstrip.h"
21 #include "content/public/browser/global_routing_id.h"
22 #include "content/public/browser/keyboard_event_processing_result.h"
23 #include "content/public/browser/native_web_keyboard_event.h"
24 
25 using content::KeyboardEventProcessingResult;
26 
ChromeBrowserDelegate(Browser * browser,const CefBrowserCreateParams & create_params)27 ChromeBrowserDelegate::ChromeBrowserDelegate(
28     Browser* browser,
29     const CefBrowserCreateParams& create_params)
30     : browser_(browser), create_params_(create_params) {
31   DCHECK(browser_);
32 }
33 
34 ChromeBrowserDelegate::~ChromeBrowserDelegate() = default;
35 
OnWebContentsCreated(content::WebContents * new_contents)36 void ChromeBrowserDelegate::OnWebContentsCreated(
37     content::WebContents* new_contents) {
38   // Necessary to receive LoadingStateChanged calls during initial navigation.
39   // This will be called again in Browser::SetAsDelegate, which should be fine.
40   new_contents->SetDelegate(browser_);
41 
42   SetAsDelegate(new_contents, /*set_delegate=*/true);
43 }
44 
SetAsDelegate(content::WebContents * web_contents,bool set_delegate)45 void ChromeBrowserDelegate::SetAsDelegate(content::WebContents* web_contents,
46                                           bool set_delegate) {
47   DCHECK(web_contents);
48   auto browser_host =
49       ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
50 
51   // |set_delegate=false| only makes sense if we already have a browser host.
52   DCHECK(browser_host || set_delegate);
53 
54   if (browser_host) {
55     // We already have a browser host, so just change the associated Browser.
56     browser_host->SetBrowser(set_delegate ? browser_ : nullptr);
57     return;
58   }
59 
60   auto platform_delegate = CefBrowserPlatformDelegate::Create(create_params_);
61   CHECK(platform_delegate);
62 
63   auto browser_info = CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
64       /*is_popup=*/false, /*is_windowless=*/false, create_params_.extra_info);
65 
66   auto request_context_impl =
67       CefRequestContextImpl::GetOrCreateForRequestContext(
68           create_params_.request_context);
69 
70   CreateBrowser(web_contents, create_params_.settings, create_params_.client,
71                 std::move(platform_delegate), browser_info, /*opener=*/nullptr,
72                 request_context_impl);
73 }
74 
WebContentsCreated(content::WebContents * source_contents,int opener_render_process_id,int opener_render_frame_id,const std::string & frame_name,const GURL & target_url,content::WebContents * new_contents)75 void ChromeBrowserDelegate::WebContentsCreated(
76     content::WebContents* source_contents,
77     int opener_render_process_id,
78     int opener_render_frame_id,
79     const std::string& frame_name,
80     const GURL& target_url,
81     content::WebContents* new_contents) {
82   CefBrowserSettings settings;
83   CefRefPtr<CefClient> client;
84   std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate;
85   CefRefPtr<CefDictionaryValue> extra_info;
86 
87   CefBrowserInfoManager::GetInstance()->WebContentsCreated(
88       target_url,
89       frame_util::MakeGlobalId(opener_render_process_id,
90                                opener_render_frame_id),
91       settings, client, platform_delegate, extra_info);
92 
93   auto opener = ChromeBrowserHostImpl::GetBrowserForContents(source_contents);
94   if (!opener) {
95     LOG(ERROR) << "No opener found for chrome popup browser";
96     return;
97   }
98 
99   auto browser_info =
100       CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo(
101           new_contents, /*is_windowless=*/false, extra_info);
102   CHECK(browser_info->is_popup());
103 
104   // Popups must share the same RequestContext as the parent.
105   auto request_context_impl = opener->request_context();
106   CHECK(request_context_impl);
107 
108   // We don't officially own |new_contents| until AddNewContents() is called.
109   // However, we need to install observers/delegates here.
110   CreateBrowser(new_contents, settings, client, std::move(platform_delegate),
111                 browser_info, opener, request_context_impl);
112 }
113 
AddNewContents(content::WebContents * source_contents,std::unique_ptr<content::WebContents> new_contents,const GURL & target_url,WindowOpenDisposition disposition,const gfx::Rect & initial_rect,bool user_gesture,bool * was_blocked)114 void ChromeBrowserDelegate::AddNewContents(
115     content::WebContents* source_contents,
116     std::unique_ptr<content::WebContents> new_contents,
117     const GURL& target_url,
118     WindowOpenDisposition disposition,
119     const gfx::Rect& initial_rect,
120     bool user_gesture,
121     bool* was_blocked) {
122   auto new_browser =
123       ChromeBrowserHostImpl::GetBrowserForContents(new_contents.get());
124   if (new_browser) {
125     // Create a new Browser and give it ownership of the WebContents.
126     new_browser->AddNewContents(std::move(new_contents));
127     return;
128   }
129 
130   // Fall back to default behavior from Browser::AddNewContents.
131   chrome::AddWebContents(browser_, source_contents, std::move(new_contents),
132                          target_url, disposition, initial_rect);
133 }
134 
OpenURLFromTab(content::WebContents * source,const content::OpenURLParams & params)135 content::WebContents* ChromeBrowserDelegate::OpenURLFromTab(
136     content::WebContents* source,
137     const content::OpenURLParams& params) {
138   // |source| may be nullptr when opening a link from chrome UI such as the
139   // Reading List sidebar. In that case we default to using the Browser's
140   // currently active WebContents.
141   if (!source) {
142     source = browser_->tab_strip_model()->GetActiveWebContents();
143     DCHECK(source);
144   }
145 
146   // Return nullptr to cancel the navigation. Otherwise, proceed with default
147   // chrome handling.
148   if (auto delegate = GetDelegateForWebContents(source)) {
149     return delegate->OpenURLFromTab(source, params);
150   }
151   return nullptr;
152 }
153 
LoadingStateChanged(content::WebContents * source,bool should_show_loading_ui)154 void ChromeBrowserDelegate::LoadingStateChanged(content::WebContents* source,
155                                                 bool should_show_loading_ui) {
156   if (auto delegate = GetDelegateForWebContents(source)) {
157     delegate->LoadingStateChanged(source, should_show_loading_ui);
158   }
159 }
160 
UpdateTargetURL(content::WebContents * source,const GURL & url)161 void ChromeBrowserDelegate::UpdateTargetURL(content::WebContents* source,
162                                             const GURL& url) {
163   if (auto delegate = GetDelegateForWebContents(source)) {
164     delegate->UpdateTargetURL(source, url);
165   }
166 }
167 
DidAddMessageToConsole(content::WebContents * source,blink::mojom::ConsoleMessageLevel log_level,const std::u16string & message,int32_t line_no,const std::u16string & source_id)168 bool ChromeBrowserDelegate::DidAddMessageToConsole(
169     content::WebContents* source,
170     blink::mojom::ConsoleMessageLevel log_level,
171     const std::u16string& message,
172     int32_t line_no,
173     const std::u16string& source_id) {
174   if (auto delegate = GetDelegateForWebContents(source)) {
175     return delegate->DidAddMessageToConsole(source, log_level, message, line_no,
176                                             source_id);
177   }
178   return false;
179 }
180 
DidNavigatePrimaryMainFramePostCommit(content::WebContents * web_contents)181 void ChromeBrowserDelegate::DidNavigatePrimaryMainFramePostCommit(
182     content::WebContents* web_contents) {
183   if (auto delegate = GetDelegateForWebContents(web_contents)) {
184     delegate->DidNavigatePrimaryMainFramePostCommit(web_contents);
185   }
186 }
187 
EnterFullscreenModeForTab(content::RenderFrameHost * requesting_frame,const blink::mojom::FullscreenOptions & options)188 void ChromeBrowserDelegate::EnterFullscreenModeForTab(
189     content::RenderFrameHost* requesting_frame,
190     const blink::mojom::FullscreenOptions& options) {
191   auto web_contents =
192       content::WebContents::FromRenderFrameHost(requesting_frame);
193   if (!web_contents)
194     return;
195 
196   if (auto delegate = GetDelegateForWebContents(web_contents)) {
197     delegate->EnterFullscreenModeForTab(requesting_frame, options);
198   }
199 }
200 
ExitFullscreenModeForTab(content::WebContents * web_contents)201 void ChromeBrowserDelegate::ExitFullscreenModeForTab(
202     content::WebContents* web_contents) {
203   if (auto delegate = GetDelegateForWebContents(web_contents)) {
204     delegate->ExitFullscreenModeForTab(web_contents);
205   }
206 }
207 
PreHandleKeyboardEvent(content::WebContents * source,const content::NativeWebKeyboardEvent & event)208 KeyboardEventProcessingResult ChromeBrowserDelegate::PreHandleKeyboardEvent(
209     content::WebContents* source,
210     const content::NativeWebKeyboardEvent& event) {
211   if (auto delegate = GetDelegateForWebContents(source)) {
212     return delegate->PreHandleKeyboardEvent(source, event);
213   }
214   return KeyboardEventProcessingResult::NOT_HANDLED;
215 }
216 
HandleKeyboardEvent(content::WebContents * source,const content::NativeWebKeyboardEvent & event)217 bool ChromeBrowserDelegate::HandleKeyboardEvent(
218     content::WebContents* source,
219     const content::NativeWebKeyboardEvent& event) {
220   if (auto delegate = GetDelegateForWebContents(source)) {
221     return delegate->HandleKeyboardEvent(source, event);
222   }
223   return false;
224 }
225 
CreateBrowser(content::WebContents * web_contents,CefBrowserSettings settings,CefRefPtr<CefClient> client,std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,scoped_refptr<CefBrowserInfo> browser_info,CefRefPtr<ChromeBrowserHostImpl> opener,CefRefPtr<CefRequestContextImpl> request_context_impl)226 void ChromeBrowserDelegate::CreateBrowser(
227     content::WebContents* web_contents,
228     CefBrowserSettings settings,
229     CefRefPtr<CefClient> client,
230     std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
231     scoped_refptr<CefBrowserInfo> browser_info,
232     CefRefPtr<ChromeBrowserHostImpl> opener,
233     CefRefPtr<CefRequestContextImpl> request_context_impl) {
234   CEF_REQUIRE_UIT();
235   DCHECK(web_contents);
236   DCHECK(platform_delegate);
237   DCHECK(browser_info);
238   DCHECK(request_context_impl);
239 
240   // If |opener| is non-nullptr it must be a popup window.
241   DCHECK(!opener.get() || browser_info->is_popup());
242 
243   if (!client) {
244     if (auto app = CefAppManager::Get()->GetApplication()) {
245       if (auto bph = app->GetBrowserProcessHandler()) {
246         client = bph->GetDefaultClient();
247       }
248     }
249   }
250 
251   if (!client) {
252     LOG(WARNING) << "Creating a chrome browser without a client";
253   }
254 
255   // Check if chrome and CEF are using the same browser context.
256   // TODO(chrome-runtime): Verify if/when this might occur.
257   auto chrome_browser_context =
258       CefBrowserContext::FromBrowserContext(browser_->create_params().profile);
259   if (chrome_browser_context != request_context_impl->GetBrowserContext()) {
260     LOG(WARNING) << "Creating a chrome browser with mismatched context";
261   }
262 
263   // Remains alive until the associated WebContents is destroyed.
264   CefRefPtr<ChromeBrowserHostImpl> browser_host =
265       new ChromeBrowserHostImpl(settings, client, std::move(platform_delegate),
266                                 browser_info, request_context_impl);
267   browser_host->Attach(web_contents, opener);
268 
269   // The Chrome browser for a popup won't be created until AddNewContents().
270   if (!opener) {
271     browser_host->SetBrowser(browser_);
272   }
273 }
274 
GetDelegateForWebContents(content::WebContents * web_contents)275 CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents(
276     content::WebContents* web_contents) {
277   auto browser_host =
278       ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
279   if (browser_host)
280     return browser_host->contents_delegate();
281   return nullptr;
282 }
283 
284 namespace cef {
285 
286 // static
Create(Browser * browser,scoped_refptr<CreateParams> cef_params)287 std::unique_ptr<BrowserDelegate> BrowserDelegate::Create(
288     Browser* browser,
289     scoped_refptr<CreateParams> cef_params) {
290   CefBrowserCreateParams create_params;
291 
292   // Parameters from ChromeBrowserHostImpl::Create, or nullptr if the Browser
293   // was created from somewhere else.
294   auto params = static_cast<ChromeBrowserHostImpl::DelegateCreateParams*>(
295       cef_params.get());
296   if (params) {
297     create_params = params->create_params_;
298 
299     // Clear these values so they're not persisted to additional Browsers.
300 #if defined(TOOLKIT_VIEWS)
301     params->create_params_.browser_view = nullptr;
302 #endif
303   }
304 
305   return std::make_unique<ChromeBrowserDelegate>(browser, create_params);
306 }
307 
308 }  // namespace cef
309