• 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/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