1 // Copyright (c) 2012 The Chromium Embedded Framework Authors.
2 // Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "libcef/browser/alloy/alloy_browser_host_impl.h"
7
8 #include <string>
9 #include <utility>
10
11 #include "libcef/browser/alloy/alloy_browser_context.h"
12 #include "libcef/browser/audio_capturer.h"
13 #include "libcef/browser/browser_context.h"
14 #include "libcef/browser/browser_info.h"
15 #include "libcef/browser/browser_info_manager.h"
16 #include "libcef/browser/browser_platform_delegate.h"
17 #include "libcef/browser/context.h"
18 #include "libcef/browser/devtools/devtools_manager.h"
19 #include "libcef/browser/media_capture_devices_dispatcher.h"
20 #include "libcef/browser/native/cursor_util.h"
21 #include "libcef/browser/osr/osr_util.h"
22 #include "libcef/browser/request_context_impl.h"
23 #include "libcef/browser/thread_util.h"
24 #include "libcef/common/cef_messages.h"
25 #include "libcef/common/cef_switches.h"
26 #include "libcef/common/drag_data_impl.h"
27 #include "libcef/common/net/url_util.h"
28 #include "libcef/common/request_impl.h"
29 #include "libcef/common/values_impl.h"
30 #include "libcef/features/runtime_checks.h"
31
32 #include "base/bind.h"
33 #include "base/callback_helpers.h"
34 #include "base/command_line.h"
35 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
36 #include "content/browser/gpu/compositor_util.h"
37 #include "content/browser/renderer_host/render_widget_host_impl.h"
38 #include "content/public/browser/desktop_media_id.h"
39 #include "content/public/browser/file_select_listener.h"
40 #include "content/public/browser/host_zoom_map.h"
41 #include "content/public/browser/keyboard_event_processing_result.h"
42 #include "content/public/browser/native_web_keyboard_event.h"
43 #include "content/public/browser/navigation_controller.h"
44 #include "content/public/browser/navigation_handle.h"
45 #include "content/public/browser/render_frame_host.h"
46 #include "content/public/browser/render_process_host.h"
47 #include "content/public/browser/render_view_host.h"
48 #include "content/public/browser/render_widget_host.h"
49 #include "content/public/browser/render_widget_host_observer.h"
50 #include "content/public/browser/web_contents.h"
51 #include "extensions/common/constants.h"
52 #include "extensions/common/extension.h"
53 #include "net/base/net_errors.h"
54 #include "third_party/blink/public/mojom/page/widget.mojom-test-utils.h"
55 #include "ui/events/base_event_utils.h"
56
57 using content::KeyboardEventProcessingResult;
58
59 namespace {
60
61 class ShowDevToolsHelper {
62 public:
ShowDevToolsHelper(CefRefPtr<AlloyBrowserHostImpl> browser,const CefWindowInfo & windowInfo,CefRefPtr<CefClient> client,const CefBrowserSettings & settings,const CefPoint & inspect_element_at)63 ShowDevToolsHelper(CefRefPtr<AlloyBrowserHostImpl> browser,
64 const CefWindowInfo& windowInfo,
65 CefRefPtr<CefClient> client,
66 const CefBrowserSettings& settings,
67 const CefPoint& inspect_element_at)
68 : browser_(browser),
69 window_info_(windowInfo),
70 client_(client),
71 settings_(settings),
72 inspect_element_at_(inspect_element_at) {}
73
74 CefRefPtr<AlloyBrowserHostImpl> browser_;
75 CefWindowInfo window_info_;
76 CefRefPtr<CefClient> client_;
77 CefBrowserSettings settings_;
78 CefPoint inspect_element_at_;
79 };
80
ShowDevToolsWithHelper(ShowDevToolsHelper * helper)81 void ShowDevToolsWithHelper(ShowDevToolsHelper* helper) {
82 helper->browser_->ShowDevTools(helper->window_info_, helper->client_,
83 helper->settings_,
84 helper->inspect_element_at_);
85 delete helper;
86 }
87
88 class CefWidgetHostInterceptor
89 : public blink::mojom::WidgetHostInterceptorForTesting,
90 public content::RenderWidgetHostObserver {
91 public:
CefWidgetHostInterceptor(AlloyBrowserHostImpl * browser,content::RenderViewHost * render_view_host)92 CefWidgetHostInterceptor(AlloyBrowserHostImpl* browser,
93 content::RenderViewHost* render_view_host)
94 : browser_(browser),
95 render_widget_host_(
96 content::RenderWidgetHostImpl::From(render_view_host->GetWidget())),
97 impl_(render_widget_host_->widget_host_receiver_for_testing()
98 .SwapImplForTesting(this)) {
99 render_widget_host_->AddObserver(this);
100 }
101
GetForwardingInterface()102 blink::mojom::WidgetHost* GetForwardingInterface() override { return impl_; }
103
104 // WidgetHostInterceptorForTesting method:
SetCursor(const ui::Cursor & cursor)105 void SetCursor(const ui::Cursor& cursor) override {
106 if (cursor_util::OnCursorChange(browser_, cursor)) {
107 // Don't change the cursor.
108 return;
109 }
110
111 GetForwardingInterface()->SetCursor(cursor);
112 }
113
114 // RenderWidgetHostObserver method:
RenderWidgetHostDestroyed(content::RenderWidgetHost * widget_host)115 void RenderWidgetHostDestroyed(
116 content::RenderWidgetHost* widget_host) override {
117 widget_host->RemoveObserver(this);
118 delete this;
119 }
120
121 private:
122 AlloyBrowserHostImpl* const browser_;
123 content::RenderWidgetHostImpl* const render_widget_host_;
124 blink::mojom::WidgetHost* const impl_;
125
126 DISALLOW_COPY_AND_ASSIGN(CefWidgetHostInterceptor);
127 };
128
129 static constexpr base::TimeDelta kRecentlyAudibleTimeout =
130 base::TimeDelta::FromSeconds(2);
131
132 } // namespace
133
134 // AlloyBrowserHostImpl static methods.
135 // -----------------------------------------------------------------------------
136
137 // static
Create(CefBrowserCreateParams & create_params)138 CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::Create(
139 CefBrowserCreateParams& create_params) {
140 std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate =
141 CefBrowserPlatformDelegate::Create(create_params);
142 CHECK(platform_delegate);
143
144 const bool is_devtools_popup = !!create_params.devtools_opener;
145
146 scoped_refptr<CefBrowserInfo> info =
147 CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
148 is_devtools_popup, platform_delegate->IsWindowless(),
149 create_params.extra_info);
150
151 bool own_web_contents = false;
152
153 // This call may modify |create_params|.
154 auto web_contents =
155 platform_delegate->CreateWebContents(create_params, own_web_contents);
156
157 auto request_context_impl =
158 static_cast<CefRequestContextImpl*>(create_params.request_context.get());
159
160 CefRefPtr<CefExtension> cef_extension;
161 if (create_params.extension) {
162 auto cef_browser_context = request_context_impl->GetBrowserContext();
163 cef_extension =
164 cef_browser_context->GetExtension(create_params.extension->id());
165 CHECK(cef_extension);
166 }
167
168 auto platform_delegate_ptr = platform_delegate.get();
169
170 CefRefPtr<AlloyBrowserHostImpl> browser = CreateInternal(
171 create_params.settings, create_params.client, web_contents,
172 own_web_contents, info,
173 static_cast<AlloyBrowserHostImpl*>(create_params.devtools_opener.get()),
174 is_devtools_popup, request_context_impl, std::move(platform_delegate),
175 cef_extension);
176 if (!browser)
177 return nullptr;
178
179 GURL url = url_util::MakeGURL(create_params.url, /*fixup=*/true);
180
181 if (create_params.extension) {
182 platform_delegate_ptr->CreateExtensionHost(
183 create_params.extension, url, create_params.extension_host_type);
184 } else if (!url.is_empty()) {
185 content::OpenURLParams params(url, content::Referrer(),
186 WindowOpenDisposition::CURRENT_TAB,
187 CefFrameHostImpl::kPageTransitionExplicit,
188 /*is_renderer_initiated=*/false);
189 browser->LoadMainFrameURL(params);
190 }
191
192 return browser.get();
193 }
194
195 // static
CreateInternal(const CefBrowserSettings & settings,CefRefPtr<CefClient> client,content::WebContents * web_contents,bool own_web_contents,scoped_refptr<CefBrowserInfo> browser_info,CefRefPtr<AlloyBrowserHostImpl> opener,bool is_devtools_popup,CefRefPtr<CefRequestContextImpl> request_context,std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,CefRefPtr<CefExtension> extension)196 CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::CreateInternal(
197 const CefBrowserSettings& settings,
198 CefRefPtr<CefClient> client,
199 content::WebContents* web_contents,
200 bool own_web_contents,
201 scoped_refptr<CefBrowserInfo> browser_info,
202 CefRefPtr<AlloyBrowserHostImpl> opener,
203 bool is_devtools_popup,
204 CefRefPtr<CefRequestContextImpl> request_context,
205 std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
206 CefRefPtr<CefExtension> extension) {
207 CEF_REQUIRE_UIT();
208 DCHECK(web_contents);
209 DCHECK(browser_info);
210 DCHECK(request_context);
211 DCHECK(platform_delegate);
212
213 // If |opener| is non-NULL it must be a popup window.
214 DCHECK(!opener.get() || browser_info->is_popup());
215
216 if (opener) {
217 if (!opener->platform_delegate_) {
218 // The opener window is being destroyed. Cancel the popup.
219 if (own_web_contents)
220 delete web_contents;
221 return nullptr;
222 }
223
224 // Give the opener browser's platform delegate an opportunity to modify the
225 // new browser's platform delegate.
226 opener->platform_delegate_->PopupWebContentsCreated(
227 settings, client, web_contents, platform_delegate.get(),
228 is_devtools_popup);
229 }
230
231 // Take ownership of |web_contents| if |own_web_contents| is true.
232 platform_delegate->WebContentsCreated(web_contents, own_web_contents);
233
234 CefRefPtr<AlloyBrowserHostImpl> browser = new AlloyBrowserHostImpl(
235 settings, client, web_contents, browser_info, opener, request_context,
236 std::move(platform_delegate), extension);
237 browser->InitializeBrowser();
238
239 if (!browser->CreateHostWindow())
240 return nullptr;
241
242 // Notify that the browser has been created. These must be delivered in the
243 // expected order.
244
245 // 1. Notify the browser's LifeSpanHandler. This must always be the first
246 // notification for the browser. Block navigation to avoid issues with focus
247 // changes being sent to an unbound interface.
248 {
249 auto navigation_lock = browser_info->CreateNavigationLock();
250 browser->OnAfterCreated();
251 }
252
253 // 2. Notify the platform delegate. With Views this will result in a call to
254 // CefBrowserViewDelegate::OnBrowserCreated().
255 browser->platform_delegate_->NotifyBrowserCreated();
256
257 if (opener && opener->platform_delegate_) {
258 // 3. Notify the opener browser's platform delegate. With Views this will
259 // result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
260 opener->platform_delegate_->PopupBrowserCreated(browser.get(),
261 is_devtools_popup);
262 }
263
264 return browser;
265 }
266
267 // static
GetBrowserForHost(const content::RenderViewHost * host)268 CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForHost(
269 const content::RenderViewHost* host) {
270 REQUIRE_ALLOY_RUNTIME();
271 auto browser = CefBrowserHostBase::GetBrowserForHost(host);
272 return static_cast<AlloyBrowserHostImpl*>(browser.get());
273 }
274
275 // static
GetBrowserForHost(const content::RenderFrameHost * host)276 CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForHost(
277 const content::RenderFrameHost* host) {
278 REQUIRE_ALLOY_RUNTIME();
279 auto browser = CefBrowserHostBase::GetBrowserForHost(host);
280 return static_cast<AlloyBrowserHostImpl*>(browser.get());
281 }
282
283 // static
GetBrowserForContents(const content::WebContents * contents)284 CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForContents(
285 const content::WebContents* contents) {
286 REQUIRE_ALLOY_RUNTIME();
287 auto browser = CefBrowserHostBase::GetBrowserForContents(contents);
288 return static_cast<AlloyBrowserHostImpl*>(browser.get());
289 }
290
291 // static
292 CefRefPtr<AlloyBrowserHostImpl>
GetBrowserForFrameTreeNode(int frame_tree_node_id)293 AlloyBrowserHostImpl::GetBrowserForFrameTreeNode(int frame_tree_node_id) {
294 REQUIRE_ALLOY_RUNTIME();
295 auto browser =
296 CefBrowserHostBase::GetBrowserForFrameTreeNode(frame_tree_node_id);
297 return static_cast<AlloyBrowserHostImpl*>(browser.get());
298 }
299
300 // static
GetBrowserForFrameRoute(int render_process_id,int render_routing_id)301 CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForFrameRoute(
302 int render_process_id,
303 int render_routing_id) {
304 REQUIRE_ALLOY_RUNTIME();
305 auto browser = CefBrowserHostBase::GetBrowserForFrameRoute(render_process_id,
306 render_routing_id);
307 return static_cast<AlloyBrowserHostImpl*>(browser.get());
308 }
309
310 // AlloyBrowserHostImpl methods.
311 // -----------------------------------------------------------------------------
312
~AlloyBrowserHostImpl()313 AlloyBrowserHostImpl::~AlloyBrowserHostImpl() {}
314
CloseBrowser(bool force_close)315 void AlloyBrowserHostImpl::CloseBrowser(bool force_close) {
316 if (CEF_CURRENTLY_ON_UIT()) {
317 // Exit early if a close attempt is already pending and this method is
318 // called again from somewhere other than WindowDestroyed().
319 if (destruction_state_ >= DESTRUCTION_STATE_PENDING &&
320 (IsWindowless() || !window_destroyed_)) {
321 if (force_close && destruction_state_ == DESTRUCTION_STATE_PENDING) {
322 // Upgrade the destruction state.
323 destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
324 }
325 return;
326 }
327
328 if (destruction_state_ < DESTRUCTION_STATE_ACCEPTED) {
329 destruction_state_ = (force_close ? DESTRUCTION_STATE_ACCEPTED
330 : DESTRUCTION_STATE_PENDING);
331 }
332
333 content::WebContents* contents = web_contents();
334 if (contents && contents->NeedToFireBeforeUnloadOrUnloadEvents()) {
335 // Will result in a call to BeforeUnloadFired() and, if the close isn't
336 // canceled, CloseContents().
337 contents->DispatchBeforeUnload(false /* auto_cancel */);
338 } else {
339 CloseContents(contents);
340 }
341 } else {
342 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::CloseBrowser,
343 this, force_close));
344 }
345 }
346
TryCloseBrowser()347 bool AlloyBrowserHostImpl::TryCloseBrowser() {
348 if (!CEF_CURRENTLY_ON_UIT()) {
349 NOTREACHED() << "called on invalid thread";
350 return false;
351 }
352
353 // Protect against multiple requests to close while the close is pending.
354 if (destruction_state_ <= DESTRUCTION_STATE_PENDING) {
355 if (destruction_state_ == DESTRUCTION_STATE_NONE) {
356 // Request that the browser close.
357 CloseBrowser(false);
358 }
359
360 // Cancel the close.
361 return false;
362 }
363
364 // Allow the close.
365 return true;
366 }
367
SetFocus(bool focus)368 void AlloyBrowserHostImpl::SetFocus(bool focus) {
369 // Always execute asynchronously to work around issue #3040.
370 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::SetFocusInternal,
371 this, focus));
372 }
373
SetFocusInternal(bool focus)374 void AlloyBrowserHostImpl::SetFocusInternal(bool focus) {
375 CEF_REQUIRE_UIT();
376 if (focus)
377 OnSetFocus(FOCUS_SOURCE_SYSTEM);
378 else if (platform_delegate_)
379 platform_delegate_->SendFocusEvent(false);
380 }
381
GetWindowHandle()382 CefWindowHandle AlloyBrowserHostImpl::GetWindowHandle() {
383 if (is_views_hosted_ && CEF_CURRENTLY_ON_UIT()) {
384 // Always return the most up-to-date window handle for a views-hosted
385 // browser since it may change if the view is re-parented.
386 if (platform_delegate_)
387 return platform_delegate_->GetHostWindowHandle();
388 }
389 return host_window_handle_;
390 }
391
GetOpenerWindowHandle()392 CefWindowHandle AlloyBrowserHostImpl::GetOpenerWindowHandle() {
393 return opener_;
394 }
395
GetZoomLevel()396 double AlloyBrowserHostImpl::GetZoomLevel() {
397 // Verify that this method is being called on the UI thread.
398 if (!CEF_CURRENTLY_ON_UIT()) {
399 NOTREACHED() << "called on invalid thread";
400 return 0;
401 }
402
403 if (web_contents())
404 return content::HostZoomMap::GetZoomLevel(web_contents());
405
406 return 0;
407 }
408
SetZoomLevel(double zoomLevel)409 void AlloyBrowserHostImpl::SetZoomLevel(double zoomLevel) {
410 if (CEF_CURRENTLY_ON_UIT()) {
411 if (web_contents())
412 content::HostZoomMap::SetZoomLevel(web_contents(), zoomLevel);
413 } else {
414 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::SetZoomLevel,
415 this, zoomLevel));
416 }
417 }
418
RunFileDialog(FileDialogMode mode,const CefString & title,const CefString & default_file_path,const std::vector<CefString> & accept_filters,int selected_accept_filter,CefRefPtr<CefRunFileDialogCallback> callback)419 void AlloyBrowserHostImpl::RunFileDialog(
420 FileDialogMode mode,
421 const CefString& title,
422 const CefString& default_file_path,
423 const std::vector<CefString>& accept_filters,
424 int selected_accept_filter,
425 CefRefPtr<CefRunFileDialogCallback> callback) {
426 if (!CEF_CURRENTLY_ON_UIT()) {
427 CEF_POST_TASK(CEF_UIT,
428 base::BindOnce(&AlloyBrowserHostImpl::RunFileDialog, this,
429 mode, title, default_file_path, accept_filters,
430 selected_accept_filter, callback));
431 return;
432 }
433
434 EnsureFileDialogManager();
435 file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
436 accept_filters, selected_accept_filter,
437 callback);
438 }
439
Print()440 void AlloyBrowserHostImpl::Print() {
441 if (!CEF_CURRENTLY_ON_UIT()) {
442 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::Print, this));
443 return;
444 }
445
446 if (platform_delegate_)
447 platform_delegate_->Print();
448 }
449
PrintToPDF(const CefString & path,const CefPdfPrintSettings & settings,CefRefPtr<CefPdfPrintCallback> callback)450 void AlloyBrowserHostImpl::PrintToPDF(const CefString& path,
451 const CefPdfPrintSettings& settings,
452 CefRefPtr<CefPdfPrintCallback> callback) {
453 if (!CEF_CURRENTLY_ON_UIT()) {
454 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::PrintToPDF,
455 this, path, settings, callback));
456 return;
457 }
458
459 if (platform_delegate_) {
460 platform_delegate_->PrintToPDF(path, settings, callback);
461 }
462 }
463
Find(int identifier,const CefString & searchText,bool forward,bool matchCase,bool findNext)464 void AlloyBrowserHostImpl::Find(int identifier,
465 const CefString& searchText,
466 bool forward,
467 bool matchCase,
468 bool findNext) {
469 if (!CEF_CURRENTLY_ON_UIT()) {
470 CEF_POST_TASK(CEF_UIT,
471 base::BindOnce(&AlloyBrowserHostImpl::Find, this, identifier,
472 searchText, forward, matchCase, findNext));
473 return;
474 }
475
476 if (platform_delegate_) {
477 platform_delegate_->Find(identifier, searchText, forward, matchCase,
478 findNext);
479 }
480 }
481
StopFinding(bool clearSelection)482 void AlloyBrowserHostImpl::StopFinding(bool clearSelection) {
483 if (!CEF_CURRENTLY_ON_UIT()) {
484 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::StopFinding,
485 this, clearSelection));
486 return;
487 }
488
489 if (platform_delegate_)
490 platform_delegate_->StopFinding(clearSelection);
491 }
492
ShowDevTools(const CefWindowInfo & windowInfo,CefRefPtr<CefClient> client,const CefBrowserSettings & settings,const CefPoint & inspect_element_at)493 void AlloyBrowserHostImpl::ShowDevTools(const CefWindowInfo& windowInfo,
494 CefRefPtr<CefClient> client,
495 const CefBrowserSettings& settings,
496 const CefPoint& inspect_element_at) {
497 if (!CEF_CURRENTLY_ON_UIT()) {
498 ShowDevToolsHelper* helper = new ShowDevToolsHelper(
499 this, windowInfo, client, settings, inspect_element_at);
500 CEF_POST_TASK(CEF_UIT, base::BindOnce(ShowDevToolsWithHelper, helper));
501 return;
502 }
503
504 if (!EnsureDevToolsManager())
505 return;
506 devtools_manager_->ShowDevTools(windowInfo, client, settings,
507 inspect_element_at);
508 }
509
CloseDevTools()510 void AlloyBrowserHostImpl::CloseDevTools() {
511 if (!CEF_CURRENTLY_ON_UIT()) {
512 CEF_POST_TASK(CEF_UIT,
513 base::BindOnce(&AlloyBrowserHostImpl::CloseDevTools, this));
514 return;
515 }
516
517 if (!devtools_manager_)
518 return;
519 devtools_manager_->CloseDevTools();
520 }
521
HasDevTools()522 bool AlloyBrowserHostImpl::HasDevTools() {
523 if (!CEF_CURRENTLY_ON_UIT()) {
524 NOTREACHED() << "called on invalid thread";
525 return false;
526 }
527
528 if (!devtools_manager_)
529 return false;
530 return devtools_manager_->HasDevTools();
531 }
532
SetAccessibilityState(cef_state_t accessibility_state)533 void AlloyBrowserHostImpl::SetAccessibilityState(
534 cef_state_t accessibility_state) {
535 if (!CEF_CURRENTLY_ON_UIT()) {
536 CEF_POST_TASK(CEF_UIT,
537 base::BindOnce(&AlloyBrowserHostImpl::SetAccessibilityState,
538 this, accessibility_state));
539 return;
540 }
541
542 if (platform_delegate_) {
543 platform_delegate_->SetAccessibilityState(accessibility_state);
544 }
545 }
546
SetAutoResizeEnabled(bool enabled,const CefSize & min_size,const CefSize & max_size)547 void AlloyBrowserHostImpl::SetAutoResizeEnabled(bool enabled,
548 const CefSize& min_size,
549 const CefSize& max_size) {
550 if (!CEF_CURRENTLY_ON_UIT()) {
551 CEF_POST_TASK(CEF_UIT,
552 base::BindOnce(&AlloyBrowserHostImpl::SetAutoResizeEnabled,
553 this, enabled, min_size, max_size));
554 return;
555 }
556
557 if (platform_delegate_) {
558 platform_delegate_->SetAutoResizeEnabled(enabled, min_size, max_size);
559 }
560 }
561
GetExtension()562 CefRefPtr<CefExtension> AlloyBrowserHostImpl::GetExtension() {
563 return extension_;
564 }
565
IsBackgroundHost()566 bool AlloyBrowserHostImpl::IsBackgroundHost() {
567 return is_background_host_;
568 }
569
IsWindowRenderingDisabled()570 bool AlloyBrowserHostImpl::IsWindowRenderingDisabled() {
571 return IsWindowless();
572 }
573
WasResized()574 void AlloyBrowserHostImpl::WasResized() {
575 if (!CEF_CURRENTLY_ON_UIT()) {
576 CEF_POST_TASK(CEF_UIT,
577 base::BindOnce(&AlloyBrowserHostImpl::WasResized, this));
578 return;
579 }
580
581 if (platform_delegate_)
582 platform_delegate_->WasResized();
583 }
584
WasHidden(bool hidden)585 void AlloyBrowserHostImpl::WasHidden(bool hidden) {
586 if (!IsWindowless()) {
587 NOTREACHED() << "Window rendering is not disabled";
588 return;
589 }
590
591 if (!CEF_CURRENTLY_ON_UIT()) {
592 CEF_POST_TASK(CEF_UIT,
593 base::BindOnce(&CefBrowserHost::WasHidden, this, hidden));
594 return;
595 }
596
597 if (platform_delegate_)
598 platform_delegate_->WasHidden(hidden);
599 }
600
NotifyScreenInfoChanged()601 void AlloyBrowserHostImpl::NotifyScreenInfoChanged() {
602 if (!IsWindowless()) {
603 NOTREACHED() << "Window rendering is not disabled";
604 return;
605 }
606
607 if (!CEF_CURRENTLY_ON_UIT()) {
608 CEF_POST_TASK(
609 CEF_UIT,
610 base::BindOnce(&AlloyBrowserHostImpl::NotifyScreenInfoChanged, this));
611 return;
612 }
613
614 if (platform_delegate_)
615 platform_delegate_->NotifyScreenInfoChanged();
616 }
617
Invalidate(PaintElementType type)618 void AlloyBrowserHostImpl::Invalidate(PaintElementType type) {
619 if (!IsWindowless()) {
620 NOTREACHED() << "Window rendering is not disabled";
621 return;
622 }
623
624 if (!CEF_CURRENTLY_ON_UIT()) {
625 CEF_POST_TASK(
626 CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::Invalidate, this, type));
627 return;
628 }
629
630 if (platform_delegate_)
631 platform_delegate_->Invalidate(type);
632 }
633
SendExternalBeginFrame()634 void AlloyBrowserHostImpl::SendExternalBeginFrame() {
635 if (!IsWindowless()) {
636 NOTREACHED() << "Window rendering is not disabled";
637 return;
638 }
639
640 if (!CEF_CURRENTLY_ON_UIT()) {
641 CEF_POST_TASK(
642 CEF_UIT,
643 base::Bind(&AlloyBrowserHostImpl::SendExternalBeginFrame, this));
644 return;
645 }
646
647 if (platform_delegate_)
648 platform_delegate_->SendExternalBeginFrame();
649 }
650
SendTouchEvent(const CefTouchEvent & event)651 void AlloyBrowserHostImpl::SendTouchEvent(const CefTouchEvent& event) {
652 if (!IsWindowless()) {
653 NOTREACHED() << "Window rendering is not disabled";
654 return;
655 }
656
657 if (!CEF_CURRENTLY_ON_UIT()) {
658 CEF_POST_TASK(CEF_UIT, base::Bind(&AlloyBrowserHostImpl::SendTouchEvent,
659 this, event));
660 return;
661 }
662
663 if (platform_delegate_)
664 platform_delegate_->SendTouchEvent(event);
665 }
666
SendFocusEvent(bool setFocus)667 void AlloyBrowserHostImpl::SendFocusEvent(bool setFocus) {
668 SetFocus(setFocus);
669 }
670
SendCaptureLostEvent()671 void AlloyBrowserHostImpl::SendCaptureLostEvent() {
672 if (!CEF_CURRENTLY_ON_UIT()) {
673 CEF_POST_TASK(
674 CEF_UIT,
675 base::BindOnce(&AlloyBrowserHostImpl::SendCaptureLostEvent, this));
676 return;
677 }
678
679 if (platform_delegate_)
680 platform_delegate_->SendCaptureLostEvent();
681 }
682
NotifyMoveOrResizeStarted()683 void AlloyBrowserHostImpl::NotifyMoveOrResizeStarted() {
684 #if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MAC))
685 if (!CEF_CURRENTLY_ON_UIT()) {
686 CEF_POST_TASK(
687 CEF_UIT,
688 base::BindOnce(&AlloyBrowserHostImpl::NotifyMoveOrResizeStarted, this));
689 return;
690 }
691
692 if (platform_delegate_)
693 platform_delegate_->NotifyMoveOrResizeStarted();
694 #endif
695 }
696
GetWindowlessFrameRate()697 int AlloyBrowserHostImpl::GetWindowlessFrameRate() {
698 // Verify that this method is being called on the UI thread.
699 if (!CEF_CURRENTLY_ON_UIT()) {
700 NOTREACHED() << "called on invalid thread";
701 return 0;
702 }
703
704 return osr_util::ClampFrameRate(settings_.windowless_frame_rate);
705 }
706
SetWindowlessFrameRate(int frame_rate)707 void AlloyBrowserHostImpl::SetWindowlessFrameRate(int frame_rate) {
708 if (!CEF_CURRENTLY_ON_UIT()) {
709 CEF_POST_TASK(CEF_UIT,
710 base::BindOnce(&AlloyBrowserHostImpl::SetWindowlessFrameRate,
711 this, frame_rate));
712 return;
713 }
714
715 settings_.windowless_frame_rate = frame_rate;
716
717 if (platform_delegate_)
718 platform_delegate_->SetWindowlessFrameRate(frame_rate);
719 }
720
721 // AlloyBrowserHostImpl public methods.
722 // -----------------------------------------------------------------------------
723
IsWindowless() const724 bool AlloyBrowserHostImpl::IsWindowless() const {
725 return is_windowless_;
726 }
727
IsPictureInPictureSupported() const728 bool AlloyBrowserHostImpl::IsPictureInPictureSupported() const {
729 // Not currently supported with OSR.
730 return !IsWindowless();
731 }
732
WindowDestroyed()733 void AlloyBrowserHostImpl::WindowDestroyed() {
734 CEF_REQUIRE_UIT();
735 DCHECK(!window_destroyed_);
736 window_destroyed_ = true;
737 CloseBrowser(true);
738 }
739
DestroyBrowser()740 void AlloyBrowserHostImpl::DestroyBrowser() {
741 CEF_REQUIRE_UIT();
742
743 destruction_state_ = DESTRUCTION_STATE_COMPLETED;
744
745 // Notify that this browser has been destroyed. These must be delivered in
746 // the expected order.
747
748 // 1. Notify the platform delegate. With Views this will result in a call to
749 // CefBrowserViewDelegate::OnBrowserDestroyed().
750 platform_delegate_->NotifyBrowserDestroyed();
751
752 // 2. Notify the browser's LifeSpanHandler. This must always be the last
753 // notification for this browser.
754 OnBeforeClose();
755
756 // Destroy any platform constructs first.
757 if (file_dialog_manager_.get())
758 file_dialog_manager_->Destroy();
759 if (javascript_dialog_manager_.get())
760 javascript_dialog_manager_->Destroy();
761 if (menu_manager_.get())
762 menu_manager_->Destroy();
763
764 // Notify any observers that may have state associated with this browser.
765 OnBrowserDestroyed();
766
767 // If the WebContents still exists at this point, signal destruction before
768 // browser destruction.
769 if (web_contents()) {
770 WebContentsDestroyed();
771 }
772
773 // Disassociate the platform delegate from this browser.
774 platform_delegate_->BrowserDestroyed(this);
775
776 // Delete objects created by the platform delegate that may be referenced by
777 // the WebContents.
778 file_dialog_manager_.reset(nullptr);
779 javascript_dialog_manager_.reset(nullptr);
780 menu_manager_.reset(nullptr);
781
782 // Delete the audio capturer
783 recently_audible_timer_.Stop();
784 audio_capturer_.reset(nullptr);
785
786 CefBrowserHostBase::DestroyBrowser();
787 }
788
CancelContextMenu()789 void AlloyBrowserHostImpl::CancelContextMenu() {
790 CEF_REQUIRE_UIT();
791 if (menu_manager_)
792 menu_manager_->CancelContextMenu();
793 }
794
MaybeAllowNavigation(content::RenderFrameHost * opener,bool is_guest_view,const content::OpenURLParams & params)795 bool AlloyBrowserHostImpl::MaybeAllowNavigation(
796 content::RenderFrameHost* opener,
797 bool is_guest_view,
798 const content::OpenURLParams& params) {
799 if (is_guest_view && !params.url.SchemeIs(extensions::kExtensionScheme) &&
800 !params.url.SchemeIs(content::kChromeUIScheme)) {
801 // The PDF viewer will load the PDF extension in the guest view, and print
802 // preview will load chrome://print in the guest view. All other navigations
803 // are passed to the owner browser.
804 CEF_POST_TASK(
805 CEF_UIT,
806 base::Bind(base::IgnoreResult(&AlloyBrowserHostImpl::OpenURLFromTab),
807 this, nullptr, params));
808
809 return false;
810 }
811
812 return true;
813 }
814
GetExtensionHost() const815 extensions::ExtensionHost* AlloyBrowserHostImpl::GetExtensionHost() const {
816 CEF_REQUIRE_UIT();
817 DCHECK(platform_delegate_);
818 return platform_delegate_->GetExtensionHost();
819 }
820
OnSetFocus(cef_focus_source_t source)821 void AlloyBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
822 if (!CEF_CURRENTLY_ON_UIT()) {
823 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::OnSetFocus,
824 this, source));
825 return;
826 }
827
828 if (contents_delegate_->OnSetFocus(source))
829 return;
830
831 if (platform_delegate_)
832 platform_delegate_->SendFocusEvent(true);
833 }
834
RunFileChooser(const CefFileDialogRunner::FileChooserParams & params,CefFileDialogRunner::RunFileChooserCallback callback)835 void AlloyBrowserHostImpl::RunFileChooser(
836 const CefFileDialogRunner::FileChooserParams& params,
837 CefFileDialogRunner::RunFileChooserCallback callback) {
838 EnsureFileDialogManager();
839 file_dialog_manager_->RunFileChooser(params, std::move(callback));
840 }
841
EnterFullscreenModeForTab(content::RenderFrameHost * requesting_frame,const blink::mojom::FullscreenOptions & options)842 void AlloyBrowserHostImpl::EnterFullscreenModeForTab(
843 content::RenderFrameHost* requesting_frame,
844 const blink::mojom::FullscreenOptions& options) {
845 contents_delegate_->EnterFullscreenModeForTab(requesting_frame, options);
846 WasResized();
847 }
848
ExitFullscreenModeForTab(content::WebContents * web_contents)849 void AlloyBrowserHostImpl::ExitFullscreenModeForTab(
850 content::WebContents* web_contents) {
851 contents_delegate_->ExitFullscreenModeForTab(web_contents);
852 WasResized();
853 }
854
IsFullscreenForTabOrPending(const content::WebContents * web_contents)855 bool AlloyBrowserHostImpl::IsFullscreenForTabOrPending(
856 const content::WebContents* web_contents) {
857 return is_fullscreen_;
858 }
859
GetDisplayMode(const content::WebContents * web_contents)860 blink::mojom::DisplayMode AlloyBrowserHostImpl::GetDisplayMode(
861 const content::WebContents* web_contents) {
862 return is_fullscreen_ ? blink::mojom::DisplayMode::kFullscreen
863 : blink::mojom::DisplayMode::kBrowser;
864 }
865
FindReply(content::WebContents * web_contents,int request_id,int number_of_matches,const gfx::Rect & selection_rect,int active_match_ordinal,bool final_update)866 void AlloyBrowserHostImpl::FindReply(content::WebContents* web_contents,
867 int request_id,
868 int number_of_matches,
869 const gfx::Rect& selection_rect,
870 int active_match_ordinal,
871 bool final_update) {
872 if (client_.get()) {
873 CefRefPtr<CefFindHandler> handler = client_->GetFindHandler();
874 if (handler.get()) {
875 CefRect rect(selection_rect.x(), selection_rect.y(),
876 selection_rect.width(), selection_rect.height());
877 handler->OnFindResult(this, request_id, number_of_matches, rect,
878 active_match_ordinal, final_update);
879 }
880 }
881 }
882
ImeSetComposition(const CefString & text,const std::vector<CefCompositionUnderline> & underlines,const CefRange & replacement_range,const CefRange & selection_range)883 void AlloyBrowserHostImpl::ImeSetComposition(
884 const CefString& text,
885 const std::vector<CefCompositionUnderline>& underlines,
886 const CefRange& replacement_range,
887 const CefRange& selection_range) {
888 if (!IsWindowless()) {
889 NOTREACHED() << "Window rendering is not disabled";
890 return;
891 }
892
893 if (!CEF_CURRENTLY_ON_UIT()) {
894 CEF_POST_TASK(
895 CEF_UIT,
896 base::BindOnce(&AlloyBrowserHostImpl::ImeSetComposition, this, text,
897 underlines, replacement_range, selection_range));
898 return;
899 }
900
901 if (platform_delegate_) {
902 platform_delegate_->ImeSetComposition(text, underlines, replacement_range,
903 selection_range);
904 }
905 }
906
ImeCommitText(const CefString & text,const CefRange & replacement_range,int relative_cursor_pos)907 void AlloyBrowserHostImpl::ImeCommitText(const CefString& text,
908 const CefRange& replacement_range,
909 int relative_cursor_pos) {
910 if (!IsWindowless()) {
911 NOTREACHED() << "Window rendering is not disabled";
912 return;
913 }
914
915 if (!CEF_CURRENTLY_ON_UIT()) {
916 CEF_POST_TASK(CEF_UIT,
917 base::BindOnce(&AlloyBrowserHostImpl::ImeCommitText, this,
918 text, replacement_range, relative_cursor_pos));
919 return;
920 }
921
922 if (platform_delegate_) {
923 platform_delegate_->ImeCommitText(text, replacement_range,
924 relative_cursor_pos);
925 }
926 }
927
ImeFinishComposingText(bool keep_selection)928 void AlloyBrowserHostImpl::ImeFinishComposingText(bool keep_selection) {
929 if (!IsWindowless()) {
930 NOTREACHED() << "Window rendering is not disabled";
931 return;
932 }
933
934 if (!CEF_CURRENTLY_ON_UIT()) {
935 CEF_POST_TASK(CEF_UIT,
936 base::BindOnce(&AlloyBrowserHostImpl::ImeFinishComposingText,
937 this, keep_selection));
938 return;
939 }
940
941 if (platform_delegate_) {
942 platform_delegate_->ImeFinishComposingText(keep_selection);
943 }
944 }
945
ImeCancelComposition()946 void AlloyBrowserHostImpl::ImeCancelComposition() {
947 if (!IsWindowless()) {
948 NOTREACHED() << "Window rendering is not disabled";
949 return;
950 }
951
952 if (!CEF_CURRENTLY_ON_UIT()) {
953 CEF_POST_TASK(
954 CEF_UIT,
955 base::BindOnce(&AlloyBrowserHostImpl::ImeCancelComposition, this));
956 return;
957 }
958
959 if (platform_delegate_)
960 platform_delegate_->ImeCancelComposition();
961 }
962
DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,const CefMouseEvent & event,CefBrowserHost::DragOperationsMask allowed_ops)963 void AlloyBrowserHostImpl::DragTargetDragEnter(
964 CefRefPtr<CefDragData> drag_data,
965 const CefMouseEvent& event,
966 CefBrowserHost::DragOperationsMask allowed_ops) {
967 if (!IsWindowless()) {
968 NOTREACHED() << "Window rendering is not disabled";
969 return;
970 }
971
972 if (!CEF_CURRENTLY_ON_UIT()) {
973 CEF_POST_TASK(CEF_UIT,
974 base::BindOnce(&AlloyBrowserHostImpl::DragTargetDragEnter,
975 this, drag_data, event, allowed_ops));
976 return;
977 }
978
979 if (!drag_data.get()) {
980 NOTREACHED();
981 return;
982 }
983
984 if (platform_delegate_) {
985 platform_delegate_->DragTargetDragEnter(drag_data, event, allowed_ops);
986 }
987 }
988
DragTargetDragOver(const CefMouseEvent & event,CefBrowserHost::DragOperationsMask allowed_ops)989 void AlloyBrowserHostImpl::DragTargetDragOver(
990 const CefMouseEvent& event,
991 CefBrowserHost::DragOperationsMask allowed_ops) {
992 if (!IsWindowless()) {
993 NOTREACHED() << "Window rendering is not disabled";
994 return;
995 }
996
997 if (!CEF_CURRENTLY_ON_UIT()) {
998 CEF_POST_TASK(
999 CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::DragTargetDragOver, this,
1000 event, allowed_ops));
1001 return;
1002 }
1003
1004 if (platform_delegate_) {
1005 platform_delegate_->DragTargetDragOver(event, allowed_ops);
1006 }
1007 }
1008
DragTargetDragLeave()1009 void AlloyBrowserHostImpl::DragTargetDragLeave() {
1010 if (!IsWindowless()) {
1011 NOTREACHED() << "Window rendering is not disabled";
1012 return;
1013 }
1014
1015 if (!CEF_CURRENTLY_ON_UIT()) {
1016 CEF_POST_TASK(
1017 CEF_UIT,
1018 base::BindOnce(&AlloyBrowserHostImpl::DragTargetDragLeave, this));
1019 return;
1020 }
1021
1022 if (platform_delegate_)
1023 platform_delegate_->DragTargetDragLeave();
1024 }
1025
DragTargetDrop(const CefMouseEvent & event)1026 void AlloyBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) {
1027 if (!IsWindowless()) {
1028 NOTREACHED() << "Window rendering is not disabled";
1029 return;
1030 }
1031
1032 if (!CEF_CURRENTLY_ON_UIT()) {
1033 CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::DragTargetDrop,
1034 this, event));
1035 return;
1036 }
1037
1038 if (platform_delegate_)
1039 platform_delegate_->DragTargetDrop(event);
1040 }
1041
DragSourceSystemDragEnded()1042 void AlloyBrowserHostImpl::DragSourceSystemDragEnded() {
1043 if (!IsWindowless()) {
1044 NOTREACHED() << "Window rendering is not disabled";
1045 return;
1046 }
1047
1048 if (!CEF_CURRENTLY_ON_UIT()) {
1049 CEF_POST_TASK(
1050 CEF_UIT,
1051 base::BindOnce(&AlloyBrowserHostImpl::DragSourceSystemDragEnded, this));
1052 return;
1053 }
1054
1055 if (platform_delegate_)
1056 platform_delegate_->DragSourceSystemDragEnded();
1057 }
1058
DragSourceEndedAt(int x,int y,CefBrowserHost::DragOperationsMask op)1059 void AlloyBrowserHostImpl::DragSourceEndedAt(
1060 int x,
1061 int y,
1062 CefBrowserHost::DragOperationsMask op) {
1063 if (!IsWindowless()) {
1064 NOTREACHED() << "Window rendering is not disabled";
1065 return;
1066 }
1067
1068 if (!CEF_CURRENTLY_ON_UIT()) {
1069 CEF_POST_TASK(CEF_UIT,
1070 base::BindOnce(&AlloyBrowserHostImpl::DragSourceEndedAt, this,
1071 x, y, op));
1072 return;
1073 }
1074
1075 if (platform_delegate_)
1076 platform_delegate_->DragSourceEndedAt(x, y, op);
1077 }
1078
SetAudioMuted(bool mute)1079 void AlloyBrowserHostImpl::SetAudioMuted(bool mute) {
1080 if (!CEF_CURRENTLY_ON_UIT()) {
1081 CEF_POST_TASK(CEF_UIT,
1082 base::Bind(&AlloyBrowserHostImpl::SetAudioMuted, this, mute));
1083 return;
1084 }
1085 if (!web_contents())
1086 return;
1087 web_contents()->SetAudioMuted(mute);
1088 }
1089
IsAudioMuted()1090 bool AlloyBrowserHostImpl::IsAudioMuted() {
1091 if (!CEF_CURRENTLY_ON_UIT()) {
1092 NOTREACHED() << "called on invalid thread";
1093 return false;
1094 }
1095 if (!web_contents())
1096 return false;
1097 return web_contents()->IsAudioMuted();
1098 }
1099
1100 // content::WebContentsDelegate methods.
1101 // -----------------------------------------------------------------------------
1102
OpenURLFromTab(content::WebContents * source,const content::OpenURLParams & params)1103 content::WebContents* AlloyBrowserHostImpl::OpenURLFromTab(
1104 content::WebContents* source,
1105 const content::OpenURLParams& params) {
1106 auto target_contents = contents_delegate_->OpenURLFromTab(source, params);
1107 if (target_contents) {
1108 // Start a navigation in the current browser that will result in the
1109 // creation of a new render process.
1110 LoadMainFrameURL(params);
1111 return target_contents;
1112 }
1113
1114 // Cancel the navigation.
1115 return nullptr;
1116 }
1117
ShouldTransferNavigation(bool is_main_frame_navigation)1118 bool AlloyBrowserHostImpl::ShouldTransferNavigation(
1119 bool is_main_frame_navigation) {
1120 return platform_delegate_->ShouldTransferNavigation(is_main_frame_navigation);
1121 }
1122
AddNewContents(content::WebContents * source,std::unique_ptr<content::WebContents> new_contents,const GURL & target_url,WindowOpenDisposition disposition,const gfx::Rect & initial_rect,bool user_gesture,bool * was_blocked)1123 void AlloyBrowserHostImpl::AddNewContents(
1124 content::WebContents* source,
1125 std::unique_ptr<content::WebContents> new_contents,
1126 const GURL& target_url,
1127 WindowOpenDisposition disposition,
1128 const gfx::Rect& initial_rect,
1129 bool user_gesture,
1130 bool* was_blocked) {
1131 platform_delegate_->AddNewContents(source, std::move(new_contents),
1132 target_url, disposition, initial_rect,
1133 user_gesture, was_blocked);
1134 }
1135
LoadingStateChanged(content::WebContents * source,bool to_different_document)1136 void AlloyBrowserHostImpl::LoadingStateChanged(content::WebContents* source,
1137 bool to_different_document) {
1138 contents_delegate_->LoadingStateChanged(source, to_different_document);
1139 }
1140
CloseContents(content::WebContents * source)1141 void AlloyBrowserHostImpl::CloseContents(content::WebContents* source) {
1142 CEF_REQUIRE_UIT();
1143
1144 if (destruction_state_ == DESTRUCTION_STATE_COMPLETED)
1145 return;
1146
1147 bool close_browser = true;
1148
1149 // If this method is called in response to something other than
1150 // WindowDestroyed() ask the user if the browser should close.
1151 if (client_.get() && (IsWindowless() || !window_destroyed_)) {
1152 CefRefPtr<CefLifeSpanHandler> handler = client_->GetLifeSpanHandler();
1153 if (handler.get()) {
1154 close_browser = !handler->DoClose(this);
1155 }
1156 }
1157
1158 if (close_browser) {
1159 if (destruction_state_ != DESTRUCTION_STATE_ACCEPTED)
1160 destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
1161
1162 if (!IsWindowless() && !window_destroyed_) {
1163 // A window exists so try to close it using the platform method. Will
1164 // result in a call to WindowDestroyed() if/when the window is destroyed
1165 // via the platform window destruction mechanism.
1166 platform_delegate_->CloseHostWindow();
1167 } else {
1168 // Keep a reference to the browser while it's in the process of being
1169 // destroyed.
1170 CefRefPtr<AlloyBrowserHostImpl> browser(this);
1171
1172 if (source) {
1173 // Try to fast shutdown the associated process.
1174 source->GetMainFrame()->GetProcess()->FastShutdownIfPossible(1, false);
1175 }
1176
1177 // No window exists. Destroy the browser immediately. Don't call other
1178 // browser methods after calling DestroyBrowser().
1179 DestroyBrowser();
1180 }
1181 } else if (destruction_state_ != DESTRUCTION_STATE_NONE) {
1182 destruction_state_ = DESTRUCTION_STATE_NONE;
1183 }
1184 }
1185
UpdateTargetURL(content::WebContents * source,const GURL & url)1186 void AlloyBrowserHostImpl::UpdateTargetURL(content::WebContents* source,
1187 const GURL& url) {
1188 contents_delegate_->UpdateTargetURL(source, url);
1189 }
1190
DidAddMessageToConsole(content::WebContents * source,blink::mojom::ConsoleMessageLevel level,const std::u16string & message,int32_t line_no,const std::u16string & source_id)1191 bool AlloyBrowserHostImpl::DidAddMessageToConsole(
1192 content::WebContents* source,
1193 blink::mojom::ConsoleMessageLevel level,
1194 const std::u16string& message,
1195 int32_t line_no,
1196 const std::u16string& source_id) {
1197 return contents_delegate_->DidAddMessageToConsole(source, level, message,
1198 line_no, source_id);
1199 }
1200
BeforeUnloadFired(content::WebContents * source,bool proceed,bool * proceed_to_fire_unload)1201 void AlloyBrowserHostImpl::BeforeUnloadFired(content::WebContents* source,
1202 bool proceed,
1203 bool* proceed_to_fire_unload) {
1204 if (destruction_state_ == DESTRUCTION_STATE_ACCEPTED || proceed) {
1205 *proceed_to_fire_unload = true;
1206 } else if (!proceed) {
1207 *proceed_to_fire_unload = false;
1208 destruction_state_ = DESTRUCTION_STATE_NONE;
1209 }
1210 }
1211
TakeFocus(content::WebContents * source,bool reverse)1212 bool AlloyBrowserHostImpl::TakeFocus(content::WebContents* source,
1213 bool reverse) {
1214 if (client_.get()) {
1215 CefRefPtr<CefFocusHandler> handler = client_->GetFocusHandler();
1216 if (handler.get())
1217 handler->OnTakeFocus(this, !reverse);
1218 }
1219
1220 return false;
1221 }
1222
HandleContextMenu(content::RenderFrameHost * render_frame_host,const content::ContextMenuParams & params)1223 bool AlloyBrowserHostImpl::HandleContextMenu(
1224 content::RenderFrameHost* render_frame_host,
1225 const content::ContextMenuParams& params) {
1226 return HandleContextMenu(web_contents(), params);
1227 }
1228
PreHandleKeyboardEvent(content::WebContents * source,const content::NativeWebKeyboardEvent & event)1229 KeyboardEventProcessingResult AlloyBrowserHostImpl::PreHandleKeyboardEvent(
1230 content::WebContents* source,
1231 const content::NativeWebKeyboardEvent& event) {
1232 return contents_delegate_->PreHandleKeyboardEvent(source, event);
1233 }
1234
HandleKeyboardEvent(content::WebContents * source,const content::NativeWebKeyboardEvent & event)1235 bool AlloyBrowserHostImpl::HandleKeyboardEvent(
1236 content::WebContents* source,
1237 const content::NativeWebKeyboardEvent& event) {
1238 // Check to see if event should be ignored.
1239 if (event.skip_in_browser)
1240 return false;
1241
1242 if (contents_delegate_->HandleKeyboardEvent(source, event))
1243 return true;
1244
1245 if (platform_delegate_)
1246 return platform_delegate_->HandleKeyboardEvent(event);
1247 return false;
1248 }
1249
PreHandleGestureEvent(content::WebContents * source,const blink::WebGestureEvent & event)1250 bool AlloyBrowserHostImpl::PreHandleGestureEvent(
1251 content::WebContents* source,
1252 const blink::WebGestureEvent& event) {
1253 return platform_delegate_->PreHandleGestureEvent(source, event);
1254 }
1255
CanDragEnter(content::WebContents * source,const content::DropData & data,blink::DragOperationsMask mask)1256 bool AlloyBrowserHostImpl::CanDragEnter(content::WebContents* source,
1257 const content::DropData& data,
1258 blink::DragOperationsMask mask) {
1259 CefRefPtr<CefDragHandler> handler;
1260 if (client_)
1261 handler = client_->GetDragHandler();
1262 if (handler) {
1263 CefRefPtr<CefDragDataImpl> drag_data(new CefDragDataImpl(data));
1264 drag_data->SetReadOnly(true);
1265 if (handler->OnDragEnter(
1266 this, drag_data.get(),
1267 static_cast<CefDragHandler::DragOperationsMask>(mask))) {
1268 return false;
1269 }
1270 }
1271 return true;
1272 }
1273
GetCustomWebContentsView(content::WebContents * web_contents,const GURL & target_url,int opener_render_process_id,int opener_render_frame_id,content::WebContentsView ** view,content::RenderViewHostDelegateView ** delegate_view)1274 void AlloyBrowserHostImpl::GetCustomWebContentsView(
1275 content::WebContents* web_contents,
1276 const GURL& target_url,
1277 int opener_render_process_id,
1278 int opener_render_frame_id,
1279 content::WebContentsView** view,
1280 content::RenderViewHostDelegateView** delegate_view) {
1281 CefBrowserInfoManager::GetInstance()->GetCustomWebContentsView(
1282 target_url, opener_render_process_id, opener_render_frame_id, view,
1283 delegate_view);
1284 }
1285
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)1286 void AlloyBrowserHostImpl::WebContentsCreated(
1287 content::WebContents* source_contents,
1288 int opener_render_process_id,
1289 int opener_render_frame_id,
1290 const std::string& frame_name,
1291 const GURL& target_url,
1292 content::WebContents* new_contents) {
1293 CefBrowserSettings settings;
1294 CefRefPtr<CefClient> client;
1295 std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate;
1296 CefRefPtr<CefDictionaryValue> extra_info;
1297
1298 CefBrowserInfoManager::GetInstance()->WebContentsCreated(
1299 target_url, opener_render_process_id, opener_render_frame_id, settings,
1300 client, platform_delegate, extra_info);
1301
1302 scoped_refptr<CefBrowserInfo> info =
1303 CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo(
1304 new_contents, platform_delegate->IsWindowless(), extra_info);
1305 CHECK(info.get());
1306 CHECK(info->is_popup());
1307
1308 CefRefPtr<AlloyBrowserHostImpl> opener =
1309 GetBrowserForContents(source_contents);
1310 if (!opener)
1311 return;
1312
1313 // Popups must share the same RequestContext as the parent.
1314 CefRefPtr<CefRequestContextImpl> request_context = opener->request_context();
1315 CHECK(request_context);
1316
1317 // We don't officially own |new_contents| until AddNewContents() is called.
1318 // However, we need to install observers/delegates here.
1319 CefRefPtr<AlloyBrowserHostImpl> browser =
1320 CreateInternal(settings, client, new_contents, /*own_web_contents=*/false,
1321 info, opener, /*is_devtools_popup=*/false, request_context,
1322 std::move(platform_delegate), /*cef_extension=*/nullptr);
1323 }
1324
DidNavigateMainFramePostCommit(content::WebContents * web_contents)1325 void AlloyBrowserHostImpl::DidNavigateMainFramePostCommit(
1326 content::WebContents* web_contents) {
1327 contents_delegate_->DidNavigateMainFramePostCommit(web_contents);
1328 }
1329
1330 content::JavaScriptDialogManager*
GetJavaScriptDialogManager(content::WebContents * source)1331 AlloyBrowserHostImpl::GetJavaScriptDialogManager(content::WebContents* source) {
1332 if (!javascript_dialog_manager_.get() && platform_delegate_) {
1333 javascript_dialog_manager_.reset(new CefJavaScriptDialogManager(
1334 this, platform_delegate_->CreateJavaScriptDialogRunner()));
1335 }
1336 return javascript_dialog_manager_.get();
1337 }
1338
RunFileChooser(content::RenderFrameHost * render_frame_host,scoped_refptr<content::FileSelectListener> listener,const blink::mojom::FileChooserParams & params)1339 void AlloyBrowserHostImpl::RunFileChooser(
1340 content::RenderFrameHost* render_frame_host,
1341 scoped_refptr<content::FileSelectListener> listener,
1342 const blink::mojom::FileChooserParams& params) {
1343 EnsureFileDialogManager();
1344 file_dialog_manager_->RunFileChooser(listener, params);
1345 }
1346
HandleContextMenu(content::WebContents * web_contents,const content::ContextMenuParams & params)1347 bool AlloyBrowserHostImpl::HandleContextMenu(
1348 content::WebContents* web_contents,
1349 const content::ContextMenuParams& params) {
1350 CEF_REQUIRE_UIT();
1351 if (!menu_manager_.get() && platform_delegate_) {
1352 menu_manager_.reset(
1353 new CefMenuManager(this, platform_delegate_->CreateMenuRunner()));
1354 }
1355 return menu_manager_->CreateContextMenu(params);
1356 }
1357
UpdatePreferredSize(content::WebContents * source,const gfx::Size & pref_size)1358 void AlloyBrowserHostImpl::UpdatePreferredSize(content::WebContents* source,
1359 const gfx::Size& pref_size) {
1360 #if defined(OS_WIN) || (defined(OS_POSIX) && !defined(OS_MAC))
1361 CEF_REQUIRE_UIT();
1362 if (platform_delegate_)
1363 platform_delegate_->SizeTo(pref_size.width(), pref_size.height());
1364 #endif
1365 }
1366
ResizeDueToAutoResize(content::WebContents * source,const gfx::Size & new_size)1367 void AlloyBrowserHostImpl::ResizeDueToAutoResize(content::WebContents* source,
1368 const gfx::Size& new_size) {
1369 CEF_REQUIRE_UIT();
1370
1371 if (client_) {
1372 CefRefPtr<CefDisplayHandler> handler = client_->GetDisplayHandler();
1373 if (handler && handler->OnAutoResize(
1374 this, CefSize(new_size.width(), new_size.height()))) {
1375 return;
1376 }
1377 }
1378
1379 UpdatePreferredSize(source, new_size);
1380 }
1381
RequestMediaAccessPermission(content::WebContents * web_contents,const content::MediaStreamRequest & request,content::MediaResponseCallback callback)1382 void AlloyBrowserHostImpl::RequestMediaAccessPermission(
1383 content::WebContents* web_contents,
1384 const content::MediaStreamRequest& request,
1385 content::MediaResponseCallback callback) {
1386 CEF_REQUIRE_UIT();
1387
1388 blink::MediaStreamDevices devices;
1389
1390 const base::CommandLine* command_line =
1391 base::CommandLine::ForCurrentProcess();
1392 if (!command_line->HasSwitch(switches::kEnableMediaStream)) {
1393 // Cancel the request.
1394 std::move(callback).Run(
1395 devices, blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED,
1396 std::unique_ptr<content::MediaStreamUI>());
1397 return;
1398 }
1399
1400 // Based on chrome/browser/media/media_stream_devices_controller.cc
1401 bool microphone_requested =
1402 (request.audio_type ==
1403 blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE);
1404 bool webcam_requested = (request.video_type ==
1405 blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE);
1406 bool screen_requested =
1407 (request.video_type ==
1408 blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE);
1409 if (microphone_requested || webcam_requested || screen_requested) {
1410 // Pick the desired device or fall back to the first available of the
1411 // given type.
1412 if (microphone_requested) {
1413 CefMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
1414 request.requested_audio_device_id, true, false, &devices);
1415 }
1416 if (webcam_requested) {
1417 CefMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
1418 request.requested_video_device_id, false, true, &devices);
1419 }
1420 if (screen_requested) {
1421 content::DesktopMediaID media_id;
1422 if (request.requested_video_device_id.empty()) {
1423 media_id =
1424 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
1425 -1 /* webrtc::kFullDesktopScreenId */);
1426 } else {
1427 media_id =
1428 content::DesktopMediaID::Parse(request.requested_video_device_id);
1429 }
1430 devices.push_back(blink::MediaStreamDevice(
1431 blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE,
1432 media_id.ToString(), "Screen"));
1433 }
1434 }
1435
1436 std::move(callback).Run(devices, blink::mojom::MediaStreamRequestResult::OK,
1437 std::unique_ptr<content::MediaStreamUI>());
1438 }
1439
CheckMediaAccessPermission(content::RenderFrameHost * render_frame_host,const GURL & security_origin,blink::mojom::MediaStreamType type)1440 bool AlloyBrowserHostImpl::CheckMediaAccessPermission(
1441 content::RenderFrameHost* render_frame_host,
1442 const GURL& security_origin,
1443 blink::mojom::MediaStreamType type) {
1444 // Check media access permission without prompting the user.
1445 const base::CommandLine* command_line =
1446 base::CommandLine::ForCurrentProcess();
1447 return command_line->HasSwitch(switches::kEnableMediaStream);
1448 }
1449
IsNeverComposited(content::WebContents * web_contents)1450 bool AlloyBrowserHostImpl::IsNeverComposited(
1451 content::WebContents* web_contents) {
1452 return platform_delegate_->IsNeverComposited(web_contents);
1453 }
1454
EnterPictureInPicture(content::WebContents * web_contents,const viz::SurfaceId & surface_id,const gfx::Size & natural_size)1455 content::PictureInPictureResult AlloyBrowserHostImpl::EnterPictureInPicture(
1456 content::WebContents* web_contents,
1457 const viz::SurfaceId& surface_id,
1458 const gfx::Size& natural_size) {
1459 if (!IsPictureInPictureSupported()) {
1460 return content::PictureInPictureResult::kNotSupported;
1461 }
1462
1463 return PictureInPictureWindowManager::GetInstance()->EnterPictureInPicture(
1464 web_contents, surface_id, natural_size);
1465 }
1466
ExitPictureInPicture()1467 void AlloyBrowserHostImpl::ExitPictureInPicture() {
1468 DCHECK(IsPictureInPictureSupported());
1469 PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture();
1470 }
1471
1472 // content::WebContentsObserver methods.
1473 // -----------------------------------------------------------------------------
1474
RenderFrameCreated(content::RenderFrameHost * render_frame_host)1475 void AlloyBrowserHostImpl::RenderFrameCreated(
1476 content::RenderFrameHost* render_frame_host) {
1477 if (render_frame_host->GetParent() == nullptr) {
1478 auto render_view_host = render_frame_host->GetRenderViewHost();
1479 new CefWidgetHostInterceptor(this, render_view_host);
1480 platform_delegate_->RenderViewCreated(render_view_host);
1481 }
1482 }
1483
RenderViewReady()1484 void AlloyBrowserHostImpl::RenderViewReady() {
1485 platform_delegate_->RenderViewReady();
1486 }
1487
DidFinishNavigation(content::NavigationHandle * navigation_handle)1488 void AlloyBrowserHostImpl::DidFinishNavigation(
1489 content::NavigationHandle* navigation_handle) {
1490 if (web_contents()) {
1491 auto cef_browser_context =
1492 static_cast<AlloyBrowserContext*>(web_contents()->GetBrowserContext());
1493 if (cef_browser_context) {
1494 cef_browser_context->AddVisitedURLs(
1495 navigation_handle->GetRedirectChain());
1496 }
1497 }
1498 }
1499
OnAudioStateChanged(bool audible)1500 void AlloyBrowserHostImpl::OnAudioStateChanged(bool audible) {
1501 if (audible) {
1502 recently_audible_timer_.Stop();
1503 StartAudioCapturer();
1504 } else if (audio_capturer_) {
1505 // If you have a media playing that has a short quiet moment, web_contents
1506 // will immediately switch to non-audible state. We don't want to stop
1507 // audio stream so quickly, let's give the stream some time to resume
1508 // playing.
1509 recently_audible_timer_.Start(
1510 FROM_HERE, kRecentlyAudibleTimeout,
1511 base::BindOnce(&AlloyBrowserHostImpl::OnRecentlyAudibleTimerFired,
1512 this));
1513 }
1514 }
1515
OnRecentlyAudibleTimerFired()1516 void AlloyBrowserHostImpl::OnRecentlyAudibleTimerFired() {
1517 audio_capturer_.reset();
1518 }
1519
AccessibilityEventReceived(const content::AXEventNotificationDetails & content_event_bundle)1520 void AlloyBrowserHostImpl::AccessibilityEventReceived(
1521 const content::AXEventNotificationDetails& content_event_bundle) {
1522 // Only needed in windowless mode.
1523 if (IsWindowless()) {
1524 if (!web_contents() || !platform_delegate_)
1525 return;
1526
1527 platform_delegate_->AccessibilityEventReceived(content_event_bundle);
1528 }
1529 }
1530
AccessibilityLocationChangesReceived(const std::vector<content::AXLocationChangeNotificationDetails> & locData)1531 void AlloyBrowserHostImpl::AccessibilityLocationChangesReceived(
1532 const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
1533 // Only needed in windowless mode.
1534 if (IsWindowless()) {
1535 if (!web_contents() || !platform_delegate_)
1536 return;
1537
1538 platform_delegate_->AccessibilityLocationChangesReceived(locData);
1539 }
1540 }
1541
WebContentsDestroyed()1542 void AlloyBrowserHostImpl::WebContentsDestroyed() {
1543 auto wc = web_contents();
1544 content::WebContentsObserver::Observe(nullptr);
1545 if (platform_delegate_)
1546 platform_delegate_->WebContentsDestroyed(wc);
1547 }
1548
StartAudioCapturer()1549 void AlloyBrowserHostImpl::StartAudioCapturer() {
1550 if (!client_.get() || audio_capturer_)
1551 return;
1552
1553 CefRefPtr<CefAudioHandler> audio_handler = client_->GetAudioHandler();
1554 if (!audio_handler.get())
1555 return;
1556
1557 CefAudioParameters params;
1558 params.channel_layout = CEF_CHANNEL_LAYOUT_STEREO;
1559 params.sample_rate = media::AudioParameters::kAudioCDSampleRate;
1560 params.frames_per_buffer = 1024;
1561
1562 if (!audio_handler->GetAudioParameters(this, params))
1563 return;
1564
1565 audio_capturer_.reset(new CefAudioCapturer(params, this, audio_handler));
1566 }
1567
1568 // AlloyBrowserHostImpl private methods.
1569 // -----------------------------------------------------------------------------
1570
AlloyBrowserHostImpl(const CefBrowserSettings & settings,CefRefPtr<CefClient> client,content::WebContents * web_contents,scoped_refptr<CefBrowserInfo> browser_info,CefRefPtr<AlloyBrowserHostImpl> opener,CefRefPtr<CefRequestContextImpl> request_context,std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,CefRefPtr<CefExtension> extension)1571 AlloyBrowserHostImpl::AlloyBrowserHostImpl(
1572 const CefBrowserSettings& settings,
1573 CefRefPtr<CefClient> client,
1574 content::WebContents* web_contents,
1575 scoped_refptr<CefBrowserInfo> browser_info,
1576 CefRefPtr<AlloyBrowserHostImpl> opener,
1577 CefRefPtr<CefRequestContextImpl> request_context,
1578 std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
1579 CefRefPtr<CefExtension> extension)
1580 : CefBrowserHostBase(settings,
1581 client,
1582 std::move(platform_delegate),
1583 browser_info,
1584 request_context),
1585 content::WebContentsObserver(web_contents),
1586 opener_(kNullWindowHandle),
1587 is_windowless_(platform_delegate_->IsWindowless()),
1588 extension_(extension) {
1589 contents_delegate_->ObserveWebContents(web_contents);
1590
1591 if (opener.get() && !is_views_hosted_) {
1592 // GetOpenerWindowHandle() only returns a value for non-views-hosted
1593 // popup browsers.
1594 opener_ = opener->GetWindowHandle();
1595 }
1596
1597 // Associate the platform delegate with this browser.
1598 platform_delegate_->BrowserCreated(this);
1599
1600 // Make sure RenderFrameCreated is called at least one time.
1601 RenderFrameCreated(web_contents->GetMainFrame());
1602 }
1603
CreateHostWindow()1604 bool AlloyBrowserHostImpl::CreateHostWindow() {
1605 // |host_window_handle_| will not change after initial host creation for
1606 // non-views-hosted browsers.
1607 bool success = true;
1608 if (!IsWindowless())
1609 success = platform_delegate_->CreateHostWindow();
1610 if (success && !is_views_hosted_)
1611 host_window_handle_ = platform_delegate_->GetHostWindowHandle();
1612 return success;
1613 }
1614
GetScreenPoint(const gfx::Point & view) const1615 gfx::Point AlloyBrowserHostImpl::GetScreenPoint(const gfx::Point& view) const {
1616 CEF_REQUIRE_UIT();
1617 if (platform_delegate_)
1618 return platform_delegate_->GetScreenPoint(view);
1619 return gfx::Point();
1620 }
1621
StartDragging(const content::DropData & drop_data,blink::DragOperationsMask allowed_ops,const gfx::ImageSkia & image,const gfx::Vector2d & image_offset,const blink::mojom::DragEventSourceInfo & event_info,content::RenderWidgetHostImpl * source_rwh)1622 void AlloyBrowserHostImpl::StartDragging(
1623 const content::DropData& drop_data,
1624 blink::DragOperationsMask allowed_ops,
1625 const gfx::ImageSkia& image,
1626 const gfx::Vector2d& image_offset,
1627 const blink::mojom::DragEventSourceInfo& event_info,
1628 content::RenderWidgetHostImpl* source_rwh) {
1629 if (platform_delegate_) {
1630 platform_delegate_->StartDragging(drop_data, allowed_ops, image,
1631 image_offset, event_info, source_rwh);
1632 }
1633 }
1634
UpdateDragCursor(ui::mojom::DragOperation operation)1635 void AlloyBrowserHostImpl::UpdateDragCursor(
1636 ui::mojom::DragOperation operation) {
1637 if (platform_delegate_)
1638 platform_delegate_->UpdateDragCursor(operation);
1639 }
1640
EnsureFileDialogManager()1641 void AlloyBrowserHostImpl::EnsureFileDialogManager() {
1642 CEF_REQUIRE_UIT();
1643 if (!file_dialog_manager_.get() && platform_delegate_) {
1644 file_dialog_manager_.reset(new CefFileDialogManager(
1645 this, platform_delegate_->CreateFileDialogRunner()));
1646 }
1647 }
1648