1141 lines
32 KiB
C++
1141 lines
32 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 "libcef/browser/browser_host_base.h"
|
|
|
|
#include <tuple>
|
|
|
|
#include "libcef/browser/browser_info_manager.h"
|
|
#include "libcef/browser/browser_platform_delegate.h"
|
|
#include "libcef/browser/context.h"
|
|
#include "libcef/browser/image_impl.h"
|
|
#include "libcef/browser/navigation_entry_impl.h"
|
|
#include "libcef/browser/printing/print_util.h"
|
|
#include "libcef/browser/thread_util.h"
|
|
#include "libcef/common/frame_util.h"
|
|
#include "libcef/common/net/url_util.h"
|
|
|
|
#include "base/logging.h"
|
|
#include "chrome/browser/platform_util.h"
|
|
#include "chrome/browser/spellchecker/spellcheck_factory.h"
|
|
#include "chrome/browser/spellchecker/spellcheck_service.h"
|
|
#include "components/favicon/core/favicon_url.h"
|
|
#include "components/spellcheck/common/spellcheck_features.h"
|
|
#include "content/browser/renderer_host/render_frame_host_impl.h"
|
|
#include "content/public/browser/browser_context.h"
|
|
#include "content/public/browser/download_manager.h"
|
|
#include "content/public/browser/download_request_utils.h"
|
|
#include "content/public/browser/file_select_listener.h"
|
|
#include "content/public/browser/navigation_entry.h"
|
|
#include "ui/base/resource/resource_scale_factor.h"
|
|
#include "ui/gfx/image/image_skia.h"
|
|
#include "ui/shell_dialogs/select_file_policy.h"
|
|
|
|
#if BUILDFLAG(IS_MAC)
|
|
#include "components/spellcheck/browser/spellcheck_platform.h"
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
// Associates a CefBrowserHostBase instance with a WebContents. This object will
|
|
// be deleted automatically when the WebContents is destroyed.
|
|
class WebContentsUserDataAdapter : public base::SupportsUserData::Data {
|
|
public:
|
|
static void Register(CefRefPtr<CefBrowserHostBase> browser) {
|
|
new WebContentsUserDataAdapter(browser);
|
|
}
|
|
|
|
static CefRefPtr<CefBrowserHostBase> Get(
|
|
const content::WebContents* web_contents) {
|
|
WebContentsUserDataAdapter* adapter =
|
|
static_cast<WebContentsUserDataAdapter*>(
|
|
web_contents->GetUserData(UserDataKey()));
|
|
if (adapter) {
|
|
return adapter->browser_;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
WebContentsUserDataAdapter(CefRefPtr<CefBrowserHostBase> browser)
|
|
: browser_(browser) {
|
|
auto web_contents = browser->GetWebContents();
|
|
DCHECK(web_contents);
|
|
web_contents->SetUserData(UserDataKey(), base::WrapUnique(this));
|
|
}
|
|
|
|
static void* UserDataKey() {
|
|
// We just need a unique constant. Use the address of a static that
|
|
// COMDAT folding won't touch in an optimizing linker.
|
|
static int data_key = 0;
|
|
return reinterpret_cast<void*>(&data_key);
|
|
}
|
|
|
|
CefRefPtr<CefBrowserHostBase> browser_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForHost(
|
|
const content::RenderViewHost* host) {
|
|
DCHECK(host);
|
|
CEF_REQUIRE_UIT();
|
|
content::WebContents* web_contents = content::WebContents::FromRenderViewHost(
|
|
const_cast<content::RenderViewHost*>(host));
|
|
if (web_contents) {
|
|
return GetBrowserForContents(web_contents);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForHost(
|
|
const content::RenderFrameHost* host) {
|
|
DCHECK(host);
|
|
CEF_REQUIRE_UIT();
|
|
content::WebContents* web_contents =
|
|
content::WebContents::FromRenderFrameHost(
|
|
const_cast<content::RenderFrameHost*>(host));
|
|
if (web_contents) {
|
|
return GetBrowserForContents(web_contents);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForContents(
|
|
const content::WebContents* contents) {
|
|
DCHECK(contents);
|
|
CEF_REQUIRE_UIT();
|
|
return WebContentsUserDataAdapter::Get(contents);
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForGlobalId(
|
|
const content::GlobalRenderFrameHostId& global_id) {
|
|
if (!frame_util::IsValidGlobalId(global_id)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (CEF_CURRENTLY_ON_UIT()) {
|
|
// Use the non-thread-safe but potentially faster approach.
|
|
content::RenderFrameHost* render_frame_host =
|
|
content::RenderFrameHost::FromID(global_id);
|
|
if (!render_frame_host) {
|
|
return nullptr;
|
|
}
|
|
return GetBrowserForHost(render_frame_host);
|
|
} else {
|
|
// Use the thread-safe approach.
|
|
bool is_guest_view = false;
|
|
auto info = CefBrowserInfoManager::GetInstance()->GetBrowserInfo(
|
|
global_id, &is_guest_view);
|
|
if (info && !is_guest_view) {
|
|
auto browser = info->browser();
|
|
if (!browser) {
|
|
LOG(WARNING) << "Found browser id " << info->browser_id()
|
|
<< " but no browser object matching frame "
|
|
<< frame_util::GetFrameDebugString(global_id);
|
|
}
|
|
return browser;
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserHostBase>
|
|
CefBrowserHostBase::GetBrowserForTopLevelNativeWindow(
|
|
gfx::NativeWindow owning_window) {
|
|
DCHECK(owning_window);
|
|
CEF_REQUIRE_UIT();
|
|
|
|
for (const auto& browser_info :
|
|
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
|
|
if (auto browser = browser_info->browser()) {
|
|
if (browser->GetTopLevelNativeWindow() == owning_window) {
|
|
return browser;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetLikelyFocusedBrowser() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
for (const auto& browser_info :
|
|
CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
|
|
if (auto browser = browser_info->browser()) {
|
|
if (browser->IsFocused()) {
|
|
return browser;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
CefBrowserHostBase::CefBrowserHostBase(
|
|
const CefBrowserSettings& settings,
|
|
CefRefPtr<CefClient> client,
|
|
std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
|
|
scoped_refptr<CefBrowserInfo> browser_info,
|
|
CefRefPtr<CefRequestContextImpl> request_context)
|
|
: settings_(settings),
|
|
client_(client),
|
|
platform_delegate_(std::move(platform_delegate)),
|
|
browser_info_(browser_info),
|
|
request_context_(request_context),
|
|
is_views_hosted_(platform_delegate_->IsViewsHosted()) {
|
|
CEF_REQUIRE_UIT();
|
|
DCHECK(!browser_info_->browser().get());
|
|
browser_info_->SetBrowser(this);
|
|
|
|
contents_delegate_ =
|
|
std::make_unique<CefBrowserContentsDelegate>(browser_info_);
|
|
contents_delegate_->AddObserver(this);
|
|
}
|
|
|
|
void CefBrowserHostBase::InitializeBrowser() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
// Associate the WebContents with this browser object.
|
|
DCHECK(GetWebContents());
|
|
WebContentsUserDataAdapter::Register(this);
|
|
}
|
|
|
|
void CefBrowserHostBase::DestroyBrowser() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
devtools_manager_.reset();
|
|
media_stream_registrar_.reset();
|
|
|
|
platform_delegate_.reset();
|
|
|
|
contents_delegate_->RemoveObserver(this);
|
|
contents_delegate_->ObserveWebContents(nullptr);
|
|
|
|
CefBrowserInfoManager::GetInstance()->RemoveBrowserInfo(browser_info_);
|
|
browser_info_->SetBrowser(nullptr);
|
|
}
|
|
|
|
CefRefPtr<CefBrowser> CefBrowserHostBase::GetBrowser() {
|
|
return this;
|
|
}
|
|
|
|
CefRefPtr<CefClient> CefBrowserHostBase::GetClient() {
|
|
return client_;
|
|
}
|
|
|
|
CefRefPtr<CefRequestContext> CefBrowserHostBase::GetRequestContext() {
|
|
return request_context_;
|
|
}
|
|
|
|
bool CefBrowserHostBase::HasView() {
|
|
return is_views_hosted_;
|
|
}
|
|
|
|
void CefBrowserHostBase::SetFocus(bool focus) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::SetFocus, this, focus));
|
|
return;
|
|
}
|
|
|
|
if (focus) {
|
|
OnSetFocus(FOCUS_SOURCE_SYSTEM);
|
|
} else if (platform_delegate_) {
|
|
platform_delegate_->SetFocus(false);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::RunFileDialog(
|
|
FileDialogMode mode,
|
|
const CefString& title,
|
|
const CefString& default_file_path,
|
|
const std::vector<CefString>& accept_filters,
|
|
CefRefPtr<CefRunFileDialogCallback> callback) {
|
|
DCHECK(callback);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::RunFileDialog,
|
|
this, mode, title, default_file_path,
|
|
accept_filters, callback));
|
|
return;
|
|
}
|
|
|
|
if (!callback || !EnsureFileDialogManager()) {
|
|
LOG(ERROR) << "File dialog canceled due to invalid state.";
|
|
if (callback) {
|
|
callback->OnFileDialogDismissed({});
|
|
}
|
|
return;
|
|
}
|
|
|
|
file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
|
|
accept_filters, callback);
|
|
}
|
|
|
|
void CefBrowserHostBase::StartDownload(const CefString& url) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT, base::BindOnce(&CefBrowserHostBase::StartDownload, this, url));
|
|
return;
|
|
}
|
|
|
|
GURL gurl = GURL(url.ToString());
|
|
if (gurl.is_empty() || !gurl.is_valid()) {
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (!web_contents) {
|
|
return;
|
|
}
|
|
|
|
auto browser_context = web_contents->GetBrowserContext();
|
|
if (!browser_context) {
|
|
return;
|
|
}
|
|
|
|
content::DownloadManager* manager = browser_context->GetDownloadManager();
|
|
if (!manager) {
|
|
return;
|
|
}
|
|
|
|
std::unique_ptr<download::DownloadUrlParameters> params(
|
|
content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
|
|
web_contents, gurl, MISSING_TRAFFIC_ANNOTATION));
|
|
manager->DownloadUrl(std::move(params));
|
|
}
|
|
|
|
void CefBrowserHostBase::DownloadImage(
|
|
const CefString& image_url,
|
|
bool is_favicon,
|
|
uint32_t max_image_size,
|
|
bool bypass_cache,
|
|
CefRefPtr<CefDownloadImageCallback> callback) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::DownloadImage, this, image_url,
|
|
is_favicon, max_image_size, bypass_cache, callback));
|
|
return;
|
|
}
|
|
|
|
if (!callback) {
|
|
return;
|
|
}
|
|
|
|
GURL gurl = GURL(image_url.ToString());
|
|
if (gurl.is_empty() || !gurl.is_valid()) {
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (!web_contents) {
|
|
return;
|
|
}
|
|
|
|
const float scale = ui::GetScaleForMaxSupportedResourceScaleFactor();
|
|
web_contents->DownloadImage(
|
|
gurl, is_favicon, gfx::Size(max_image_size, max_image_size),
|
|
max_image_size * scale, bypass_cache,
|
|
base::BindOnce(
|
|
[](uint32_t max_image_size,
|
|
CefRefPtr<CefDownloadImageCallback> callback, int id,
|
|
int http_status_code, const GURL& image_url,
|
|
const std::vector<SkBitmap>& bitmaps,
|
|
const std::vector<gfx::Size>& sizes) {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
CefRefPtr<CefImageImpl> image_impl;
|
|
|
|
if (!bitmaps.empty()) {
|
|
image_impl = new CefImageImpl();
|
|
image_impl->AddBitmaps(max_image_size, bitmaps);
|
|
}
|
|
|
|
callback->OnDownloadImageFinished(
|
|
image_url.spec(), http_status_code, image_impl.get());
|
|
},
|
|
max_image_size, callback));
|
|
}
|
|
|
|
void CefBrowserHostBase::Print() {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::Print, this));
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (!web_contents) {
|
|
return;
|
|
}
|
|
|
|
const bool print_preview_disabled =
|
|
!platform_delegate_ || !platform_delegate_->IsPrintPreviewSupported();
|
|
print_util::Print(web_contents, print_preview_disabled);
|
|
}
|
|
|
|
void CefBrowserHostBase::PrintToPDF(const CefString& path,
|
|
const CefPdfPrintSettings& settings,
|
|
CefRefPtr<CefPdfPrintCallback> callback) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::PrintToPDF, this,
|
|
path, settings, callback));
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (!web_contents) {
|
|
return;
|
|
}
|
|
|
|
print_util::PrintToPDF(web_contents, path, settings, callback);
|
|
}
|
|
|
|
bool CefBrowserHostBase::SendDevToolsMessage(const void* message,
|
|
size_t message_size) {
|
|
if (!message || message_size == 0) {
|
|
return false;
|
|
}
|
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
std::string message_str(static_cast<const char*>(message), message_size);
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(
|
|
[](CefRefPtr<CefBrowserHostBase> self, std::string message_str) {
|
|
self->SendDevToolsMessage(message_str.data(), message_str.size());
|
|
},
|
|
CefRefPtr<CefBrowserHostBase>(this), std::move(message_str)));
|
|
return false;
|
|
}
|
|
|
|
if (!EnsureDevToolsManager()) {
|
|
return false;
|
|
}
|
|
return devtools_manager_->SendDevToolsMessage(message, message_size);
|
|
}
|
|
|
|
int CefBrowserHostBase::ExecuteDevToolsMethod(
|
|
int message_id,
|
|
const CefString& method,
|
|
CefRefPtr<CefDictionaryValue> params) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT, base::BindOnce(base::IgnoreResult(
|
|
&CefBrowserHostBase::ExecuteDevToolsMethod),
|
|
this, message_id, method, params));
|
|
return 0;
|
|
}
|
|
|
|
if (!EnsureDevToolsManager()) {
|
|
return 0;
|
|
}
|
|
return devtools_manager_->ExecuteDevToolsMethod(message_id, method, params);
|
|
}
|
|
|
|
CefRefPtr<CefRegistration> CefBrowserHostBase::AddDevToolsMessageObserver(
|
|
CefRefPtr<CefDevToolsMessageObserver> observer) {
|
|
if (!observer) {
|
|
return nullptr;
|
|
}
|
|
auto registration = CefDevToolsManager::CreateRegistration(observer);
|
|
InitializeDevToolsRegistrationOnUIThread(registration);
|
|
return registration.get();
|
|
}
|
|
|
|
void CefBrowserHostBase::GetNavigationEntries(
|
|
CefRefPtr<CefNavigationEntryVisitor> visitor,
|
|
bool current_only) {
|
|
DCHECK(visitor.get());
|
|
if (!visitor.get()) {
|
|
return;
|
|
}
|
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT, base::BindOnce(&CefBrowserHostBase::GetNavigationEntries, this,
|
|
visitor, current_only));
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (!web_contents) {
|
|
return;
|
|
}
|
|
|
|
content::NavigationController& controller = web_contents->GetController();
|
|
const int total = controller.GetEntryCount();
|
|
const int current = controller.GetCurrentEntryIndex();
|
|
|
|
if (current_only) {
|
|
// Visit only the current entry.
|
|
CefRefPtr<CefNavigationEntryImpl> entry =
|
|
new CefNavigationEntryImpl(controller.GetEntryAtIndex(current));
|
|
visitor->Visit(entry.get(), true, current, total);
|
|
std::ignore = entry->Detach(nullptr);
|
|
} else {
|
|
// Visit all entries.
|
|
bool cont = true;
|
|
for (int i = 0; i < total && cont; ++i) {
|
|
CefRefPtr<CefNavigationEntryImpl> entry =
|
|
new CefNavigationEntryImpl(controller.GetEntryAtIndex(i));
|
|
cont = visitor->Visit(entry.get(), (i == current), i, total);
|
|
std::ignore = entry->Detach(nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
CefRefPtr<CefNavigationEntry> CefBrowserHostBase::GetVisibleNavigationEntry() {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
DCHECK(false) << "called on invalid thread";
|
|
return nullptr;
|
|
}
|
|
|
|
content::NavigationEntry* entry = nullptr;
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
entry = web_contents->GetController().GetVisibleEntry();
|
|
}
|
|
|
|
if (!entry) {
|
|
return nullptr;
|
|
}
|
|
|
|
return new CefNavigationEntryImpl(entry);
|
|
}
|
|
|
|
void CefBrowserHostBase::NotifyMoveOrResizeStarted() {
|
|
#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::NotifyMoveOrResizeStarted, this));
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->NotifyMoveOrResizeStarted();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CefBrowserHostBase::ReplaceMisspelling(const CefString& word) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::ReplaceMisspelling, this, word));
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
web_contents->ReplaceMisspelling(word);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::AddWordToDictionary(const CefString& word) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::AddWordToDictionary, this, word));
|
|
return;
|
|
}
|
|
|
|
auto web_contents = GetWebContents();
|
|
if (!web_contents) {
|
|
return;
|
|
}
|
|
|
|
SpellcheckService* spellcheck = nullptr;
|
|
content::BrowserContext* browser_context = web_contents->GetBrowserContext();
|
|
if (browser_context) {
|
|
spellcheck = SpellcheckServiceFactory::GetForContext(browser_context);
|
|
if (spellcheck) {
|
|
spellcheck->GetCustomDictionary()->AddWord(word);
|
|
}
|
|
}
|
|
#if BUILDFLAG(IS_MAC)
|
|
if (spellcheck && spellcheck::UseBrowserSpellChecker()) {
|
|
spellcheck_platform::AddWord(spellcheck->platform_spell_checker(), word);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CefBrowserHostBase::SendKeyEvent(const CefKeyEvent& event) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::SendKeyEvent,
|
|
this, event));
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->SendKeyEvent(event);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::SendMouseClickEvent(const CefMouseEvent& event,
|
|
MouseButtonType type,
|
|
bool mouseUp,
|
|
int clickCount) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::SendMouseClickEvent, this,
|
|
event, type, mouseUp, clickCount));
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->SendMouseClickEvent(event, type, mouseUp, clickCount);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::SendMouseMoveEvent(const CefMouseEvent& event,
|
|
bool mouseLeave) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::SendMouseMoveEvent, this,
|
|
event, mouseLeave));
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->SendMouseMoveEvent(event, mouseLeave);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::SendMouseWheelEvent(const CefMouseEvent& event,
|
|
int deltaX,
|
|
int deltaY) {
|
|
if (deltaX == 0 && deltaY == 0) {
|
|
// Nothing to do.
|
|
return;
|
|
}
|
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::SendMouseWheelEvent, this,
|
|
event, deltaX, deltaY));
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->SendMouseWheelEvent(event, deltaX, deltaY);
|
|
}
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsValid() {
|
|
return browser_info_->browser() == this;
|
|
}
|
|
|
|
CefRefPtr<CefBrowserHost> CefBrowserHostBase::GetHost() {
|
|
return this;
|
|
}
|
|
|
|
bool CefBrowserHostBase::CanGoBack() {
|
|
base::AutoLock lock_scope(state_lock_);
|
|
return can_go_back_;
|
|
}
|
|
|
|
void CefBrowserHostBase::GoBack() {
|
|
auto callback = base::BindOnce(&CefBrowserHostBase::GoBack, this);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, std::move(callback));
|
|
return;
|
|
}
|
|
|
|
if (browser_info_->IsNavigationLocked(std::move(callback))) {
|
|
return;
|
|
}
|
|
|
|
auto wc = GetWebContents();
|
|
if (wc && wc->GetController().CanGoBack()) {
|
|
wc->GetController().GoBack();
|
|
}
|
|
}
|
|
|
|
bool CefBrowserHostBase::CanGoForward() {
|
|
base::AutoLock lock_scope(state_lock_);
|
|
return can_go_forward_;
|
|
}
|
|
|
|
void CefBrowserHostBase::GoForward() {
|
|
auto callback = base::BindOnce(&CefBrowserHostBase::GoForward, this);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, std::move(callback));
|
|
return;
|
|
}
|
|
|
|
if (browser_info_->IsNavigationLocked(std::move(callback))) {
|
|
return;
|
|
}
|
|
|
|
auto wc = GetWebContents();
|
|
if (wc && wc->GetController().CanGoForward()) {
|
|
wc->GetController().GoForward();
|
|
}
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsLoading() {
|
|
base::AutoLock lock_scope(state_lock_);
|
|
return is_loading_;
|
|
}
|
|
|
|
void CefBrowserHostBase::Reload() {
|
|
auto callback = base::BindOnce(&CefBrowserHostBase::Reload, this);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, std::move(callback));
|
|
return;
|
|
}
|
|
|
|
if (browser_info_->IsNavigationLocked(std::move(callback))) {
|
|
return;
|
|
}
|
|
|
|
auto wc = GetWebContents();
|
|
if (wc) {
|
|
wc->GetController().Reload(content::ReloadType::NORMAL, true);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::ReloadIgnoreCache() {
|
|
auto callback = base::BindOnce(&CefBrowserHostBase::ReloadIgnoreCache, this);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, std::move(callback));
|
|
return;
|
|
}
|
|
|
|
if (browser_info_->IsNavigationLocked(std::move(callback))) {
|
|
return;
|
|
}
|
|
|
|
auto wc = GetWebContents();
|
|
if (wc) {
|
|
wc->GetController().Reload(content::ReloadType::BYPASSING_CACHE, true);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::StopLoad() {
|
|
auto callback = base::BindOnce(&CefBrowserHostBase::StopLoad, this);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, std::move(callback));
|
|
return;
|
|
}
|
|
|
|
if (browser_info_->IsNavigationLocked(std::move(callback))) {
|
|
return;
|
|
}
|
|
|
|
auto wc = GetWebContents();
|
|
if (wc) {
|
|
wc->Stop();
|
|
}
|
|
}
|
|
|
|
int CefBrowserHostBase::GetIdentifier() {
|
|
return browser_id();
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsSame(CefRefPtr<CefBrowser> that) {
|
|
auto impl = static_cast<CefBrowserHostBase*>(that.get());
|
|
return (impl == this);
|
|
}
|
|
|
|
bool CefBrowserHostBase::HasDocument() {
|
|
base::AutoLock lock_scope(state_lock_);
|
|
return has_document_;
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsPopup() {
|
|
return browser_info_->is_popup();
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserHostBase::GetMainFrame() {
|
|
return GetFrame(CefFrameHostImpl::kMainFrameId);
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserHostBase::GetFocusedFrame() {
|
|
return GetFrame(CefFrameHostImpl::kFocusedFrameId);
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserHostBase::GetFrame(int64_t identifier) {
|
|
if (identifier == CefFrameHostImpl::kInvalidFrameId) {
|
|
return nullptr;
|
|
} else if (identifier == CefFrameHostImpl::kMainFrameId) {
|
|
return browser_info_->GetMainFrame();
|
|
} else if (identifier == CefFrameHostImpl::kFocusedFrameId) {
|
|
base::AutoLock lock_scope(state_lock_);
|
|
if (!focused_frame_) {
|
|
// The main frame is focused by default.
|
|
return browser_info_->GetMainFrame();
|
|
}
|
|
return focused_frame_;
|
|
}
|
|
|
|
return browser_info_->GetFrameForGlobalId(
|
|
frame_util::MakeGlobalId(identifier));
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserHostBase::GetFrame(const CefString& name) {
|
|
for (const auto& frame : browser_info_->GetAllFrames()) {
|
|
if (frame->GetName() == name) {
|
|
return frame;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
size_t CefBrowserHostBase::GetFrameCount() {
|
|
return browser_info_->GetAllFrames().size();
|
|
}
|
|
|
|
void CefBrowserHostBase::GetFrameIdentifiers(
|
|
std::vector<int64_t>& identifiers) {
|
|
if (identifiers.size() > 0) {
|
|
identifiers.clear();
|
|
}
|
|
|
|
const auto frames = browser_info_->GetAllFrames();
|
|
if (frames.empty()) {
|
|
return;
|
|
}
|
|
|
|
identifiers.reserve(frames.size());
|
|
for (const auto& frame : frames) {
|
|
identifiers.push_back(frame->GetIdentifier());
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::GetFrameNames(std::vector<CefString>& names) {
|
|
if (names.size() > 0) {
|
|
names.clear();
|
|
}
|
|
|
|
const auto frames = browser_info_->GetAllFrames();
|
|
if (frames.empty()) {
|
|
return;
|
|
}
|
|
|
|
names.reserve(frames.size());
|
|
for (const auto& frame : frames) {
|
|
names.push_back(frame->GetName());
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::OnStateChanged(CefBrowserContentsState state_changed) {
|
|
// Make sure that CefBrowser state is consistent before the associated
|
|
// CefClient callback is executed.
|
|
base::AutoLock lock_scope(state_lock_);
|
|
if ((state_changed & CefBrowserContentsState::kNavigation) ==
|
|
CefBrowserContentsState::kNavigation) {
|
|
is_loading_ = contents_delegate_->is_loading();
|
|
can_go_back_ = contents_delegate_->can_go_back();
|
|
can_go_forward_ = contents_delegate_->can_go_forward();
|
|
}
|
|
if ((state_changed & CefBrowserContentsState::kDocument) ==
|
|
CefBrowserContentsState::kDocument) {
|
|
has_document_ = contents_delegate_->has_document();
|
|
}
|
|
if ((state_changed & CefBrowserContentsState::kFullscreen) ==
|
|
CefBrowserContentsState::kFullscreen) {
|
|
is_fullscreen_ = contents_delegate_->is_fullscreen();
|
|
}
|
|
if ((state_changed & CefBrowserContentsState::kFocusedFrame) ==
|
|
CefBrowserContentsState::kFocusedFrame) {
|
|
focused_frame_ = contents_delegate_->focused_frame();
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::OnWebContentsDestroyed(
|
|
content::WebContents* web_contents) {}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserHostBase::GetFrameForHost(
|
|
const content::RenderFrameHost* host) {
|
|
CEF_REQUIRE_UIT();
|
|
if (!host) {
|
|
return nullptr;
|
|
}
|
|
|
|
return browser_info_->GetFrameForHost(host);
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserHostBase::GetFrameForGlobalId(
|
|
const content::GlobalRenderFrameHostId& global_id) {
|
|
return browser_info_->GetFrameForGlobalId(global_id, nullptr);
|
|
}
|
|
|
|
void CefBrowserHostBase::AddObserver(Observer* observer) {
|
|
CEF_REQUIRE_UIT();
|
|
observers_.AddObserver(observer);
|
|
}
|
|
|
|
void CefBrowserHostBase::RemoveObserver(Observer* observer) {
|
|
CEF_REQUIRE_UIT();
|
|
observers_.RemoveObserver(observer);
|
|
}
|
|
|
|
bool CefBrowserHostBase::HasObserver(Observer* observer) const {
|
|
CEF_REQUIRE_UIT();
|
|
return observers_.HasObserver(observer);
|
|
}
|
|
|
|
void CefBrowserHostBase::LoadMainFrameURL(
|
|
const content::OpenURLParams& params) {
|
|
auto callback =
|
|
base::BindOnce(&CefBrowserHostBase::LoadMainFrameURL, this, params);
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT, std::move(callback));
|
|
return;
|
|
}
|
|
|
|
if (browser_info_->IsNavigationLocked(std::move(callback))) {
|
|
return;
|
|
}
|
|
|
|
if (Navigate(params)) {
|
|
OnSetFocus(FOCUS_SOURCE_NAVIGATION);
|
|
}
|
|
}
|
|
|
|
bool CefBrowserHostBase::Navigate(const content::OpenURLParams& params) {
|
|
CEF_REQUIRE_UIT();
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
GURL gurl = params.url;
|
|
if (!url_util::FixupGURL(gurl)) {
|
|
return false;
|
|
}
|
|
|
|
web_contents->GetController().LoadURL(
|
|
gurl, params.referrer, params.transition, params.extra_headers);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CefBrowserHostBase::ViewText(const std::string& text) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(CEF_UIT,
|
|
base::BindOnce(&CefBrowserHostBase::ViewText, this, text));
|
|
return;
|
|
}
|
|
|
|
if (platform_delegate_) {
|
|
platform_delegate_->ViewText(text);
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::RunFileChooserForBrowser(
|
|
const blink::mojom::FileChooserParams& params,
|
|
CefFileDialogManager::RunFileChooserCallback callback) {
|
|
if (!EnsureFileDialogManager()) {
|
|
LOG(ERROR) << "File dialog canceled due to invalid state.";
|
|
std::move(callback).Run({});
|
|
return;
|
|
}
|
|
file_dialog_manager_->RunFileChooser(params, std::move(callback));
|
|
}
|
|
|
|
void CefBrowserHostBase::RunSelectFile(
|
|
ui::SelectFileDialog::Listener* listener,
|
|
std::unique_ptr<ui::SelectFilePolicy> policy,
|
|
ui::SelectFileDialog::Type type,
|
|
const std::u16string& title,
|
|
const base::FilePath& default_path,
|
|
const ui::SelectFileDialog::FileTypeInfo* file_types,
|
|
int file_type_index,
|
|
const base::FilePath::StringType& default_extension,
|
|
gfx::NativeWindow owning_window,
|
|
void* params) {
|
|
if (!EnsureFileDialogManager()) {
|
|
LOG(ERROR) << "File dialog canceled due to invalid state.";
|
|
listener->FileSelectionCanceled(params);
|
|
return;
|
|
}
|
|
file_dialog_manager_->RunSelectFile(listener, std::move(policy), type, title,
|
|
default_path, file_types, file_type_index,
|
|
default_extension, owning_window, params);
|
|
}
|
|
|
|
void CefBrowserHostBase::SelectFileListenerDestroyed(
|
|
ui::SelectFileDialog::Listener* listener) {
|
|
if (file_dialog_manager_) {
|
|
file_dialog_manager_->SelectFileListenerDestroyed(listener);
|
|
}
|
|
}
|
|
|
|
bool CefBrowserHostBase::MaybeAllowNavigation(
|
|
content::RenderFrameHost* opener,
|
|
bool is_guest_view,
|
|
const content::OpenURLParams& params) {
|
|
return true;
|
|
}
|
|
|
|
void CefBrowserHostBase::OnAfterCreated() {
|
|
CEF_REQUIRE_UIT();
|
|
if (client_) {
|
|
if (auto handler = client_->GetLifeSpanHandler()) {
|
|
handler->OnAfterCreated(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CefBrowserHostBase::OnBeforeClose() {
|
|
CEF_REQUIRE_UIT();
|
|
if (client_) {
|
|
if (auto handler = client_->GetLifeSpanHandler()) {
|
|
handler->OnBeforeClose(this);
|
|
}
|
|
}
|
|
browser_info_->SetClosing();
|
|
}
|
|
|
|
void CefBrowserHostBase::OnBrowserDestroyed() {
|
|
CEF_REQUIRE_UIT();
|
|
|
|
// Destroy any platform constructs.
|
|
if (file_dialog_manager_) {
|
|
file_dialog_manager_->Destroy();
|
|
file_dialog_manager_.reset();
|
|
}
|
|
|
|
for (auto& observer : observers_) {
|
|
observer.OnBrowserDestroyed(this);
|
|
}
|
|
}
|
|
|
|
int CefBrowserHostBase::browser_id() const {
|
|
return browser_info_->browser_id();
|
|
}
|
|
|
|
SkColor CefBrowserHostBase::GetBackgroundColor() const {
|
|
// Don't use |platform_delegate_| because it's not thread-safe.
|
|
return CefContext::Get()->GetBackgroundColor(
|
|
&settings_, IsWindowless() ? STATE_ENABLED : STATE_DISABLED);
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsWindowless() const {
|
|
return false;
|
|
}
|
|
|
|
content::WebContents* CefBrowserHostBase::GetWebContents() const {
|
|
CEF_REQUIRE_UIT();
|
|
return contents_delegate_->web_contents();
|
|
}
|
|
|
|
content::BrowserContext* CefBrowserHostBase::GetBrowserContext() const {
|
|
CEF_REQUIRE_UIT();
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
return web_contents->GetBrowserContext();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CefMediaStreamRegistrar* CefBrowserHostBase::GetMediaStreamRegistrar() {
|
|
CEF_REQUIRE_UIT();
|
|
if (!media_stream_registrar_) {
|
|
media_stream_registrar_ = std::make_unique<CefMediaStreamRegistrar>(this);
|
|
}
|
|
return media_stream_registrar_.get();
|
|
}
|
|
|
|
views::Widget* CefBrowserHostBase::GetWindowWidget() const {
|
|
CEF_REQUIRE_UIT();
|
|
if (!platform_delegate_) {
|
|
return nullptr;
|
|
}
|
|
return platform_delegate_->GetWindowWidget();
|
|
}
|
|
|
|
CefRefPtr<CefBrowserView> CefBrowserHostBase::GetBrowserView() const {
|
|
CEF_REQUIRE_UIT();
|
|
if (is_views_hosted_ && platform_delegate_) {
|
|
return platform_delegate_->GetBrowserView();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
gfx::NativeWindow CefBrowserHostBase::GetTopLevelNativeWindow() const {
|
|
CEF_REQUIRE_UIT();
|
|
// Windowless browsers always return nullptr from GetTopLevelNativeWindow().
|
|
if (!IsWindowless()) {
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
return web_contents->GetTopLevelNativeWindow();
|
|
}
|
|
}
|
|
return gfx::NativeWindow();
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsFocused() const {
|
|
CEF_REQUIRE_UIT();
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
return static_cast<content::RenderFrameHostImpl*>(
|
|
web_contents->GetPrimaryMainFrame())
|
|
->IsFocused();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CefBrowserHostBase::IsVisible() const {
|
|
CEF_REQUIRE_UIT();
|
|
// Windowless browsers always return nullptr from GetNativeView().
|
|
if (!IsWindowless()) {
|
|
auto web_contents = GetWebContents();
|
|
if (web_contents) {
|
|
return platform_util::IsVisible(web_contents->GetNativeView());
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CefBrowserHostBase::EnsureDevToolsManager() {
|
|
CEF_REQUIRE_UIT();
|
|
if (!contents_delegate_->web_contents()) {
|
|
return false;
|
|
}
|
|
|
|
if (!devtools_manager_) {
|
|
devtools_manager_ = std::make_unique<CefDevToolsManager>(this);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CefBrowserHostBase::InitializeDevToolsRegistrationOnUIThread(
|
|
CefRefPtr<CefRegistration> registration) {
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
CEF_POST_TASK(
|
|
CEF_UIT,
|
|
base::BindOnce(
|
|
&CefBrowserHostBase::InitializeDevToolsRegistrationOnUIThread, this,
|
|
registration));
|
|
return;
|
|
}
|
|
|
|
if (!EnsureDevToolsManager()) {
|
|
return;
|
|
}
|
|
devtools_manager_->InitializeRegistrationOnUIThread(registration);
|
|
}
|
|
|
|
bool CefBrowserHostBase::EnsureFileDialogManager() {
|
|
CEF_REQUIRE_UIT();
|
|
if (!contents_delegate_->web_contents()) {
|
|
return false;
|
|
}
|
|
|
|
if (!file_dialog_manager_) {
|
|
file_dialog_manager_ = std::make_unique<CefFileDialogManager>(this);
|
|
}
|
|
return true;
|
|
}
|