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