• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
6 
7 #include "libcef/browser/alloy/alloy_browser_host_impl.h"
8 #include "libcef/browser/extensions/browser_extensions_util.h"
9 #include "libcef/browser/extensions/extension_background_host.h"
10 #include "libcef/browser/extensions/extension_system.h"
11 #include "libcef/browser/extensions/extension_view_host.h"
12 #include "libcef/browser/extensions/extension_web_contents_observer.h"
13 #include "libcef/browser/printing/print_view_manager.h"
14 #include "libcef/common/extensions/extensions_util.h"
15 #include "libcef/common/net/url_util.h"
16 #include "libcef/features/runtime_checks.h"
17 
18 #include "base/logging.h"
19 #include "chrome/browser/printing/print_view_manager.h"
20 #include "chrome/browser/printing/print_view_manager_common.h"
21 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
22 #include "components/find_in_page/find_tab_helper.h"
23 #include "components/find_in_page/find_types.h"
24 #include "components/zoom/zoom_controller.h"
25 #include "content/browser/renderer_host/render_widget_host_impl.h"
26 #include "content/browser/web_contents/web_contents_impl.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/render_widget_host.h"
29 #include "extensions/browser/process_manager.h"
30 #include "pdf/pdf_features.h"
31 #include "printing/mojom/print.mojom.h"
32 #include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
33 
34 namespace {
35 
GetPrintViewManager(content::WebContents * web_contents)36 printing::CefPrintViewManager* GetPrintViewManager(
37     content::WebContents* web_contents) {
38   return printing::CefPrintViewManager::FromWebContents(web_contents);
39 }
40 
41 }  // namespace
42 
CefBrowserPlatformDelegateAlloy()43 CefBrowserPlatformDelegateAlloy::CefBrowserPlatformDelegateAlloy()
44     : weak_ptr_factory_(this) {}
45 
CreateWebContents(CefBrowserCreateParams & create_params,bool & own_web_contents)46 content::WebContents* CefBrowserPlatformDelegateAlloy::CreateWebContents(
47     CefBrowserCreateParams& create_params,
48     bool& own_web_contents) {
49   REQUIRE_ALLOY_RUNTIME();
50   DCHECK(primary_);
51 
52   // Get or create the request context and browser context.
53   CefRefPtr<CefRequestContextImpl> request_context_impl =
54       CefRequestContextImpl::GetOrCreateForRequestContext(
55           create_params.request_context);
56   CHECK(request_context_impl);
57   auto cef_browser_context = request_context_impl->GetBrowserContext();
58   CHECK(cef_browser_context);
59   auto browser_context = cef_browser_context->AsBrowserContext();
60 
61   if (!create_params.request_context) {
62     // Using the global request context.
63     create_params.request_context = request_context_impl.get();
64   }
65 
66   scoped_refptr<content::SiteInstance> site_instance;
67   if (extensions::ExtensionsEnabled() && !create_params.url.empty()) {
68     GURL gurl = url_util::MakeGURL(create_params.url, /*fixup=*/true);
69     if (!create_params.extension) {
70       // We might be loading an extension app view where the extension URL is
71       // provided by the client.
72       create_params.extension =
73           extensions::GetExtensionForUrl(browser_context, gurl);
74     }
75     if (create_params.extension) {
76       if (create_params.extension_host_type ==
77           extensions::mojom::ViewType::kInvalid) {
78         // Default to dialog behavior.
79         create_params.extension_host_type =
80             extensions::mojom::ViewType::kExtensionDialog;
81       }
82 
83       // Extension resources will fail to load if we don't use a SiteInstance
84       // associated with the extension.
85       // (AlloyContentBrowserClient::SiteInstanceGotProcess won't find the
86       // extension to register with InfoMap, and AllowExtensionResourceLoad in
87       // ExtensionProtocolHandler::MaybeCreateJob will return false resulting in
88       // ERR_BLOCKED_BY_CLIENT).
89       site_instance = extensions::ProcessManager::Get(browser_context)
90                           ->GetSiteInstanceForURL(gurl);
91       DCHECK(site_instance);
92     }
93   }
94 
95   content::WebContents::CreateParams wc_create_params(browser_context,
96                                                       site_instance);
97 
98   if (IsWindowless()) {
99     // Create the OSR view for the WebContents.
100     CreateViewForWebContents(&wc_create_params.view,
101                              &wc_create_params.delegate_view);
102   }
103 
104   auto web_contents = content::WebContents::Create(wc_create_params);
105   CHECK(web_contents);
106 
107   own_web_contents = true;
108   return web_contents.release();
109 }
110 
WebContentsCreated(content::WebContents * web_contents,bool owned)111 void CefBrowserPlatformDelegateAlloy::WebContentsCreated(
112     content::WebContents* web_contents,
113     bool owned) {
114   CefBrowserPlatformDelegate::WebContentsCreated(web_contents, owned);
115   find_in_page::FindTabHelper::CreateForWebContents(web_contents);
116 
117   if (owned) {
118     SetOwnedWebContents(web_contents);
119   }
120 }
121 
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)122 void CefBrowserPlatformDelegateAlloy::AddNewContents(
123     content::WebContents* source,
124     std::unique_ptr<content::WebContents> new_contents,
125     const GURL& target_url,
126     WindowOpenDisposition disposition,
127     const gfx::Rect& initial_rect,
128     bool user_gesture,
129     bool* was_blocked) {
130   REQUIRE_ALLOY_RUNTIME();
131   DCHECK(primary_);
132 
133   CefRefPtr<AlloyBrowserHostImpl> owner =
134       AlloyBrowserHostImpl::GetBrowserForContents(new_contents.get());
135   if (owner) {
136     // Taking ownership of |new_contents|.
137     static_cast<CefBrowserPlatformDelegateAlloy*>(
138         owner->platform_delegate_.get())
139         ->SetOwnedWebContents(new_contents.release());
140     return;
141   }
142 
143   if (extension_host_) {
144     extension_host_->AddNewContents(source, std::move(new_contents), target_url,
145                                     disposition, initial_rect, user_gesture,
146                                     was_blocked);
147   }
148 }
149 
150 bool CefBrowserPlatformDelegateAlloy::
ShouldAllowRendererInitiatedCrossProcessNavigation(bool is_main_frame_navigation)151     ShouldAllowRendererInitiatedCrossProcessNavigation(
152         bool is_main_frame_navigation) {
153   if (extension_host_) {
154     return extension_host_->ShouldAllowRendererInitiatedCrossProcessNavigation(
155         is_main_frame_navigation);
156   }
157   return true;
158 }
159 
RenderViewCreated(content::RenderViewHost * render_view_host)160 void CefBrowserPlatformDelegateAlloy::RenderViewCreated(
161     content::RenderViewHost* render_view_host) {
162   // Indicate that the view has an external parent (namely us). This changes the
163   // default view behavior in some cases (e.g. focus handling on Linux).
164   if (!IsViewsHosted() && render_view_host->GetWidget()->GetView())
165     render_view_host->GetWidget()->GetView()->SetHasExternalParent(true);
166 }
167 
RenderViewReady()168 void CefBrowserPlatformDelegateAlloy::RenderViewReady() {
169   ConfigureAutoResize();
170 }
171 
BrowserCreated(CefBrowserHostBase * browser)172 void CefBrowserPlatformDelegateAlloy::BrowserCreated(
173     CefBrowserHostBase* browser) {
174   CefBrowserPlatformDelegate::BrowserCreated(browser);
175 
176   // Only register WebContents delegate/observers if we're the primary delegate.
177   if (!primary_)
178     return;
179 
180   DCHECK(!web_contents_->GetDelegate());
181   web_contents_->SetDelegate(static_cast<AlloyBrowserHostImpl*>(browser));
182 
183   PrefsTabHelper::CreateForWebContents(web_contents_);
184   printing::CefPrintViewManager::CreateForWebContents(web_contents_);
185 
186   if (extensions::ExtensionsEnabled()) {
187     // Used by the tabs extension API.
188     zoom::ZoomController::CreateForWebContents(web_contents_);
189   }
190 
191   if (IsPrintPreviewSupported()) {
192     web_contents_dialog_helper_.reset(
193         new CefWebContentsDialogHelper(web_contents_, this));
194   }
195 }
196 
CreateExtensionHost(const extensions::Extension * extension,const GURL & url,extensions::mojom::ViewType host_type)197 void CefBrowserPlatformDelegateAlloy::CreateExtensionHost(
198     const extensions::Extension* extension,
199     const GURL& url,
200     extensions::mojom::ViewType host_type) {
201   REQUIRE_ALLOY_RUNTIME();
202   DCHECK(primary_);
203 
204   // Should get WebContentsCreated and BrowserCreated calls first.
205   DCHECK(web_contents_);
206   DCHECK(browser_);
207   DCHECK(!extension_host_);
208 
209   auto alloy_browser = static_cast<AlloyBrowserHostImpl*>(browser_);
210 
211   if (host_type == extensions::mojom::ViewType::kExtensionDialog ||
212       host_type == extensions::mojom::ViewType::kExtensionPopup) {
213     // Create an extension host that we own.
214     extension_host_ = new extensions::CefExtensionViewHost(
215         alloy_browser, extension, web_contents_, url, host_type);
216     // Trigger load of the extension URL.
217     extension_host_->CreateRendererSoon();
218   } else if (host_type ==
219              extensions::mojom::ViewType::kExtensionBackgroundPage) {
220     is_background_host_ = true;
221     alloy_browser->is_background_host_ = true;
222     // Create an extension host that will be owned by ProcessManager.
223     extension_host_ = new extensions::CefExtensionBackgroundHost(
224         alloy_browser,
225         base::BindOnce(&CefBrowserPlatformDelegateAlloy::OnExtensionHostDeleted,
226                        weak_ptr_factory_.GetWeakPtr()),
227         extension, web_contents_, url, host_type);
228     // Load will be triggered by ProcessManager::CreateBackgroundHost.
229   } else {
230     NOTREACHED() << " Unsupported extension host type: " << host_type;
231   }
232 }
233 
GetExtensionHost() const234 extensions::ExtensionHost* CefBrowserPlatformDelegateAlloy::GetExtensionHost()
235     const {
236   return extension_host_;
237 }
238 
BrowserDestroyed(CefBrowserHostBase * browser)239 void CefBrowserPlatformDelegateAlloy::BrowserDestroyed(
240     CefBrowserHostBase* browser) {
241   if (primary_) {
242     DestroyExtensionHost();
243     owned_web_contents_.reset();
244   }
245 
246   CefBrowserPlatformDelegate::BrowserDestroyed(browser);
247 }
248 
SendCaptureLostEvent()249 void CefBrowserPlatformDelegateAlloy::SendCaptureLostEvent() {
250   if (!web_contents_)
251     return;
252   content::RenderViewHost* host = web_contents_->GetRenderViewHost();
253   if (!host)
254     return;
255 
256   content::RenderWidgetHostImpl* widget =
257       content::RenderWidgetHostImpl::From(host->GetWidget());
258   if (widget)
259     widget->LostCapture();
260 }
261 
262 #if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
NotifyMoveOrResizeStarted()263 void CefBrowserPlatformDelegateAlloy::NotifyMoveOrResizeStarted() {
264   if (!browser_)
265     return;
266 
267   // Dismiss any existing popups.
268   auto frame = browser_->GetMainFrame();
269   if (frame && frame->IsValid()) {
270     static_cast<CefFrameHostImpl*>(frame.get())->NotifyMoveOrResizeStarted();
271   }
272 }
273 #endif
274 
PreHandleGestureEvent(content::WebContents * source,const blink::WebGestureEvent & event)275 bool CefBrowserPlatformDelegateAlloy::PreHandleGestureEvent(
276     content::WebContents* source,
277     const blink::WebGestureEvent& event) {
278   if (extension_host_)
279     return extension_host_->PreHandleGestureEvent(source, event);
280   return false;
281 }
282 
IsNeverComposited(content::WebContents * web_contents)283 bool CefBrowserPlatformDelegateAlloy::IsNeverComposited(
284     content::WebContents* web_contents) {
285   if (extension_host_)
286     return extension_host_->IsNeverComposited(web_contents);
287   return false;
288 }
289 
SetAutoResizeEnabled(bool enabled,const CefSize & min_size,const CefSize & max_size)290 void CefBrowserPlatformDelegateAlloy::SetAutoResizeEnabled(
291     bool enabled,
292     const CefSize& min_size,
293     const CefSize& max_size) {
294   if (enabled == auto_resize_enabled_)
295     return;
296 
297   auto_resize_enabled_ = enabled;
298   if (enabled) {
299     auto_resize_min_ = gfx::Size(min_size.width, min_size.height);
300     auto_resize_max_ = gfx::Size(max_size.width, max_size.height);
301   } else {
302     auto_resize_min_ = auto_resize_max_ = gfx::Size();
303   }
304   ConfigureAutoResize();
305 }
306 
ConfigureAutoResize()307 void CefBrowserPlatformDelegateAlloy::ConfigureAutoResize() {
308   if (!web_contents_ || !web_contents_->GetRenderWidgetHostView()) {
309     return;
310   }
311 
312   if (auto_resize_enabled_) {
313     web_contents_->GetRenderWidgetHostView()->EnableAutoResize(
314         auto_resize_min_, auto_resize_max_);
315   } else {
316     web_contents_->GetRenderWidgetHostView()->DisableAutoResize(gfx::Size());
317   }
318 }
319 
SetAccessibilityState(cef_state_t accessibility_state)320 void CefBrowserPlatformDelegateAlloy::SetAccessibilityState(
321     cef_state_t accessibility_state) {
322   // Do nothing if state is set to default. It'll be disabled by default and
323   // controlled by the commmand-line flags "force-renderer-accessibility" and
324   // "disable-renderer-accessibility".
325   if (accessibility_state == STATE_DEFAULT)
326     return;
327 
328   content::WebContentsImpl* web_contents_impl =
329       static_cast<content::WebContentsImpl*>(web_contents_);
330 
331   if (!web_contents_impl)
332     return;
333 
334   ui::AXMode accMode;
335   // In windowless mode set accessibility to TreeOnly mode. Else native
336   // accessibility APIs, specific to each platform, are also created.
337   if (accessibility_state == STATE_ENABLED) {
338     accMode = IsWindowless() ? ui::kAXModeWebContentsOnly : ui::kAXModeComplete;
339   }
340   web_contents_impl->SetAccessibilityMode(accMode);
341 }
342 
IsPrintPreviewSupported() const343 bool CefBrowserPlatformDelegateAlloy::IsPrintPreviewSupported() const {
344   REQUIRE_ALLOY_RUNTIME();
345 
346   // Print preview is not currently supported with OSR.
347   if (IsWindowless())
348     return false;
349 
350   auto cef_browser_context =
351       CefBrowserContext::FromBrowserContext(web_contents_->GetBrowserContext());
352   return cef_browser_context->IsPrintPreviewSupported();
353 }
354 
Print()355 void CefBrowserPlatformDelegateAlloy::Print() {
356   REQUIRE_ALLOY_RUNTIME();
357 
358   auto contents_to_use = printing::GetWebContentsToUse(web_contents_);
359   if (!contents_to_use)
360     return;
361 
362   auto rfh_to_use = printing::GetRenderFrameHostToUse(contents_to_use);
363   if (!rfh_to_use)
364     return;
365 
366   if (IsPrintPreviewSupported()) {
367     GetPrintViewManager(contents_to_use)->PrintPreviewNow(rfh_to_use, false);
368   } else {
369     GetPrintViewManager(contents_to_use)->PrintNow(rfh_to_use);
370   }
371 }
372 
PrintToPDF(const CefString & path,const CefPdfPrintSettings & settings,CefRefPtr<CefPdfPrintCallback> callback)373 void CefBrowserPlatformDelegateAlloy::PrintToPDF(
374     const CefString& path,
375     const CefPdfPrintSettings& settings,
376     CefRefPtr<CefPdfPrintCallback> callback) {
377   REQUIRE_ALLOY_RUNTIME();
378 
379   auto contents_to_use = printing::GetWebContentsToUse(web_contents_);
380   if (!contents_to_use)
381     return;
382 
383   auto rfh_to_use = printing::GetRenderFrameHostToUse(contents_to_use);
384   if (!rfh_to_use)
385     return;
386 
387   printing::CefPrintViewManager::PdfPrintCallback pdf_callback;
388   if (callback.get()) {
389     pdf_callback = base::BindOnce(&CefPdfPrintCallback::OnPdfPrintFinished,
390                                   callback.get(), path);
391   }
392   GetPrintViewManager(contents_to_use)
393       ->PrintToPDF(rfh_to_use, base::FilePath(path), settings,
394                    std::move(pdf_callback));
395 }
396 
Find(const CefString & searchText,bool forward,bool matchCase,bool findNext)397 void CefBrowserPlatformDelegateAlloy::Find(const CefString& searchText,
398                                            bool forward,
399                                            bool matchCase,
400                                            bool findNext) {
401   if (!web_contents_)
402     return;
403 
404   find_in_page::FindTabHelper::FromWebContents(web_contents_)
405       ->StartFinding(searchText.ToString16(), forward, matchCase, findNext,
406                      /*run_synchronously_for_testing=*/false);
407 }
408 
StopFinding(bool clearSelection)409 void CefBrowserPlatformDelegateAlloy::StopFinding(bool clearSelection) {
410   if (!web_contents_)
411     return;
412 
413   last_search_result_ = find_in_page::FindNotificationDetails();
414   find_in_page::FindTabHelper::FromWebContents(web_contents_)
415       ->StopFinding(clearSelection ? find_in_page::SelectionAction::kClear
416                                    : find_in_page::SelectionAction::kKeep);
417 }
418 
HandleFindReply(int request_id,int number_of_matches,const gfx::Rect & selection_rect,int active_match_ordinal,bool final_update)419 bool CefBrowserPlatformDelegateAlloy::HandleFindReply(
420     int request_id,
421     int number_of_matches,
422     const gfx::Rect& selection_rect,
423     int active_match_ordinal,
424     bool final_update) {
425   if (!web_contents_)
426     return false;
427 
428   auto find_in_page =
429       find_in_page::FindTabHelper::FromWebContents(web_contents_);
430 
431   find_in_page->HandleFindReply(request_id, number_of_matches, selection_rect,
432                                 active_match_ordinal, final_update);
433   if (!(find_in_page->find_result() == last_search_result_)) {
434     last_search_result_ = find_in_page->find_result();
435     return true;
436   }
437   return false;
438 }
439 
440 base::RepeatingClosure
GetBoundsChangedCallback()441 CefBrowserPlatformDelegateAlloy::GetBoundsChangedCallback() {
442   if (web_contents_dialog_helper_) {
443     return web_contents_dialog_helper_->GetBoundsChangedCallback();
444   }
445 
446   return base::RepeatingClosure();
447 }
448 
SetOwnedWebContents(content::WebContents * owned_contents)449 void CefBrowserPlatformDelegateAlloy::SetOwnedWebContents(
450     content::WebContents* owned_contents) {
451   DCHECK(primary_);
452 
453   // Should not currently own a WebContents.
454   CHECK(!owned_web_contents_);
455   owned_web_contents_.reset(owned_contents);
456 }
457 
DestroyExtensionHost()458 void CefBrowserPlatformDelegateAlloy::DestroyExtensionHost() {
459   if (!extension_host_)
460     return;
461   if (extension_host_->extension_host_type() ==
462       extensions::mojom::ViewType::kExtensionBackgroundPage) {
463     DCHECK(is_background_host_);
464     // Close notification for background pages arrives via CloseContents.
465     // The extension host will be deleted by
466     // ProcessManager::CloseBackgroundHost and OnExtensionHostDeleted will be
467     // called to notify us.
468     extension_host_->Close();
469   } else {
470     DCHECK(!is_background_host_);
471     // We own the extension host and must delete it.
472     delete extension_host_;
473     extension_host_ = nullptr;
474   }
475 }
476 
OnExtensionHostDeleted()477 void CefBrowserPlatformDelegateAlloy::OnExtensionHostDeleted() {
478   DCHECK(is_background_host_);
479   DCHECK(extension_host_);
480   extension_host_ = nullptr;
481 }
482