mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	If the background color is set too early it won't be sent to renderer process. Also force refresh of the background color for newly created popups.
		
			
				
	
	
		
			395 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			395 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2020 The Chromium Embedded Framework Authors.
 | 
						|
// Portions copyright 2012 The Chromium 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/chrome/chrome_content_browser_client_cef.h"
 | 
						|
 | 
						|
#include "libcef/browser/browser_frame.h"
 | 
						|
#include "libcef/browser/browser_info_manager.h"
 | 
						|
#include "libcef/browser/browser_manager.h"
 | 
						|
#include "libcef/browser/chrome/chrome_browser_host_impl.h"
 | 
						|
#include "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h"
 | 
						|
#include "libcef/browser/context.h"
 | 
						|
#include "libcef/browser/net/chrome_scheme_handler.h"
 | 
						|
#include "libcef/browser/net/throttle_handler.h"
 | 
						|
#include "libcef/browser/net_service/cookie_manager_impl.h"
 | 
						|
#include "libcef/browser/net_service/login_delegate.h"
 | 
						|
#include "libcef/browser/net_service/proxy_url_loader_factory.h"
 | 
						|
#include "libcef/browser/net_service/resource_request_handler_wrapper.h"
 | 
						|
#include "libcef/browser/prefs/browser_prefs.h"
 | 
						|
#include "libcef/browser/prefs/renderer_prefs.h"
 | 
						|
#include "libcef/common/app_manager.h"
 | 
						|
#include "libcef/common/cef_switches.h"
 | 
						|
#include "libcef/common/command_line_impl.h"
 | 
						|
 | 
						|
#include "base/command_line.h"
 | 
						|
#include "base/path_service.h"
 | 
						|
#include "chrome/browser/chrome_browser_main.h"
 | 
						|
#include "chrome/common/chrome_paths.h"
 | 
						|
#include "chrome/common/chrome_switches.h"
 | 
						|
#include "content/public/browser/navigation_throttle.h"
 | 
						|
#include "content/public/browser/render_process_host.h"
 | 
						|
#include "content/public/browser/render_view_host.h"
 | 
						|
#include "content/public/browser/render_widget_host.h"
 | 
						|
#include "content/public/browser/render_widget_host_view.h"
 | 
						|
#include "content/public/common/content_switches.h"
 | 
						|
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
 | 
						|
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
void HandleExternalProtocolHelper(
 | 
						|
    ChromeContentBrowserClientCef* self,
 | 
						|
    content::WebContents::Getter web_contents_getter,
 | 
						|
    int frame_tree_node_id,
 | 
						|
    content::NavigationUIData* navigation_data,
 | 
						|
    const network::ResourceRequest& resource_request) {
 | 
						|
  // Match the logic of the original call in
 | 
						|
  // NavigationURLLoaderImpl::PrepareForNonInterceptedRequest.
 | 
						|
  self->HandleExternalProtocol(
 | 
						|
      resource_request.url, web_contents_getter,
 | 
						|
      content::ChildProcessHost::kInvalidUniqueID, frame_tree_node_id,
 | 
						|
      navigation_data,
 | 
						|
      resource_request.resource_type ==
 | 
						|
          static_cast<int>(blink::mojom::ResourceType::kMainFrame),
 | 
						|
      static_cast<ui::PageTransition>(resource_request.transition_type),
 | 
						|
      resource_request.has_user_gesture, resource_request.request_initiator,
 | 
						|
      nullptr);
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
ChromeContentBrowserClientCef::ChromeContentBrowserClientCef() = default;
 | 
						|
ChromeContentBrowserClientCef::~ChromeContentBrowserClientCef() = default;
 | 
						|
 | 
						|
std::unique_ptr<content::BrowserMainParts>
 | 
						|
ChromeContentBrowserClientCef::CreateBrowserMainParts(
 | 
						|
    const content::MainFunctionParams& parameters) {
 | 
						|
  auto main_parts =
 | 
						|
      ChromeContentBrowserClient::CreateBrowserMainParts(parameters);
 | 
						|
  browser_main_parts_ = new ChromeBrowserMainExtraPartsCef;
 | 
						|
  static_cast<ChromeBrowserMainParts*>(main_parts.get())
 | 
						|
      ->AddParts(
 | 
						|
          base::WrapUnique<ChromeBrowserMainExtraParts>(browser_main_parts_));
 | 
						|
  return main_parts;
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::AppendExtraCommandLineSwitches(
 | 
						|
    base::CommandLine* command_line,
 | 
						|
    int child_process_id) {
 | 
						|
  ChromeContentBrowserClient::AppendExtraCommandLineSwitches(command_line,
 | 
						|
                                                             child_process_id);
 | 
						|
 | 
						|
  // Necessary to launch sub-processes in the correct mode.
 | 
						|
  command_line->AppendSwitch(switches::kEnableChromeRuntime);
 | 
						|
 | 
						|
  // Necessary to populate DIR_USER_DATA in sub-processes.
 | 
						|
  // See resource_util.cc GetUserDataPath.
 | 
						|
  base::FilePath user_data_dir;
 | 
						|
  if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
 | 
						|
    command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
 | 
						|
  }
 | 
						|
 | 
						|
  const base::CommandLine* browser_cmd = base::CommandLine::ForCurrentProcess();
 | 
						|
 | 
						|
  {
 | 
						|
    // Propagate the following switches to all command lines (along with any
 | 
						|
    // associated values) if present in the browser command line.
 | 
						|
    static const char* const kSwitchNames[] = {
 | 
						|
        switches::kUserAgentProductAndVersion,
 | 
						|
    };
 | 
						|
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
 | 
						|
                                   base::size(kSwitchNames));
 | 
						|
  }
 | 
						|
 | 
						|
  const std::string& process_type =
 | 
						|
      command_line->GetSwitchValueASCII(switches::kProcessType);
 | 
						|
  if (process_type == switches::kRendererProcess) {
 | 
						|
    // Propagate the following switches to the renderer command line (along with
 | 
						|
    // any associated values) if present in the browser command line.
 | 
						|
    static const char* const kSwitchNames[] = {
 | 
						|
        switches::kUncaughtExceptionStackSize,
 | 
						|
    };
 | 
						|
    command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
 | 
						|
                                   base::size(kSwitchNames));
 | 
						|
  }
 | 
						|
 | 
						|
  CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
 | 
						|
  if (app.get()) {
 | 
						|
    CefRefPtr<CefBrowserProcessHandler> handler =
 | 
						|
        app->GetBrowserProcessHandler();
 | 
						|
    if (handler.get()) {
 | 
						|
      CefRefPtr<CefCommandLineImpl> commandLinePtr(
 | 
						|
          new CefCommandLineImpl(command_line, false, false));
 | 
						|
      handler->OnBeforeChildProcessLaunch(commandLinePtr.get());
 | 
						|
      ignore_result(commandLinePtr->Detach(nullptr));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::RenderProcessWillLaunch(
 | 
						|
    content::RenderProcessHost* host) {
 | 
						|
  ChromeContentBrowserClient::RenderProcessWillLaunch(host);
 | 
						|
 | 
						|
  // If the renderer process crashes then the host may already have
 | 
						|
  // CefBrowserInfoManager as an observer. Try to remove it first before adding
 | 
						|
  // to avoid DCHECKs.
 | 
						|
  host->RemoveObserver(CefBrowserInfoManager::GetInstance());
 | 
						|
  host->AddObserver(CefBrowserInfoManager::GetInstance());
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeContentBrowserClientCef::CanCreateWindow(
 | 
						|
    content::RenderFrameHost* opener,
 | 
						|
    const GURL& opener_url,
 | 
						|
    const GURL& opener_top_level_frame_url,
 | 
						|
    const url::Origin& source_origin,
 | 
						|
    content::mojom::WindowContainerType container_type,
 | 
						|
    const GURL& target_url,
 | 
						|
    const content::Referrer& referrer,
 | 
						|
    const std::string& frame_name,
 | 
						|
    WindowOpenDisposition disposition,
 | 
						|
    const blink::mojom::WindowFeatures& features,
 | 
						|
    bool user_gesture,
 | 
						|
    bool opener_suppressed,
 | 
						|
    bool* no_javascript_access) {
 | 
						|
  // The chrome layer has popup blocker, extensions, etc.
 | 
						|
  if (!ChromeContentBrowserClient::CanCreateWindow(
 | 
						|
          opener, opener_url, opener_top_level_frame_url, source_origin,
 | 
						|
          container_type, target_url, referrer, frame_name, disposition,
 | 
						|
          features, user_gesture, opener_suppressed, no_javascript_access)) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
 | 
						|
      opener, target_url, referrer, frame_name, disposition, features,
 | 
						|
      user_gesture, opener_suppressed, no_javascript_access);
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::OverrideWebkitPrefs(
 | 
						|
    content::WebContents* web_contents,
 | 
						|
    blink::web_pref::WebPreferences* prefs) {
 | 
						|
  renderer_prefs::SetDefaultPrefs(*prefs);
 | 
						|
 | 
						|
  ChromeContentBrowserClient::OverrideWebkitPrefs(web_contents, prefs);
 | 
						|
 | 
						|
  SkColor base_background_color;
 | 
						|
  auto browser = ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
 | 
						|
  if (browser) {
 | 
						|
    renderer_prefs::SetCefPrefs(browser->settings(), *prefs);
 | 
						|
 | 
						|
    // Set the background color for the WebView.
 | 
						|
    base_background_color = browser->GetBackgroundColor();
 | 
						|
  } else {
 | 
						|
    // We don't know for sure that the browser will be windowless but assume
 | 
						|
    // that the global windowless state is likely to be accurate.
 | 
						|
    base_background_color =
 | 
						|
        CefContext::Get()->GetBackgroundColor(nullptr, STATE_DEFAULT);
 | 
						|
  }
 | 
						|
 | 
						|
  web_contents->SetPageBaseBackgroundColor(base_background_color);
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeContentBrowserClientCef::WillCreateURLLoaderFactory(
 | 
						|
    content::BrowserContext* browser_context,
 | 
						|
    content::RenderFrameHost* frame,
 | 
						|
    int render_process_id,
 | 
						|
    URLLoaderFactoryType type,
 | 
						|
    const url::Origin& request_initiator,
 | 
						|
    absl::optional<int64_t> navigation_id,
 | 
						|
    ukm::SourceIdObj ukm_source_id,
 | 
						|
    mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
 | 
						|
    mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
 | 
						|
        header_client,
 | 
						|
    bool* bypass_redirect_checks,
 | 
						|
    bool* disable_secure_dns,
 | 
						|
    network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
 | 
						|
  bool use_proxy = ChromeContentBrowserClient::WillCreateURLLoaderFactory(
 | 
						|
      browser_context, frame, render_process_id, type, request_initiator,
 | 
						|
      navigation_id, ukm_source_id, factory_receiver, header_client,
 | 
						|
      bypass_redirect_checks, disable_secure_dns, factory_override);
 | 
						|
  if (use_proxy) {
 | 
						|
    // The chrome layer will handle the request.
 | 
						|
    return use_proxy;
 | 
						|
  }
 | 
						|
 | 
						|
  // Don't intercept requests for Profiles that were not created by CEF.
 | 
						|
  // For example, the User Manager profile created via
 | 
						|
  // profiles::CreateSystemProfileForUserManager.
 | 
						|
  auto profile = Profile::FromBrowserContext(browser_context);
 | 
						|
  if (!CefBrowserContext::FromProfile(profile))
 | 
						|
    return false;
 | 
						|
 | 
						|
  auto request_handler = net_service::CreateInterceptedRequestHandler(
 | 
						|
      browser_context, frame, render_process_id,
 | 
						|
      type == URLLoaderFactoryType::kNavigation,
 | 
						|
      type == URLLoaderFactoryType::kDownload, request_initiator);
 | 
						|
 | 
						|
  net_service::ProxyURLLoaderFactory::CreateProxy(
 | 
						|
      browser_context, factory_receiver, header_client,
 | 
						|
      std::move(request_handler));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeContentBrowserClientCef::HandleExternalProtocol(
 | 
						|
    const GURL& url,
 | 
						|
    content::WebContents::Getter web_contents_getter,
 | 
						|
    int child_id,
 | 
						|
    int frame_tree_node_id,
 | 
						|
    content::NavigationUIData* navigation_data,
 | 
						|
    bool is_main_frame,
 | 
						|
    ui::PageTransition page_transition,
 | 
						|
    bool has_user_gesture,
 | 
						|
    const absl::optional<url::Origin>& initiating_origin,
 | 
						|
    mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
 | 
						|
  // |out_factory| will be non-nullptr when this method is initially called
 | 
						|
  // from NavigationURLLoaderImpl::PrepareForNonInterceptedRequest.
 | 
						|
  if (out_factory) {
 | 
						|
    // Let the other HandleExternalProtocol variant handle the request.
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  // The request was unhandled and we've recieved a callback from
 | 
						|
  // HandleExternalProtocolHelper. Forward to the chrome layer for default
 | 
						|
  // handling.
 | 
						|
  return ChromeContentBrowserClient::HandleExternalProtocol(
 | 
						|
      url, web_contents_getter, child_id, frame_tree_node_id, navigation_data,
 | 
						|
      is_main_frame, page_transition, has_user_gesture, initiating_origin,
 | 
						|
      nullptr);
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeContentBrowserClientCef::HandleExternalProtocol(
 | 
						|
    content::WebContents::Getter web_contents_getter,
 | 
						|
    int frame_tree_node_id,
 | 
						|
    content::NavigationUIData* navigation_data,
 | 
						|
    const network::ResourceRequest& resource_request,
 | 
						|
    mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
 | 
						|
  mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
 | 
						|
      out_factory->InitWithNewPipeAndPassReceiver();
 | 
						|
 | 
						|
  // HandleExternalProtocolHelper may be called if nothing handles the request.
 | 
						|
  auto request_handler = net_service::CreateInterceptedRequestHandler(
 | 
						|
      web_contents_getter, frame_tree_node_id, resource_request,
 | 
						|
      base::BindRepeating(HandleExternalProtocolHelper, base::Unretained(this),
 | 
						|
                          web_contents_getter, frame_tree_node_id,
 | 
						|
                          navigation_data, resource_request));
 | 
						|
 | 
						|
  net_service::ProxyURLLoaderFactory::CreateProxy(
 | 
						|
      web_contents_getter, std::move(receiver), std::move(request_handler));
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
std::vector<std::unique_ptr<content::NavigationThrottle>>
 | 
						|
ChromeContentBrowserClientCef::CreateThrottlesForNavigation(
 | 
						|
    content::NavigationHandle* navigation_handle) {
 | 
						|
  auto throttles = ChromeContentBrowserClient::CreateThrottlesForNavigation(
 | 
						|
      navigation_handle);
 | 
						|
  throttle::CreateThrottlesForNavigation(navigation_handle, throttles);
 | 
						|
  return throttles;
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::ConfigureNetworkContextParams(
 | 
						|
    content::BrowserContext* context,
 | 
						|
    bool in_memory,
 | 
						|
    const base::FilePath& relative_partition_path,
 | 
						|
    network::mojom::NetworkContextParams* network_context_params,
 | 
						|
    cert_verifier::mojom::CertVerifierCreationParams*
 | 
						|
        cert_verifier_creation_params) {
 | 
						|
  ChromeContentBrowserClient::ConfigureNetworkContextParams(
 | 
						|
      context, in_memory, relative_partition_path, network_context_params,
 | 
						|
      cert_verifier_creation_params);
 | 
						|
 | 
						|
  auto cef_context = CefBrowserContext::FromBrowserContext(context);
 | 
						|
  network_context_params->cookieable_schemes =
 | 
						|
      cef_context ? cef_context->GetCookieableSchemes()
 | 
						|
                  : CefBrowserContext::GetGlobalCookieableSchemes();
 | 
						|
 | 
						|
  // Prefer the CEF settings configuration, if specified, instead of the
 | 
						|
  // kAcceptLanguages preference which is controlled by the
 | 
						|
  // chrome://settings/languages configuration.
 | 
						|
  const std::string& accept_language_list =
 | 
						|
      browser_prefs::GetAcceptLanguageList(cef_context, /*browser=*/nullptr,
 | 
						|
                                           /*expand=*/true);
 | 
						|
  if (!accept_language_list.empty() &&
 | 
						|
      accept_language_list != network_context_params->accept_language) {
 | 
						|
    network_context_params->accept_language = accept_language_list;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
std::unique_ptr<content::LoginDelegate>
 | 
						|
ChromeContentBrowserClientCef::CreateLoginDelegate(
 | 
						|
    const net::AuthChallengeInfo& auth_info,
 | 
						|
    content::WebContents* web_contents,
 | 
						|
    const content::GlobalRequestID& request_id,
 | 
						|
    bool is_request_for_main_frame,
 | 
						|
    const GURL& url,
 | 
						|
    scoped_refptr<net::HttpResponseHeaders> response_headers,
 | 
						|
    bool first_auth_attempt,
 | 
						|
    LoginAuthRequiredCallback auth_required_callback) {
 | 
						|
  // |web_contents| is nullptr for CefURLRequests without an associated frame.
 | 
						|
  if (!web_contents || base::CommandLine::ForCurrentProcess()->HasSwitch(
 | 
						|
                           switches::kDisableChromeLoginPrompt)) {
 | 
						|
    // Delegate auth callbacks to GetAuthCredentials.
 | 
						|
    return std::make_unique<net_service::LoginDelegate>(
 | 
						|
        auth_info, web_contents, request_id, url,
 | 
						|
        std::move(auth_required_callback));
 | 
						|
  }
 | 
						|
 | 
						|
  return ChromeContentBrowserClient::CreateLoginDelegate(
 | 
						|
      auth_info, web_contents, request_id, is_request_for_main_frame, url,
 | 
						|
      response_headers, first_auth_attempt, std::move(auth_required_callback));
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::BrowserURLHandlerCreated(
 | 
						|
    content::BrowserURLHandler* handler) {
 | 
						|
  // Register the Chrome handlers first for proper URL rewriting.
 | 
						|
  ChromeContentBrowserClient::BrowserURLHandlerCreated(handler);
 | 
						|
  scheme::BrowserURLHandlerCreated(handler);
 | 
						|
}
 | 
						|
 | 
						|
bool ChromeContentBrowserClientCef::IsWebUIAllowedToMakeNetworkRequests(
 | 
						|
    const url::Origin& origin) {
 | 
						|
  return scheme::IsWebUIAllowedToMakeNetworkRequests(origin);
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::ExposeInterfacesToRenderer(
 | 
						|
    service_manager::BinderRegistry* registry,
 | 
						|
    blink::AssociatedInterfaceRegistry* associated_registry,
 | 
						|
    content::RenderProcessHost* host) {
 | 
						|
  ChromeContentBrowserClient::ExposeInterfacesToRenderer(
 | 
						|
      registry, associated_registry, host);
 | 
						|
 | 
						|
  CefBrowserManager::ExposeInterfacesToRenderer(registry, associated_registry,
 | 
						|
                                                host);
 | 
						|
}
 | 
						|
 | 
						|
void ChromeContentBrowserClientCef::RegisterBrowserInterfaceBindersForFrame(
 | 
						|
    content::RenderFrameHost* render_frame_host,
 | 
						|
    mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
 | 
						|
  ChromeContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
 | 
						|
      render_frame_host, map);
 | 
						|
 | 
						|
  CefBrowserFrame::RegisterBrowserInterfaceBindersForFrame(render_frame_host,
 | 
						|
                                                           map);
 | 
						|
}
 | 
						|
 | 
						|
CefRefPtr<CefRequestContextImpl>
 | 
						|
ChromeContentBrowserClientCef::request_context() const {
 | 
						|
  return browser_main_parts_->request_context();
 | 
						|
}
 | 
						|
 | 
						|
scoped_refptr<base::SingleThreadTaskRunner>
 | 
						|
ChromeContentBrowserClientCef::background_task_runner() const {
 | 
						|
  return browser_main_parts_->background_task_runner();
 | 
						|
}
 | 
						|
 | 
						|
scoped_refptr<base::SingleThreadTaskRunner>
 | 
						|
ChromeContentBrowserClientCef::user_visible_task_runner() const {
 | 
						|
  return browser_main_parts_->user_visible_task_runner();
 | 
						|
}
 | 
						|
 | 
						|
scoped_refptr<base::SingleThreadTaskRunner>
 | 
						|
ChromeContentBrowserClientCef::user_blocking_task_runner() const {
 | 
						|
  return browser_main_parts_->user_blocking_task_runner();
 | 
						|
}
 |