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::DidNavigatePrimaryMainFramePostCommit(
|
|
content::WebContents* web_contents) {
|
|
if (auto delegate = GetDelegateForWebContents(web_contents)) {
|
|
delegate->DidNavigatePrimaryMainFramePostCommit(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
|