mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	The Chrome browser can now be hosted in a Views-based application on Windows and Linux. To launch a fully-featured Chrome window using cefsimple: $ cefsimple --enable-chrome-runtime To launch a minimally-styled Views-hosted window using cefsimple: $ cefsimple --enable-chrome-runtime --use-views To launch a fully-styled Views-hosted window using cefclient: $ cefclient --enable-chrome-runtime --use-views Views unit tests also now pass with the Chrome runtime enabled: $ ceftests --gtest_filter=Views* --enable-chrome-runtime Known issues: - Popup browsers cannot be intercepted and reparented.
		
			
				
	
	
		
			266 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			9.1 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 "chrome/browser/profiles/profile.h"
 | 
						|
#include "chrome/browser/ui/browser.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,
 | 
						|
                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, 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, request_context_impl);
 | 
						|
}
 | 
						|
 | 
						|
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 base::string16& message,
 | 
						|
    int32_t line_no,
 | 
						|
    const base::string16& 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<CefRequestContextImpl> request_context_impl) {
 | 
						|
  CEF_REQUIRE_UIT();
 | 
						|
  DCHECK(web_contents);
 | 
						|
  DCHECK(platform_delegate);
 | 
						|
  DCHECK(browser_info);
 | 
						|
  DCHECK(request_context_impl);
 | 
						|
 | 
						|
  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(browser_, web_contents);
 | 
						|
}
 | 
						|
 | 
						|
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
 |