mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	The "Find" widget will be excluded from regions near the edges of the window that contain overlays, draggable regions or titlebar.
		
			
				
	
	
		
			419 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			14 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/media_access_query.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;
 | 
						|
 | 
						|
std::unique_ptr<content::WebContents> ChromeBrowserDelegate::AddWebContents(
 | 
						|
    std::unique_ptr<content::WebContents> new_contents) {
 | 
						|
  if (CefBrowserInfoManager::GetInstance()->AddWebContents(
 | 
						|
          new_contents.get())) {
 | 
						|
    // The browser host should have been created in WebContentsCreated().
 | 
						|
    auto new_browser =
 | 
						|
        ChromeBrowserHostImpl::GetBrowserForContents(new_contents.get());
 | 
						|
    if (new_browser) {
 | 
						|
      // Create a new Browser and give it ownership of the new WebContents.
 | 
						|
      new_browser->AddNewContents(std::move(new_contents));
 | 
						|
    } else {
 | 
						|
      LOG(ERROR) << "No host found for chrome popup browser";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Proceed with default chrome::AddWebContents behavior.
 | 
						|
  return new_contents;
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeBrowserDelegate::ShowStatusBubble(bool show_by_default) {
 | 
						|
  if (!show_status_bubble_.has_value()) {
 | 
						|
    show_status_bubble_ = show_by_default;
 | 
						|
    if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
 | 
						|
      const auto& state = browser->settings().chrome_status_bubble;
 | 
						|
      if (show_by_default && state == STATE_DISABLED) {
 | 
						|
        show_status_bubble_ = false;
 | 
						|
      } else if (!show_by_default && state == STATE_ENABLED) {
 | 
						|
        show_status_bubble_ = true;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return *show_status_bubble_;
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeBrowserDelegate::HandleCommand(int command_id,
 | 
						|
                                          WindowOpenDisposition disposition) {
 | 
						|
  if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
 | 
						|
    if (auto client = browser->GetClient()) {
 | 
						|
      if (auto handler = client->GetCommandHandler()) {
 | 
						|
        return handler->OnChromeCommand(
 | 
						|
            browser.get(), command_id,
 | 
						|
            static_cast<cef_window_open_disposition_t>(disposition));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeBrowserDelegate::IsAppMenuItemVisible(int command_id) {
 | 
						|
  if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
 | 
						|
    if (auto client = browser->GetClient()) {
 | 
						|
      if (auto handler = client->GetCommandHandler()) {
 | 
						|
        return handler->IsChromeAppMenuItemVisible(browser.get(), command_id);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeBrowserDelegate::IsAppMenuItemEnabled(int command_id) {
 | 
						|
  if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
 | 
						|
    if (auto client = browser->GetClient()) {
 | 
						|
      if (auto handler = client->GetCommandHandler()) {
 | 
						|
        return handler->IsChromeAppMenuItemEnabled(browser.get(), command_id);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeBrowserDelegate::IsPageActionIconVisible(
 | 
						|
    PageActionIconType icon_type) {
 | 
						|
  // Verify that our enum matches Chromium's values.
 | 
						|
  static_assert(static_cast<int>(CEF_CPAIT_MAX_VALUE) ==
 | 
						|
                    static_cast<int>(PageActionIconType::kMaxValue),
 | 
						|
                "enum mismatch");
 | 
						|
 | 
						|
  if (auto client = create_params_.client) {
 | 
						|
    if (auto handler = client->GetCommandHandler()) {
 | 
						|
      return handler->IsChromePageActionIconVisible(
 | 
						|
          static_cast<cef_chrome_page_action_icon_type_t>(icon_type));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeBrowserDelegate::IsToolbarButtonVisible(
 | 
						|
    ToolbarButtonType button_type) {
 | 
						|
  // Verify that our enum matches BrowserDelegate's values.
 | 
						|
  static_assert(static_cast<int>(CEF_CTBT_MAX_VALUE) ==
 | 
						|
                    static_cast<int>(ToolbarButtonType::kMaxValue),
 | 
						|
                "enum mismatch");
 | 
						|
 | 
						|
  if (auto client = create_params_.client) {
 | 
						|
    if (auto handler = client->GetCommandHandler()) {
 | 
						|
      return handler->IsChromeToolbarButtonVisible(
 | 
						|
          static_cast<cef_chrome_toolbar_button_type_t>(button_type));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void ChromeBrowserDelegate::UpdateFindBarBoundingBox(gfx::Rect* bounds) {
 | 
						|
  if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
 | 
						|
    browser->platform_delegate()->UpdateFindBarBoundingBox(bounds);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
content::MediaResponseCallback
 | 
						|
ChromeBrowserDelegate::RequestMediaAccessPermissionEx(
 | 
						|
    content::WebContents* web_contents,
 | 
						|
    const content::MediaStreamRequest& request,
 | 
						|
    content::MediaResponseCallback callback) {
 | 
						|
  if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
 | 
						|
    return media_access_query::RequestMediaAccessPermission(
 | 
						|
        browser.get(), request, std::move(callback),
 | 
						|
        /*default_disallow=*/false);
 | 
						|
  }
 | 
						|
  return callback;
 | 
						|
}
 | 
						|
 | 
						|
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, new_contents);
 | 
						|
 | 
						|
  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);
 | 
						|
}
 | 
						|
 | 
						|
content::WebContents* ChromeBrowserDelegate::OpenURLFromTab(
 | 
						|
    content::WebContents* source,
 | 
						|
    const content::OpenURLParams& params) {
 | 
						|
  // |source| may be nullptr when opening a link from chrome UI such as the
 | 
						|
  // Reading List sidebar. In that case we default to using the Browser's
 | 
						|
  // currently active WebContents.
 | 
						|
  if (!source) {
 | 
						|
    source = browser_->tab_strip_model()->GetActiveWebContents();
 | 
						|
    DCHECK(source);
 | 
						|
  }
 | 
						|
 | 
						|
  // 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 should_show_loading_ui) {
 | 
						|
  if (auto delegate = GetDelegateForWebContents(source)) {
 | 
						|
    delegate->LoadingStateChanged(source, should_show_loading_ui);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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::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);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ChromeBrowserDelegate::CanDownload(
 | 
						|
    const GURL& url,
 | 
						|
    const std::string& request_method,
 | 
						|
    base::OnceCallback<void(bool)> callback) {
 | 
						|
  auto source = browser_->tab_strip_model()->GetActiveWebContents();
 | 
						|
  DCHECK(source);
 | 
						|
 | 
						|
  if (auto delegate = GetDelegateForWebContents(source)) {
 | 
						|
    delegate->CanDownload(url, request_method, std::move(callback));
 | 
						|
    return;
 | 
						|
  }
 | 
						|
  std::move(callback).Run(true);
 | 
						|
}
 | 
						|
 | 
						|
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.
 | 
						|
    params->create_params_.window_info.reset();
 | 
						|
    params->create_params_.browser_view = nullptr;
 | 
						|
  }
 | 
						|
 | 
						|
  return std::make_unique<ChromeBrowserDelegate>(browser, create_params);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace cef
 |