mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	With the introduction of prerendering in Chromium it is now possible for RenderFrameHosts (RFH) to move between FrameTrees. As a consequence we can no longer rely on FrameTreeNode IDs to uniquely identify a RFH over its lifespan. We must now switch to using GlobalRenderFrameHostId (child_id, frame_routing_id) instead for that purpose. Additionally, we simplify existing code by using the GlobalRenderFrameHostId struct in all places that previously used a (render_process_id, render_frame_id) pair, since these concepts are equivalent. See https://crbug.com/1179502#c8 for additional background.
		
			
				
	
	
		
			301 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			301 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style license that can be
 | |
| // found in the LICENSE file.
 | |
| 
 | |
| #include <memory>
 | |
| 
 | |
| #include "libcef/browser/chrome/chrome_browser_delegate.h"
 | |
| 
 | |
| #include "libcef/browser/browser_contents_delegate.h"
 | |
| #include "libcef/browser/browser_host_base.h"
 | |
| #include "libcef/browser/browser_info_manager.h"
 | |
| #include "libcef/browser/browser_platform_delegate.h"
 | |
| #include "libcef/browser/chrome/chrome_browser_host_impl.h"
 | |
| #include "libcef/browser/request_context_impl.h"
 | |
| #include "libcef/common/app_manager.h"
 | |
| #include "libcef/common/frame_util.h"
 | |
| 
 | |
| #include "chrome/browser/profiles/profile.h"
 | |
| #include "chrome/browser/ui/browser.h"
 | |
| #include "chrome/browser/ui/browser_tabstrip.h"
 | |
| #include "content/public/browser/global_routing_id.h"
 | |
| #include "content/public/browser/keyboard_event_processing_result.h"
 | |
| #include "content/public/browser/native_web_keyboard_event.h"
 | |
| 
 | |
| using content::KeyboardEventProcessingResult;
 | |
| 
 | |
| ChromeBrowserDelegate::ChromeBrowserDelegate(
 | |
|     Browser* browser,
 | |
|     const CefBrowserCreateParams& create_params)
 | |
|     : browser_(browser), create_params_(create_params) {
 | |
|   DCHECK(browser_);
 | |
| }
 | |
| 
 | |
| ChromeBrowserDelegate::~ChromeBrowserDelegate() = default;
 | |
| 
 | |
| void ChromeBrowserDelegate::OnWebContentsCreated(
 | |
|     content::WebContents* new_contents) {
 | |
|   // Necessary to receive LoadingStateChanged calls during initial navigation.
 | |
|   // This will be called again in Browser::SetAsDelegate, which should be fine.
 | |
|   new_contents->SetDelegate(browser_);
 | |
| 
 | |
|   SetAsDelegate(new_contents, /*set_delegate=*/true);
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::SetAsDelegate(content::WebContents* web_contents,
 | |
|                                           bool set_delegate) {
 | |
|   DCHECK(web_contents);
 | |
|   auto browser_host =
 | |
|       ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
 | |
| 
 | |
|   // |set_delegate=false| only makes sense if we already have a browser host.
 | |
|   DCHECK(browser_host || set_delegate);
 | |
| 
 | |
|   if (browser_host) {
 | |
|     // We already have a browser host, so just change the associated Browser.
 | |
|     browser_host->SetBrowser(set_delegate ? browser_ : nullptr);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto platform_delegate = CefBrowserPlatformDelegate::Create(create_params_);
 | |
|   CHECK(platform_delegate);
 | |
| 
 | |
|   auto browser_info = CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
 | |
|       /*is_popup=*/false, /*is_windowless=*/false, create_params_.extra_info);
 | |
| 
 | |
|   auto request_context_impl =
 | |
|       CefRequestContextImpl::GetOrCreateForRequestContext(
 | |
|           create_params_.request_context);
 | |
| 
 | |
|   CreateBrowser(web_contents, create_params_.settings, create_params_.client,
 | |
|                 std::move(platform_delegate), browser_info, /*opener=*/nullptr,
 | |
|                 request_context_impl);
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::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) {
 | |
|   CefBrowserSettings settings;
 | |
|   CefRefPtr<CefClient> client;
 | |
|   std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate;
 | |
|   CefRefPtr<CefDictionaryValue> extra_info;
 | |
| 
 | |
|   CefBrowserInfoManager::GetInstance()->WebContentsCreated(
 | |
|       target_url,
 | |
|       frame_util::MakeGlobalId(opener_render_process_id,
 | |
|                                opener_render_frame_id),
 | |
|       settings, client, platform_delegate, extra_info);
 | |
| 
 | |
|   auto opener = ChromeBrowserHostImpl::GetBrowserForContents(source_contents);
 | |
|   if (!opener) {
 | |
|     LOG(ERROR) << "No opener found for chrome popup browser";
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto browser_info =
 | |
|       CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo(
 | |
|           new_contents, /*is_windowless=*/false, extra_info);
 | |
|   CHECK(browser_info->is_popup());
 | |
| 
 | |
|   // Popups must share the same RequestContext as the parent.
 | |
|   auto request_context_impl = opener->request_context();
 | |
|   CHECK(request_context_impl);
 | |
| 
 | |
|   // We don't officially own |new_contents| until AddNewContents() is called.
 | |
|   // However, we need to install observers/delegates here.
 | |
|   CreateBrowser(new_contents, settings, client, std::move(platform_delegate),
 | |
|                 browser_info, opener, request_context_impl);
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::AddNewContents(
 | |
|     content::WebContents* source_contents,
 | |
|     std::unique_ptr<content::WebContents> new_contents,
 | |
|     const GURL& target_url,
 | |
|     WindowOpenDisposition disposition,
 | |
|     const gfx::Rect& initial_rect,
 | |
|     bool user_gesture,
 | |
|     bool* was_blocked) {
 | |
|   auto new_browser =
 | |
|       ChromeBrowserHostImpl::GetBrowserForContents(new_contents.get());
 | |
|   if (new_browser) {
 | |
|     // Create a new Browser and give it ownership of the WebContents.
 | |
|     new_browser->AddNewContents(std::move(new_contents));
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Fall back to default behavior from Browser::AddNewContents.
 | |
|   chrome::AddWebContents(browser_, source_contents, std::move(new_contents),
 | |
|                          target_url, disposition, initial_rect);
 | |
| }
 | |
| 
 | |
| content::WebContents* ChromeBrowserDelegate::OpenURLFromTab(
 | |
|     content::WebContents* source,
 | |
|     const content::OpenURLParams& params) {
 | |
|   // Return nullptr to cancel the navigation. Otherwise, proceed with default
 | |
|   // chrome handling.
 | |
|   if (auto delegate = GetDelegateForWebContents(source)) {
 | |
|     return delegate->OpenURLFromTab(source, params);
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::LoadingStateChanged(content::WebContents* source,
 | |
|                                                 bool to_different_document) {
 | |
|   if (auto delegate = GetDelegateForWebContents(source)) {
 | |
|     delegate->LoadingStateChanged(source, to_different_document);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::UpdateTargetURL(content::WebContents* source,
 | |
|                                             const GURL& url) {
 | |
|   if (auto delegate = GetDelegateForWebContents(source)) {
 | |
|     delegate->UpdateTargetURL(source, url);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool ChromeBrowserDelegate::DidAddMessageToConsole(
 | |
|     content::WebContents* source,
 | |
|     blink::mojom::ConsoleMessageLevel log_level,
 | |
|     const std::u16string& message,
 | |
|     int32_t line_no,
 | |
|     const std::u16string& source_id) {
 | |
|   if (auto delegate = GetDelegateForWebContents(source)) {
 | |
|     return delegate->DidAddMessageToConsole(source, log_level, message, line_no,
 | |
|                                             source_id);
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::DidNavigateMainFramePostCommit(
 | |
|     content::WebContents* web_contents) {
 | |
|   if (auto delegate = GetDelegateForWebContents(web_contents)) {
 | |
|     delegate->DidNavigateMainFramePostCommit(web_contents);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::EnterFullscreenModeForTab(
 | |
|     content::RenderFrameHost* requesting_frame,
 | |
|     const blink::mojom::FullscreenOptions& options) {
 | |
|   auto web_contents =
 | |
|       content::WebContents::FromRenderFrameHost(requesting_frame);
 | |
|   if (!web_contents)
 | |
|     return;
 | |
| 
 | |
|   if (auto delegate = GetDelegateForWebContents(web_contents)) {
 | |
|     delegate->EnterFullscreenModeForTab(requesting_frame, options);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::ExitFullscreenModeForTab(
 | |
|     content::WebContents* web_contents) {
 | |
|   if (auto delegate = GetDelegateForWebContents(web_contents)) {
 | |
|     delegate->ExitFullscreenModeForTab(web_contents);
 | |
|   }
 | |
| }
 | |
| 
 | |
| KeyboardEventProcessingResult ChromeBrowserDelegate::PreHandleKeyboardEvent(
 | |
|     content::WebContents* source,
 | |
|     const content::NativeWebKeyboardEvent& event) {
 | |
|   if (auto delegate = GetDelegateForWebContents(source)) {
 | |
|     return delegate->PreHandleKeyboardEvent(source, event);
 | |
|   }
 | |
|   return KeyboardEventProcessingResult::NOT_HANDLED;
 | |
| }
 | |
| 
 | |
| bool ChromeBrowserDelegate::HandleKeyboardEvent(
 | |
|     content::WebContents* source,
 | |
|     const content::NativeWebKeyboardEvent& event) {
 | |
|   if (auto delegate = GetDelegateForWebContents(source)) {
 | |
|     return delegate->HandleKeyboardEvent(source, event);
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void ChromeBrowserDelegate::CreateBrowser(
 | |
|     content::WebContents* web_contents,
 | |
|     CefBrowserSettings settings,
 | |
|     CefRefPtr<CefClient> client,
 | |
|     std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
 | |
|     scoped_refptr<CefBrowserInfo> browser_info,
 | |
|     CefRefPtr<ChromeBrowserHostImpl> opener,
 | |
|     CefRefPtr<CefRequestContextImpl> request_context_impl) {
 | |
|   CEF_REQUIRE_UIT();
 | |
|   DCHECK(web_contents);
 | |
|   DCHECK(platform_delegate);
 | |
|   DCHECK(browser_info);
 | |
|   DCHECK(request_context_impl);
 | |
| 
 | |
|   // If |opener| is non-nullptr it must be a popup window.
 | |
|   DCHECK(!opener.get() || browser_info->is_popup());
 | |
| 
 | |
|   if (!client) {
 | |
|     if (auto app = CefAppManager::Get()->GetApplication()) {
 | |
|       if (auto bph = app->GetBrowserProcessHandler()) {
 | |
|         client = bph->GetDefaultClient();
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!client) {
 | |
|     LOG(WARNING) << "Creating a chrome browser without a client";
 | |
|   }
 | |
| 
 | |
|   // Check if chrome and CEF are using the same browser context.
 | |
|   // TODO(chrome-runtime): Verify if/when this might occur.
 | |
|   auto chrome_browser_context =
 | |
|       CefBrowserContext::FromBrowserContext(browser_->create_params().profile);
 | |
|   if (chrome_browser_context != request_context_impl->GetBrowserContext()) {
 | |
|     LOG(WARNING) << "Creating a chrome browser with mismatched context";
 | |
|   }
 | |
| 
 | |
|   // Remains alive until the associated WebContents is destroyed.
 | |
|   CefRefPtr<ChromeBrowserHostImpl> browser_host =
 | |
|       new ChromeBrowserHostImpl(settings, client, std::move(platform_delegate),
 | |
|                                 browser_info, request_context_impl);
 | |
|   browser_host->Attach(web_contents, opener);
 | |
| 
 | |
|   // The Chrome browser for a popup won't be created until AddNewContents().
 | |
|   if (!opener) {
 | |
|     browser_host->SetBrowser(browser_);
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents(
 | |
|     content::WebContents* web_contents) {
 | |
|   auto browser_host =
 | |
|       ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
 | |
|   if (browser_host)
 | |
|     return browser_host->contents_delegate();
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| namespace cef {
 | |
| 
 | |
| // static
 | |
| std::unique_ptr<BrowserDelegate> BrowserDelegate::Create(
 | |
|     Browser* browser,
 | |
|     scoped_refptr<CreateParams> cef_params) {
 | |
|   CefBrowserCreateParams create_params;
 | |
| 
 | |
|   // Parameters from ChromeBrowserHostImpl::Create, or nullptr if the Browser
 | |
|   // was created from somewhere else.
 | |
|   auto params = static_cast<ChromeBrowserHostImpl::DelegateCreateParams*>(
 | |
|       cef_params.get());
 | |
|   if (params) {
 | |
|     create_params = params->create_params_;
 | |
| 
 | |
|     // Clear these values so they're not persisted to additional Browsers.
 | |
| #if defined(TOOLKIT_VIEWS)
 | |
|     params->create_params_.browser_view = nullptr;
 | |
| #endif
 | |
|   }
 | |
| 
 | |
|   return std::make_unique<ChromeBrowserDelegate>(browser, create_params);
 | |
| }
 | |
| 
 | |
| }  // namespace cef
 |