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