Compare commits

...

29 Commits
7204 ... 6998

Author SHA1 Message Date
Marshall Greenblatt
3b5a9dfb50 Pin depot_tools version for out-of-support branch 2025-04-07 17:08:03 -04:00
Marshall Greenblatt
7c94248e45 linux: Fix stack-related sub-process shutdown crashes (fixes #3912)
On Linux systems the stack frame reference canary will be purposely
changed when forking sub-processes (see https://crbug.com/40181003).
To avoid sub-process shutdown crashes the NO_STACK_PROTECTOR
annotation must be added to all functions in the call stack leading to
CefExecuteProcess(). Applications that cannot add this annotation must
instead pass the `--change-stack-guard-on-fork=disable` command-line
flag.
2025-03-31 14:16:08 -04:00
Marshall Greenblatt
344f01c1a8 Fix crash on invalid chromeMediaSourceId (fixes #3911) 2025-03-31 12:20:42 -04:00
Marshall Greenblatt
5dc6f2f29c Update to Chromium version 134.0.6998.178 2025-03-26 13:39:24 +00:00
Marshall Greenblatt
fe66d80346 Update to Chromium version 134.0.6998.166 2025-03-24 17:53:26 +00:00
Marshall Greenblatt
37e6a4002e mac: Fix compile error
Caused by https://crrev.com/0a4a424cc4
2025-03-21 13:41:35 -04:00
Marshall Greenblatt
96006d1193 Update to Chromium version 134.0.6998.118 2025-03-20 14:34:20 +00:00
Marshall Greenblatt
36934ebbc5 distrib: Include CREDITS.html with third-party licenses
This is the same content currently available via about:credits.
2025-03-19 14:04:26 -04:00
Michael Bragg
84beb5a7e1 alloy: win: Add spelling suggestions in context menu (fixes #3055) 2025-03-18 12:20:03 -04:00
David Cernoch
d1c786e7fe Make PrintToPDF path parameter optional (fixes #3879) 2025-03-18 12:19:57 -04:00
Marshall Greenblatt
615db2f583 tests: Destroy |scheme_factory_| on IO thread
This avoids a thread race between ShutdownSchemeHandler and
GetResourceHandler when running `CookieTest.AccessResource*` tests.
2025-03-13 12:28:14 -04:00
Marshall Greenblatt
4de18f0d4b Update to Chromium version 134.0.6998.89 2025-03-11 14:47:25 +00:00
Marshall Greenblatt
2830d3a706 Tag 13401 API version 2025-03-10 12:12:58 -04:00
Marshall Greenblatt
8e5da68011 Add visualization for Chrome configuration changes (fixes #3892)
- Add new API to retrieve/observe configuration values.
- cefclient: Add https://tests/config to inspect configuration
  values in real time.
2025-03-10 12:12:50 -04:00
Marshall Greenblatt
9eac4fa487 Fix Chrome toolbar initialization (fixes #3898)
Change BrowserWindowFeatures initialization to consider CEF browsers
with TYPE_POPUP as normal.
2025-03-07 15:02:00 -05:00
Marshall Greenblatt
059f2446c0 tools: Fix assert when all file contents are excluded (see #3836)
The full contents of a file may be excluded at certain API versions.
2025-03-07 12:20:57 -05:00
Jacobo Aragunde Pérez
f3023f8ca0 tools: Add non-zero exit code for single patch failure (fixes #3903) 2025-03-07 12:20:49 -05:00
Marshall Greenblatt
8311b6cfba tools: Fix get_all_versions for newly added class (see #3836) 2025-02-28 18:31:05 -05:00
Marshall Greenblatt
a5cda9c3dc tools: Also check for CEF_NEXT in .cc files (see #3836) 2025-02-28 18:27:28 -05:00
Marshall Greenblatt
b36991c674 tools: Use short copyright for capi_versions.h headers (see #3836)
These files are not distributed and therefore don't require the
full copyright header.
2025-02-28 18:27:18 -05:00
Marshall Greenblatt
74f62fd38c cefclient: Add global option to https://tests/preferences (see #3892) 2025-02-28 18:27:10 -05:00
Marshall Greenblatt
071f544b5a Update to Chromium version 134.0.6998.44 2025-02-28 16:12:46 +00:00
Marshall Greenblatt
2cb5ebb3db Update to Chromium version 134.0.6998.35 2025-02-27 14:37:29 +00:00
Nik Pavlov
3463fdd061 Support API versioning in platform-specific headers (see #3836)
- Exclude platform-specific includes (anything in < >) from the
  clang preprocessor by using `!defined(GENERATING_CEF_API_HASH)`
  in CEF header files.
- Define "target platforms" by passing platform- and architecture-
  specific ifdefs to the clang preprocessor. Grep for `defined(OS_`
  to identify headers that require target platform processing, and
  then process for each target as the platform-specific API hash
  contribution.
- Delete the univeral hash which is no longer a useful concept.
2025-02-25 12:39:33 -05:00
Marshall Greenblatt
b3fe8ad6d7 Update to Chromium version 134.0.6998.23 2025-02-20 14:29:57 +00:00
Marshall Greenblatt
0bebcc9e97 cmake: win: Set LPAC ACLs required for sandbox support (fixes #3791) 2025-02-19 13:39:45 -05:00
Marshall Greenblatt
9eb3683b09 Tag 13400 API version 2025-02-19 12:13:19 -05:00
Marshall Greenblatt
0c9655dfb7 tools: win: Fix grep usage with system Git (see #3836) 2025-02-19 12:13:06 -05:00
Marshall Greenblatt
7b50b32953 Update to Chromium version 134.0.6998.15 2025-02-19 11:12:35 -05:00
98 changed files with 3186 additions and 727 deletions

View File

@@ -677,6 +677,8 @@ source_set("libcef_static") {
"libcef/browser/scheme_impl.cc",
"libcef/browser/server_impl.cc",
"libcef/browser/server_impl.h",
"libcef/browser/setting_helper.cc",
"libcef/browser/setting_helper.h",
"libcef/browser/simple_menu_model_impl.cc",
"libcef/browser/simple_menu_model_impl.h",
"libcef/browser/ssl_info_impl.cc",

View File

@@ -7,5 +7,6 @@
# https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding
{
'chromium_checkout': 'refs/tags/134.0.6998.0'
'chromium_checkout': 'refs/tags/134.0.6998.178',
'depot_tools_checkout': 'f35efa5b85'
}

View File

@@ -1,41 +1,48 @@
{
"hashes": {
"13300": {
"comment": "Added February 17, 2025.",
"linux": "87d31692cf1ff1f0f2445dd026dcc0aeb02c5786",
"mac": "3891d2358697f15e046afc65fefd7019d888817a",
"universal": "c1a7d47be6fc130795366a1627573aa8eba1106f",
"windows": "0efb201c9e981c4513aeea04f9f2f8041ee9ce1f"
"comment": "Added February 21, 2025.",
"linux": "2508f3f0b0e5dfa191036fa6c04f8dcfa18c94b9",
"mac": "80c0b59ba9dd783aa71fae0aa5f7dad64620e8c9",
"windows": "45d39c3669ba75467e3e609f626c31506c0eae22"
},
"13301": {
"comment": "Added February 17, 2025.",
"linux": "747f624e5059839e6a7d385de7997d45bbd42184",
"mac": "d3ec7d79adbde067590ab1bfff1f30dd8b06546a",
"universal": "892e654249acc7360f8aca4ee77da896753b87b8",
"windows": "cf9fbb7aa6778fedce78b8557044f219f2b5ba0b"
"comment": "Added February 21, 2025.",
"linux": "aa073dd1c586812503ca293c718358460d8c2dd6",
"mac": "fda40a5df44628cac50a589ff979c0746011591e",
"windows": "7109702038d51512d35dd2ed77231f9100e38214"
},
"13302": {
"comment": "Added February 17, 2025.",
"linux": "ae4ab1c52ad951d37e6397db9f4e0ab0ce5044cf",
"mac": "cfe09351db37aa275613c27145fe622d9c28d4cc",
"universal": "acab8df1244923f1f80b18214e73c276a553ded6",
"windows": "c4b5a65478bc1a679f4a47ba5ff6899e5c3d8761"
"comment": "Added February 21, 2025.",
"linux": "d5597ebfa30081953425e897209a8387b9584205",
"mac": "4aa24470ba3a4bd9c06bc0e4a201b896394a86b5",
"windows": "18799961f4461a9cbae2aed89ac04b73ab7c37f3"
},
"13303": {
"comment": "Added February 17, 2025.",
"linux": "2683698b779f11bba19f4051e3760fe327a1c8b2",
"mac": "8085a0f62f15946343c63788300e5c2b422b3301",
"universal": "128210b71e3f621cb6d2c4b05c6d0408a4547f2f",
"windows": "5a22d42c3e6294eb4ee2424053eebdeae3027899"
"comment": "Added February 21, 2025.",
"linux": "f3a696ee30ce1e00490a58df017393c126c89709",
"mac": "f2cdce2b9a4b635c28b5b92c42c35625a937380c",
"windows": "20016fd6a9b87ef4c539cd1f42bf1ca09b6903ca"
},
"13304": {
"comment": "Added February 17, 2025.",
"linux": "c709233cd071e0d715eb10ceec4c5aea805df997",
"mac": "32af7e8f8828b04cf2908de9857940faa54deb8a",
"universal": "131b720865dd5c54c72041c0fbfb7c9bbfee8e0b",
"windows": "979b48138012378192dac7ee972fa731e9c0dae9"
"comment": "Added February 21, 2025.",
"linux": "f1ababb4ff51ecbf77c481cee3721ef0eca9c8ca",
"mac": "98964c37b8917d83da4b173e22905503d38ad08f",
"windows": "19c014af0082aa901398e006381b6980e4f806e9"
},
"13400": {
"comment": "Added February 21, 2025.",
"linux": "ea2106b5bc012c25d735521e0c7fb719d433ea4a",
"mac": "ba5ab71db4f9447f19eb7b1943024981c88064dd",
"windows": "6ab74b90e88b7397aab9911baac5484f12466eef"
},
"13401": {
"comment": "Added March 10, 2025.",
"linux": "b14bee2c0fd250da67faea421f620b58e5dea9a2",
"mac": "b54732b528bc2669481ec0cf17c7b97b033720b9",
"windows": "751255204f006b8b883a8baf552a2da792f8aa44"
}
},
"last": "13304",
"last": "13401",
"min": "13300"
}

View File

@@ -247,6 +247,8 @@
'tests/cefclient/browser/client_prefs.cc',
'tests/cefclient/browser/client_prefs.h',
'tests/cefclient/browser/client_types.h',
'tests/cefclient/browser/config_test.cc',
'tests/cefclient/browser/config_test.h',
'tests/cefclient/browser/default_client_handler.cc',
'tests/cefclient/browser/default_client_handler.h',
'tests/cefclient/browser/dialog_test.cc',
@@ -324,6 +326,7 @@
'cefclient_sources_resources': [
'tests/cefclient/resources/binary_transfer.html',
'tests/cefclient/resources/binding.html',
'tests/cefclient/resources/config.html',
'tests/cefclient/resources/dialogs.html',
'tests/cefclient/resources/draggable.html',
'tests/cefclient/resources/hang.html',

View File

@@ -271,6 +271,17 @@ macro(ADD_WINDOWS_MANIFEST manifest_path target extension)
)
endmacro()
# Set LPAC ACLs required for Windows sandbox support.
# See https://github.com/chromiumembedded/cef/issues/3791#issuecomment-2664128961
macro(SET_LPAC_ACLS target)
add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND "icacls" "${CEF_TARGET_OUT_DIR}" "/grant" "*S-1-15-2-2:(OI)(CI)(RX)"
COMMENT "Setting LPAC ACLs..."
)
endmacro()
endif(OS_WINDOWS)

View File

@@ -313,6 +313,30 @@
#define STACK_UNINITIALIZED
#endif
// Attribute "no_stack_protector" disables -fstack-protector for the specified
// function.
//
// "stack_protector" is enabled on most POSIX builds. The flag adds a canary
// to each stack frame, which on function return is checked against a reference
// canary. If the canaries do not match, it's likely that a stack buffer
// overflow has occurred, so immediately crashing will prevent exploitation in
// many cases.
//
// In some cases it's desirable to remove this, e.g. on hot functions, or if
// we have purposely changed the reference canary.
//
// On Linux systems the reference canary will be purposely changed when forking
// sub-processes (see https://crbug.com/40181003). To avoid sub-process shutdown
// crashes the NO_STACK_PROTECTOR annotation must be added to all functions in
// the call stack leading to CefExecuteProcess(). Applications that cannot add
// this annotation must instead pass the `--change-stack-guard-on-fork=disable`
// command-line flag.
#if defined(COMPILER_GCC) || defined(__clang__)
#define NO_STACK_PROTECTOR __attribute__((no_stack_protector))
#else
#define NO_STACK_PROTECTOR
#endif
// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
// to Clang which control what code paths are statically analyzed,
// and is meant to be used in conjunction with assert & assert-like functions.

View File

@@ -77,19 +77,15 @@
#endif
#endif
#define _CEF_AH_PASTE(a, b, c) a##_##b##_##c
#define _CEF_AH_EVAL(a, b, c) _CEF_AH_PASTE(a, b, c)
#define _CEF_AH_DECLARE(version, suffix) \
_CEF_AH_EVAL(CEF_API_HASH, version, suffix)
#define _CEF_AH_PASTE(a, b) a##_##b
#define _CEF_AH_EVAL(a, b) _CEF_AH_PASTE(a, b)
#define _CEF_AH_DECLARE(version) _CEF_AH_EVAL(CEF_API_HASH, version)
// API hashes for the selected CEF_API_VERSION. API hashes are created for
// each version by analyzing CEF header files for C API type definitions. The
// hash value will change when header files are modified in a way that may
// cause binary incompatibility with other builds. The universal hash value
// will change if any platform is affected whereas the platform hash values
// will change only if that particular platform is affected.
#define CEF_API_HASH_UNIVERSAL _CEF_AH_DECLARE(CEF_API_VERSION, UNIVERSAL)
#define CEF_API_HASH_PLATFORM _CEF_AH_DECLARE(CEF_API_VERSION, PLATFORM)
// cause binary incompatibility with other builds.
#define CEF_API_HASH_PLATFORM _CEF_AH_DECLARE(CEF_API_VERSION)
#if defined(BUILDING_CEF_SHARED)
@@ -132,7 +128,7 @@ extern "C" {
/// parameter describes which hash value will be returned:
///
/// 0 - CEF_API_HASH_PLATFORM
/// 1 - CEF_API_HASH_UNIVERSAL
/// 1 - CEF_API_HASH_UNIVERSAL (deprecated, same as CEF_API_HASH_PLATFORM)
/// 2 - CEF_COMMIT_HASH (from cef_version.h)
///
CEF_EXPORT const char* cef_api_hash(int version, int entry);

View File

@@ -59,7 +59,7 @@ class CefApp;
/// |windows_sandbox_info| parameter is only used on Windows and may be NULL
/// (see cef_sandbox_win.h for details).
///
/*--cef(api_hash_check,optional_param=application,
/*--cef(api_hash_check,no_stack_protector,optional_param=application,
optional_param=windows_sandbox_info)--*/
int CefExecuteProcess(const CefMainArgs& args,
CefRefPtr<CefApp> application,

View File

@@ -31,8 +31,11 @@
#define CEF_INCLUDE_CEF_BASE_H_
#pragma once
#include "include/base/cef_atomic_ref_count.h"
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#include "include/base/cef_atomic_ref_count.h"
#include "include/base/cef_macros.h"
// Bring in common C++ type definitions used by CEF consumers.

View File

@@ -249,7 +249,7 @@ class CefPdfPrintCallback : public virtual CefBaseRefCounted {
/// is the output path. |ok| will be true if the printing completed
/// successfully or false otherwise.
///
/*--cef()--*/
/*--cef(optional_param=path)--*/
virtual void OnPdfPrintFinished(const CefString& path, bool ok) = 0;
};

View File

@@ -41,6 +41,7 @@
#include <vector>
#include "include/cef_base.h"
#include "include/cef_registration.h"
#include "include/cef_values.h"
///
@@ -65,6 +66,24 @@ class CefPreferenceRegistrar : public CefBaseScoped {
CefRefPtr<CefValue> default_value) = 0;
};
#if CEF_API_ADDED(13401)
///
/// Implemented by the client to observe preference changes and registered via
/// CefPreferenceManager::AddPreferenceObserver. The methods of this class will
/// be called on the browser process UI thread.
///
/*--cef(source=client,added=13401)--*/
class CefPreferenceObserver : public virtual CefBaseRefCounted {
public:
///
/// Called when a preference has changed. The new value can be retrieved using
/// CefPreferenceManager::GetPreference.
///
/*--cef()--*/
virtual void OnPreferenceChanged(const CefString& name) = 0;
};
#endif
///
/// Manage access to preferences. Many built-in preferences are registered by
/// Chromium. Custom preferences can be registered in
@@ -73,6 +92,36 @@ class CefPreferenceRegistrar : public CefBaseScoped {
/*--cef(source=library,no_debugct_check)--*/
class CefPreferenceManager : public virtual CefBaseRefCounted {
public:
#if CEF_API_ADDED(13401)
///
/// Returns the current Chrome Variations configuration (combination of field
/// trials and chrome://flags) as equivalent command-line switches
/// (`--[enable|disable]-features=XXXX`, etc). These switches can be used to
/// apply the same configuration when launching a CEF-based application. See
/// https://developer.chrome.com/docs/web-platform/chrome-variations for
/// background and details. Note that field trial tests are disabled by
/// default in Official CEF builds (via the
/// `disable_fieldtrial_testing_config=true` GN flag). This method must be
/// called on the browser process UI thread.
///
/*--cef(added=13401)--*/
static void GetChromeVariationsAsSwitches(std::vector<CefString>& switches);
///
/// Returns the current Chrome Variations configuration (combination of field
/// trials and chrome://flags) as human-readable strings. This is the
/// human-readable equivalent of the "Active Variations" section of
/// chrome://version. See
/// https://developer.chrome.com/docs/web-platform/chrome-variations for
/// background and details. Note that field trial tests are disabled by
/// default in Official CEF builds (via the
/// `disable_fieldtrial_testing_config=true` GN flag). This method must be
/// called on the browser process UI thread.
///
/*--cef(added=13401)--*/
static void GetChromeVariationsAsStrings(std::vector<CefString>& strings);
#endif
///
/// Returns the global preference manager object.
///
@@ -129,6 +178,21 @@ class CefPreferenceManager : public virtual CefBaseRefCounted {
virtual bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) = 0;
#if CEF_API_ADDED(13401)
///
/// Add an observer for preference changes. |name| is the name of the
/// preference to observe. If |name| is empty then all preferences will
/// be observed. Observing all preferences has performance consequences and
/// is not recommended outside of testing scenarios. The observer will remain
/// registered until the returned Registration object is destroyed. This
/// method must be called on the browser process UI thread.
///
/*--cef(optional_param=name,added=13401)--*/
virtual CefRefPtr<CefRegistration> AddPreferenceObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer) = 0;
#endif
};
#endif // CEF_INCLUDE_CEF_PREFERENCE_H_

View File

@@ -44,6 +44,7 @@
#include "include/cef_cookie.h"
#include "include/cef_media_router.h"
#include "include/cef_preference.h"
#include "include/cef_registration.h"
#include "include/cef_values.h"
class CefRequestContextHandler;
@@ -66,6 +67,27 @@ class CefResolveCallback : public virtual CefBaseRefCounted {
const std::vector<CefString>& resolved_ips) = 0;
};
#if CEF_API_ADDED(13401)
///
/// Implemented by the client to observe content and website setting changes and
/// registered via CefRequestContext::AddSettingObserver. The methods of this
/// class will be called on the browser process UI thread.
///
/*--cef(source=client,added=13401)--*/
class CefSettingObserver : public virtual CefBaseRefCounted {
public:
///
/// Called when a content or website setting has changed. The new value can be
/// retrieved using CefRequestContext::GetContentSetting or
/// CefRequestContext::GetWebsiteSetting.
///
/*--cef(optional_param=requesting_url,optional_param=top_level_url)--*/
virtual void OnSettingChanged(const CefString& requesting_url,
const CefString& top_level_url,
cef_content_setting_types_t content_type) = 0;
};
#endif
///
/// A request context provides request handling for a set of related browser
/// or URL request objects. A request context can be specified when creating a
@@ -292,6 +314,17 @@ class CefRequestContext : public CefPreferenceManager {
cef_content_setting_types_t content_type,
cef_content_setting_values_t value) = 0;
#if CEF_API_ADDED(13401)
///
/// Add an observer for content and website setting changes. The observer will
/// remain registered until the returned Registration object is destroyed.
/// This method must be called on the browser process UI thread.
///
/*--cef(added=13401)--*/
virtual CefRefPtr<CefRegistration> AddSettingObserver(
CefRefPtr<CefSettingObserver> observer) = 0;
#endif
///
/// Sets the Chrome color scheme for all browsers that share this request
/// context. |variant| values of SYSTEM, LIGHT and DARK change the underlying

View File

@@ -31,7 +31,10 @@
#define CEF_INCLUDE_CEF_SANDBOX_MAC_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#include "include/internal/cef_export.h"
#if defined(OS_MAC)

View File

@@ -31,7 +31,9 @@
#define CEF_INCLUDE_CEF_SANDBOX_WIN_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_WIN)

View File

@@ -31,7 +31,9 @@
#define CEF_INCLUDE_INTERNAL_CEF_APP_WIN_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_WIN)

View File

@@ -32,7 +32,9 @@
#define CEF_INCLUDE_INTERNAL_CEF_EXPORT_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(COMPILER_MSVC)

View File

@@ -31,12 +31,14 @@
#define CEF_INCLUDE_INTERNAL_CEF_THREAD_INTERNAL_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_POSIX)
#include <pthread.h>
#include <unistd.h>
#endif
#endif
#include "include/internal/cef_export.h"

View File

@@ -35,8 +35,11 @@
extern "C" {
#endif
#include <stdint.h>
#if !defined(GENERATING_CEF_API_HASH)
#include <time.h>
#endif
#include <stdint.h>
#include "include/internal/cef_export.h"

View File

@@ -3622,7 +3622,7 @@ typedef enum {
#if CEF_API_ADDED(13304)
CEF_CPAIT_COLLABORATION_MESSAGING,
#endif
#if CEF_API_ADDED(CEF_NEXT)
#if CEF_API_ADDED(13400)
CEF_CPAIT_CHANGE_PASSWORD,
#endif
CEF_CPAIT_NUM_VALUES,

View File

@@ -486,7 +486,7 @@ typedef enum {
/// or legacy behavior.
CEF_CONTENT_SETTING_TYPE_LEGACY_COOKIE_SCOPE,
#if CEF_API_ADDED(CEF_NEXT)
#if CEF_API_ADDED(13400)
/// Website setting to indicate whether the user has allowlisted suspicious
/// notifications for the origin.
CEF_CONTENT_SETTING_TYPE_ARE_SUSPICIOUS_NOTIFICATIONS_ALLOWLISTED_BY_USER,

View File

@@ -31,15 +31,12 @@
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_LINUX)
#if defined(CEF_X11)
typedef union _XEvent XEvent;
typedef struct _XDisplay XDisplay;
#endif
#include "include/internal/cef_export.h"
#include "include/internal/cef_string.h"
#include "include/internal/cef_types_color.h"
@@ -47,17 +44,6 @@ typedef struct _XDisplay XDisplay;
#include "include/internal/cef_types_osr.h"
#include "include/internal/cef_types_runtime.h"
// Handle types.
#if defined(CEF_X11)
#define cef_cursor_handle_t unsigned long
#define cef_event_handle_t XEvent*
#else
#define cef_cursor_handle_t void*
#define cef_event_handle_t void*
#endif
#define cef_window_handle_t unsigned long
#define kNullCursorHandle 0
#define kNullEventHandle NULL
#define kNullWindowHandle 0
@@ -66,6 +52,20 @@ typedef struct _XDisplay XDisplay;
extern "C" {
#endif
#if defined(CEF_X11)
typedef union _XEvent XEvent;
typedef struct _XDisplay XDisplay;
// Handle types.
typedef unsigned long cef_cursor_handle_t;
typedef XEvent* cef_event_handle_t;
#else
typedef void* cef_cursor_handle_t;
typedef void* cef_event_handle_t;
#endif
typedef unsigned long cef_window_handle_t;
///
/// Return the singleton X11 display shared with Chromium. The display is not
/// thread-safe and must only be accessed on the browser process UI thread.

View File

@@ -31,7 +31,9 @@
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_MAC)
#include "include/internal/cef_string.h"
@@ -40,16 +42,6 @@
#include "include/internal/cef_types_osr.h"
#include "include/internal/cef_types_runtime.h"
// Handle types.
// Actually NSCursor*
#define cef_cursor_handle_t void*
// Acutally NSEvent*
#define cef_event_handle_t void*
// Actually NSView*
#define cef_window_handle_t void*
// Actually IOSurface*
#define cef_shared_texture_handle_t void*
#define kNullCursorHandle NULL
#define kNullEventHandle NULL
#define kNullWindowHandle NULL
@@ -78,6 +70,16 @@
extern "C" {
#endif
// Handle types.
// Actually NSCursor*
typedef void* cef_cursor_handle_t;
// Actually NSEvent*
typedef void* cef_event_handle_t;
// Actually NSView*
typedef void* cef_window_handle_t;
// Actually IOSurface*
typedef void* cef_shared_texture_handle_t;
///
/// Structure representing CefExecuteProcess arguments.
///

View File

@@ -31,10 +31,15 @@
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_WIN)
#if !defined(GENERATING_CEF_API_HASH)
#include <windows.h>
#endif
#include "include/internal/cef_string.h"
#include "include/internal/cef_types_color.h"
@@ -42,12 +47,6 @@
#include "include/internal/cef_types_osr.h"
#include "include/internal/cef_types_runtime.h"
// Handle types.
#define cef_cursor_handle_t HCURSOR
#define cef_event_handle_t MSG*
#define cef_window_handle_t HWND
#define cef_shared_texture_handle_t HANDLE
#define kNullCursorHandle NULL
#define kNullEventHandle NULL
#define kNullWindowHandle NULL
@@ -56,6 +55,12 @@
extern "C" {
#endif
// Handle types.
typedef HCURSOR cef_cursor_handle_t;
typedef MSG* cef_event_handle_t;
typedef HWND cef_window_handle_t;
typedef HANDLE cef_shared_texture_handle_t;
///
/// Structure representing CefExecuteProcess arguments.
///

View File

@@ -12,10 +12,12 @@
#include "base/task/current_thread.h"
#include "base/threading/thread_restrictions.h"
#include "cef/libcef/browser/browser_info_manager.h"
#include "cef/libcef/browser/prefs/pref_helper.h"
#include "cef/libcef/browser/request_context_impl.h"
#include "cef/libcef/browser/thread_util.h"
#include "cef/libcef/browser/trace_subscriber.h"
#include "cef/libcef/common/cef_switches.h"
#include "chrome/browser/browser_process_impl.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "ui/base/ui_base_switches.h"
@@ -289,6 +291,7 @@ int RunMainWithPreferredStackSize(FiberState& fiber_state) {
} // namespace
NO_STACK_PROTECTOR
int CefExecuteProcess(const CefMainArgs& args,
CefRefPtr<CefApp> application,
void* windows_sandbox_info) {
@@ -570,12 +573,24 @@ CefTraceSubscriber* CefContext::GetTraceSubscriber() {
if (shutting_down_) {
return nullptr;
}
if (!trace_subscriber_.get()) {
if (!trace_subscriber_) {
trace_subscriber_ = std::make_unique<CefTraceSubscriber>();
}
return trace_subscriber_.get();
}
pref_helper::Registrar* CefContext::GetPrefRegistrar() {
CEF_REQUIRE_UIT();
if (shutting_down_) {
return nullptr;
}
if (!pref_registrar_) {
pref_registrar_ = std::make_unique<pref_helper::Registrar>();
pref_registrar_->Init(g_browser_process->local_state());
}
return pref_registrar_.get();
}
void CefContext::PopulateGlobalRequestContextSettings(
CefRequestContextSettings* settings) {
CefRefPtr<CefCommandLine> command_line =
@@ -645,12 +660,15 @@ void CefContext::ShutdownOnUIThread() {
observer.OnContextDestroyed();
}
if (trace_subscriber_.get()) {
trace_subscriber_.reset(nullptr);
if (trace_subscriber_) {
trace_subscriber_.reset();
}
if (pref_registrar_) {
pref_registrar_.reset();
}
}
void CefContext::FinalizeShutdown() {
browser_info_manager_.reset(nullptr);
browser_info_manager_.reset();
application_ = nullptr;
}

View File

@@ -16,6 +16,10 @@
#include "cef/libcef/browser/main_runner.h"
#include "third_party/skia/include/core/SkColor.h"
namespace pref_helper {
class Registrar;
}
class CefBrowserInfoManager;
class CefTraceSubscriber;
@@ -73,6 +77,7 @@ class CefContext {
cef_state_t windowless_state) const;
CefTraceSubscriber* GetTraceSubscriber();
pref_helper::Registrar* GetPrefRegistrar();
// Populate request context settings for the global system context based on
// CefSettings and command-line flags.
@@ -112,6 +117,7 @@ class CefContext {
std::unique_ptr<CefMainRunner> main_runner_;
std::unique_ptr<CefTraceSubscriber> trace_subscriber_;
std::unique_ptr<pref_helper::Registrar> pref_registrar_;
std::unique_ptr<CefBrowserInfoManager> browser_info_manager_;
// Observers that want to be notified of changes to this object.

View File

@@ -4,10 +4,28 @@
#include "cef/libcef/browser/global_preference_manager_impl.h"
#include "base/metrics/field_trial_list_including_low_anonymity.h"
#include "base/strings/string_util.h"
#include "cef/libcef/browser/context.h"
#include "cef/libcef/browser/prefs/pref_helper.h"
#include "cef/libcef/browser/thread_util.h"
#include "cef/libcef/common/api_version_util.h"
#include "chrome/browser/about_flags.h"
#include "chrome/browser/browser_process.h"
#include "components/flags_ui/pref_service_flags_storage.h"
#include "components/variations/synthetic_trials_active_group_id_provider.h"
namespace {
std::string GetActiveGroupNameAsString(
const base::FieldTrial::ActiveGroup& group) {
constexpr std::string_view kNonBreakingHyphenUTF8 = "\xE2\x80\x91";
std::string result = group.trial_name + ":" + group.group_name;
base::ReplaceChars(result, "-", kNonBreakingHyphenUTF8, &result);
return result;
}
} // namespace
bool CefGlobalPreferenceManagerImpl::HasPreference(const CefString& name) {
CEF_REQUIRE_UIT_RETURN(false);
@@ -40,6 +58,77 @@ bool CefGlobalPreferenceManagerImpl::SetPreference(const CefString& name,
value, error);
}
CefRefPtr<CefRegistration>
CefGlobalPreferenceManagerImpl::AddPreferenceObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer) {
CEF_API_REQUIRE_ADDED(13401);
CEF_REQUIRE_UIT_RETURN(nullptr);
return CefContext::Get()->GetPrefRegistrar()->AddObserver(name, observer);
}
// static
void CefPreferenceManager::GetChromeVariationsAsSwitches(
std::vector<CefString>& switches) {
CEF_API_REQUIRE_ADDED(13401);
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
DCHECK(false) << "context not valid";
return;
}
switches.clear();
// Based on ChromeFeatureListCreator::ConvertFlagsToSwitches().
flags_ui::PrefServiceFlagsStorage flags_storage(
g_browser_process->local_state());
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
about_flags::ConvertFlagsToSwitches(&flags_storage, &command_line,
flags_ui::kNoSentinels);
for (const auto& arg : command_line.argv()) {
if (!arg.empty()) {
switches.push_back(arg);
}
}
}
// static
void CefPreferenceManager::GetChromeVariationsAsStrings(
std::vector<CefString>& strings) {
CEF_API_REQUIRE_ADDED(13401);
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
DCHECK(false) << "context not valid";
return;
}
strings.clear();
// Based on components/webui/version/version_handler_helper.cc
// GetVariationsList().
base::FieldTrial::ActiveGroups active_groups;
// Include low anonymity trial groups in the version string, as it is only
// displayed locally (and is useful for diagnostics purposes).
base::FieldTrialListIncludingLowAnonymity::
GetActiveFieldTrialGroupsForTesting(&active_groups);
for (const auto& group : active_groups) {
strings.push_back(GetActiveGroupNameAsString(group));
}
// Synthetic field trials.
for (const auto& group :
variations::SyntheticTrialsActiveGroupIdProvider::GetInstance()
->GetGroups()) {
strings.push_back(GetActiveGroupNameAsString(group.active_group()));
}
}
// static
CefRefPtr<CefPreferenceManager>
CefPreferenceManager::GetGlobalPreferenceManager() {

View File

@@ -27,6 +27,9 @@ class CefGlobalPreferenceManagerImpl : public CefPreferenceManager {
bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) override;
CefRefPtr<CefRegistration> AddPreferenceObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer) override;
private:
IMPLEMENT_REFCOUNTING(CefGlobalPreferenceManagerImpl);

View File

@@ -207,6 +207,7 @@ void CefMainRunner::QuitMessageLoop() {
}
// static
NO_STACK_PROTECTOR
int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
CefRefPtr<CefApp> application,
void* windows_sandbox_info) {

View File

@@ -215,8 +215,10 @@ class CefMediaAccessQuery {
content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
-1 /* webrtc::kFullDesktopScreenId */);
}
video_devices.emplace_back(request_.video_type, media_id.ToString(),
"Screen");
if (media_id.type != content::DesktopMediaID::TYPE_NONE) {
video_devices.emplace_back(request_.video_type, media_id.ToString(),
"Screen");
}
}
blink::mojom::StreamDevicesSetPtr stream_devices_set =

View File

@@ -20,6 +20,12 @@
#include "content/public/browser/render_widget_host_view.h"
#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
#if BUILDFLAG(IS_WIN)
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "components/spellcheck/browser/spellcheck_platform.h"
#endif
namespace {
CefString GetLabel(int message_id) {
@@ -120,8 +126,8 @@ bool CefMenuManager::IsShowingContextMenu() {
return web_contents()->IsShowingContextMenu();
}
bool CefMenuManager::CreateContextMenu(
const content::ContextMenuParams& params) {
bool CefMenuManager::CreateContextMenu(const content::ContextMenuParams& params,
bool query_spellcheck) {
// The renderer may send the "show context menu" message multiple times, one
// for each right click mouse event it receives. Normally, this doesn't happen
// because mouse events are not forwarded once the context menu is showing.
@@ -134,6 +140,24 @@ bool CefMenuManager::CreateContextMenu(
}
params_ = params;
#if BUILDFLAG(IS_WIN)
// System spellcheck suggestions need to be queried asynchronously.
if (query_spellcheck && !params_.misspelled_word.empty() &&
params_.dictionary_suggestions.empty()) {
SpellcheckService* spellcheck_service =
SpellcheckServiceFactory::GetForContext(
browser_->web_contents()->GetBrowserContext());
if (spellcheck_service) {
spellcheck_platform::GetPerLanguageSuggestions(
spellcheck_service->platform_spell_checker(), params_.misspelled_word,
base::BindOnce(&CefMenuManager::OnGetPlatformSuggestionsComplete,
weak_ptr_factory_.GetWeakPtr()));
}
return true;
}
#endif
model_->Clear();
// Create the default menu model.
@@ -511,3 +535,18 @@ bool CefMenuManager::IsCustomContextMenuCommand(int command_id) {
}
return false;
}
#if BUILDFLAG(IS_WIN)
void CefMenuManager::OnGetPlatformSuggestionsComplete(
const spellcheck::PerLanguageSuggestions&
platform_per_language_suggestions) {
std::vector<std::u16string> combined_suggestions;
spellcheck::FillSuggestions(platform_per_language_suggestions,
&combined_suggestions);
params_.dictionary_suggestions = combined_suggestions;
// Now that we have spelling suggestions, call CreateContextMenu again.
CreateContextMenu(params_, /*query_spellcheck=*/false);
}
#endif

View File

@@ -13,6 +13,10 @@
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/web_contents_observer.h"
#if BUILDFLAG(IS_WIN)
#include "components/spellcheck/common/spellcheck_common.h"
#endif
namespace content {
class RenderFrameHost;
class WebContents;
@@ -39,7 +43,8 @@ class CefMenuManager : public CefMenuModelImpl::Delegate,
bool IsShowingContextMenu();
// Create the context menu.
bool CreateContextMenu(const content::ContextMenuParams& params);
bool CreateContextMenu(const content::ContextMenuParams& params,
bool query_spellcheck = true);
void CancelContextMenu();
private:
@@ -62,6 +67,12 @@ class CefMenuManager : public CefMenuModelImpl::Delegate,
// Returns true if the specified id is a custom context menu command.
bool IsCustomContextMenuCommand(int command_id);
#if BUILDFLAG(IS_WIN)
void OnGetPlatformSuggestionsComplete(
const spellcheck::PerLanguageSuggestions&
platform_per_language_suggestions);
#endif
// AlloyBrowserHostImpl pointer is guaranteed to outlive this object.
raw_ptr<AlloyBrowserHostImpl> browser_;

View File

@@ -21,7 +21,8 @@ bool CefMenuRunnerMac::RunContextMenu(
// Create a menu controller based on the model.
MenuControllerCocoa* menu_controller =
[[MenuControllerCocoa alloc] initWithModel:model->model()
delegate:nil];
delegate:nil
useWithPopUpButtonCell:NO];
menu_controller_ = menu_controller;

View File

@@ -6,6 +6,7 @@
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "cef/include/cef_preference.h"
#include "cef/libcef/browser/thread_util.h"
#include "cef/libcef/common/values_impl.h"
#include "components/prefs/pref_service.h"
@@ -118,4 +119,145 @@ bool SetPreference(PrefService* pref_service,
return true;
}
class RegistrationImpl final : public Registration, public CefRegistration {
public:
RegistrationImpl(Registrar* registrar,
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer)
: registrar_(registrar), name_(name), observer_(observer) {
DCHECK(registrar_);
DCHECK(observer_);
}
RegistrationImpl(const RegistrationImpl&) = delete;
RegistrationImpl& operator=(const RegistrationImpl&) = delete;
~RegistrationImpl() override {
CEF_REQUIRE_UIT();
if (registrar_) {
registrar_->RemoveObserver(name_.ToString(), this);
}
}
void Detach() override {
registrar_ = nullptr;
observer_ = nullptr;
}
void RunCallback() const override { RunCallback(name_); }
void RunCallback(const CefString& name) const override {
observer_->OnPreferenceChanged(name);
}
private:
raw_ptr<Registrar> registrar_;
CefString name_;
CefRefPtr<CefPreferenceObserver> observer_;
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(RegistrationImpl);
};
Registrar::~Registrar() {
RemoveAll();
}
void Registrar::Init(PrefService* service) {
DCHECK(service);
DCHECK(IsEmpty() || service_ == service);
service_ = service;
}
void Registrar::Reset() {
RemoveAll();
service_ = nullptr;
}
void Registrar::RemoveAll() {
if (!name_observers_.empty()) {
for (auto& [name, registrations] : name_observers_) {
service_->RemovePrefObserver(name, this);
for (auto& registration : registrations) {
registration.Detach();
}
}
name_observers_.clear();
}
if (!all_observers_.empty()) {
service_->RemovePrefObserverAllPrefs(this);
for (auto& registration : all_observers_) {
registration.Detach();
}
all_observers_.Clear();
}
}
bool Registrar::IsEmpty() const {
return name_observers_.empty() && all_observers_.empty();
}
CefRefPtr<CefRegistration> Registrar::AddObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer) {
CHECK(service_);
RegistrationImpl* impl = new RegistrationImpl(this, name, observer);
if (name.empty()) {
if (all_observers_.empty()) {
service_->AddPrefObserverAllPrefs(this);
}
all_observers_.AddObserver(impl);
} else {
const std::string& name_str = name.ToString();
if (!name_observers_.contains(name_str)) {
service_->AddPrefObserver(name_str, this);
}
name_observers_[name_str].AddObserver(impl);
}
return impl;
}
void Registrar::RemoveObserver(std::string_view name,
Registration* registration) {
CHECK(service_);
if (name.empty()) {
all_observers_.RemoveObserver(registration);
if (all_observers_.empty()) {
service_->RemovePrefObserverAllPrefs(this);
}
} else {
auto it = name_observers_.find(std::string(name));
DCHECK(it != name_observers_.end());
it->second.RemoveObserver(registration);
if (it->second.empty()) {
name_observers_.erase(it);
service_->RemovePrefObserver(name, this);
}
}
}
void Registrar::OnPreferenceChanged(PrefService* service,
std::string_view pref_name) {
std::string pref_name_str(pref_name);
if (!name_observers_.empty()) {
auto it = name_observers_.find(pref_name_str);
if (it != name_observers_.end()) {
for (Registration& registration : it->second) {
registration.RunCallback();
}
}
}
if (!all_observers_.empty()) {
CefString name_str(pref_name_str);
for (Registration& registration : all_observers_) {
registration.RunCallback(name_str);
}
}
}
} // namespace pref_helper

View File

@@ -5,8 +5,16 @@
#ifndef CEF_LIBCEF_BROWSER_PREFS_PREF_HELPER_H_
#define CEF_LIBCEF_BROWSER_PREFS_PREF_HELPER_H_
#include "cef/include/cef_values.h"
#include <unordered_map>
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "cef/include/cef_registration.h"
#include "cef/include/cef_values.h"
#include "components/prefs/pref_observer.h"
class CefPreferenceObserver;
class CefRegistration;
class PrefService;
namespace pref_helper {
@@ -28,6 +36,69 @@ bool SetPreference(PrefService* pref_service,
CefRefPtr<CefValue> value,
CefString& error);
class Registration : public base::CheckedObserver {
public:
virtual void Detach() = 0;
virtual void RunCallback() const = 0;
virtual void RunCallback(const CefString& name) const = 0;
};
class RegistrationImpl;
// Automatically manages the registration of one or more CefPreferenceObserver
// objects with a PrefService. When the Registrar is destroyed, all registered
// observers are automatically unregistered with the PrefService. Loosely based
// on PrefChangeRegistrar.
class Registrar final : public PrefObserver {
public:
Registrar() = default;
Registrar(const Registrar&) = delete;
Registrar& operator=(const Registrar&) = delete;
~Registrar();
// Must be called before adding or removing observers. Can be called more
// than once as long as the value of |service| doesn't change.
void Init(PrefService* service);
// Removes all observers and clears the reference to the PrefService.
// `Init` must be called before adding or removing any observers.
void Reset();
// Removes all observers that have been previously added with a call to Add.
void RemoveAll();
// Returns true if no observers are registered.
bool IsEmpty() const;
// Adds a pref |observer| for the specified pref |name|. All registered
// observers will be automatically unregistered and detached when the
// Registrar's destructor is called.
CefRefPtr<CefRegistration> AddObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer);
private:
friend class RegistrationImpl;
void RemoveObserver(std::string_view name, Registration* registration);
// PrefObserver:
void OnPreferenceChanged(PrefService* service,
std::string_view pref_name) override;
raw_ptr<PrefService, AcrossTasksDanglingUntriaged> service_ = nullptr;
// Observers registered for a preference by name.
using ObserverMap =
std::unordered_map<std::string, base::ObserverList<Registration>>;
ObserverMap name_observers_;
// Observers registered for all preferences.
base::ObserverList<Registration> all_observers_;
};
} // namespace pref_helper
#endif // CEF_LIBCEF_BROWSER_PREFS_PREF_HELPER_H_

View File

@@ -10,7 +10,9 @@
#include "cef/libcef/browser/browser_context.h"
#include "cef/libcef/browser/context.h"
#include "cef/libcef/browser/prefs/pref_helper.h"
#include "cef/libcef/browser/setting_helper.h"
#include "cef/libcef/browser/thread_util.h"
#include "cef/libcef/common/api_version_util.h"
#include "cef/libcef/common/app_manager.h"
#include "cef/libcef/common/task_runner_impl.h"
#include "cef/libcef/common/values_impl.h"
@@ -459,6 +461,22 @@ bool CefRequestContextImpl::SetPreference(const CefString& name,
return pref_helper::SetPreference(pref_service, name, value, error);
}
CefRefPtr<CefRegistration> CefRequestContextImpl::AddPreferenceObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer) {
CEF_API_REQUIRE_ADDED(13401);
if (!VerifyBrowserContext()) {
return nullptr;
}
if (!pref_registrar_) {
pref_registrar_ = std::make_unique<pref_helper::Registrar>();
pref_registrar_->Init(browser_context()->AsProfile()->GetPrefs());
}
return pref_registrar_->AddObserver(name, observer);
}
void CefRequestContextImpl::ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) {
GetBrowserContext(
@@ -588,6 +606,26 @@ void CefRequestContextImpl::SetContentSetting(
requesting_url, top_level_url, content_type, value));
}
CefRefPtr<CefRegistration> CefRequestContextImpl::AddSettingObserver(
CefRefPtr<CefSettingObserver> observer) {
CEF_API_REQUIRE_ADDED(13401);
if (!VerifyBrowserContext()) {
return nullptr;
}
if (!setting_registrar_) {
auto* settings_map = HostContentSettingsMapFactory::GetForProfile(
browser_context()->AsProfile());
if (!settings_map) {
return nullptr;
}
setting_registrar_ = std::make_unique<setting_helper::Registrar>();
setting_registrar_->Init(settings_map);
}
return setting_registrar_->AddObserver(observer);
}
void CefRequestContextImpl::SetChromeColorScheme(cef_color_variant_t variant,
cef_color_t user_color) {
GetBrowserContext(

View File

@@ -17,6 +17,14 @@ namespace content {
struct GlobalRenderFrameHostId;
}
namespace pref_helper {
class Registrar;
}
namespace setting_helper {
class Registrar;
}
class CefBrowserContext;
// Implementation of the CefRequestContext interface. All methods are thread-
@@ -80,6 +88,20 @@ class CefRequestContextImpl : public CefRequestContext {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
BrowserContextCallback callback);
// CefPreferenceManager methods.
bool HasPreference(const CefString& name) override;
CefRefPtr<CefValue> GetPreference(const CefString& name) override;
CefRefPtr<CefDictionaryValue> GetAllPreferences(
bool include_defaults) override;
bool CanSetPreference(const CefString& name) override;
bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) override;
CefRefPtr<CefRegistration> AddPreferenceObserver(
const CefString& name,
CefRefPtr<CefPreferenceObserver> observer) override;
// CefRequestContext methods.
bool IsSame(CefRefPtr<CefRequestContext> other) override;
bool IsSharingWith(CefRefPtr<CefRequestContext> other) override;
bool IsGlobal() override;
@@ -92,14 +114,6 @@ class CefRequestContextImpl : public CefRequestContext {
const CefString& domain_name,
CefRefPtr<CefSchemeHandlerFactory> factory) override;
bool ClearSchemeHandlerFactories() override;
bool HasPreference(const CefString& name) override;
CefRefPtr<CefValue> GetPreference(const CefString& name) override;
CefRefPtr<CefDictionaryValue> GetAllPreferences(
bool include_defaults) override;
bool CanSetPreference(const CefString& name) override;
bool SetPreference(const CefString& name,
CefRefPtr<CefValue> value,
CefString& error) override;
void ClearCertificateExceptions(
CefRefPtr<CefCompletionCallback> callback) override;
void ClearHttpAuthCredentials(
@@ -125,6 +139,8 @@ class CefRequestContextImpl : public CefRequestContext {
const CefString& top_level_url,
cef_content_setting_types_t content_type,
cef_content_setting_values_t value) override;
CefRefPtr<CefRegistration> AddSettingObserver(
CefRefPtr<CefSettingObserver> observer) override;
void SetChromeColorScheme(cef_color_variant_t variant,
cef_color_t user_color) override;
cef_color_variant_t GetChromeColorSchemeMode() override;
@@ -218,6 +234,9 @@ class CefRequestContextImpl : public CefRequestContext {
Config config_;
std::unique_ptr<pref_helper::Registrar> pref_registrar_;
std::unique_ptr<setting_helper::Registrar> setting_registrar_;
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefRequestContextImpl);
};

View File

@@ -0,0 +1,118 @@
// Copyright (c) 2025 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 "cef/libcef/browser/setting_helper.h"
#include "cef/include/cef_request_context.h"
#include "cef/libcef/browser/thread_util.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "url/gurl.h"
namespace setting_helper {
class RegistrationImpl final : public Registration, public CefRegistration {
public:
RegistrationImpl(Registrar* registrar, CefRefPtr<CefSettingObserver> observer)
: registrar_(registrar), observer_(observer) {
DCHECK(registrar_);
DCHECK(observer_);
}
RegistrationImpl(const RegistrationImpl&) = delete;
RegistrationImpl& operator=(const RegistrationImpl&) = delete;
~RegistrationImpl() override {
CEF_REQUIRE_UIT();
if (registrar_) {
registrar_->RemoveObserver(this);
}
}
void Detach() override {
registrar_ = nullptr;
observer_ = nullptr;
}
void RunCallback(const CefString& requesting_url,
const CefString& top_level_url,
cef_content_setting_types_t content_type) const override {
observer_->OnSettingChanged(requesting_url, top_level_url, content_type);
}
private:
raw_ptr<Registrar> registrar_;
CefRefPtr<CefSettingObserver> observer_;
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(RegistrationImpl);
};
Registrar::~Registrar() {
RemoveAll();
}
void Registrar::Init(HostContentSettingsMap* settings) {
DCHECK(settings);
DCHECK(IsEmpty() || settings_ == settings);
settings_ = settings;
}
void Registrar::Reset() {
RemoveAll();
settings_ = nullptr;
}
void Registrar::RemoveAll() {
if (!observers_.empty()) {
settings_->RemoveObserver(this);
for (auto& registration : observers_) {
registration.Detach();
}
observers_.Clear();
}
}
bool Registrar::IsEmpty() const {
return observers_.empty();
}
CefRefPtr<CefRegistration> Registrar::AddObserver(
CefRefPtr<CefSettingObserver> observer) {
CHECK(settings_);
RegistrationImpl* impl = new RegistrationImpl(this, observer);
if (observers_.empty()) {
settings_->AddObserver(this);
}
observers_.AddObserver(impl);
return impl;
}
void Registrar::RemoveObserver(Registration* registration) {
CHECK(settings_);
observers_.RemoveObserver(registration);
if (observers_.empty()) {
settings_->RemoveObserver(this);
}
}
void Registrar::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsTypeSet content_type_set) {
DCHECK(!IsEmpty());
const CefString requesting_url(primary_pattern.ToRepresentativeUrl().spec());
const CefString top_level_url(secondary_pattern.ToRepresentativeUrl().spec());
const auto content_type =
static_cast<cef_content_setting_types_t>(content_type_set.GetType());
for (Registration& registration : observers_) {
registration.RunCallback(requesting_url, top_level_url, content_type);
}
}
} // namespace setting_helper

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2025 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.
#ifndef CEF_LIBCEF_BROWSER_SETTING_HELPER_H_
#define CEF_LIBCEF_BROWSER_SETTING_HELPER_H_
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "cef/include/cef_registration.h"
#include "components/content_settings/core/browser/content_settings_observer.h"
class CefSettingObserver;
class CefRegistration;
class HostContentSettingsMap;
namespace setting_helper {
class Registration : public base::CheckedObserver {
public:
virtual void Detach() = 0;
virtual void RunCallback(const CefString& requesting_url,
const CefString& top_level_url,
cef_content_setting_types_t content_type) const = 0;
};
class RegistrationImpl;
// Automatically manages the registration of one or more CefSettingObserver
// objects with a HostContentSettingsMap. When the Registrar is destroyed, all
// registered observers are automatically unregistered with the
// HostContentSettingsMap. Loosely based on PrefChangeRegistrar.
class Registrar final : public content_settings::Observer {
public:
Registrar() = default;
Registrar(const Registrar&) = delete;
Registrar& operator=(const Registrar&) = delete;
~Registrar();
// Must be called before adding or removing observers. Can be called more
// than once as long as the value of |settings| doesn't change.
void Init(HostContentSettingsMap* settings);
// Removes all observers and clears the reference to the
// HostContentSettingsMap. `Init` must be called before adding or removing any
// observers.
void Reset();
// Removes all observers that have been previously added with a call to Add.
void RemoveAll();
// Returns true if no observers are registered.
bool IsEmpty() const;
// Adds a setting observer. All registered observers will be automatically
// unregistered and detached when the Registrar's destructor is called.
CefRefPtr<CefRegistration> AddObserver(
CefRefPtr<CefSettingObserver> observer);
private:
friend class RegistrationImpl;
void RemoveObserver(Registration* registration);
// content_settings::Observer:
void OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsTypeSet content_type_set) override;
raw_ptr<HostContentSettingsMap, AcrossTasksDanglingUntriaged> settings_ =
nullptr;
base::ObserverList<Registration> observers_;
};
} // namespace setting_helper
#endif // CEF_LIBCEF_BROWSER_SETTING_HELPER_H_

View File

@@ -48,23 +48,23 @@ CEF_EXPORT int cef_version_info(int entry) {
#include "cef/libcef_dll/cef_api_versions.inc"
CEF_EXPORT const char* cef_api_hash(int version, int entry) {
static const ApiVersionHash* hash = nullptr;
static const ApiVersionHash* current_version_hash = nullptr;
// Initialize on the first successful lookup.
if (!hash) {
for (size_t i = 0; i < kApiVersionHashesSize; ++i) {
if (version == kApiVersionHashes[i].version) {
hash = &kApiVersionHashes[i];
if (!current_version_hash) {
for (const auto& version_hash : kApiVersionHashes) {
if (version == version_hash.version) {
current_version_hash = &version_hash;
break;
}
}
if (hash) {
if (current_version_hash) {
g_version = version;
}
}
if (!hash) {
if (!current_version_hash) {
LOG(ERROR) << "Request for unsupported CEF API version " << version;
return nullptr;
}
@@ -76,9 +76,8 @@ CEF_EXPORT const char* cef_api_hash(int version, int entry) {
switch (entry) {
case 0:
return hash->platform;
case 1:
return hash->universal;
return current_version_hash->hash;
case 2:
return CEF_COMMIT_HASH;
default:
@@ -97,9 +96,8 @@ CEF_EXPORT int cef_id_for_pack_resource_name(const char* name) {
// Initialize on the first call.
if (string_to_id_map->empty()) {
for (size_t i = 0; i < kIdNamesPackResourcesSize; ++i) {
(*string_to_id_map)[kIdNamesPackResources[i].name] =
kIdNamesPackResources[i].id;
for (const auto& pack_resource : kIdNamesPackResources) {
(*string_to_id_map)[pack_resource.name] = pack_resource.id;
}
}
@@ -119,9 +117,8 @@ CEF_EXPORT int cef_id_for_pack_string_name(const char* name) {
// Initialize on the first call.
if (string_to_id_map->empty()) {
for (size_t i = 0; i < kIdNamesPackStringsSize; ++i) {
(*string_to_id_map)[kIdNamesPackStrings[i].name] =
kIdNamesPackStrings[i].id;
for (const auto& pack_string : kIdNamesPackStrings) {
(*string_to_id_map)[pack_string.name] = pack_string.id;
}
}
@@ -141,9 +138,8 @@ CEF_EXPORT int cef_id_for_command_id_name(const char* name) {
// Initialize on the first call.
if (string_to_id_map->empty()) {
for (size_t i = 0; i < kIdNamesCommandIdsSize; ++i) {
(*string_to_id_map)[kIdNamesCommandIds[i].name] =
kIdNamesCommandIds[i].id;
for (const auto& command : kIdNamesCommandIds) {
(*string_to_id_map)[command.name] = command.id;
}
}

View File

@@ -764,5 +764,14 @@ patches = [
# Expose Mojo Connector error state to Receiver disconnect handlers.
# https://github.com/chromiumembedded/cef/issues/3664
'name': 'mojo_connect_result_3664'
},
{
# Support for configuration accessors/observers.
# - Allow pref_service::Registrar access to
# PrefService::[Add|Remove]PrefObserver.
# - Enable SyntheticTrialsActiveGroupIdProvider::GetGroups in Release
# builds.
# https://github.com/chromiumembedded/cef/issues/3892
'name': 'config_3892'
}
]

View File

@@ -20,7 +20,7 @@ index 53a73d6c75b7a..05290de4c03a0 100644
// Make an exception to allow most visited tiles to commit in third-party
diff --git content/browser/renderer_host/navigation_request.cc content/browser/renderer_host/navigation_request.cc
index 84b894ac879b5..07d5b00e53e31 100644
index e51bcccd6f63f..a4250481a396e 100644
--- content/browser/renderer_host/navigation_request.cc
+++ content/browser/renderer_host/navigation_request.cc
@@ -8358,10 +8358,22 @@ NavigationRequest::GetOriginForURLLoaderFactoryBeforeResponseWithDebugInfo(

View File

@@ -1,5 +1,5 @@
diff --git chrome/browser/BUILD.gn chrome/browser/BUILD.gn
index 9f293f4ddd146..e9b20e7c5f39d 100644
index ab4deb1a228f5..c98b27c19a611 100644
--- chrome/browser/BUILD.gn
+++ chrome/browser/BUILD.gn
@@ -11,6 +11,7 @@ import("//build/config/compiler/pgo/pgo.gni")
@@ -10,7 +10,7 @@ index 9f293f4ddd146..e9b20e7c5f39d 100644
import("//chrome/browser/buildflags.gni")
import("//chrome/browser/downgrade/buildflags.gni")
import("//chrome/browser/request_header_integrity/buildflags.gni")
@@ -1838,6 +1839,7 @@ static_library("browser") {
@@ -1844,6 +1845,7 @@ static_library("browser") {
"//build/config/compiler:compiler_buildflags",
"//build/config/linux/dbus:buildflags",
"//cc",
@@ -18,7 +18,7 @@ index 9f293f4ddd146..e9b20e7c5f39d 100644
"//chrome:extra_resources",
"//chrome:resources",
"//chrome:strings",
@@ -2524,6 +2526,10 @@ static_library("browser") {
@@ -2530,6 +2532,10 @@ static_library("browser") {
sources += [ "net/net_error_diagnostics_dialog_stub.cc" ]
}

View File

@@ -648,3 +648,59 @@ index f12ba73369a65..23c43dcb1dd24 100644
NavigateParams params(browser, std::move(new_contents));
params.source_contents = source_contents;
params.url = target_url;
diff --git chrome/browser/ui/browser_window/browser_window_features.cc chrome/browser/ui/browser_window/browser_window_features.cc
index e584d77d67bda..a38a8504abd85 100644
--- chrome/browser/ui/browser_window/browser_window_features.cc
+++ chrome/browser/ui/browser_window/browser_window_features.cc
@@ -67,6 +67,14 @@ BrowserWindowFeatures::BrowserWindowFeaturesFactory& GetFactory() {
return *factory;
}
+bool IsNormalBrowser(Browser* browser) {
+ // CEF normal browsers have TYPE_POPUP.
+ if (browser->is_type_popup() && browser->cef_delegate()) {
+ return true;
+ }
+ return browser->is_type_normal();
+}
+
} // namespace
// static
@@ -153,10 +161,12 @@ void BrowserWindowFeatures::Init(BrowserWindowInterface* browser) {
}
void BrowserWindowFeatures::InitPostWindowConstruction(Browser* browser) {
+ const bool supports_toolbar = IsNormalBrowser(browser);
+
// Features that are only enabled for normal browser windows (e.g. a window
// with an omnibox and a tab strip). By default most features should be
// instantiated in this block.
- if (browser->is_type_normal()) {
+ if (supports_toolbar) {
if (IsChromeLabsEnabled()) {
chrome_labs_coordinator_ =
std::make_unique<ChromeLabsCoordinator>(browser);
@@ -198,7 +208,7 @@ void BrowserWindowFeatures::InitPostWindowConstruction(Browser* browser) {
}
}
- if ((browser->is_type_normal() || browser->is_type_app()) &&
+ if ((supports_toolbar || browser->is_type_app()) &&
base::FeatureList::IsEnabled(toast_features::kToastFramework)) {
toast_service_ = std::make_unique<ToastService>(browser);
}
@@ -231,10 +241,12 @@ void BrowserWindowFeatures::InitPostBrowserViewConstruction(
browser_view->browser(),
side_panel_coordinator_->GetWindowRegistry());
+ const bool supports_toolbar = IsNormalBrowser(browser_view->browser());
+
// Memory Saver mode is default off but is available to turn on.
// The controller relies on performance manager which isn't initialized in
// some unit tests without browser view.
- if (browser_view->GetIsNormalType()) {
+ if (supports_toolbar) {
memory_saver_opt_in_iph_controller_ =
std::make_unique<MemorySaverOptInIPHController>(
browser_view->browser());

View File

@@ -1,5 +1,5 @@
diff --git chrome/browser/renderer_context_menu/render_view_context_menu.cc chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 58add8ca095aa..9fe7728f8ccad 100644
index b14b639735870..0cba06a45f327 100644
--- chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -352,6 +352,18 @@ base::OnceCallback<void(RenderViewContextMenu*)>* GetMenuShownCallback() {
@@ -136,7 +136,7 @@ index cb51224f9892c..b5a3946999d8f 100644
private:
// RenderViewContextMenuViewsMac:
diff --git chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
index 2e34cf104fbe6..850489d12a458 100644
index 5e266a42d3df6..e57211944d6a6 100644
--- chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
+++ chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa.mm
@@ -70,6 +70,10 @@ RenderViewContextMenuMacCocoa::~RenderViewContextMenuMacCocoa() {
@@ -150,7 +150,7 @@ index 2e34cf104fbe6..850489d12a458 100644
views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
source_web_contents_->GetNativeView());
@@ -94,6 +98,10 @@ void RenderViewContextMenuMacCocoa::Show() {
@@ -95,6 +99,10 @@ void RenderViewContextMenuMacCocoa::Show() {
views::ElementTrackerViews::GetContextForWidget(widget));
}

View File

@@ -34,10 +34,10 @@ index f61ec524109fe..92ca490728855 100644
WebViewGuestDelegate* ChromeExtensionsAPIClient::CreateWebViewGuestDelegate(
diff --git chrome/browser/extensions/api/tabs/tabs_api.cc chrome/browser/extensions/api/tabs/tabs_api.cc
index d19671bad0e0d..639a1737a0ef5 100644
index b3921038447a8..dd5225f5e7227 100644
--- chrome/browser/extensions/api/tabs/tabs_api.cc
+++ chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -1674,7 +1674,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
@@ -1680,7 +1680,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
return RespondNow(Error(ExtensionTabUtil::kTabStripNotEditableError));
}
@@ -46,7 +46,7 @@ index d19671bad0e0d..639a1737a0ef5 100644
tab_strip->ActivateTabAt(tab_index);
DCHECK_EQ(contents, tab_strip->GetActiveWebContents());
}
@@ -1688,7 +1688,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
@@ -1694,7 +1694,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
}
bool highlighted = *params->update_properties.highlighted;
@@ -55,7 +55,7 @@ index d19671bad0e0d..639a1737a0ef5 100644
tab_strip->ToggleSelectionAt(tab_index);
}
}
@@ -1700,7 +1700,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
@@ -1706,7 +1706,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
kCannotUpdateMuteCaptured, base::NumberToString(tab_id))));
}
@@ -64,7 +64,7 @@ index d19671bad0e0d..639a1737a0ef5 100644
int opener_id = *params->update_properties.opener_tab_id;
WebContents* opener_contents = nullptr;
if (opener_id == tab_id) {
@@ -1735,7 +1735,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
@@ -1741,7 +1741,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
->SetAutoDiscardable(state);
}
@@ -73,7 +73,7 @@ index d19671bad0e0d..639a1737a0ef5 100644
// Bug fix for crbug.com/1197888. Don't let the extension update the tab if
// the user is dragging tabs.
if (!ExtensionTabUtil::IsTabStripEditable()) {
@@ -1756,7 +1756,8 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
@@ -1762,7 +1762,8 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
// Navigate the tab to a new location if the url is different.
if (params->update_properties.url) {
std::string updated_url = *params->update_properties.url;
@@ -83,7 +83,7 @@ index d19671bad0e0d..639a1737a0ef5 100644
!IsURLAllowedInIncognito(GURL(updated_url))) {
return RespondNow(Error(ErrorUtils::FormatErrorMessage(
tabs_constants::kURLsNotAllowedInIncognitoError, updated_url)));
@@ -1771,7 +1772,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
@@ -1777,7 +1778,7 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
return RespondNow(Error(std::move(error)));
}

View File

@@ -17,10 +17,10 @@ index fbce13c16ad10..0512b2f09937e 100644
std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPrompt(
content::WebContents* web_contents,
diff --git chrome/browser/ui/views/permissions/permission_prompt_factory.cc chrome/browser/ui/views/permissions/permission_prompt_factory.cc
index 0f19f3eeeea54..20a942f2e4007 100644
index ab9701eb9ce8c..7c1dbe9adb0e8 100644
--- chrome/browser/ui/views/permissions/permission_prompt_factory.cc
+++ chrome/browser/ui/views/permissions/permission_prompt_factory.cc
@@ -209,11 +209,28 @@ std::unique_ptr<permissions::PermissionPrompt> CreateQuietPrompt(
@@ -210,11 +210,28 @@ std::unique_ptr<permissions::PermissionPrompt> CreateQuietPrompt(
}
}

View File

@@ -1,5 +1,5 @@
diff --git chrome/browser/safe_browsing/BUILD.gn chrome/browser/safe_browsing/BUILD.gn
index c30c5ab55232d..2380f3595ce71 100644
index 31a8d9d259f7b..267ef1c830a69 100644
--- chrome/browser/safe_browsing/BUILD.gn
+++ chrome/browser/safe_browsing/BUILD.gn
@@ -40,6 +40,7 @@ static_library("safe_browsing") {

View File

@@ -592,7 +592,7 @@ index 388954e9b504a..7fd8d7b36fa04 100644
#endif
diff --git chrome/browser/prefs/browser_prefs.cc chrome/browser/prefs/browser_prefs.cc
index dc8800d422a2c..675410378cc6f 100644
index 3cc0bb183d1d1..57ea33377a7e4 100644
--- chrome/browser/prefs/browser_prefs.cc
+++ chrome/browser/prefs/browser_prefs.cc
@@ -16,6 +16,7 @@
@@ -614,7 +614,7 @@ index dc8800d422a2c..675410378cc6f 100644
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "chrome/browser/accessibility/animation_policy_prefs.h"
#include "chrome/browser/apps/platform_apps/shortcut_manager.h"
@@ -1940,6 +1945,11 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
@@ -1937,6 +1942,11 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
// This is intentionally last.
RegisterLocalStatePrefsForMigration(registry);
@@ -626,7 +626,7 @@ index dc8800d422a2c..675410378cc6f 100644
}
// Register prefs applicable to all profiles.
@@ -2390,6 +2400,10 @@ void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
@@ -2387,6 +2397,10 @@ void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
const std::string& locale) {
RegisterProfilePrefs(registry, locale);

View File

@@ -397,10 +397,10 @@ index 3d8a15049d4d2..66c4789581fe1 100644
// regenerated.
bool RegenerateFrameOnThemeChange(BrowserThemeChangeType theme_change_type);
diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc
index 127aa3ef3ba70..506cb33978bed 100644
index 76c889780c153..80e31b0c2986b 100644
--- chrome/browser/ui/views/frame/browser_view.cc
+++ chrome/browser/ui/views/frame/browser_view.cc
@@ -363,10 +363,6 @@ using web_modal::WebContentsModalDialogHost;
@@ -364,10 +364,6 @@ using web_modal::WebContentsModalDialogHost;
namespace {
@@ -411,7 +411,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
#if BUILDFLAG(IS_CHROMEOS)
// UMA histograms that record animation smoothness for tab loading animation.
constexpr char kTabLoadingSmoothnessHistogramName[] =
@@ -776,6 +772,14 @@ class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate {
@@ -777,6 +773,14 @@ class BrowserViewLayoutDelegateImpl : public BrowserViewLayoutDelegate {
return browser_view_->frame()->GetTopInset() - browser_view_->y();
}
@@ -426,7 +426,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
bool IsToolbarVisible() const override {
return browser_view_->IsToolbarVisible();
}
@@ -927,11 +931,21 @@ class BrowserView::AccessibilityModeObserver : public ui::AXModeObserver {
@@ -928,11 +932,21 @@ class BrowserView::AccessibilityModeObserver : public ui::AXModeObserver {
///////////////////////////////////////////////////////////////////////////////
// BrowserView, public:
@@ -449,7 +449,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
SetShowIcon(::ShouldShowWindowIcon(
browser_.get(), AppUsesWindowControlsOverlay(), AppUsesTabbed()));
@@ -1071,8 +1085,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
@@ -1072,8 +1086,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
watermark_view_));
#endif
@@ -467,7 +467,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
contents_separator_ =
top_container_->AddChildView(std::make_unique<ContentsSeparator>());
@@ -1144,7 +1165,9 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
@@ -1145,7 +1166,9 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
}
BrowserView::~BrowserView() {
@@ -477,7 +477,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
// Remove the layout manager to avoid dangling. This needs to be earlier than
// other cleanups that destroy views referenced in the layout manager.
@@ -1156,7 +1179,9 @@ BrowserView::~BrowserView() {
@@ -1157,7 +1180,9 @@ BrowserView::~BrowserView() {
// All the tabs should have been destroyed already. If we were closed by the
// OS with some tabs than the NativeBrowserFrame should have destroyed them.
@@ -487,7 +487,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
// Stop the animation timer explicitly here to avoid running it in a nested
// message loop, which may run by Browser destructor.
@@ -1165,17 +1190,18 @@ BrowserView::~BrowserView() {
@@ -1166,17 +1191,18 @@ BrowserView::~BrowserView() {
// Immersive mode may need to reparent views before they are removed/deleted.
immersive_mode_controller_.reset();
@@ -510,7 +510,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
// These are raw pointers to child views, so they need to be set to null
// before `RemoveAllChildViews()` is called to avoid dangling.
@@ -1800,6 +1826,28 @@ gfx::Point BrowserView::GetThemeOffsetFromBrowserView() const {
@@ -1801,6 +1827,28 @@ gfx::Point BrowserView::GetThemeOffsetFromBrowserView() const {
ThemeProperties::kFrameHeightAboveTabs - browser_view_origin.y());
}
@@ -539,7 +539,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
// static:
BrowserView::DevToolsDockedPlacement BrowserView::GetDevToolsDockedPlacement(
const gfx::Rect& contents_webview_bounds,
@@ -2220,7 +2268,13 @@ void BrowserView::OnExclusiveAccessUserInput() {
@@ -2221,7 +2269,13 @@ void BrowserView::OnExclusiveAccessUserInput() {
bool BrowserView::ShouldHideUIForFullscreen() const {
// Immersive mode needs UI for the slide-down top panel.
@@ -554,7 +554,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
return false;
}
@@ -3459,7 +3513,9 @@ DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() {
@@ -3460,7 +3514,9 @@ DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() {
}
return nullptr;
}
@@ -565,7 +565,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
if (auto* download_button = toolbar_button_provider_->GetDownloadButton()) {
return download_button->bubble_controller();
}
@@ -4089,7 +4145,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() {
@@ -4094,7 +4150,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() {
return;
}
@@ -575,7 +575,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
top_container()->DestroyLayer();
AddChildViewAt(top_container(), 0);
EnsureFocusOrder();
@@ -4607,11 +4664,38 @@ void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) {
@@ -4612,11 +4669,38 @@ void BrowserView::GetAccessiblePanes(std::vector<views::View*>* panes) {
bool BrowserView::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) {
@@ -616,7 +616,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
// Draggable regions are defined relative to the web contents.
gfx::Point point_in_contents_web_view_coords(location);
views::View::ConvertPointToTarget(GetWidget()->GetRootView(),
@@ -4620,7 +4704,7 @@ bool BrowserView::ShouldDescendIntoChildForEventHandling(
@@ -4625,7 +4709,7 @@ bool BrowserView::ShouldDescendIntoChildForEventHandling(
// Draggable regions should be ignored for clicks into any browser view's
// owned widgets, for example alerts, permission prompts or find bar.
@@ -625,7 +625,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
point_in_contents_web_view_coords.x(),
point_in_contents_web_view_coords.y()) ||
WidgetOwnedByAnchorContainsPoint(point_in_contents_web_view_coords);
@@ -4734,8 +4818,10 @@ void BrowserView::Layout(PassKey) {
@@ -4739,8 +4823,10 @@ void BrowserView::Layout(PassKey) {
// TODO(jamescook): Why was this in the middle of layout code?
toolbar_->location_bar()->omnibox_view()->SetFocusBehavior(
@@ -638,7 +638,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
// Some of the situations when the BrowserView is laid out are:
// - Enter/exit immersive fullscreen mode.
@@ -4802,6 +4888,11 @@ void BrowserView::AddedToWidget() {
@@ -4807,6 +4893,11 @@ void BrowserView::AddedToWidget() {
SetThemeProfileForWindow(GetNativeWindow(), browser_->profile());
#endif
@@ -650,7 +650,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
toolbar_->Init();
if (download::IsDownloadBubbleEnabled() &&
features::IsToolbarPinningEnabled() &&
@@ -4849,14 +4940,10 @@ void BrowserView::AddedToWidget() {
@@ -4854,14 +4945,10 @@ void BrowserView::AddedToWidget() {
EnsureFocusOrder();
@@ -668,7 +668,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
using_native_frame_ = frame_->ShouldUseNativeFrame();
MaybeInitializeWebUITabStrip();
@@ -5252,7 +5339,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen, const int64_t display_id) {
@@ -5257,7 +5344,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen, const int64_t display_id) {
// Undo our anti-jankiness hacks and force a re-layout.
in_process_fullscreen_ = false;
ToolbarSizeChanged(false);
@@ -678,7 +678,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
}
void BrowserView::RequestFullscreen(bool fullscreen, int64_t display_id) {
@@ -5748,6 +5836,8 @@ Profile* BrowserView::GetProfile() {
@@ -5753,6 +5841,8 @@ Profile* BrowserView::GetProfile() {
}
void BrowserView::UpdateUIForTabFullscreen() {
@@ -687,7 +687,7 @@ index 127aa3ef3ba70..506cb33978bed 100644
frame()->GetFrameView()->UpdateFullscreenTopUI();
}
@@ -5777,6 +5867,8 @@ bool BrowserView::CanUserEnterFullscreen() const {
@@ -5782,6 +5872,8 @@ bool BrowserView::CanUserEnterFullscreen() const {
}
bool BrowserView::CanUserExitFullscreen() const {
@@ -738,7 +738,7 @@ index b9986c6e9097d..fc8f781e6ac66 100644
// Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate
// interface to keep these two classes decoupled and testable.
diff --git chrome/browser/ui/views/frame/browser_view_layout.cc chrome/browser/ui/views/frame/browser_view_layout.cc
index 1376fdf933420..336391e29944c 100644
index 46f6be18ac556..be2ce4a9dc6da 100644
--- chrome/browser/ui/views/frame/browser_view_layout.cc
+++ chrome/browser/ui/views/frame/browser_view_layout.cc
@@ -52,6 +52,10 @@

View File

@@ -0,0 +1,85 @@
diff --git components/prefs/pref_service.h components/prefs/pref_service.h
index f1856d6ee4419..413b77e80d84d 100644
--- components/prefs/pref_service.h
+++ components/prefs/pref_service.h
@@ -52,6 +52,10 @@ namespace base {
class FilePath;
}
+namespace pref_helper {
+class Registrar;
+}
+
namespace prefs {
class ScopedDictionaryPrefUpdate;
}
@@ -441,6 +445,8 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// declared as a friend, too.
friend class PrefChangeRegistrar;
friend class subtle::PrefMemberBase;
+ // CEF registration manager.
+ friend class pref_helper::Registrar;
// These are protected so they can only be accessed by the friend
// classes listed above.
diff --git components/variations/synthetic_trials_active_group_id_provider.cc components/variations/synthetic_trials_active_group_id_provider.cc
index bd51697297471..3e669cd080457 100644
--- components/variations/synthetic_trials_active_group_id_provider.cc
+++ components/variations/synthetic_trials_active_group_id_provider.cc
@@ -27,7 +27,7 @@ SyntheticTrialsActiveGroupIdProvider::GetActiveGroupIds() {
return group_ids_;
}
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || BUILDFLAG(ENABLE_CEF)
std::vector<SyntheticTrialGroup>
SyntheticTrialsActiveGroupIdProvider::GetGroups() {
base::AutoLock scoped_lock(lock_);
@@ -38,7 +38,7 @@ SyntheticTrialsActiveGroupIdProvider::GetGroups() {
void SyntheticTrialsActiveGroupIdProvider::ResetForTesting() {
base::AutoLock scoped_lock(lock_);
group_ids_.clear();
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || BUILDFLAG(ENABLE_CEF)
groups_.clear();
#endif // !defined(NDEBUG)
}
@@ -53,7 +53,7 @@ void SyntheticTrialsActiveGroupIdProvider::OnSyntheticTrialsChanged(
for (const auto& group : groups) {
group_ids_.push_back(group.id());
}
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || BUILDFLAG(ENABLE_CEF)
groups_ = groups;
#endif // !defined(NDEBUG)
}
diff --git components/variations/synthetic_trials_active_group_id_provider.h components/variations/synthetic_trials_active_group_id_provider.h
index b4a999731d996..0bbac173fddf1 100644
--- components/variations/synthetic_trials_active_group_id_provider.h
+++ components/variations/synthetic_trials_active_group_id_provider.h
@@ -10,6 +10,7 @@
#include "base/component_export.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
+#include "cef/libcef/features/features.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/synthetic_trials.h"
@@ -36,7 +37,7 @@ class COMPONENT_EXPORT(VARIATIONS) SyntheticTrialsActiveGroupIdProvider
// Returns currently active synthetic trial group IDs.
std::vector<ActiveGroupId> GetActiveGroupIds();
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || BUILDFLAG(ENABLE_CEF)
// In debug mode, not only the group IDs are tracked but also the full group
// info, to display the names unhashed in chrome://version.
std::vector<SyntheticTrialGroup> GetGroups();
@@ -60,7 +61,7 @@ class COMPONENT_EXPORT(VARIATIONS) SyntheticTrialsActiveGroupIdProvider
base::Lock lock_;
std::vector<ActiveGroupId> group_ids_; // GUARDED_BY(lock_);
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) || BUILDFLAG(ENABLE_CEF)
// In debug builds, keep the full group information to be able to display it
// in chrome://version.
std::vector<SyntheticTrialGroup> groups_; // GUARDED_BY(lock_);

View File

@@ -1,5 +1,5 @@
diff --git content/browser/devtools/devtools_http_handler.cc content/browser/devtools/devtools_http_handler.cc
index 8a8a0bdade6fe..59b9b4a7fe9da 100644
index 1d0f19760a671..c21a9a23ff281 100644
--- content/browser/devtools/devtools_http_handler.cc
+++ content/browser/devtools/devtools_http_handler.cc
@@ -591,7 +591,7 @@ void DevToolsHttpHandler::OnJsonRequest(
@@ -12,7 +12,7 @@ index 8a8a0bdade6fe..59b9b4a7fe9da 100644
version.Set("V8-Version", V8_VERSION_STRING);
std::string host = info.GetHeaderValue("host");
diff --git content/browser/loader/navigation_url_loader_impl.cc content/browser/loader/navigation_url_loader_impl.cc
index 3bdbefae96ce6..086b906eccd9a 100644
index 7e8951316373a..189f591893c1a 100644
--- content/browser/loader/navigation_url_loader_impl.cc
+++ content/browser/loader/navigation_url_loader_impl.cc
@@ -939,7 +939,7 @@ NavigationURLLoaderImpl::CreateNonNetworkLoaderFactory(

View File

@@ -12,7 +12,7 @@ index 3f65718281973..66580417cc79e 100644
# https://crbug.com/474506.
"//clank/java/BUILD.gn",
diff --git BUILD.gn BUILD.gn
index a05810690041d..cac7f91fc271d 100644
index 704ddc0e043d8..b762c1887cd3b 100644
--- BUILD.gn
+++ BUILD.gn
@@ -19,6 +19,7 @@ import("//build/config/sanitizers/sanitizers.gni")

View File

@@ -1,8 +1,8 @@
diff --git tools/gritsettings/resource_ids.spec tools/gritsettings/resource_ids.spec
index 60e844376f968..b282af990a75a 100644
index 80494b5bb318a..61ed661f2a80a 100644
--- tools/gritsettings/resource_ids.spec
+++ tools/gritsettings/resource_ids.spec
@@ -1461,11 +1461,18 @@
@@ -1463,11 +1463,18 @@
"<(SHARED_INTERMEDIATE_DIR)/third_party/blink/public/strings/permission_element_generated_strings.grd": {
"META": {"sizes": {"messages": [2000],}},
"messages": [10080],

View File

@@ -1,8 +1,8 @@
diff --git components/metrics/persistent_system_profile.cc components/metrics/persistent_system_profile.cc
index 3cef1f28ccdb0..c91c9927436de 100644
index 5ffc5ec97f90a..d322d2a26264a 100644
--- components/metrics/persistent_system_profile.cc
+++ components/metrics/persistent_system_profile.cc
@@ -401,6 +401,10 @@ bool PersistentSystemProfile::GetSystemProfile(
@@ -415,6 +415,10 @@ bool PersistentSystemProfile::GetSystemProfile(
return true;
}

View File

@@ -56,7 +56,7 @@ index f1030a744809c..c222a209949e6 100644
return nullptr;
}
diff --git content/browser/renderer_host/render_widget_host_impl.cc content/browser/renderer_host/render_widget_host_impl.cc
index 130fb82767d53..952b34877fa89 100644
index 734e717d2cc5c..6690432edf9f6 100644
--- content/browser/renderer_host/render_widget_host_impl.cc
+++ content/browser/renderer_host/render_widget_host_impl.cc
@@ -801,7 +801,7 @@ void RenderWidgetHostImpl::WasHidden() {
@@ -68,7 +68,7 @@ index 130fb82767d53..952b34877fa89 100644
RejectPointerLockOrUnlockIfNecessary(
blink::mojom::PointerLockResult::kWrongDocument);
}
@@ -3681,6 +3681,11 @@ void RenderWidgetHostImpl::StopFling() {
@@ -3685,6 +3685,11 @@ void RenderWidgetHostImpl::StopFling() {
GetRenderInputRouter()->StopFling();
}
@@ -81,7 +81,7 @@ index 130fb82767d53..952b34877fa89 100644
uint16_t angle,
display::mojom::ScreenOrientation type) {
diff --git content/browser/renderer_host/render_widget_host_impl.h content/browser/renderer_host/render_widget_host_impl.h
index 286e3d89a6c24..1276618de2e56 100644
index c3429732757d8..09c7d25c1ba66 100644
--- content/browser/renderer_host/render_widget_host_impl.h
+++ content/browser/renderer_host/render_widget_host_impl.h
@@ -838,6 +838,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl

View File

@@ -1,8 +1,8 @@
diff --git content/browser/renderer_host/render_view_host_impl.cc content/browser/renderer_host/render_view_host_impl.cc
index ac0856149902d..1f4dda26e44dd 100644
index a387789fe4270..e5d9dc26601e8 100644
--- content/browser/renderer_host/render_view_host_impl.cc
+++ content/browser/renderer_host/render_view_host_impl.cc
@@ -752,6 +752,8 @@ bool RenderViewHostImpl::IsRenderViewLive() const {
@@ -762,6 +762,8 @@ bool RenderViewHostImpl::IsRenderViewLive() const {
}
void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {

View File

@@ -1,8 +1,8 @@
diff --git content/browser/renderer_host/render_frame_host_impl.cc content/browser/renderer_host/render_frame_host_impl.cc
index 7fc3f01731e3c..c473da6e8abbf 100644
index 6e28debbe692a..8eb96841a5347 100644
--- content/browser/renderer_host/render_frame_host_impl.cc
+++ content/browser/renderer_host/render_frame_host_impl.cc
@@ -9591,6 +9591,16 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -9616,6 +9616,16 @@ void RenderFrameHostImpl::CreateNewWindow(
return;
}
@@ -19,7 +19,7 @@ index 7fc3f01731e3c..c473da6e8abbf 100644
// Otherwise, consume user activation before we proceed. In particular, it is
// important to do this before we return from the |opener_suppressed| case
// below.
@@ -11968,6 +11978,7 @@ void RenderFrameHostImpl::CommitNavigation(
@@ -11993,6 +12003,7 @@ void RenderFrameHostImpl::CommitNavigation(
auto browser_calc_origin_to_commit =
navigation_request->GetOriginToCommitWithDebugInfo();
if (!process_lock.is_error_page() && !is_mhtml_subframe &&

View File

@@ -1,5 +1,5 @@
diff --git content/browser/renderer_host/render_widget_host_view_aura.cc content/browser/renderer_host/render_widget_host_view_aura.cc
index 612d67d06d766..5102758c7f398 100644
index 1d08f25b91496..ecac98345a92c 100644
--- content/browser/renderer_host/render_widget_host_view_aura.cc
+++ content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -6,6 +6,7 @@
@@ -28,7 +28,7 @@ index 612d67d06d766..5102758c7f398 100644
SkColor color = *GetBackgroundColor();
window_->layer()->SetColor(color);
}
@@ -2642,6 +2647,16 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
@@ -2649,6 +2654,16 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
window_->layer()->SetColor(GetBackgroundColor() ? *GetBackgroundColor()
: SK_ColorWHITE);
UpdateFrameSinkIdRegistration();

View File

@@ -58,10 +58,10 @@ index 3f0be99e0e145..0462ebbe9bedc 100644
// reset to null.
const CookieAccessDelegate* cookie_access_delegate() const {
diff --git services/network/cookie_manager.cc services/network/cookie_manager.cc
index 963ddd7d0fcce..81f37072b77fa 100644
index 95f73bcb9fb40..e17a93f69c089 100644
--- services/network/cookie_manager.cc
+++ services/network/cookie_manager.cc
@@ -347,14 +347,9 @@ void CookieManager::AllowFileSchemeCookies(
@@ -355,14 +355,9 @@ void CookieManager::AllowFileSchemeCookies(
AllowFileSchemeCookiesCallback callback) {
OnSettingsWillChange();

View File

@@ -1,8 +1,8 @@
diff --git content/browser/storage_partition_impl.cc content/browser/storage_partition_impl.cc
index 5b7298888a896..4d1d7d412179f 100644
index 29a3522bffdd0..f5edd823612a4 100644
--- content/browser/storage_partition_impl.cc
+++ content/browser/storage_partition_impl.cc
@@ -3402,9 +3402,12 @@ void StoragePartitionImpl::InitNetworkContext() {
@@ -3449,9 +3449,12 @@ void StoragePartitionImpl::InitNetworkContext() {
cert_verifier::mojom::CertVerifierCreationParamsPtr
cert_verifier_creation_params =
cert_verifier::mojom::CertVerifierCreationParams::New();

View File

@@ -1,5 +1,5 @@
diff --git BUILD.gn BUILD.gn
index 94147651f9b..c243a8ed9cf 100644
index 001b0791603..2ad30b10066 100644
--- BUILD.gn
+++ BUILD.gn
@@ -11,6 +11,7 @@ import("//build/config/mips.gni")

View File

@@ -164,7 +164,7 @@ index eed04364a8c09..a3c7cf6275838 100644
LabelButtonImageContainer* image_container() {
return image_container_.get();
diff --git ui/views/controls/label.cc ui/views/controls/label.cc
index 9ad8685569d46..00cf319a53a10 100644
index 02297c5213b62..20fd3defae442 100644
--- ui/views/controls/label.cc
+++ ui/views/controls/label.cc
@@ -52,12 +52,29 @@ enum LabelPropertyKey {
@@ -654,7 +654,7 @@ index f5b0936aac647..20f476c9abd93 100644
std::optional<std::string> show_menu_host_duration_histogram) override;
void Cancel() override;
diff --git ui/views/controls/menu/menu_runner_impl_cocoa.mm ui/views/controls/menu/menu_runner_impl_cocoa.mm
index 05322e627acab..a866a76c50372 100644
index e1e3f0d4c54dd..f8afecca2016b 100644
--- ui/views/controls/menu/menu_runner_impl_cocoa.mm
+++ ui/views/controls/menu/menu_runner_impl_cocoa.mm
@@ -72,6 +72,7 @@ void MenuRunnerImplCocoa::RunMenuAt(

View File

@@ -61,7 +61,7 @@ index 971e5273f1b05..a5d847f7f9d60 100644
case ui::mojom::WindowShowState::kMaximized:
return kSerializedShowStateMaximized;
diff --git content/browser/renderer_host/render_widget_host_view_base.cc content/browser/renderer_host/render_widget_host_view_base.cc
index 51f836176bf92..9171a879fca77 100644
index fc70d927f9692..ae66251a93264 100644
--- content/browser/renderer_host/render_widget_host_view_base.cc
+++ content/browser/renderer_host/render_widget_host_view_base.cc
@@ -591,6 +591,14 @@ float RenderWidgetHostViewBase::GetScaleOverrideForCapture() const {
@@ -80,7 +80,7 @@ index 51f836176bf92..9171a879fca77 100644
if (!GetMouseWheelPhaseHandler())
return;
diff --git content/browser/renderer_host/render_widget_host_view_base.h content/browser/renderer_host/render_widget_host_view_base.h
index 2a2edc6063b49..66860109f4191 100644
index deb5325b14ef8..5f5cbf472adf9 100644
--- content/browser/renderer_host/render_widget_host_view_base.h
+++ content/browser/renderer_host/render_widget_host_view_base.h
@@ -70,6 +70,7 @@ namespace content {
@@ -91,7 +91,7 @@ index 2a2edc6063b49..66860109f4191 100644
class ScopedViewTransitionResources;
class TextInputManager;
class TouchSelectionControllerClientManager;
@@ -151,6 +152,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
@@ -152,6 +153,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
float GetDeviceScaleFactor() const final;
bool IsPointerLocked() override;
@@ -101,7 +101,7 @@ index 2a2edc6063b49..66860109f4191 100644
// Identical to `CopyFromSurface()`, except that this method issues the
// `viz::CopyOutputRequest` against the exact `viz::Surface` currently
// embedded by this View, while `CopyFromSurface()` may return a copy of any
@@ -212,6 +216,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
@@ -213,6 +217,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
// Called when screen information or native widget bounds change.
virtual void UpdateScreenInfo();
@@ -112,7 +112,7 @@ index 2a2edc6063b49..66860109f4191 100644
// Called by the TextInputManager to notify the view about being removed from
// the list of registered views, i.e., TextInputManager is no longer tracking
// TextInputState from this view. The RWHV should reset |text_input_manager_|
@@ -339,6 +347,12 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
@@ -340,6 +348,12 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
const gfx::Rect& bounds,
const gfx::Rect& anchor_rect) = 0;
@@ -125,7 +125,7 @@ index 2a2edc6063b49..66860109f4191 100644
// Indicates whether the page has finished loading.
virtual void SetIsLoading(bool is_loading) = 0;
@@ -595,6 +609,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
@@ -599,6 +613,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
// to all displays.
gfx::Size system_cursor_size_;
@@ -136,7 +136,7 @@ index 2a2edc6063b49..66860109f4191 100644
private:
FRIEND_TEST_ALL_PREFIXES(
BrowserSideFlingBrowserTest,
@@ -616,10 +634,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
@@ -620,10 +638,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
void SynchronizeVisualProperties();
@@ -196,10 +196,10 @@ index 41b34a27176a3..bdf5f9d4bb61e 100644
if (host_ && set_focus_on_mouse_down_or_key_event_) {
set_focus_on_mouse_down_or_key_event_ = false;
diff --git content/public/browser/render_widget_host_view.h content/public/browser/render_widget_host_view.h
index 7cd4d56bb2ac2..19034a43949b1 100644
index 027dd27577fdc..cee885246b3e1 100644
--- content/public/browser/render_widget_host_view.h
+++ content/public/browser/render_widget_host_view.h
@@ -254,6 +254,14 @@ class CONTENT_EXPORT RenderWidgetHostView {
@@ -255,6 +255,14 @@ class CONTENT_EXPORT RenderWidgetHostView {
// This must always return the same device scale factor as GetScreenInfo.
virtual float GetDeviceScaleFactor() const = 0;
@@ -500,10 +500,10 @@ index 932351e288f37..7897f4b72f605 100644
// the implementation of ::ShowCursor() is based on a counter, so making this
// member static ensures that ::ShowCursor() is always called exactly once
diff --git ui/views/widget/native_widget_mac.mm ui/views/widget/native_widget_mac.mm
index 89247a9ed3522..2d997ff8fda51 100644
index a616400ddaa71..90d424a854c13 100644
--- ui/views/widget/native_widget_mac.mm
+++ ui/views/widget/native_widget_mac.mm
@@ -699,6 +699,7 @@ void NativeWidgetMac::Show(ui::mojom::WindowShowState show_state,
@@ -702,6 +702,7 @@ void NativeWidgetMac::Show(ui::mojom::WindowShowState show_state,
break;
case ui::mojom::WindowShowState::kMaximized:
case ui::mojom::WindowShowState::kFullscreen:
@@ -512,7 +512,7 @@ index 89247a9ed3522..2d997ff8fda51 100644
break;
case ui::mojom::WindowShowState::kEnd:
diff --git ui/views/widget/widget.cc ui/views/widget/widget.cc
index a4c1dba98b0d2..b8f9b62260637 100644
index 6853d63ce96bd..1327b1e3cbaac 100644
--- ui/views/widget/widget.cc
+++ ui/views/widget/widget.cc
@@ -234,8 +234,8 @@ bool Widget::InitParams::ShouldInitAsHeadless() const {
@@ -565,7 +565,7 @@ index a4c1dba98b0d2..b8f9b62260637 100644
}
}
@@ -1922,10 +1933,16 @@ void Widget::OnNativeWidgetParentChanged(gfx::NativeView parent) {
@@ -1923,10 +1934,16 @@ void Widget::OnNativeWidgetParentChanged(gfx::NativeView parent) {
}
gfx::Size Widget::GetMinimumSize() const {
@@ -582,7 +582,7 @@ index a4c1dba98b0d2..b8f9b62260637 100644
return non_client_view_ ? non_client_view_->GetMaximumSize() : gfx::Size();
}
@@ -2206,7 +2223,8 @@ bool Widget::SetInitialFocus(ui::mojom::WindowShowState show_state) {
@@ -2207,7 +2224,8 @@ bool Widget::SetInitialFocus(ui::mojom::WindowShowState show_state) {
View* v = widget_delegate_->GetInitiallyFocusedView();
if (!focus_on_creation_ ||
show_state == ui::mojom::WindowShowState::kInactive ||

View File

@@ -1,5 +1,5 @@
diff --git content/browser/web_contents/web_contents_impl.cc content/browser/web_contents/web_contents_impl.cc
index 5ff43afce429c..587130d6d4f2a 100644
index 94917dc412682..308bcea0b770d 100644
--- content/browser/web_contents/web_contents_impl.cc
+++ content/browser/web_contents/web_contents_impl.cc
@@ -3830,6 +3830,12 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
@@ -60,7 +60,7 @@ index 5ff43afce429c..587130d6d4f2a 100644
FrameTree* WebContentsImpl::GetOwnedPictureInPictureFrameTree() {
diff --git content/public/browser/web_contents.h content/public/browser/web_contents.h
index 5e89cbf0ed5fd..49a6449c46fad 100644
index 24afa41509bec..560f83dea80de 100644
--- content/public/browser/web_contents.h
+++ content/public/browser/web_contents.h
@@ -116,10 +116,12 @@ class BrowserPluginGuestDelegate;

View File

@@ -317,4 +317,9 @@ if(OS_WINDOWS)
# Copy CEF binary and resource files to the target output directory.
COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
if(USE_SANDBOX)
# Set LPAC ACLs required for Windows sandbox support.
SET_LPAC_ACLS("${CEF_TARGET}")
endif()
endif()

View File

@@ -0,0 +1,334 @@
// Copyright (c) 2025 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 "tests/cefclient/browser/config_test.h"
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "include/base/cef_logging.h"
#include "include/cef_parser.h"
#include "include/cef_request_context.h"
#include "tests/cefclient/browser/test_runner.h"
namespace client::config_test {
namespace {
const char kTestUrlPath[] = "/config";
// Application-specific error codes.
const int kMessageFormatError = 1;
const int kRequestFailedError = 2;
// Common to all messages.
const char kNameKey[] = "name";
const char kNameGlobalConfig[] = "global_config";
const char kNameSubscribe[] = "subscribe";
// Convert a dictionary value to a JSON string.
CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(dictionary);
return CefWriteJSON(value, JSON_WRITER_DEFAULT);
}
using CallbackType = CefMessageRouterBrowserSide::Callback;
void SendSuccess(CefRefPtr<CallbackType> callback,
CefRefPtr<CefDictionaryValue> result) {
callback->Success(GetJSON(result));
}
void SendFailure(CefRefPtr<CallbackType> callback,
int error_code,
const std::string& error_message) {
callback->Failure(error_code, error_message);
}
class PreferenceObserver : public CefPreferenceObserver {
public:
PreferenceObserver(CefRefPtr<CefPreferenceManager> manager,
bool global,
CefRefPtr<CallbackType> callback)
: manager_(manager), global_(global), callback_(callback) {}
PreferenceObserver(const PreferenceObserver&) = delete;
PreferenceObserver& operator=(const PreferenceObserver&) = delete;
void OnPreferenceChanged(const CefString& name) override {
CEF_REQUIRE_UI_THREAD();
auto value = manager_->GetPreference(name);
auto payload = CefDictionaryValue::Create();
payload->SetString("type", "preference");
payload->SetBool("global", global_);
payload->SetString("name", name);
if (value) {
payload->SetInt("value_type", value->GetType());
payload->SetValue("value", value);
} else {
payload->SetInt("value_type", VTYPE_NULL);
payload->SetNull("value");
}
SendSuccess(callback_, payload);
}
private:
const CefRefPtr<CefPreferenceManager> manager_;
const bool global_;
const CefRefPtr<CallbackType> callback_;
IMPLEMENT_REFCOUNTING(PreferenceObserver);
};
class SettingObserver : public CefSettingObserver {
public:
SettingObserver(CefRefPtr<CefRequestContext> context,
CefRefPtr<CallbackType> callback)
: context_(context), callback_(callback) {}
SettingObserver(const SettingObserver&) = delete;
SettingObserver& operator=(const SettingObserver&) = delete;
void OnSettingChanged(const CefString& requesting_url,
const CefString& top_level_url,
cef_content_setting_types_t content_type) override {
CEF_REQUIRE_UI_THREAD();
auto value = context_->GetWebsiteSetting(requesting_url, top_level_url,
content_type);
auto payload = CefDictionaryValue::Create();
payload->SetString("type", "setting");
payload->SetString("requesting_url", requesting_url);
payload->SetString("top_level_url", top_level_url);
payload->SetInt("content_type", static_cast<int>(content_type));
if (value) {
payload->SetInt("value_type", value->GetType());
payload->SetValue("value", value);
} else {
payload->SetInt("value_type", VTYPE_NULL);
payload->SetNull("value");
}
SendSuccess(callback_, payload);
}
private:
const CefRefPtr<CefRequestContext> context_;
const CefRefPtr<CallbackType> callback_;
IMPLEMENT_REFCOUNTING(SettingObserver);
};
// Handle messages in the browser process. Only accessed on the UI thread.
class Handler : public CefMessageRouterBrowserSide::Handler {
public:
typedef std::vector<std::string> NameVector;
Handler() { CEF_REQUIRE_UI_THREAD(); }
Handler(const Handler&) = delete;
Handler& operator=(const Handler&) = delete;
~Handler() override {
for (auto& pair : subscription_state_map_) {
delete pair.second;
}
}
// Called due to cefQuery execution in config.html.
bool OnQuery(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64_t query_id,
const CefString& request,
bool persistent,
CefRefPtr<Callback> callback) override {
CEF_REQUIRE_UI_THREAD();
// Only handle messages from the test URL.
const std::string& url = frame->GetURL();
if (!test_runner::IsTestURL(url, kTestUrlPath)) {
return false;
}
// Parse |request| as a JSON dictionary.
CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
if (!request_dict) {
callback->Failure(kMessageFormatError, "Incorrect message format");
return true;
}
// Verify the "name" key.
if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback)) {
return true;
}
const std::string& message_name = request_dict->GetString(kNameKey);
if (message_name == kNameGlobalConfig) {
// JavaScript is requesting a JSON representation of the global config.
SendGlobalConfig(callback);
return true;
} else if (message_name == kNameSubscribe) {
// Subscribe to notifications from observers.
if (!persistent) {
SendFailure(callback, kMessageFormatError,
"Subscriptions must be persistent");
return true;
}
if (!CreateSubscription(browser, query_id, callback)) {
SendFailure(callback, kRequestFailedError,
"Browser is already subscribed");
}
return true;
}
return false;
}
void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int64_t query_id) override {
CEF_REQUIRE_UI_THREAD();
RemoveSubscription(browser->GetIdentifier(), query_id);
}
private:
// Convert a JSON string to a dictionary value.
static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
if (value.get() && value->GetType() == VTYPE_DICTIONARY) {
return value->GetDictionary();
}
return nullptr;
}
// Verify that |key| exists in |dictionary| and has type |value_type|. Fails
// |callback| and returns false on failure.
static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
const char* key,
cef_value_type_t value_type,
CefRefPtr<Callback> callback) {
if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
callback->Failure(
kMessageFormatError,
"Missing or incorrectly formatted message key: " + std::string(key));
return false;
}
return true;
}
static CefRefPtr<CefListValue> MakeListValue(std::vector<CefString> vec) {
if (vec.empty()) {
return nullptr;
}
auto list = CefListValue::Create();
list->SetSize(vec.size());
size_t idx = 0;
for (const auto& val : vec) {
list->SetString(idx++, val);
}
return list;
}
void SendGlobalConfig(CefRefPtr<Callback> callback) {
std::vector<CefString> switches;
CefPreferenceManager::GetChromeVariationsAsSwitches(switches);
std::vector<CefString> strings;
CefPreferenceManager::GetChromeVariationsAsStrings(strings);
auto payload = CefDictionaryValue::Create();
if (auto list = MakeListValue(switches)) {
payload->SetList("switches", list);
} else {
payload->SetNull("switches");
}
if (auto list = MakeListValue(strings)) {
payload->SetList("strings", list);
} else {
payload->SetNull("strings");
}
SendSuccess(callback, payload);
}
// Subscription state associated with a single browser.
struct SubscriptionState {
int64_t query_id;
CefRefPtr<PreferenceObserver> global_pref_observer;
CefRefPtr<CefRegistration> global_pref_registration;
CefRefPtr<PreferenceObserver> context_pref_observer;
CefRefPtr<CefRegistration> context_pref_registration;
CefRefPtr<SettingObserver> context_setting_observer;
CefRefPtr<CefRegistration> context_setting_registration;
};
bool CreateSubscription(CefRefPtr<CefBrowser> browser,
int64_t query_id,
CefRefPtr<Callback> callback) {
const int browser_id = browser->GetIdentifier();
if (subscription_state_map_.find(browser_id) !=
subscription_state_map_.end()) {
// An subscription already exists for this browser.
return false;
}
auto global_pref_manager =
CefPreferenceManager::GetGlobalPreferenceManager();
auto request_context = browser->GetHost()->GetRequestContext();
SubscriptionState* state = new SubscriptionState();
state->query_id = query_id;
state->global_pref_observer =
new PreferenceObserver(global_pref_manager, /*global=*/true, callback);
state->global_pref_registration =
global_pref_manager->AddPreferenceObserver(CefString(),
state->global_pref_observer);
state->context_pref_observer =
new PreferenceObserver(request_context, /*global=*/false, callback);
state->context_pref_registration = request_context->AddPreferenceObserver(
CefString(), state->context_pref_observer);
state->context_setting_observer =
new SettingObserver(request_context, callback);
state->context_setting_registration =
request_context->AddSettingObserver(state->context_setting_observer);
subscription_state_map_[browser_id] = state;
return true;
}
void RemoveSubscription(int browser_id, int64_t query_id) {
SubscriptionStateMap::iterator it =
subscription_state_map_.find(browser_id);
if (it != subscription_state_map_.end() &&
it->second->query_id == query_id) {
delete it->second;
subscription_state_map_.erase(it);
}
}
// Map of browser ID to SubscriptionState object.
typedef std::map<int, SubscriptionState*> SubscriptionStateMap;
SubscriptionStateMap subscription_state_map_;
};
} // namespace
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
handlers.insert(new Handler());
}
} // namespace client::config_test

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2025 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.
#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CONFIG_TEST_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_CONFIG_TEST_H_
#pragma once
#include "tests/cefclient/browser/test_runner.h"
namespace client::config_test {
// Create message handlers. Called from test_runner.cc.
void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
} // namespace client::config_test
#endif // CEF_TESTS_CEFCLIENT_BROWSER_CONFIG_TEST_H_

View File

@@ -30,6 +30,7 @@ const char kNameValueSet[] = "preferences_set";
const char kNameValueState[] = "preferences_state";
// Used with "preferences_get" messages.
const char kGlobalPrefsKey[] = "global_prefs";
const char kIncludeDefaultsKey[] = "include_defaults";
// Used with "preferences_set" messages.
@@ -73,30 +74,34 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
if (message_name == kNameValueGet) {
// JavaScript is requesting a JSON representation of the preferences tree.
// Verify the "include_defaults" key.
if (!VerifyKey(request_dict, kIncludeDefaultsKey, VTYPE_BOOL, callback)) {
// Verify the "global_prefs" and "include_defaults" keys.
if (!VerifyKey(request_dict, kGlobalPrefsKey, VTYPE_BOOL, callback) ||
!VerifyKey(request_dict, kIncludeDefaultsKey, VTYPE_BOOL, callback)) {
return true;
}
const bool global_prefs = request_dict->GetBool(kGlobalPrefsKey);
const bool include_defaults = request_dict->GetBool(kIncludeDefaultsKey);
OnPreferencesGet(browser, include_defaults, callback);
OnPreferencesGet(browser, global_prefs, include_defaults, callback);
return true;
} else if (message_name == kNameValueSet) {
// JavaScript is requesting that preferences be updated to match the
// specified JSON representation.
// Verify the "preferences" key.
if (!VerifyKey(request_dict, kPreferencesKey, VTYPE_DICTIONARY,
// Verify the "global_prefs" and "preferences" keys.
if (!VerifyKey(request_dict, kGlobalPrefsKey, VTYPE_BOOL, callback) ||
!VerifyKey(request_dict, kPreferencesKey, VTYPE_DICTIONARY,
callback)) {
return true;
}
const bool global_prefs = request_dict->GetBool(kGlobalPrefsKey);
CefRefPtr<CefDictionaryValue> preferences =
request_dict->GetDictionary(kPreferencesKey);
OnPreferencesSet(browser, preferences, callback);
OnPreferencesSet(browser, global_prefs, preferences, callback);
return true;
} else if (message_name == kNameValueState) {
@@ -113,14 +118,19 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
private:
// Execute |callback| with the preferences dictionary as a JSON string.
static void OnPreferencesGet(CefRefPtr<CefBrowser> browser,
bool global_prefs,
bool include_defaults,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CefPreferenceManager> pref_manager;
if (global_prefs) {
pref_manager = CefPreferenceManager::GetGlobalPreferenceManager();
} else {
pref_manager = browser->GetHost()->GetRequestContext();
}
// Retrieve all preference values.
CefRefPtr<CefDictionaryValue> prefs =
context->GetAllPreferences(include_defaults);
pref_manager->GetAllPreferences(include_defaults);
// Serialize the preferences to JSON and return to the JavaScript caller.
callback->Success(GetJSON(prefs));
@@ -129,10 +139,15 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// Set preferences based on the contents of |preferences|. Execute |callback|
// with a descriptive result message.
static void OnPreferencesSet(CefRefPtr<CefBrowser> browser,
bool global_prefs,
CefRefPtr<CefDictionaryValue> preferences,
CefRefPtr<Callback> callback) {
CefRefPtr<CefRequestContext> context =
browser->GetHost()->GetRequestContext();
CefRefPtr<CefPreferenceManager> pref_manager;
if (global_prefs) {
pref_manager = CefPreferenceManager::GetGlobalPreferenceManager();
} else {
pref_manager = browser->GetHost()->GetRequestContext();
}
CefRefPtr<CefValue> value = CefValue::Create();
value->SetDictionary(preferences);
@@ -142,7 +157,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// Apply preferences. This may result in errors.
const bool success =
ApplyPrefs(context, std::string(), value, error, changed_names);
ApplyPrefs(pref_manager, std::string(), value, error, changed_names);
// Create a message that accurately represents the result.
std::string message;
@@ -245,14 +260,14 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// Apply preferences. Returns true on success. Returns false and sets |error|
// to a descriptive error string on failure. |changed_names| is the list of
// preferences that were successfully changed.
static bool ApplyPrefs(CefRefPtr<CefRequestContext> context,
static bool ApplyPrefs(CefRefPtr<CefPreferenceManager> pref_manager,
const std::string& name,
CefRefPtr<CefValue> value,
std::string& error,
NameVector& changed_names) {
if (!name.empty() && context->HasPreference(name)) {
if (!name.empty() && pref_manager->HasPreference(name)) {
// The preference exists. Set the value.
return SetPref(context, name, value, error, changed_names);
return SetPref(pref_manager, name, value, error, changed_names);
}
if (value->GetType() == VTYPE_DICTIONARY) {
@@ -265,7 +280,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
for (const auto& i : keys) {
const std::string& key = i;
const std::string& current_name = name.empty() ? key : name + "." + key;
if (!ApplyPrefs(context, current_name, dict->GetValue(key), error,
if (!ApplyPrefs(pref_manager, current_name, dict->GetValue(key), error,
changed_names)) {
return false;
}
@@ -282,12 +297,12 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// successfully or has not changed. If the value has changed then |name| will
// be added to |changed_names|. Returns false and sets |error| to a
// descriptive error string on failure.
static bool SetPref(CefRefPtr<CefRequestContext> context,
static bool SetPref(CefRefPtr<CefPreferenceManager> pref_manager,
const std::string& name,
CefRefPtr<CefValue> value,
std::string& error,
NameVector& changed_names) {
CefRefPtr<CefValue> existing_value = context->GetPreference(name);
CefRefPtr<CefValue> existing_value = pref_manager->GetPreference(name);
DCHECK(existing_value);
if (value->GetType() == VTYPE_STRING &&
@@ -322,7 +337,7 @@ class Handler : public CefMessageRouterBrowserSide::Handler {
// Attempt to set the preference.
CefString error_str;
if (!context->SetPreference(name, value, error_str)) {
if (!pref_manager->SetPreference(name, value, error_str)) {
error = error_str.ToString() + ": " + name;
return false;
}

View File

@@ -46,32 +46,33 @@
#define IDC_STATIC -1
#define IDS_BINARY_TRANSFER_HTML 1000
#define IDS_BINDING_HTML 1001
#define IDS_DIALOGS_HTML 1002
#define IDS_DRAGGABLE_HTML 1003
#define IDS_HANG_HTML 1004
#define IDS_IPC_PERFORMANCE_HTML 1005
#define IDS_LOCALSTORAGE_HTML 1006
#define IDS_LOGO_PNG 1007
#define IDS_MEDIA_ROUTER_HTML 1008
#define IDS_MENU_ICON_1X_PNG 1009
#define IDS_MENU_ICON_2X_PNG 1010
#define IDS_OSRTEST_HTML 1011
#define IDS_OTHER_TESTS_HTML 1012
#define IDS_PDF_HTML 1013
#define IDS_PDF_PDF 1014
#define IDS_PERFORMANCE_HTML 1015
#define IDS_PERFORMANCE2_HTML 1016
#define IDS_PREFERENCES_HTML 1017
#define IDS_RESPONSE_FILTER_HTML 1018
#define IDS_SERVER_HTML 1019
#define IDS_TASK_MANAGER_HTML 1020
#define IDS_TRANSPARENCY_HTML 1021
#define IDS_URLREQUEST_HTML 1022
#define IDS_WEBSOCKET_HTML 1023
#define IDS_WINDOW_HTML 1024
#define IDS_WINDOW_ICON_1X_PNG 1025
#define IDS_WINDOW_ICON_2X_PNG 1026
#define IDS_XMLHTTPREQUEST_HTML 1027
#define IDS_CONFIG_HTML 1002
#define IDS_DIALOGS_HTML 1003
#define IDS_DRAGGABLE_HTML 1004
#define IDS_HANG_HTML 1005
#define IDS_IPC_PERFORMANCE_HTML 1006
#define IDS_LOCALSTORAGE_HTML 1007
#define IDS_LOGO_PNG 1008
#define IDS_MEDIA_ROUTER_HTML 1009
#define IDS_MENU_ICON_1X_PNG 1010
#define IDS_MENU_ICON_2X_PNG 1011
#define IDS_OSRTEST_HTML 1012
#define IDS_OTHER_TESTS_HTML 1013
#define IDS_PDF_HTML 1014
#define IDS_PDF_PDF 1015
#define IDS_PERFORMANCE_HTML 1016
#define IDS_PERFORMANCE2_HTML 1017
#define IDS_PREFERENCES_HTML 1018
#define IDS_RESPONSE_FILTER_HTML 1019
#define IDS_SERVER_HTML 1020
#define IDS_TASK_MANAGER_HTML 1021
#define IDS_TRANSPARENCY_HTML 1022
#define IDS_URLREQUEST_HTML 1023
#define IDS_WEBSOCKET_HTML 1024
#define IDS_WINDOW_HTML 1025
#define IDS_WINDOW_ICON_1X_PNG 1026
#define IDS_WINDOW_ICON_2X_PNG 1027
#define IDS_XMLHTTPREQUEST_HTML 1028
// Next default values for new objects
//

View File

@@ -15,6 +15,7 @@ int GetResourceId(const char* resource_name) {
int id;
} resource_map[] = {{"binary_transfer.html", IDS_BINARY_TRANSFER_HTML},
{"binding.html", IDS_BINDING_HTML},
{"config.html", IDS_CONFIG_HTML},
{"dialogs.html", IDS_DIALOGS_HTML},
{"draggable.html", IDS_DRAGGABLE_HTML},
{"hang.html", IDS_HANG_HTML},

View File

@@ -21,6 +21,7 @@
#include "tests/cefclient/browser/base_client_handler.h"
#include "tests/cefclient/browser/binary_transfer_test.h"
#include "tests/cefclient/browser/binding_test.h"
#include "tests/cefclient/browser/config_test.h"
#include "tests/cefclient/browser/dialog_test.h"
#include "tests/cefclient/browser/hang_test.h"
#include "tests/cefclient/browser/main_context.h"
@@ -865,6 +866,9 @@ void CreateMessageHandlers(MessageHandlerSet& handlers) {
// Create the binding test handlers.
binding_test::CreateMessageHandlers(handlers);
// Create the config test handlers.
config_test::CreateMessageHandlers(handlers);
// Create the dialog test handlers.
dialog_test::CreateMessageHandlers(handlers);

View File

@@ -48,6 +48,7 @@ void TerminationSignalHandler(int signatl) {
MainContext::Get()->GetRootWindowManager()->CloseAllWindows(true);
}
NO_STACK_PROTECTOR
int RunMain(int argc, char* argv[]) {
// Create a copy of |argv| on Linux because Chromium mangles the value
// internally (see issue #620).
@@ -158,6 +159,7 @@ int RunMain(int argc, char* argv[]) {
} // namespace client
// Program entry point function.
NO_STACK_PROTECTOR
int main(int argc, char* argv[]) {
return client::RunMain(argc, argv);
}

View File

@@ -0,0 +1,703 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Configuration Test</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<style>
body {
font-family: Verdana, Arial;
font-size: 12px;
}
#message {
color: red;
font-weight: bold;
font-size: 14px;
}
.desc {
font-size: 14px;
}
.foot {
font-size: 11px;
}
.mono {
font-family: monospace;
}
.cat_header_0 {
font-weight: bold;
font-size: 14px;
}
.cat_header_1 {
font-weight: bold;
}
.cat_header_2 {
font-family: Verdana, Arial;
}
.cat_body {
font-family: monospace;
white-space: pre;
margin-left: 10px;
}
#temp-message {
display: none;
background-color: #f0f0f0;
border: 1px solid #ccc;
padding: 10px;
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
.hr-container {
display: flex;
align-items: center;
text-align: center;
}
.hr-line {
border-top: 1px solid black;
width: 100%;
margin: 0 3px;
}
.hr-text {
padding: 0;
white-space: nowrap;
}
</style>
<script>
function onLoad() {
if (location.hostname != 'tests') {
onCefError(0, 'This page can only be run from tests.');
// Disable all form elements.
var elements = document.getElementById("form").elements;
for (var i = 0, element; element = elements[i++]; ) {
element.disabled = true;
}
return;
}
getGlobalConfig();
updateFilter();
startSubscription();
}
function onUnload() {
stopSubscription();
}
function onCefError(code, message) {
val = 'ERROR: ' + message;
if (code !== 0) {
val += ' (' + code + ')';
}
document.getElementById('message').innerHTML = val + '<br/><br/>';
}
function sendCefQuery(payload, onSuccess, onFailure=onCefError, persistent=false) {
// Results in a call to the OnQuery method in config_test.cc
return window.cefQuery({
request: JSON.stringify(payload),
onSuccess: onSuccess,
onFailure: onFailure,
persistent: persistent
});
}
// Request the global configuration.
function getGlobalConfig() {
sendCefQuery(
{name: 'global_config'},
(message) => onGlobalConfigMessage(JSON.parse(message)),
);
}
// Display the global configuration response.
function onGlobalConfigMessage(message) {
document.getElementById('global_switches').innerHTML =
message.switches !== null ? message.switches.join('<br/>') : '(none)';
if (message.strings !== null) {
document.getElementById('global_strings').innerHTML = message.strings.join('<br/>');
document.getElementById('global_strings_ct').textContent = message.strings.length;
}
}
var currentSubscriptionId = null;
// Subscribe to ongoing message notifications from the native code.
function startSubscription() {
currentSubscriptionId = sendCefQuery(
{name: 'subscribe'},
(message) => onSubscriptionMessage(JSON.parse(message)),
(code, message) => {
onCefError(code, message);
currentSubscriptionId = null;
},
true
);
}
// Unsubscribe from message notifications.
function stopSubscription() {
if (currentSubscriptionId !== null) {
// Results in a call to the OnQueryCanceled method in config_test.cc
window.cefQueryCancel(currentSubscriptionId);
}
}
// Returns a nice timestamp for display purposes.
function getNiceTimestamp() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
var paused = false;
var paused_messages = [];
var first_after_pause = false;
// Toggle whether messages are displayed or queued.
function togglePause() {
paused = !paused;
document.getElementById("pause_button").value = paused ? "Resume" : "Pause";
if (!paused) {
first_after_pause = true;
while (paused_messages.length > 0) {
onSubscriptionMessage(paused_messages.shift());
}
}
}
function doPause() {
if (!paused) {
togglePause();
showTempMessage('Event processing is paused. Click Resume to continue.');
}
}
var filter = {}
var filtered_ct = 0;
var filter_updating = false;
// Populate |filter| based on form control state.
function updateFilter() {
if (filter_updating) {
// Ignore changes triggered from individual elements while we're updating multiple.
return;
}
filter.text = document.getElementById("filter_text").value.trim().toLowerCase();
filter.global_prefs = document.getElementById("filter_global_prefs").checked;
filter.context_prefs = document.getElementById("filter_context_prefs").checked;
filter.context_settings = document.getElementById("filter_context_settings").checked;
}
function doFilter(type, text, global=false) {
filter_updating = true;
document.getElementById("filter_text").value = text;
var checked = '';
if (type === 'preference') {
checked = global ? 'filter_global_prefs' : 'filter_context_prefs';
} else if (type === 'setting') {
checked = 'filter_context_settings';
}
['filter_global_prefs', 'filter_context_prefs', 'filter_context_settings'].forEach(function(id) {
document.getElementById(id).checked = id === checked;
});
filter_updating = false;
updateFilter();
}
function doFilterReset() {
filter_updating = true;
document.getElementById("filtered_ct").textContent = 0;
document.getElementById("filter_text").value = '';
document.getElementById("filter_global_prefs").checked = true;
document.getElementById("filter_context_prefs").checked = true;
document.getElementById("filter_context_settings").checked = true;
filter_updating = false;
updateFilter();
}
// Returns true if the message should be displayed based on the current filter settings.
function passesFilter(message) {
if (message.type === 'preference') {
if (message.global) {
if (!filter.global_prefs) {
return false;
}
} else if (!filter.context_prefs) {
return false;
}
} else if (message.type === 'setting' && !filter.context_settings) {
return false;
}
if (filter.text.length > 0) {
var check_text = JSON.stringify(message).toLowerCase();
if (message.type === 'setting') {
check_text += ' ' + getSettingTypeLabel(message.content_type).toLowerCase();
}
if (check_text.indexOf(filter.text) < 0) {
return false;
}
}
return true;
}
// Match the cef_value_type_t values from include/internal/cef_types.h
const value_types = [
'INVALID',
'NULL',
'BOOL',
'INT',
'DOUBLE',
'STRING',
'BINARY',
'DICTIONARY',
'LIST',
]
function getValueType(index) {
if (index < 0 || index >= value_types.length) {
return 'UNKNOWN';
}
return value_types[index];
}
// Match the cef_content_setting_types_t values from include/internal/cef_types_content_settings.h
const setting_types = [
"COOKIES",
"IMAGES",
"JAVASCRIPT",
"POPUPS",
"GEOLOCATION",
"NOTIFICATIONS",
"AUTO_SELECT_CERTIFICATE",
"MIXEDSCRIPT",
"MEDIASTREAM_MIC",
"MEDIASTREAM_CAMERA",
"PROTOCOL_HANDLERS",
"DEPRECATED_PPAPI_BROKER",
"AUTOMATIC_DOWNLOADS",
"MIDI_SYSEX",
"SSL_CERT_DECISIONS",
"PROTECTED_MEDIA_IDENTIFIER",
"APP_BANNER",
"SITE_ENGAGEMENT",
"DURABLE_STORAGE",
"USB_CHOOSER_DATA",
"BLUETOOTH_GUARD",
"BACKGROUND_SYNC",
"AUTOPLAY",
"IMPORTANT_SITE_INFO",
"PERMISSION_AUTOBLOCKER_DATA",
"ADS",
"ADS_DATA",
"MIDI",
"PASSWORD_PROTECTION",
"MEDIA_ENGAGEMENT",
"SOUND",
"CLIENT_HINTS",
"SENSORS",
"DEPRECATED_ACCESSIBILITY_EVENTS",
"PAYMENT_HANDLER",
"USB_GUARD",
"BACKGROUND_FETCH",
"INTENT_PICKER_DISPLAY",
"IDLE_DETECTION",
"SERIAL_GUARD",
"SERIAL_CHOOSER_DATA",
"PERIODIC_BACKGROUND_SYNC",
"BLUETOOTH_SCANNING",
"HID_GUARD",
"HID_CHOOSER_DATA",
"WAKE_LOCK_SCREEN",
"WAKE_LOCK_SYSTEM",
"LEGACY_COOKIE_ACCESS",
"FILE_SYSTEM_WRITE_GUARD",
"NFC",
"BLUETOOTH_CHOOSER_DATA",
"CLIPBOARD_READ_WRITE",
"CLIPBOARD_SANITIZED_WRITE",
"SAFE_BROWSING_URL_CHECK_DATA",
"VR",
"AR",
"FILE_SYSTEM_READ_GUARD",
"STORAGE_ACCESS",
"CAMERA_PAN_TILT_ZOOM",
"WINDOW_MANAGEMENT",
"INSECURE_PRIVATE_NETWORK",
"LOCAL_FONTS",
"PERMISSION_AUTOREVOCATION_DATA",
"FILE_SYSTEM_LAST_PICKED_DIRECTORY",
"DISPLAY_CAPTURE",
"FILE_SYSTEM_ACCESS_CHOOSER_DATA",
"FEDERATED_IDENTITY_SHARING",
"JAVASCRIPT_JIT",
"HTTP_ALLOWED",
"FORMFILL_METADATA",
"DEPRECATED_FEDERATED_IDENTITY_ACTIVE_SESSION",
"AUTO_DARK_WEB_CONTENT",
"REQUEST_DESKTOP_SITE",
"FEDERATED_IDENTITY_API",
"NOTIFICATION_INTERACTIONS",
"REDUCED_ACCEPT_LANGUAGE",
"NOTIFICATION_PERMISSION_REVIEW",
"PRIVATE_NETWORK_GUARD",
"PRIVATE_NETWORK_CHOOSER_DATA",
"FEDERATED_IDENTITY_IDENTITY_PROVIDER_SIGNIN_STATUS",
"REVOKED_UNUSED_SITE_PERMISSIONS",
"TOP_LEVEL_STORAGE_ACCESS",
"FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION",
"FEDERATED_IDENTITY_IDENTITY_PROVIDER_REGISTRATION",
"ANTI_ABUSE",
"THIRD_PARTY_STORAGE_PARTITIONING",
"HTTPS_ENFORCED",
"ALL_SCREEN_CAPTURE",
"COOKIE_CONTROLS_METADATA",
"TPCD_HEURISTICS_GRANTS",
"TPCD_METADATA_GRANTS",
"TPCD_TRIAL",
"TOP_LEVEL_TPCD_TRIAL",
"TOP_LEVEL_TPCD_ORIGIN_TRIAL",
"AUTO_PICTURE_IN_PICTURE",
"FILE_SYSTEM_ACCESS_EXTENDED_PERMISSION",
"FILE_SYSTEM_ACCESS_RESTORE_PERMISSION",
"CAPTURED_SURFACE_CONTROL",
"SMART_CARD_GUARD",
"SMART_CARD_DATA",
"WEB_PRINTING",
"AUTOMATIC_FULLSCREEN",
"SUB_APP_INSTALLATION_PROMPTS",
"SPEAKER_SELECTION",
"DIRECT_SOCKETS",
"KEYBOARD_LOCK",
"POINTER_LOCK",
"REVOKED_ABUSIVE_NOTIFICATION_PERMISSIONS",
"TRACKING_PROTECTION",
"DISPLAY_MEDIA_SYSTEM_AUDIO",
"JAVASCRIPT_OPTIMIZER",
"STORAGE_ACCESS_HEADER_ORIGIN_TRIAL",
"HAND_TRACKING",
"WEB_APP_INSTALLATION",
"DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS",
"LEGACY_COOKIE_SCOPE",
"ARE_SUSPICIOUS_NOTIFICATIONS_ALLOWLISTED_BY_USER",
"CONTROLLED_FRAME",
];
function getSettingType(index) {
if (index < 0 || index >= setting_types.length) {
return 'UNKNOWN';
}
return setting_types[index];
}
function getSettingTypeLabel(type) {
return getSettingType(type) + ' (' + type + ')'
}
function makeDetails(summaryHTML, summaryClass, contentHTML, contentClass, contentId=null, open=false) {
const newDetails = document.createElement('details');
if (open) {
newDetails.open = true;
}
const newSummary = document.createElement('summary');
newSummary.innerHTML = summaryHTML;
if (summaryClass !== null) {
newSummary.className = summaryClass;
}
newDetails.append(newSummary);
const newContent = document.createElement('p');
newContent.innerHTML = contentHTML
if (contentClass !== null) {
newContent.className = contentClass;
}
if (contentId !== null) {
newContent.id = contentId;
}
newDetails.append(newContent);
const newP = document.createElement('p');
newP.append(newDetails);
return newP;
}
function makeValueExample(value, value_type) {
code = '\n// Create a CefValue object programmatically:\n' +
'auto value = CefValue::Create();\n';
if (value === null || getValueType(value_type) == 'NULL') {
code += 'value->SetNull();\n';
} else if (typeof value === 'boolean' || getValueType(value_type) == 'BOOL') {
code += 'value->SetBool(' + (value ? 'true' : 'false') + ');\n';
} else if (Number.isInteger(value) || getValueType(value_type) == 'INT') {
code += 'value->SetInt(' + value + ');\n';
} else if (typeof value === 'number' || getValueType(value_type) == 'DOUBLE') {
code += 'value->SetDouble(' + value + ');\n';
} else if (typeof value === 'string' || getValueType(value_type) == 'STRING') {
code += 'value->SetString("' + value + '");\n';
} else if (Array.isArray(value) || getValueType(value_type) == 'LIST') {
code += 'auto listValue = CefListValue::Create();\n';
if (value.length > 0) {
code += '\n// TODO: Populate |listValue| using CefListValue::Set* methods.\n\n';
}
code += 'value->SetList(listValue);\n';
if (value.length > 0) {
code += '\n// ALTERNATELY: Create a CefValue object by parsing a JSON string:\n' +
'auto value = CefParseJSON("[ ... ]", JSON_PARSER_RFC);\n';
}
} else if (typeof value === 'object' || getValueType(value_type) == 'DICTIONARY') {
code += 'auto dictValue = CefDictionaryValue::Create();\n';
const has_value = Object.keys(value).length > 0;
if (has_value) {
code += '\n// TODO: Populate |dictValue| using CefDictionaryValue::Set* methods.\n\n';
}
code += 'value->SetDictionary(dictValue);\n';
if (has_value) {
code += '\n// ALTERNATELY: Create a CefValue object by parsing a JSON string:\n' +
'auto value = CefParseJSON("{ ... }", JSON_PARSER_RFC);\n';
}
} else {
code += '\n//TODO: Populate |value|.\n\n';
}
return code;
}
function makeCopyLink(elem_id) {
return '<a href="#" onMouseDown="copyToClipboard(\'' + elem_id + '\')" onClick="return false">[copy to clipboard]</a>';
}
function makeContent(elem_id, content) {
const content_id = 'cn-' + elem_id;
return makeDetails('Content ' + makeCopyLink(content_id), 'cat_header_2', content, 'cat_body', content_id, true);
}
function makeHR(label) {
const container = document.createElement('div');
container.className = 'hr-container';
const line1 = document.createElement('div');
line1.className = 'hr-line';
container.append(line1);
const text = document.createElement('span');
text.className = 'hr-text';
text.innerHTML = label;
container.append(text);
const line2 = document.createElement('div');
line2.className = 'hr-line';
container.append(line2);
return container;
}
function makeCodeExample(elem_id, message) {
const example_id = 'ex-' + elem_id;
var code = '// Code must be executed on the browser process UI thread.\n\n';
if (message.type === "preference") {
if (message.global) {
code += 'auto pref_manager = CefPreferenceManager::GetGlobalPreferenceManager();\n';
} else {
code += '// |browser| is an existing CefBrowser instance.\n' +
'auto pref_manager = browser->GetHost()->GetRequestContext();\n';
}
code += makeValueExample(message.value, message.value_type) + '\n' +
'CefString error;\n' +
'bool success = pref_manager->SetPreference("' + message.name + '", value, error);\n' +
'if (!success) {\n' +
' // TODO: Use |error| to diagnose the failure.\n' +
'}\n';
} else if (message.type === "setting") {
const type = getSettingType(message.content_type);
const content_type = type !== 'UNKNOWN' ? 'CEF_CONTENT_SETTING_TYPE_' + type : message.content_type;
code += '// |browser| is an existing CefBrowser instance.\n' +
'auto context = browser->GetHost()->GetRequestContext();\n' +
makeValueExample(message.value, message.value_type) + '\n' +
'context->SetWebsiteSetting("' + message.requesting_url + '", "' + message.top_level_url +
'", '+ content_type +', value);\n';
}
return makeDetails('C++ Code Example ' + makeCopyLink(example_id), 'cat_header_2', code, 'cat_body', example_id, false);
}
var message_ct = 0;
// A new message has arrived. It may be queued, filtered out or displayed.
function onSubscriptionMessage(message) {
if (paused) {
// Queue the message until the user clicks Resume.
message.timestamp = getNiceTimestamp();
paused_messages.push(message);
document.getElementById("pause_button").value = 'Resume (' + paused_messages.length + ')';
return;
}
if (!passesFilter(message)) {
// Filter out the message.
filtered_ct++;
document.getElementById("filtered_ct").innerHTML = filtered_ct;
return;
}
// Use the arrival timestamp for queued messages.
var timestamp;
if (message.timestamp) {
timestamp = message.timestamp;
delete message.timestamp;
} else {
timestamp = getNiceTimestamp();
}
// Display the message.
var label = timestamp + ': ';
var content = 'value_type=' + getValueType(message.value_type);
var search = '';
var filter = '';
if (message.type === "preference") {
label += 'Preference (' + (message.global ? 'Global' : 'Profile') +
') <span class="mono">' + message.name + '</span>';
search = '%5C%22' + message.name + '%5C%22';
filter = "'preference', '" + message.name + "', " + (message.global ? 'true' : 'false');
} else if (message.type === "setting") {
label += 'Setting <span class="mono">' + getSettingTypeLabel(message.content_type) + '</span>';
const setting_type = getSettingType(message.content_type);
search = 'ContentSettingsType::' + setting_type;
filter = "'setting', '" + setting_type + "'";
content = 'requesting_url=' + message.requesting_url +
'\ntop_level_url=' + message.top_level_url +
'\n' + content;
}
content += '\nvalue=' + JSON.stringify(message.value, null, 1);
label += ' <a href="#" onMouseDown="doFilter(' + filter + ')" onClick="return false">[filter]</a>' +
' <a href="https://source.chromium.org/search?q=' + search + '" target="_blank">[search &#x1F517]</a>';
const messages = document.getElementById('messages');
if (first_after_pause) {
messages.prepend(makeHR('RESUMED'));
first_after_pause = false;
}
const elem_id = message_ct++;
const newDetails = makeDetails(label, null, makeContent(elem_id, content).outerHTML +
makeCodeExample(elem_id, message).outerHTML, 'cat_body');
messages.prepend(newDetails);
}
// Clear filter count and displayed/pending messages.
function doClear() {
filtered_ct = 0;
document.getElementById("filtered_ct").textContent = 0;
document.getElementById('messages').innerHTML = '';
if (paused) {
paused_messages = [];
document.getElementById("pause_button").value = 'Resume';
}
message_ct = 0;
}
function showTempMessage(msg) {
const element = document.getElementById("temp-message");
element.innerHTML = msg;
element.style.display = "block";
setTimeout(function() {
element.style.display = "none";
}, 3000);
}
function copyToClipboard(elementId) {
const element = document.getElementById(elementId);
if (!element) {
return;
}
// Make all parent details nodes are open, otherwise nothing will be copied to the clipboard.
var parent = element.parentNode;
while (parent) {
if (parent.nodeName === 'DETAILS') {
if (!parent.open) {
parent.open = true;
}
}
parent = parent.parentNode;
}
navigator.clipboard.writeText(element.outerText)
.then(() => {
showTempMessage('Text copied to clipboard.');
})
.catch(err => {
showTempMessage('Failed to copy text to clipboard!');
console.error('Failed to copy text: ', err);
});
}
</script>
</head>
<body bgcolor="white" onload="onLoad()" onunload="onUnload()">
<div id="message"></div>
<details open>
<summary class="cat_header_0">Startup configuration</summary>
<p class="desc">
This section displays the global configuration (Chrome Variations) that was applied at startup.
Chrome Variations can be configured via chrome://flags <sup>[*]</sup>, via the below command-line switches, or via field trials (disabled in Official builds).
The Active Variations section below is the human-readable equivalent of the "Active Variations" section of chrome://version.
See <a href="https://developer.chrome.com/docs/web-platform/chrome-variations" target="_blank">Chrome Variations docs</a> for background.
</p>
<p class="foot">
* Flags are stored in the global <span class="mono">browser.enabled_labs_experiments</span> preference.
</p>
<p class="cat_header_1">Command-Line Switches:</p>
<p class="cat_body" id="global_switches"></p>
<details>
<summary class="cat_header_1">Active Variations (<span id="global_strings_ct">0</span>)</summary>
<p class="cat_body" id="global_strings"></p>
</details>
</details>
<br/>
<details open>
<summary class="cat_header_0">Runtime configuration</summary>
<p class="desc">
This section displays preference and site settings changes that occur during runtime.
Chromium stores both global and Profile-specific preferences.
See <a href="https://www.chromium.org/developers/design-documents/preferences/" target="_blank">Preferences docs</a> for background.
To view a snapshot of all preferences go <a href="https://tests/preferences#advanced">here</a> instead.
</p>
<p id="filter">
<form id="form">
Text Contains: <input type="text" id="filter_text"/> <input type="button" onclick="updateFilter();" value="Apply"/>
<br/>Show: <input type="checkbox" id="filter_global_prefs" onChange="updateFilter()" checked /> Global preferences
<input type="checkbox" id="filter_context_prefs" onChange="updateFilter()" checked /> Profile-specific preferences
<input type="checkbox" id="filter_context_settings" onChange="updateFilter()" checked /> Site settings <sup>[*]</sup>
<br/><input type="button" id="clear_button" onclick="doClear()" value="Clear"/>
<input type="button" id="pause_button" onclick="togglePause()" value="Pause"/> <sup>[**]</sup> Filtered out: <span id="filtered_ct">0</span>
<input type="button" id="reset_button" onclick="doFilterReset()" value="Reset"/>
<p class="foot">
* Site settings are stored in the Profile-specific <span class="mono">profile.content_settings</span> preference and can be modified via chrome://settings/content.
<br/>** Events will not be displayed or filtered out while processing is paused.
</p>
</form>
</p>
<div id="messages" onMouseDown="doPause()"></div>
<div id="temp-message"></div>
</details>
</body>
</html>

View File

@@ -10,6 +10,7 @@
<li><a href="https://jigsaw.w3.org/HTTP/Basic/">Authentication (Basic)</a> - credentials returned via GetAuthCredentials</li>
<li><a href="https://jigsaw.w3.org/HTTP/Digest/">Authentication (Digest)</a> - credentials returned via GetAuthCredentials</li>
<li><a href="binary_transfer">Binary vs String Transfer Benchmark</a></li>
<li><a href="config">Chrome Configuration</a></li>
<li><a href="http://html5advent2011.digitpaint.nl/3/index.html">Cursors</a></li>
<li><a href="dialogs">Dialogs</a></li>
<li><a href="http://html5demos.com/drag">Drag & Drop</a></li>

View File

@@ -13,8 +13,12 @@
<script>
function setup() {
if (location.hostname == 'tests' || location.hostname == 'localhost')
if (location.hostname === 'tests' || location.hostname === 'localhost') {
if (location.hash === '#advanced') {
toggleView();
}
return;
}
alert('This page can only be run from tests or localhost.');
@@ -96,7 +100,8 @@
<tr>
<td align="left">
<input type="button" value="Refresh" onClick="refreshEditor()"/>
<input type="checkbox" id="hide_defaults"/> Show modified preferences only
<input type="checkbox" id="global_prefs" onChange="refreshEditor()"/> Show global preferences
<input type="checkbox" id="hide_defaults" onChange="refreshEditor()"/> Show modified preferences only
</td>
<td align="right">
<input type="button" value="Apply Changes" onClick="applyEditorChanges()"/>
@@ -161,10 +166,11 @@
// Get the preferences and execute |onSuccessCallback| with the resulting
// JSON object.
function getPreferences(include_defaults, onSuccessCallback) {
function getPreferences(global_prefs, include_defaults, onSuccessCallback) {
// Create the request object.
var request = {};
request.name = "preferences_get";
request.global_prefs = global_prefs;
request.include_defaults = include_defaults;
// Send the request to C++.
@@ -177,10 +183,11 @@
}
// Set the preferences.
function setPreferences(preferences) {
function setPreferences(global_prefs, preferences) {
// Create the request object.
var request = {};
request.name = "preferences_set";
request.global_prefs = global_prefs;
request.preferences = preferences;
// Send the request to C++.
@@ -214,8 +221,9 @@
// Refresh the editor view contents.
function refreshEditor() {
global_prefs = document.getElementById("global_prefs").checked;
include_defaults = !document.getElementById("hide_defaults").checked;
getPreferences(include_defaults, function(response) {
getPreferences(global_prefs, include_defaults, function(response) {
// Set the JSON in the editor.
editor.set(response);
});
@@ -223,12 +231,13 @@
// Apply changes from the editor view.
function applyEditorChanges() {
setPreferences(editor.get());
global_prefs = document.getElementById("global_prefs").checked;
setPreferences(global_prefs, editor.get());
}
// Refresh the simple view contents.
function refreshSimple() {
getPreferences(true, function(response) {
getPreferences(false, true, function(response) {
// Spellcheck settings.
if (preferences_state.spellcheck_disabled) {
// Cannot enable spell checking when disabled via the command-line.
@@ -318,7 +327,7 @@
}
if (has_preferences)
setPreferences(preferences);
setPreferences(false, preferences);
}
// Called when the proxy type is changed.

View File

@@ -31,6 +31,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
IDS_BINARY_TRANSFER_HTML BINARY "tests\\cefclient\\resources\\binary_transfer.html"
IDS_BINDING_HTML BINARY "tests\\cefclient\\resources\\binding.html"
IDS_CONFIG_HTML BINARY "tests\\cefclient\\resources\\config.html"
IDS_DIALOGS_HTML BINARY "tests\\cefclient\\resources\\dialogs.html"
IDS_DRAGGABLE_HTML BINARY "tests\\cefclient\\resources\\draggable.html"
IDS_HANG_HTML BINARY "tests\\cefclient\\resources\\hang.html"

View File

@@ -212,4 +212,9 @@ if(OS_WINDOWS)
# Copy binary and resource files to the target output directory.
COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
if(USE_SANDBOX)
# Set LPAC ACLs required for Windows sandbox support.
SET_LPAC_ACLS("${CEF_TARGET}")
endif()
endif()

View File

@@ -31,6 +31,7 @@ int XIOErrorHandlerImpl(Display* display) {
#endif // defined(CEF_X11)
// Entry point function for all processes.
NO_STACK_PROTECTOR
int main(int argc, char* argv[]) {
// Provide CEF with command-line arguments.
CefMainArgs main_args(argc, argv);

View File

@@ -260,4 +260,9 @@ if(OS_WINDOWS)
"resources/"
)
COPY_RESOURCES("${CEF_TARGET}" "${UNITTESTS_DATA_RESOURCES_SRCS}" "${PREFIXES}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET_OUT_DIR}/ceftests_files")
if(USE_SANDBOX)
# Set LPAC ACLs required for Windows sandbox support.
SET_LPAC_ACLS("${CEF_TARGET}")
endif()
endif()

View File

@@ -1248,11 +1248,7 @@ class CookieAccessSchemeHandlerFactory : public CefSchemeHandlerFactory,
}
void Shutdown(base::OnceClosure complete_callback) {
if (!CefCurrentlyOn(TID_IO)) {
CefPostTask(TID_IO, base::BindOnce(std::move(complete_callback)));
return;
}
EXPECT_IO_THREAD();
std::move(complete_callback).Run();
}
@@ -1587,6 +1583,7 @@ class CookieAccessTestHandler : public RoutingTestHandler,
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override {
EXPECT_IO_THREAD();
if (test_backend_ == RESOURCE_HANDLER && scheme_factory_) {
return scheme_factory_->Create(browser, frame, scheme_, request);
}
@@ -1810,6 +1807,13 @@ class CookieAccessTestHandler : public RoutingTestHandler,
}
void ShutdownSchemeHandler(base::OnceClosure complete_callback) {
if (!CefCurrentlyOn(TID_IO)) {
CefPostTask(TID_IO, base::BindOnce(
&CookieAccessTestHandler::ShutdownSchemeHandler,
this, std::move(complete_callback)));
return;
}
EXPECT_TRUE(scheme_factory_);
if (test_backend_ == SCHEME_HANDLER) {

View File

@@ -134,6 +134,7 @@ class ScopedPlatformSetup final {
} // namespace
NO_STACK_PROTECTOR
int main(int argc, char* argv[]) {
int exit_code;

View File

@@ -19,6 +19,6 @@ TEST(VersionTest, VersionInfo) {
TEST(VersionTest, ApiHash) {
EXPECT_STREQ(CEF_API_HASH_PLATFORM, cef_api_hash(CEF_API_VERSION, 0));
EXPECT_STREQ(CEF_API_HASH_UNIVERSAL, cef_api_hash(CEF_API_VERSION, 1));
EXPECT_STREQ(CEF_API_HASH_PLATFORM, cef_api_hash(CEF_API_VERSION, 1));
EXPECT_STREQ(CEF_COMMIT_HASH, cef_api_hash(CEF_API_VERSION, 2));
}

View File

@@ -4,343 +4,381 @@
from __future__ import absolute_import
from __future__ import print_function
from typing import Dict, List
from clang_util import clang_eval
from file_util import *
import hashlib
import itertools
import os
import re
import string
import sys
import time
from version_util import EXP_VERSION
# Determines string type for python 2 and python 3.
if sys.version_info[0] == 3:
string_type = str
else:
string_type = basestring
API_TOKEN = '#if CEF_API'
OS_TOKEN = '#if defined(OS_'
INCLUDE_START_MARKER = 'int begin_includes_tag;\n'
INCLUDE_DIRS = [
'.', # Includes relative to the 'src/cef' directory.
'..', # Includes relative to the 'src' directory.
]
PLATFORM_DEFINES = {
'windows': ['OS_WIN', 'ARCH_CPU_X86_64'],
'mac': ['OS_MAC', 'OS_POSIX', 'ARCH_CPU_ARM64'],
'linux': ['OS_LINUX', 'OS_POSIX', 'CEF_X11', 'ARCH_CPU_X86_64'],
}
SYSTEM_INCLUDES_PATTERN = re.compile(r'(#include <[^>]+>)')
FUNCTION_DECLARATION_PATTERN = re.compile(
r'\nCEF_EXPORT\s+?.*?\s+?(\w+)\s*?\(.*?\)\s*?;', re.DOTALL)
STRUCT_PATTERN = re.compile(
r'\ntypedef\s+?struct\s+?(\w+)\s+?\{.*?\}\s+?(\w+)\s*?;', re.DOTALL)
ENUM_PATTERN = re.compile(r'\ntypedef\s+?enum\s+?\{.*?\}\s+?(\w+)\s*?;',
re.DOTALL)
TYPEDEF_PATTERN = re.compile(r'\ntypedef\s+?.*?\s+(\w+);')
WHITESPACE_PATTERN = re.compile(r'\s+')
PARENTHESIS_PATTERN = re.compile(r'\(\s+')
SINGLE_LINE_COMMENT_PATTERN = re.compile(r'//.*\n')
CEF_STRING_TYPE_PATTERN = re.compile(
r'\n\s*?#\s*?define\s+?(CEF_STRING_TYPE_\w+)\s+?.*?\n')
DEFINE_PATTERN = re.compile(r'#define\s+?.*?')
def _run_clang_eval(filename, content, api_version, added_defines, verbose):
# Add a tag so we know where the header-specific output begins.
tag = 'int begin_includes_tag;\n'
def _prepare_content(content: str) -> str:
"""
Add a marker to the content to indicate where the header-specific output
begins and replace system includes with a placeholder
"""
find = '#ifdef __cplusplus\nextern "C" {'
pos = content.find(find)
assert pos > 0, filename
content = content[0:pos] + tag + content[pos:]
assert pos > 0, f'Cannot find "{find}" in {content}'
content = content[0:pos] + INCLUDE_START_MARKER + content[pos:]
defines = [
# Makes sure CEF_EXPORT is defined.
'USING_CEF_SHARED',
content = DEFINE_PATTERN.sub('//DEFINE_PLACEHOLDER//', content)
return SYSTEM_INCLUDES_PATTERN.sub('//INCLUDE_PLACEHOLDER//', content)
# Avoid include of generated headers.
'GENERATING_CEF_API_HASH',
]
if filename.find('test/') >= 0:
# Avoids errors parsing test includes.
defines.append('UNIT_TEST')
# Not the experimental version.
api_version = int(api_version)
if api_version != EXP_VERSION:
# Specify the exact version.
defines.append('CEF_API_VERSION=%d' % api_version)
if not added_defines is None:
defines.extend(added_defines)
includes = [
# Includes relative to the 'src/cef' directory.
'.',
# Includes relative to the 'src' directory.
'..',
]
result = clang_eval(
filename,
content,
defines=defines,
includes=includes,
as_cpp=False,
verbose=verbose)
if result is None:
return None
pos = result.find(tag)
assert pos > 0, filename
result = result[pos + len(tag):]
def _process_result(result: str) -> str:
"""
Remove the non header-specific output and undo substitutions from cef_export.h
"""
pos = result.find(INCLUDE_START_MARKER)
if pos == -1:
return result
result = result[pos + len(INCLUDE_START_MARKER):]
replacements = [
# Undo substitutions from cef_export.h
['__declspec(dllimport)', 'CEF_EXPORT'],
['__attribute__((visibility("default")))', 'CEF_EXPORT'],
['__stdcall', ''],
]
for find, replace in replacements:
result = result.replace(find, replace)
return result
# Must always start with newline as required by _parse_objects()
return '\n' + result
class cef_api_hash:
def _get_defines(filename: str, added_defines: list) -> List[str]:
defines = [
# Makes sure CEF_EXPORT is defined.
'USING_CEF_SHARED',
# Avoid include of generated headers.
'GENERATING_CEF_API_HASH',
]
# Avoids errors parsing test includes.
if filename.find('test/') >= 0:
defines.append('UNIT_TEST')
defines.extend(added_defines)
return defines
def parse_versioned_content(filename: str,
content: str,
api_version: str,
added_defines: list,
debug_dir,
verbose) -> list:
"""
Parse the header file content using clang with the specified API version
Used for files that are version-specific but not platform-specific
"""
content = _prepare_content(content)
defines = _get_defines(filename, added_defines)
if api_version != EXP_VERSION:
# Specify the exact version.
defines.append(f'CEF_API_VERSION={api_version}')
result = clang_eval(filename, content, defines, INCLUDE_DIRS, verbose)
assert result, f'clang failed to eval {filename} with {api_version=}'
result = _process_result(result)
if debug_dir:
_write_debug_file(debug_dir, 'clang-' + filename.replace('/', '-'), result)
return _parse_objects(filename, result, 'universal')
def parse_platformed_content(filename: str,
content: str,
debug_dir,
verbose,
api_version,
added_defines: list) -> list:
"""
Parse the header file content using clang for every supported platform
with the specified API version. Used for files that are both version-specific
and platform-specific.
"""
content = _prepare_content(content)
defines = _get_defines(filename, added_defines)
if api_version and api_version != EXP_VERSION:
# Specify the exact version.
defines.append(f'CEF_API_VERSION={api_version}')
content_objects = []
for platform, platform_defines in PLATFORM_DEFINES.items():
result = clang_eval(filename, content, defines + platform_defines,
INCLUDE_DIRS, verbose)
assert result, f'clang failed to eval {filename} on {platform=}'
result = _process_result(result)
if debug_dir:
_write_debug_file(
debug_dir, f'clang-{platform}-' + filename.replace('/', '-'), result)
objects = _parse_objects(filename, result, platform)
content_objects.extend(objects)
return content_objects
def _write_debug_file(debug_dir, filename, content) -> None:
make_dir(debug_dir)
outfile = os.path.join(debug_dir, filename)
dir = os.path.dirname(outfile)
make_dir(dir)
if not isinstance(content, str):
content = '\n'.join(content)
write_file(outfile, content)
def _parse_objects(filename: str, content: str, platform: str) -> list:
objects = []
content = SINGLE_LINE_COMMENT_PATTERN.sub('', content)
for m in FUNCTION_DECLARATION_PATTERN.finditer(content):
objects.append({
'filename': filename,
'name': m.group(1),
'platform': platform,
'text': _prepare_text(m.group(0))
})
for m in STRUCT_PATTERN.finditer(content):
# Remove 'CEF_CALLBACK' to normalize cross-platform clang output
objects.append({
'filename': filename,
'name': m.group(2),
'platform': platform,
'text': _prepare_text(m.group(0).replace('CEF_CALLBACK', ''))
})
for m in ENUM_PATTERN.finditer(content):
objects.append({
'filename': filename,
'name': m.group(1),
'platform': platform,
'text': _prepare_text(m.group(0))
})
for m in TYPEDEF_PATTERN.finditer(content):
if m.group(1) == 'char16_t':
# Skip char16_t typedefs to avoid platform-specific differences.
continue
objects.append({
'filename': filename,
'name': m.group(1),
'platform': platform,
'text': _prepare_text(m.group(0))
})
return objects
def _prepare_text(text: str) -> str:
""" Normalize text for hashing. """
text = WHITESPACE_PATTERN.sub(' ', text.strip())
return PARENTHESIS_PATTERN.sub('(', text)
def _parse_string_type(filename: str, content: str) -> list:
""" Grab defined CEF_STRING_TYPE_xxx """
objects = []
for m in CEF_STRING_TYPE_PATTERN.finditer(content):
objects.append({
'filename': filename,
'name': m.group(1),
'text': _prepare_text(m.group(0)),
'platform': 'universal'
})
return objects
def _get_final_sig(objects, platform) -> str:
return '\n'.join(o['text'] for o in objects
if o['platform'] == 'universal' or o['platform'] == platform)
def _get_filenames(header_dir) -> List[str]:
""" Return file names to be processed, relative to header_dir """
cef_dir = os.path.abspath(os.path.join(header_dir, os.pardir))
# Read the variables list from the autogenerated cef_paths.gypi file.
cef_paths = eval_file(os.path.join(cef_dir, 'cef_paths.gypi'))
cef_paths = cef_paths['variables']
# Read the variables list from the manually edited cef_paths2.gypi file.
cef_paths2 = eval_file(os.path.join(cef_dir, 'cef_paths2.gypi'))
cef_paths2 = cef_paths2['variables']
# List of all C API include/ files.
paths = cef_paths2['includes_capi'] + cef_paths2['includes_common_capi'] + \
cef_paths2['includes_linux_capi'] + cef_paths2['includes_mac_capi'] + \
cef_paths2['includes_win_capi'] + cef_paths['autogen_capi_includes']
return [
os.path.relpath(os.path.join(cef_dir, filename), header_dir).replace(
'\\', '/').lower() for filename in paths
]
def _save_objects_to_file(debug_dir: str, objects: list) -> None:
name_len = max([len(o['name']) for o in objects])
filename_len = max([len(o['filename']) for o in objects])
platform_len = max([len(o['platform']) for o in objects])
dump_sig = [
f"{o['name']:<{name_len}}|{o['filename']:<{filename_len}}|{o['platform']:<{platform_len}}|{o['text']}"
for o in objects
]
_write_debug_file(debug_dir, 'objects.txt', dump_sig)
class CefApiHasher:
""" CEF API hash calculator """
def __init__(self, headerdir, verbose=False):
if headerdir is None or len(headerdir) == 0:
raise AssertionError("headerdir is not specified")
def __init__(self, header_dir, debug_dir, verbose=False):
if header_dir is None or len(header_dir) == 0:
raise AssertionError('header_dir is not specified')
self.__headerdir = headerdir
self.__verbose = verbose
self.platforms = ["windows", "mac", "linux"]
cef_dir = os.path.abspath(os.path.join(self.__headerdir, os.pardir))
# Read the variables list from the autogenerated cef_paths.gypi file.
cef_paths = eval_file(os.path.join(cef_dir, 'cef_paths.gypi'))
cef_paths = cef_paths['variables']
# Read the variables list from the manually edited cef_paths2.gypi file.
cef_paths2 = eval_file(os.path.join(cef_dir, 'cef_paths2.gypi'))
cef_paths2 = cef_paths2['variables']
# Excluded files (paths relative to the include/ directory).
excluded_files = []
# List of platform-specific C API include/ files.
self.platform_files = {
"windows":
self.__get_filenames(cef_dir, cef_paths2['includes_win_capi'],
excluded_files),
"mac":
self.__get_filenames(cef_dir, cef_paths2['includes_mac_capi'],
excluded_files),
"linux":
self.__get_filenames(cef_dir, cef_paths2['includes_linux_capi'],
excluded_files)
}
# List of all C API include/ files.
paths = cef_paths2['includes_capi'] + cef_paths2['includes_common_capi'] + \
cef_paths2['includes_linux_capi'] + cef_paths2['includes_mac_capi'] + \
cef_paths2['includes_win_capi'] + cef_paths['autogen_capi_includes']
self.filenames = self.__get_filenames(cef_dir, paths, excluded_files)
self.filecontents = {}
self.filecontentobjs = {}
self.filenames = _get_filenames(header_dir)
self.debug_dir = debug_dir
self.verbose = verbose
self.versioned_contents = {}
self.platformed_contents = {}
self.file_content_objs = {}
# Cache values that will not change between calls to calculate().
for filename in self.filenames:
if self.__verbose:
print("Processing " + filename + "...")
self.print(f'Processing {filename} ...')
assert not filename in self.filecontents, filename
assert not filename in self.filecontentobjs, filename
if filename in self.versioned_contents \
or filename in self.platformed_contents \
or filename in self.file_content_objs:
self.print(f'{filename} already processed, skipping...')
continue
content = read_file(os.path.join(self.__headerdir, filename), True)
content = read_file(os.path.join(header_dir, filename), normalize=True)
content_objects = None
# Parse cef_string.h happens in special case: grab only defined CEF_STRING_TYPE_xxx declaration
if filename == "internal/cef_string.h":
content_objects = self.__parse_string_type(content)
elif content.find('#if CEF_API') >= 0:
# Needs to be passed to clang with version-specific defines.
self.filecontents[filename] = content
is_platform_specific = OS_TOKEN in content
is_version_specific = API_TOKEN in content
# Special case for parsing cef_string.h:
# Only extract declarations of the form #define CEF_STRING_TYPE_xxx
if filename == 'internal/cef_string.h':
content_objects = _parse_string_type(filename, content)
elif is_platform_specific and not is_version_specific:
# Parse once and cache for all platforms
content_objects = parse_platformed_content(
filename,
content,
debug_dir,
verbose,
api_version=None,
added_defines=[])
elif is_platform_specific and is_version_specific:
# Needs to be passed to clang with version and platform defines.
self.platformed_contents[filename] = content
elif is_version_specific:
# Needs to be passed to clang with version defines.
self.versioned_contents[filename] = content
else:
content_objects = self.__parse_objects(content)
content_objects = _parse_objects(filename, content, 'universal')
if not content_objects is None:
self.__prepare_objects(filename, content_objects)
self.filecontentobjs[filename] = content_objects
if content_objects is not None:
self.file_content_objs[filename] = content_objects
def calculate(self, api_version, debug_dir=None, added_defines=None):
debug_enabled = not (debug_dir is None) and len(debug_dir) > 0
def calculate(self, api_version: str, added_defines: list) -> Dict[str, str]:
""" Calculate the API hash per platform for the specified API version """
debug_dir = os.path.join(self.debug_dir,
api_version) if self.debug_dir else None
objects = []
for filename in self.filenames:
if self.__verbose:
print("Processing " + filename + "...")
self.print(f'Processing {filename}...')
content = self.filecontents.get(filename, None)
if not content is None:
assert content.find('#if CEF_API') >= 0, filename
content = _run_clang_eval(filename, content, api_version, added_defines,
self.__verbose)
if content is None:
sys.stderr.write(
'ERROR: Failed to compute API hash for %s\n' % filename)
return False
if debug_enabled:
self.__write_debug_file(
debug_dir, 'clang-' + filename.replace('/', '-'), content)
# content must always start with newline as required by __parse_objects()
content_objects = self.__parse_objects('\n' + content)
self.__prepare_objects(filename, content_objects)
if filename in self.versioned_contents:
content = self.versioned_contents.get(filename, None)
content_objects = parse_versioned_content(filename, content,
api_version, added_defines,
debug_dir, self.verbose)
elif filename in self.platformed_contents:
content = self.platformed_contents.get(filename, None)
content_objects = parse_platformed_content(filename, content, debug_dir,
self.verbose, api_version,
added_defines)
else:
content_objects = self.filecontentobjs.get(filename, None)
content_objects = self.file_content_objs.get(filename, None)
assert not content_objects is None, filename
objects.extend(content_objects)
# May be None if the full contents of the file are excluded at certain API versions.
if not content_objects is None:
objects.extend(content_objects)
# objects will be sorted including filename, to make stable universal hashes
objects = sorted(objects, key=lambda o: o["name"] + "@" + o["filename"])
# objects will be sorted including filename to make stable hashes
objects = sorted(objects, key=lambda o: f"{o['name']}@{o['filename']}")
if debug_enabled:
namelen = max([len(o["name"]) for o in objects])
filenamelen = max([len(o["filename"]) for o in objects])
dumpsig = []
for o in objects:
dumpsig.append(
format(o["name"], str(namelen) + "s") + "|" + format(
o["filename"], "" + str(filenamelen) + "s") + "|" + o["text"])
self.__write_debug_file(debug_dir, "objects.txt", dumpsig)
if debug_dir:
_save_objects_to_file(debug_dir, objects)
revisions = {}
hashes = {}
for platform in PLATFORM_DEFINES.keys():
sig = _get_final_sig(objects, platform)
if debug_dir:
_write_debug_file(debug_dir, f'{platform}.sig', sig)
hashes[platform] = hashlib.sha1(sig.encode('utf-8')).hexdigest()
for platform in itertools.chain(["universal"], self.platforms):
sig = self.__get_final_sig(objects, platform)
if debug_enabled:
self.__write_debug_file(debug_dir, platform + ".sig", sig)
revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest()
revisions[platform] = revstr
return hashes
return revisions
def __parse_objects(self, content):
""" Returns array of objects in content file. """
objects = []
content = re.sub(r"//.*\n", "", content)
# function declarations
for m in re.finditer(
r"\nCEF_EXPORT\s+?.*?\s+?(\w+)\s*?\(.*?\)\s*?;",
content,
flags=re.DOTALL):
object = {"name": m.group(1), "text": m.group(0).strip()}
objects.append(object)
# structs
for m in re.finditer(
r"\ntypedef\s+?struct\s+?(\w+)\s+?\{.*?\}\s+?(\w+)\s*?;",
content,
flags=re.DOTALL):
text = m.group(0).strip()
# remove 'CEF_CALLBACK' to normalize cross-platform clang output
text = text.replace('CEF_CALLBACK', '')
object = {"name": m.group(2), "text": text}
objects.append(object)
# enums
for m in re.finditer(
r"\ntypedef\s+?enum\s+?\{.*?\}\s+?(\w+)\s*?;", content,
flags=re.DOTALL):
object = {"name": m.group(1), "text": m.group(0).strip()}
objects.append(object)
# typedefs
for m in re.finditer(r"\ntypedef\s+?.*?\s+(\w+);", content, flags=0):
object = {"name": m.group(1), "text": m.group(0).strip()}
objects.append(object)
return objects
def __prepare_objects(self, filename, objects):
platforms = list(
[p for p in self.platforms if self.__is_platform_filename(filename, p)])
for o in objects:
o["text"] = self.__prepare_text(o["text"])
o["platforms"] = platforms
o["filename"] = filename
def __parse_string_type(self, content):
""" Grab defined CEF_STRING_TYPE_xxx """
objects = []
for m in re.finditer(
r"\n\s*?#\s*?define\s+?(CEF_STRING_TYPE_\w+)\s+?.*?\n",
content,
flags=0):
object = {
"name": m.group(1),
"text": m.group(0),
}
objects.append(object)
return objects
def __prepare_text(self, text):
text = text.strip()
text = re.sub(r"\s+", " ", text)
text = re.sub(r"\(\s+", "(", text)
return text
def __get_final_sig(self, objects, platform):
sig = []
for o in objects:
if platform == "universal" or platform in o["platforms"]:
sig.append(o["text"])
return "\n".join(sig)
def __get_filenames(self, cef_dir, paths, excluded_files):
""" Returns file names to be processed, relative to headerdir """
filenames = [
os.path.relpath(os.path.join(cef_dir, filename),
self.__headerdir).replace('\\', '/').lower()
for filename in paths
]
if len(excluded_files) == 0:
return filenames
return [
filename for filename in filenames if not filename in excluded_files
]
def __is_platform_filename(self, filename, platform):
if platform == "universal":
return True
if not platform in self.platform_files:
return False
listed = False
for p in self.platforms:
if filename in self.platform_files[p]:
if p == platform:
return True
else:
listed = True
return not listed
def __write_debug_file(self, debug_dir, filename, content):
make_dir(debug_dir)
outfile = os.path.join(debug_dir, filename)
dir = os.path.dirname(outfile)
make_dir(dir)
if not isinstance(content, string_type):
content = "\n".join(content)
write_file(outfile, content)
def print(self, msg):
if self.verbose:
print(msg)
if __name__ == "__main__":
if __name__ == '__main__':
from optparse import OptionParser
import time
disc = """
This utility calculates CEF API hash.
"""
parser = OptionParser(description=disc)
parser = OptionParser(description='This utility calculates CEF API hash')
parser.add_option(
'--cpp-header-dir',
dest='cppheaderdir',
dest='cpp_header_dir',
metavar='DIR',
help='input directory for C++ header files [required]')
parser.add_option(
'--debug-dir',
dest='debugdir',
dest='debug_dir',
metavar='DIR',
help='intermediate directory for easy debugging')
parser.add_option(
@@ -352,28 +390,16 @@ if __name__ == "__main__":
help='output detailed status information')
(options, args) = parser.parse_args()
# the cppheader option is required
if options.cppheaderdir is None:
# the cpp_header_dir option is required
if options.cpp_header_dir is None:
parser.print_help(sys.stdout)
sys.exit()
# calculate
c_start_time = time.time()
calc = CefApiHasher(options.cpp_header_dir, options.debug_dir,
options.verbose)
revisions = calc.calculate(EXP_VERSION, [])
calc = cef_api_hash(options.cppheaderdir, options.debugdir, options.verbose)
revisions = calc.calculate(api_version=EXP_VERSION)
c_completed_in = time.time() - c_start_time
if bool(revisions):
print("{")
for k in sorted(revisions.keys()):
print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"")
print("}")
# print
# print 'Completed in: ' + str(c_completed_in)
# print
# print "Press any key to continue...";
# sys.stdin.readline();
print('{')
for k in sorted(revisions.keys()):
print(format('"' + k + '"', '>12s') + ': "' + revisions[k] + '"')
print('}')

375
tools/cef_api_hash_test.py Normal file
View File

@@ -0,0 +1,375 @@
# Copyright (c) 2025 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.
# Execute the following command to run unit tests:
# python3 -m unittest discover -s tools -p *_test.py
from cef_api_hash import *
from collections import Counter
import unittest
# Test constants:
FILENAME = 'test.h'
NONE_DEBUG_DIR = None
VERBOSE = False
ADDED_DEFINES = []
CEF_TYPES_WIN = """#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_WIN)
#if !defined(GENERATING_CEF_API_HASH)
#include <windows.h>
#endif
#include "include/cef_api_hash.h"
#include "include/internal/cef_types_runtime.h"
#define kNullCursorHandle NULL
#define kNullEventHandle NULL
#define kNullWindowHandle NULL
#ifdef __cplusplus
extern "C" {
#endif
// Handle types.
typedef HWND cef_window_handle_t;
typedef struct _cef_window_info_t {
size_t size;
DWORD ex_style;
HMENU menu;
cef_window_handle_t parent_window;
cef_runtime_style_t runtime_style;
#if CEF_API_ADDED(13304)
int api_version_test;
#endif
} cef_window_info_t;
#ifdef __cplusplus
}
#endif
#endif // OS_WIN
#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
"""
CEF_TYPES_MAC = """#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#include <this_header_does_not_exist.h>
#if defined(OS_MAC)
#include "include/internal/cef_string.h"
#include "include/internal/cef_types_geometry.h"
#include "include/internal/cef_types_runtime.h"
#define kNullCursorHandle NULL
#ifdef __OBJC__
#if __has_feature(objc_arc)
#define CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(handle) ((__bridge NSCursor*)handle)
#define CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle) ((__bridge NSView*)handle)
#define CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor) ((__bridge void*)cursor)
#define CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view) ((__bridge void*)view)
#else // __has_feature(objc_arc)
#define CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(handle) ((NSCursor*)handle)
#define CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle) ((NSView*)handle)
#define CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor) ((void*)cursor)
#define CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view) ((void*)view)
#endif // __has_feature(objc_arc)
#endif // __OBJC__
#ifdef __cplusplus
extern "C" {
#endif
// Actually NSView*
typedef void* cef_window_handle_t;
///
/// Class representing window information.
///
typedef struct _cef_window_info_t {
size_t size;
cef_string_t window_name;
cef_rect_t bounds;
cef_window_handle_t view;
cef_runtime_style_t runtime_style;
} cef_window_info_t;
#ifdef __cplusplus
}
#endif
#endif // OS_MAC
#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
"""
CEF_TYPES_LINUX = """#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
#pragma once
#if !defined(GENERATING_CEF_API_HASH)
#include "include/base/cef_build.h"
#endif
#if defined(OS_LINUX)
#include "include/internal/cef_export.h"
#include "include/internal/cef_string.h"
#include "include/internal/cef_types_color.h"
#include "include/internal/cef_types_geometry.h"
#include "include/internal/cef_types_osr.h"
#include "include/internal/cef_types_runtime.h"
#define kNullCursorHandle 0
#define kNullEventHandle NULL
#define kNullWindowHandle 0
#ifdef __cplusplus
extern "C" {
#endif
#if defined(CEF_X11)
typedef union _XEvent XEvent;
typedef struct _XDisplay XDisplay;
// Handle types.
typedef XEvent* cef_event_handle_t;
#else
typedef void* cef_event_handle_t;
#endif
typedef unsigned long cef_window_handle_t;
///
/// Return the singleton X11 display shared with Chromium. The display is not
/// thread-safe and must only be accessed on the browser process UI thread.
///
#if defined(CEF_X11)
CEF_EXPORT XDisplay* cef_get_xdisplay(void);
#endif
typedef struct _cef_window_info_t {
size_t size;
cef_string_t window_name;
cef_rect_t bounds;
cef_window_handle_t parent_window;
cef_window_handle_t window;
cef_runtime_style_t runtime_style;
} cef_window_info_t;
#ifdef __cplusplus
}
#endif
#endif // OS_LINUX
#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
"""
CEF_TYPES = """#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_H_
#define CEF_INCLUDE_INTERNAL_CEF_TYPES_H_
#pragma once
#include "include/cef_api_hash.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
CEF_CPAIT_OPTIMIZATION_GUIDE,
#if CEF_API_ADDED(13304)
CEF_CPAIT_COLLABORATION_MESSAGING,
#endif
CEF_CPAIT_NUM_VALUES,
} cef_chrome_page_action_icon_type_t;
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_H_
"""
class TestRunClangEval(unittest.TestCase):
def test_parse_platformed_content_version_13304(self):
expected_objects = [{
'filename': FILENAME,
'name': 'cef_window_handle_t',
'platform': 'windows',
'text': 'typedef HWND cef_window_handle_t;'
}, {
'filename':
FILENAME,
'name':
'cef_window_info_t',
'platform':
'windows',
'text':
'typedef struct _cef_window_info_t { size_t size; DWORD ex_style; HMENU menu; cef_window_handle_t parent_window; cef_runtime_style_t runtime_style; int api_version_test; } cef_window_info_t;'
}]
objects = parse_platformed_content(FILENAME, CEF_TYPES_WIN, NONE_DEBUG_DIR,
VERBOSE, '13304', ADDED_DEFINES)
self.__assert_equal_objects(objects, expected_objects)
def test_parse_platformed_content_version_13300(self):
expected_objects = [{
'filename': FILENAME,
'name': 'cef_window_handle_t',
'platform': 'windows',
'text': 'typedef HWND cef_window_handle_t;'
}, {
'filename':
FILENAME,
'name':
'cef_window_info_t',
'platform':
'windows',
'text':
'typedef struct _cef_window_info_t { size_t size; DWORD ex_style; HMENU menu; cef_window_handle_t parent_window; cef_runtime_style_t runtime_style; } cef_window_info_t;'
}]
objects = parse_platformed_content(FILENAME, CEF_TYPES_WIN, NONE_DEBUG_DIR,
VERBOSE, '13300', ADDED_DEFINES)
self.__assert_equal_objects(objects, expected_objects)
def test_parse_platformed_content_mac(self):
expected_objects = [{
'filename': FILENAME,
'name': 'cef_window_handle_t',
'platform': 'mac',
'text': 'typedef void* cef_window_handle_t;'
}, {
'filename':
FILENAME,
'name':
'cef_window_info_t',
'platform':
'mac',
'text':
'typedef struct _cef_window_info_t { size_t size; cef_string_t window_name; cef_rect_t bounds; cef_window_handle_t view; cef_runtime_style_t runtime_style; } cef_window_info_t;'
}]
objects = parse_platformed_content(
FILENAME,
CEF_TYPES_MAC,
NONE_DEBUG_DIR,
VERBOSE,
api_version=None,
added_defines=[])
self.__assert_equal_objects(objects, expected_objects)
def test_parse_platformed_content_linux(self):
expected_objects = [{
'filename': FILENAME,
'name': 'XEvent',
'platform': 'linux',
'text': 'typedef union _XEvent XEvent;'
}, {
'filename': FILENAME,
'name': 'XDisplay',
'platform': 'linux',
'text': 'typedef struct _XDisplay XDisplay;'
}, {
'filename': FILENAME,
'name': 'cef_event_handle_t',
'platform': 'linux',
'text': 'typedef XEvent* cef_event_handle_t;'
}, {
'filename': FILENAME,
'name': 'cef_window_handle_t',
'platform': 'linux',
'text': 'typedef unsigned long cef_window_handle_t;'
}, {
'filename': FILENAME,
'name': 'cef_get_xdisplay',
'platform': 'linux',
'text': 'CEF_EXPORT XDisplay* cef_get_xdisplay(void);'
}, {
'filename':
FILENAME,
'name':
'cef_window_info_t',
'platform':
'linux',
'text':
'typedef struct _cef_window_info_t { size_t size; cef_string_t window_name; cef_rect_t bounds; cef_window_handle_t parent_window; cef_window_handle_t window; cef_runtime_style_t runtime_style; } cef_window_info_t;'
}]
objects = parse_platformed_content(
FILENAME,
CEF_TYPES_LINUX,
NONE_DEBUG_DIR,
VERBOSE,
api_version=None,
added_defines=[])
self.__assert_equal_objects(objects, expected_objects)
def test_parse_versioned_content_version_13304(self):
expected_objects = [{
'filename':
FILENAME,
'name':
'cef_chrome_page_action_icon_type_t',
'platform':
'universal',
'text':
'typedef enum { CEF_CPAIT_OPTIMIZATION_GUIDE, CEF_CPAIT_COLLABORATION_MESSAGING, CEF_CPAIT_NUM_VALUES, } cef_chrome_page_action_icon_type_t;'
}]
objects = parse_versioned_content(FILENAME, CEF_TYPES, '13304',
ADDED_DEFINES, NONE_DEBUG_DIR, VERBOSE)
self.assertEqual(objects, expected_objects)
def test_parse_versioned_content_version_13303(self):
expected_objects = [{
'filename':
FILENAME,
'name':
'cef_chrome_page_action_icon_type_t',
'platform':
'universal',
'text':
'typedef enum { CEF_CPAIT_OPTIMIZATION_GUIDE, CEF_CPAIT_NUM_VALUES, } cef_chrome_page_action_icon_type_t;'
}]
objects = parse_versioned_content(FILENAME, CEF_TYPES, '13303',
ADDED_DEFINES, NONE_DEBUG_DIR, VERBOSE)
self.assertEqual(objects, expected_objects)
def __assert_equal_objects(self, actual, expected):
# Compare the objects as sets since the order is not guaranteed
expected = Counter(tuple(sorted(d.items())) for d in expected)
actual = Counter(tuple(sorted(d.items())) for d in actual)
self.assertEqual(expected, actual)
if __name__ == '__main__':
unittest.main()

View File

@@ -522,9 +522,9 @@ def dict_to_str(dict):
# Attribute keys allowed in CEF metadata comments.
COMMON_ATTRIB_KEYS = ('added', 'removed')
CLASS_ATTRIB_KEYS = COMMON_ATTRIB_KEYS + ('no_debugct_check', 'source')
FUNCTION_ATTRIB_KEYS = COMMON_ATTRIB_KEYS + ('api_hash_check', 'capi_name',
'count_func', 'default_retval',
'index_param', 'optional_param')
FUNCTION_ATTRIB_KEYS = COMMON_ATTRIB_KEYS + (
'api_hash_check', 'capi_name', 'count_func', 'default_retval',
'index_param', 'no_stack_protector', 'optional_param')
# regex for matching comment-formatted attributes
_cre_attrib = r'/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/'
@@ -1352,10 +1352,15 @@ class obj_class:
# Clamp to class versions, if specified.
if self.has_version_added():
versions = [x for x in versions if x >= self.get_version_added()]
version_added = self.get_version_added()
versions = [x for x in versions if x >= version_added]
if not version_added in versions:
versions.append(version_added)
if self.has_version_removed():
versions = [x for x in versions if x < self.get_version_removed()]
assert len(versions) > 0, self.get_name()
self.allversions = sorted(versions)
return self.allversions

View File

@@ -161,7 +161,7 @@ class VersionFormatter:
# - "X" is the Chromium major version (e.g. 74).
# - "Y" is an incremental number that starts at 0 when a release branch is
# created and changes only when the CEF C/C++ API changes (similar to how
# the CEF_API_HASH_UNIVERSAL value behaves in cef_api_hash.h) (release
# the CEF_API_HASH_PLATFORM value behaves in cef_api_hash.h) (release
# branch only).
# - "Z" is an incremental number that starts at 0 when a release branch is
# created and changes on each commit, with reset to 0 when "Y" changes

View File

@@ -27,7 +27,7 @@ else:
def clang_format(file_name, file_contents):
# -assume-filename is necessary to find the .clang-format file and determine
# the language when specifying contents via stdin.
result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name), \
result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name),
cef_dir, file_contents.encode('utf-8'))
if result['err'] != '':
sys.stderr.write("clang-format error: %s\n" % result['err'])
@@ -48,40 +48,28 @@ def clang_format_inplace(file_name):
return True
def clang_eval(file_name,
file_contents,
defines=[],
includes=[],
as_cpp=True,
verbose=False):
lang = 'c++' if as_cpp else 'c'
def clang_eval(file_name, file_contents, defines, includes, verbose):
lang = 'c'
if file_name.lower().endswith('.h'):
lang += '-header'
# The -P option removes unnecessary line markers and whitespace.
format = '/EP' if sys.platform == 'win32' else '-E -P'
sdkroot = ''
if sys.platform == 'darwin':
result = exec_cmd('xcrun --show-sdk-path', '.')
if result['ret'] == 0:
sdkroot = " -isysroot %s" % result['out'].strip()
cmd = "%s -x %s %s %s %s %s -" % (clang_exe, lang, format,
' '.join(['-D' + v for v in defines]),
' '.join(['-I' + v
for v in includes]), sdkroot)
cmd = "%s -x %s %s %s %s -" % (clang_exe, lang, format,
' '.join(['-D' + v for v in defines]),
' '.join(['-I' + v for v in includes]))
if verbose:
print('--- Running "%s" in "%s"' % (cmd, cef_dir))
print(f'--- Running "{cmd}" in "{cef_dir}"')
result = exec_cmd(cmd, cef_dir, file_contents.encode('utf-8'))
if result['err'] != '':
err = result['err'].replace('<stdin>', file_name)
sys.stderr.write("clang error: %s\n" % err)
if result['err'] != '' or result['ret'] != 0:
error = result['err'].replace('<stdin>', file_name)
return_code = result['ret']
sys.stderr.write(f'clang {return_code=} {error=}\n')
return None
if result['out'] != '':
output = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
output = output.replace("\r", "")
return output
return None
output = result['out']
if output and sys.platform == 'win32':
# Convert to Unix line endings.
output = output.replace("\r", "")
return output

View File

@@ -3,6 +3,6 @@ LICENSING
The CEF project is BSD licensed. Please read the LICENSE.txt file included with
this binary distribution for licensing terms and conditions. Other software
included in this distribution is provided under other licenses. Please visit
"about:credits" in a CEF-based application for complete Chromium and third-party
licensing information.
included in this distribution is provided under other licenses. Please see the
CREDITS.html file or visit "about:credits" in a CEF-based application for
complete Chromium and third-party licensing information.

View File

@@ -13,29 +13,25 @@ def exec_cmd(cmd, path, input_string=None):
err = ''
ret = -1
parts = cmd.split()
try:
if input_string is None:
process = Popen(
parts,
cwd=path,
stdout=PIPE,
stderr=PIPE,
shell=(sys.platform == 'win32'))
out, err = process.communicate()
ret = process.returncode
else:
process = Popen(
parts,
cwd=path,
stdin=PIPE,
stdout=PIPE,
stderr=PIPE,
shell=(sys.platform == 'win32'))
out, err = process.communicate(input=input_string)
ret = process.returncode
except IOError as e:
(errno, strerror) = e.args
raise
except:
raise
if input_string is None:
process = Popen(
parts,
cwd=path,
stdout=PIPE,
stderr=PIPE,
shell=(sys.platform == 'win32'))
out, err = process.communicate()
ret = process.returncode
else:
process = Popen(
parts,
cwd=path,
stdin=PIPE,
stdout=PIPE,
stderr=PIPE,
shell=(sys.platform == 'win32'))
out, err = process.communicate(input=input_string)
ret = process.returncode
return {'out': out.decode('utf-8'), 'err': err.decode('utf-8'), 'ret': ret}

View File

@@ -8,8 +8,8 @@ import os
import sys
if sys.platform == 'win32':
# Force use of the git version bundled with depot_tools.
git_exe = 'git.bat'
# Force use of the system installed Git version.
git_exe = 'git.exe'
else:
git_exe = 'git'
@@ -30,6 +30,15 @@ def exec_git_cmd(args, path='.'):
""" Executes a git command with the specified |args|. """
cmd = "%s %s" % (git_exe, args)
result = exec_cmd(cmd, path)
if result['ret'] != 0:
sys.stderr.write('Command \"%s\" exited with retval %d\n' % (cmd,
result['ret']))
if result['err'] != '':
err = result['err'].strip()
if sys.platform == 'win32':
# Convert to Unix line endings.
err = err.replace('\r\n', '\n')
sys.stderr.write(err + '\n')
if result['out'] != '':
out = result['out'].strip()
if sys.platform == 'win32':

View File

@@ -11,8 +11,8 @@ import sys
def make_api_versions_header(json):
result = get_copyright(full=True, translator=False) + \
"""//
result = get_copyright(
full=True, translator=False) + """//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_api_versions_header.py tool. Versions
@@ -27,42 +27,40 @@ def make_api_versions_header(json):
"""
for version, hashes in json['hashes'].items():
version_part = """
version_part = f"""
// $COMMENT$
#define CEF_API_VERSION_$VER$ $VER$
#define CEF_API_HASH_$VER$_UNIVERSAL "$UNIVERSAL$"
#define CEF_API_VERSION_{version} {version}
#if defined(OS_WIN)
#define CEF_API_HASH_$VER$_PLATFORM "$WINDOWS$"
#define CEF_API_HASH_{version} "$WINDOWS$"
#elif defined(OS_MAC)
#define CEF_API_HASH_$VER$_PLATFORM "$MAC$"
#define CEF_API_HASH_{version} "$MAC$"
#elif defined(OS_LINUX)
#define CEF_API_HASH_$VER$_PLATFORM "$LINUX$"
#define CEF_API_HASH_{version} "$LINUX$"
#endif
""".replace('$VER$', version)
"""
# Substitute hash values for placeholders.
for key, value in hashes.items():
version_part = version_part.replace('$%s$' % key.upper(), value)
version_part = version_part.replace(f"${key.upper()}$", value)
result += version_part
result += \
"""
result += f"""
// Oldest supported CEF version.
#define CEF_API_VERSION_MIN CEF_API_VERSION_$MIN$
#define CEF_API_VERSION_MIN CEF_API_VERSION_{json['min']}
// Newest supported CEF version.
#define CEF_API_VERSION_LAST CEF_API_VERSION_$LAST$
#define CEF_API_VERSION_LAST CEF_API_VERSION_{json['last']}
#endif // CEF_INCLUDE_CEF_API_VERSIONS_H_
""".replace('$LAST$', json['last']).replace('$MIN$', json['min'])
"""
return result
def make_api_versions_inc(json):
result = get_copyright(full=False, translator=False) + \
"""//
result = get_copyright(
full=False, translator=False) + """//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_api_versions_header.py tool.
@@ -72,56 +70,53 @@ namespace {
struct ApiVersionHash {
int version;
const char* const universal;
const char* const platform;
const char* const hash;
};
const ApiVersionHash kApiVersionHashes[] = {"""
for version, hashes in json['hashes'].items():
result += """
{$VER$, CEF_API_HASH_$VER$_UNIVERSAL, CEF_API_HASH_$VER$_PLATFORM},""".replace(
'$VER$', version)
for version in json['hashes'].keys():
result += f"\n{{{version}, CEF_API_HASH_{version}}},"
result += \
"""
result += """
};
const size_t kApiVersionHashesSize = std::size(kApiVersionHashes);
} // namespace
"""
return result
def write_api_versions(out_header_file, out_inc_file, json):
def write_api_versions(out_header_file, out_inc_file, json) -> bool:
"""
Return True if the files were written, False if no changes were made.
"""
out_file = os.path.abspath(out_header_file)
result = make_api_versions_header(json)
if not bool(result):
sys.stderr.write('Failed to create %s\n' % out_file)
if not result:
sys.stderr.write(f'Failed to create {out_file}\n')
sys.exit(1)
retval1 = write_file_if_changed(out_file, result)
header_write_result = write_file_if_changed(out_file, result)
out_file = os.path.abspath(out_inc_file)
result = make_api_versions_inc(json)
if not bool(result):
sys.stderr.write('Failed to create %s\n' % out_file)
if not result:
sys.stderr.write(f'Failed to create {out_file}\n')
sys.exit(1)
retval2 = write_file_if_changed(out_file, result)
inc_write_result = write_file_if_changed(out_file, result)
return retval1 or retval2
return header_write_result or inc_write_result
def main(argv):
if len(argv) < 5:
print(
"Usage:\n %s <output_header_file> <output_inc_file> <api_versions_file> <api_untracked_file>"
% argv[0])
f"Usage:\n {argv[0]} <output_header_file> <output_inc_file> <api_versions_file> <api_untracked_file>"
)
sys.exit(-1)
json, initialized = \
read_version_files(argv[3], argv[4], True, combine=True)
json = read_version_files(argv[3], argv[4], initialize=True, combine=True)[0]
if not write_api_versions(argv[1], argv[2], json):
print('Nothing done')

View File

@@ -43,7 +43,7 @@ def make_capi_versions_header(header, filename):
translate_map = header.get_capi_translations()
# header string
result = get_copyright(full=True, translator=False) + \
result = get_copyright(full=False, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//

View File

@@ -9,10 +9,13 @@ import functools
def make_cpptoc_impl_proto(name, func, parts):
proto = ''
if func.has_attrib('no_stack_protector'):
proto += 'NO_STACK_PROTECTOR '
if isinstance(func, obj_function_virtual):
proto = parts['retval'] + ' CEF_CALLBACK'
proto += parts['retval'] + ' CEF_CALLBACK'
else:
proto = 'CEF_EXPORT ' + parts['retval']
proto += 'CEF_EXPORT ' + parts['retval']
proto += ' ' + name + '(' + ', '.join(parts['args']) + ')'
return proto

View File

@@ -11,6 +11,8 @@ def make_ctocpp_impl_proto(clsname, name, func, parts):
const = ''
proto = 'NO_SANITIZE("cfi-icall") '
if func.has_attrib('no_stack_protector'):
proto += 'NO_STACK_PROTECTOR '
if clsname is None:
proto += 'CEF_GLOBAL ' + parts['retval'] + ' '
else:

View File

@@ -913,6 +913,16 @@ out_dir = os.path.join(src_dir, 'out')
build_dir_debug = os.path.join(out_dir, 'Debug' + build_dir_suffix)
build_dir_release = os.path.join(out_dir, 'Release' + build_dir_suffix)
# Transfer the about_credits.html file.
# Debug and Release build should be the same so grab whichever exists.
rel_path = os.path.join('gen', 'components', 'resources', 'about_credits.html')
src_path = os.path.join(build_dir_release, rel_path)
if not os.path.exists(src_path):
src_path = os.path.join(build_dir_debug, rel_path)
if not os.path.exists(src_path):
raise Exception('Missing generated resources file: %s' % rel_path)
copy_file(src_path, os.path.join(output_dir, 'CREDITS.html'), options.quiet)
if mode == 'standard' or mode == 'minimal':
# create the include directory
include_dir = os.path.join(output_dir, 'include')

View File

@@ -115,6 +115,8 @@ parser.add_option(
(options, args) = parser.parse_args()
if not options.patchfile is None:
apply_patch_file(options.patchfile, options.patchdir)
result = apply_patch_file(options.patchfile, options.patchdir)
if result == 'fail':
sys.exit(1)
else:
apply_patch_config()

View File

@@ -4,7 +4,8 @@
from __future__ import absolute_import
from __future__ import print_function
from cef_api_hash import cef_api_hash
from typing import Dict
from cef_api_hash import CefApiHasher
from cef_version import VersionFormatter
from date_util import get_date
from file_util import read_file, read_json_file, write_file, write_json_file
@@ -41,49 +42,37 @@ def get_next_api_revision(api_versions_file, major_version):
return 0
_CALC = None
def compute_api_hashes(cpp_header_dir, api_version, next_allowed, debug_dir,
verbose):
""" Computes API hashes for the specified |api_version|.
"""
if not debug_dir is None:
debug_dir = os.path.join(debug_dir, api_version)
def compute_api_hashes(api_version: str,
hasher: CefApiHasher,
next_allowed: bool) -> Dict[str, str]:
""" Computes API hashes for the specified |api_version|. """
if not next_allowed:
# Next usage is banned with explicit API versions.
assert not api_version in UNTRACKED_VERSIONS, api_version
assert api_version not in UNTRACKED_VERSIONS, api_version
added_defines = [
# Using CEF_API_VERSION_NEXT is an error.
'CEF_API_VERSION_NEXT="Please_specify_an_exact_CEF_version"',
]
else:
added_defines = None
added_defines = []
global _CALC
if _CALC is None:
_CALC = cef_api_hash(cpp_header_dir, verbose=verbose)
hashes = _CALC.calculate(api_version, debug_dir, added_defines)
if bool(hashes):
hashes = hasher.calculate(api_version, added_defines)
if hashes:
if api_version in UNTRACKED_VERSIONS:
label = version_label(api_version)
label = label[0:1].upper() + label[1:]
hashes['comment'] = '%s last updated %s.' % (label, get_date())
hashes['comment'] = f'{label} last updated {get_date()}.'
else:
hashes['comment'] = 'Added %s.' % get_date()
hashes['comment'] = f'Added {get_date()}.'
return hashes
def same_api_hashes(hashes1, hashes2):
for key in ('universal', 'linux', 'mac', 'windows'):
if hashes1[key] != hashes2[key]:
return False
return True
return all(hashes1[key] == hashes2[key]
for key in ['linux', 'mac', 'windows'])
def compute_next_api_verson(api_versions_file):
def compute_next_api_version(api_versions_file):
""" Computes the next available API version number.
"""
major_version = int(VersionFormatter().get_chrome_major_version())
@@ -95,7 +84,10 @@ def compute_next_api_verson(api_versions_file):
def git_grep_next(cef_dir):
cmd = "grep --no-color -n -E (CEF_NEXT|CEF_NEXT)|=next -- :!include/cef_api_hash.h *.h"
cmd = "grep --no-color -n -E (CEF_NEXT|CEF_NEXT)|=next -- :!include/cef_api_hash.h *.h *.cc"
if sys.platform == 'win32':
# Pass the pipe (|) character as a literal argument.
cmd = cmd.replace('|', '^|')
return exec_git_cmd(cmd, cef_dir)
@@ -105,7 +97,7 @@ def find_next_usage(cpp_header_dir):
if result is None:
return False
sys.stderr.write('ERROR: NEXT usage found in CEF headers:\n\n' + result +
sys.stderr.write('ERROR: NEXT usage found in CEF source files:\n\n' + result +
'\n\nFix manually or run with --replace-next.\n')
return True
@@ -204,8 +196,11 @@ def find_replace_next_usage(cpp_header_dir, next_version):
return 0
def exec_apply(cpp_header_dir, api_versions_file, api_untracked_file,
next_version, debug_dir, apply_next, verbose):
def exec_apply(api_versions_file,
api_untracked_file,
next_version,
apply_next,
hasher: CefApiHasher) -> int:
""" Updates untracked API hashes if necessary.
Saves the hash for the next API version if |apply_next| is true.
"""
@@ -219,9 +214,8 @@ def exec_apply(cpp_header_dir, api_versions_file, api_untracked_file,
untracked_changed = False
for version in UNTRACKED_VERSIONS:
label = version_label(version)
hashes = compute_api_hashes(cpp_header_dir, version, True, debug_dir,
verbose)
if not bool(hashes):
hashes = compute_api_hashes(version, hasher, next_allowed=True)
if not hashes:
sys.stderr.write('ERROR: Failed to process %s\n' % label)
return 1
@@ -237,9 +231,8 @@ def exec_apply(cpp_header_dir, api_versions_file, api_untracked_file,
if apply_next:
next_label = version_label(next_version)
hashes = compute_api_hashes(cpp_header_dir, next_version, False, debug_dir,
verbose)
if not bool(hashes):
hashes = compute_api_hashes(next_version, hasher, next_allowed=False)
if not hashes:
sys.stderr.write('ERROR: Failed to process %s\n' % next_label)
return 1
@@ -275,29 +268,33 @@ def exec_apply(cpp_header_dir, api_versions_file, api_untracked_file,
return 0
def exec_check(cpp_header_dir, api_versions_file, api_untracked_file, debug_dir,
fast_check, force_update, skip_untracked, verbose):
def exec_check(api_versions_file,
api_untracked_file,
fast_check,
force_update,
skip_untracked,
hasher: CefApiHasher) -> int:
""" Checks existing API version hashes.
Resaves all API hashes if |force_update| is true. Otherwise, hash
changes are considered an error.
"""
assert not (fast_check and force_update)
json_versions, json_untracked, initialized = \
read_version_files(api_versions_file, api_untracked_file, False)
json_versions, json_untracked, initialized = read_version_files(
api_versions_file, api_untracked_file, initialize=False)
assert not initialized
versions = []
len_versioned_existing = len_versioned_checked = len_versioned_failed = 0
len_untracked_existing = len_untracked_checked = len_untracked_failed = 0
if not json_versions is None:
if json_versions is not None:
keys = json_versions['hashes'].keys()
len_versioned_existing = len(keys)
if len_versioned_existing > 0:
if fast_check:
# Only checking a subset of versions.
for key in ('last', 'min'):
for key in ['last', 'min']:
if key in json_versions:
version = json_versions[key]
assert version in json_versions['hashes'], version
@@ -307,14 +304,14 @@ def exec_check(cpp_header_dir, api_versions_file, api_untracked_file, debug_dir,
versions.extend(keys)
len_versioned_checked = len_versioned_existing
if not json_untracked is None:
if json_untracked is not None:
keys = json_untracked['hashes'].keys()
len_untracked_existing = len(keys)
if len_untracked_existing > 0 and not skip_untracked:
versions.extend(keys)
len_untracked_checked = len_untracked_existing
if len(versions) == 0:
if not versions:
print('No hashes to check.')
return 0
@@ -328,8 +325,7 @@ def exec_check(cpp_header_dir, api_versions_file, api_untracked_file, debug_dir,
else:
stored_hashes = json_versions['hashes'][version]
label = version_label(version)
computed_hashes = compute_api_hashes(cpp_header_dir, version, True,
debug_dir, verbose)
computed_hashes = compute_api_hashes(version, hasher, next_allowed=True)
if not bool(computed_hashes):
sys.stderr.write('ERROR: Failed to process %s\n' % label)
return 1
@@ -362,8 +358,10 @@ def exec_check(cpp_header_dir, api_versions_file, api_untracked_file, debug_dir,
print('WARNING: This change can break back/forward binary compatibility.')
else:
sys.stderr.write('ERROR: %d hashes checked and failed\n' % len_failed)
sys.stderr.write('\nFor debugging tips/tricks see\n' +
'https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2587767028\n\n')
sys.stderr.write(
'\nFor debugging tips/tricks see\n' +
'https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2587767028\n\n'
)
print('%d hashes checked and match (%d/%d versioned, %d/%d untracked).' %
(len(versions) - len_failed,
@@ -412,7 +410,7 @@ https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
parser = CustomParser(description=desc, epilog=epilog)
parser.add_option(
'--debug-dir',
dest='debugdir',
dest='debug_dir',
metavar='DIR',
help='intermediate directory for easy debugging')
parser.add_option(
@@ -472,7 +470,7 @@ https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
parser.add_option(
'--force-update',
action='store_true',
dest='forceupdate',
dest='force_update',
default=False,
help='force update all API hashes (use with -c)')
(options, args) = parser.parse_args()
@@ -496,7 +494,7 @@ https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
parser.print_help(sys.stdout)
sys.exit(1)
next_version = compute_next_api_verson(api_versions_file)
next_version = compute_next_api_version(api_versions_file)
if next_version is None:
sys.exit(1)
@@ -522,17 +520,13 @@ https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
changed = translate(cef_dir, verbose=options.verbose) > 0
skip_untracked = False
hasher = CefApiHasher(cpp_header_dir, options.debug_dir, options.verbose)
if options.update or will_apply_next or changed or not os.path.isfile(
api_untracked_file):
skip_untracked = True
if exec_apply(
cpp_header_dir,
api_versions_file,
api_untracked_file,
next_version,
options.debugdir,
apply_next=options.apply,
verbose=options.verbose) > 0:
if exec_apply(api_versions_file, api_untracked_file, next_version,
options.apply, hasher) > 0:
# Apply failed.
sys.exit(1)
elif not options.check:
@@ -540,12 +534,6 @@ https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
sys.exit(0)
sys.exit(
exec_check(
cpp_header_dir,
api_versions_file,
api_untracked_file,
options.debugdir,
options.fastcheck and not options.forceupdate,
options.check and options.forceupdate,
skip_untracked,
verbose=options.verbose))
exec_check(api_versions_file, api_untracked_file, options.fastcheck and
not options.force_update, options.check and
options.force_update, skip_untracked, hasher))

View File

@@ -92,7 +92,7 @@ def read_version_files(api_versions_file,
}
initialized = True
else:
json_version = None
json_versions = None
else:
assert 'hashes' in json_versions, api_versions_file
assert 'last' in json_versions, api_versions_file