• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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