Add initial support for API versioning (see #3836)

- Generated files are now created when running cef_create_projects or
  the new version_manager.py tool. These files are still created in the
  cef/ source tree (same location as before) but Git ignores them due to
  the generated .gitignore file.
- API hashes are committed to Git as a new cef_api_versions.json file.
  This file is used for both code generation and CEF version calculation
  (replacing the previous usage of cef_api_hash.h for this purpose).
  It will be updated by the CEF admin before merging breaking API
  changes upstream.
- As an added benefit to the above, contributor PRs will no longer
  contain generated code that is susceptible to frequent merge conflicts.
- From a code generation perspective, the main difference is that we now
  use versioned structs (e.g. cef_browser_0_t instead of cef_browser_t)
  on the libcef (dll/framework) side. Most of the make_*.py tool changes
  are related to supporting this.
- From the client perspective, you can now define CEF_API_VERSION in the
  project configuration (or get CEF_EXPERIMENTAL by default). This
  define will change the API exposed in CEF’s include/ and include/capi
  header files. All client-side targets including libcef_dll_wrapper
  will need be recompiled when changing this define.
- Examples of the new API-related define usage are provided in
  cef_api_version_test.h, api_version_test_impl.cc and
  api_version_unittest.cc.

To test:
- Run `ceftests --gtest_filter=ApiVersionTest.*`
- Add `cef_api_version=13300` to GN_DEFINES. Re-run configure, build and
  ceftests steps.
- Repeat with 13301, 13302, 13303 (all supported test versions).
This commit is contained in:
Marshall Greenblatt
2024-12-09 15:20:44 -05:00
parent 219bf3406c
commit dd81904a2f
68 changed files with 7466 additions and 1265 deletions

55
.gitignore.in Normal file
View File

@ -0,0 +1,55 @@
*.gypcmd
*.mk
*.ncb
*.opensdf
*.props
*.pyc
*.rules
*.sdf
*.sln
*.sublime-project
*.sublime-workspace
*.suo
*.targets
*.user
*.vcproj
*.vcxproj
*.vcxproj.filters
*.vpj
*.vpw
*.vpwhistu
*.vtg
*.xcodeproj
*.xcworkspace
*_proto.xml
*_proto_cpp.xml
*~
!Android.mk
.*.sw?
.DS_Store
.classpath
.cproject
.gdb_history
.gdbinit
.landmines
.metadata
.project
.pydevproject
.vscode
# Settings directory for eclipse
/.settings
.checkstyle
cscope.*
Session.vim
tags
Thumbs.db
# IDE's
.vs/
.kdev4/
*.kdev4
# CEF generated directories
/binary_distrib
/docs
# CEF generated files
.ccls-cache/
/cef_api_untracked.json

110
BUILD.gn
View File

@ -360,6 +360,8 @@ if (is_win) {
}
deps = [
":make_version_header",
"//components/crash/core/common", # crash_keys
# Required by chrome_switches.cc
@ -441,6 +443,7 @@ source_set("libcef_test_support") {
"libcef/browser/test/test_helpers_impl.cc",
"libcef/browser/test/test_server_impl.cc",
"libcef/browser/test/test_server_impl.h",
"libcef/common/test/api_version_test_impl.cc",
"libcef/common/test/translator_test_impl.cc",
]
@ -451,6 +454,10 @@ source_set("libcef_test_support") {
# Support for UI input events.
"//ui/views:test_support",
]
configs += [
":libcef_includes_config",
]
}
@ -758,6 +765,7 @@ source_set("libcef_static") {
"libcef/browser/xml_reader_impl.h",
"libcef/browser/zip_reader_impl.cc",
"libcef/browser/zip_reader_impl.h",
"libcef/common/api_version_util.h",
"libcef/common/app_manager.cc",
"libcef/common/app_manager.h",
"libcef/common/base_impl.cc",
@ -1159,6 +1167,10 @@ config("libcef_dll_wrapper_config") {
if (is_mac) {
cflags_objcc = [ "-std=c++17" ]
}
if (cef_api_version != "") {
defines = [ "CEF_API_VERSION=$cef_api_version" ]
}
}
# libcef_dll_wrapper target.
@ -1245,16 +1257,16 @@ grit("cef_resources") {
# Helper for generating pack header files.
template("make_pack_header") {
assert(defined(invoker.header))
assert(defined(invoker.inc))
assert(defined(invoker.inputs))
action("make_pack_header_${target_name}") {
script = "tools/make_pack_header.py"
inputs = invoker.inputs
outputs = [ invoker.header ]
outputs = [ invoker.header, invoker.inc ]
args = rebase_path(outputs, root_build_dir) +
rebase_path(inputs, root_build_dir)
args = rebase_path(outputs + inputs, root_build_dir)
if (defined(invoker.deps)) {
deps = invoker.deps
@ -1265,6 +1277,7 @@ template("make_pack_header") {
# Generate cef_pack_resources.h.
make_pack_header("resources") {
header = "$root_out_dir/includes/cef/include/cef_pack_resources.h"
inc = "$root_gen_dir/cef/libcef_dll/cef_pack_resources.inc"
inputs = [
"$root_gen_dir/base/tracing/protos/grit/tracing_proto_resources.h",
"$root_gen_dir/cef/grit/cef_resources.h",
@ -1331,6 +1344,7 @@ make_pack_header("resources") {
# Generate cef_pack_strings.h.
make_pack_header("strings") {
header = "$root_out_dir/includes/cef/include/cef_pack_strings.h"
inc = "$root_gen_dir/cef/libcef_dll/cef_pack_strings.inc"
inputs = [
"$root_gen_dir/cef/grit/cef_strings.h",
"$root_gen_dir/chrome/grit/branded_strings.h",
@ -1374,26 +1388,39 @@ make_pack_header("strings") {
# Generate cef_command_ids.h.
make_pack_header("command_ids") {
header = "$root_out_dir/includes/cef/include/cef_command_ids.h"
inc = "$root_gen_dir/cef/libcef_dll/cef_command_ids.inc"
inputs = [
"//chrome/app/chrome_command_ids.h",
]
}
# Generate cef_api_hash.h.
action("make_api_hash_header") {
script = "tools/make_api_hash_header.py"
# Generate cef_api_versions.h.
action("make_api_versions_header") {
script = "tools/make_api_versions_header.py"
# List of all C API files that will be checked for changes by cef_api_hash.py.
inputs = gypi_paths2.includes_common_capi +
gypi_paths2.includes_linux_capi +
gypi_paths2.includes_mac_capi +
gypi_paths2.includes_win_capi +
gypi_paths2.includes_capi +
gypi_paths.autogen_capi_includes
include_dir = [ "include" ]
outputs = [ "$root_out_dir/includes/cef/include/cef_api_hash.h" ]
inputs = [
"cef_api_versions.json",
"cef_api_untracked.json",
]
outputs = [
"$root_out_dir/includes/cef/include/cef_api_versions.h",
"$root_gen_dir/cef/libcef_dll/cef_api_versions.inc",
]
args = rebase_path(outputs + include_dir, root_build_dir)
args = rebase_path(outputs + inputs, root_build_dir)
}
# Generate cef_version.h.
action("make_version_header") {
script = "tools/make_version_header.py"
inputs = [
"VERSION.stamp",
"//chrome/VERSION",
]
outputs = [ "$root_out_dir/includes/cef/include/cef_version.h" ]
args = rebase_path(outputs, root_build_dir)
}
# This no-op action lists args.gn as an output, allowing it to be referenced as
@ -1436,7 +1463,8 @@ group("cef_make_headers") {
":make_pack_header_resources",
":make_pack_header_strings",
":make_pack_header_command_ids",
":make_api_hash_header",
":make_api_versions_header",
":make_version_header",
":make_config_header",
":make_colorids_header",
]
@ -1447,6 +1475,28 @@ group("cef_make_headers") {
# libcef dll/framework target.
#
libcef_sources_common = includes_common +
gypi_paths.autogen_cpp_includes +
gypi_paths2.includes_capi +
gypi_paths.autogen_capi_includes +
gypi_paths.autogen_capi_versions_includes +
gypi_paths2.libcef_sources_common +
gypi_paths.autogen_library_side + [
"$root_gen_dir/cef/libcef_dll/cef_pack_resources.inc",
"$root_gen_dir/cef/libcef_dll/cef_pack_strings.inc",
"$root_gen_dir/cef/libcef_dll/cef_command_ids.inc",
"$root_gen_dir/cef/libcef_dll/cef_api_versions.inc",
]
libcef_deps_common = [
":libcef_static",
":libcef_test_support",
":make_pack_header_resources",
":make_pack_header_strings",
":make_pack_header_command_ids",
":make_api_versions_header",
]
if (is_mac) {
cef_framework_name = "Chromium Embedded Framework"
@ -1530,24 +1580,17 @@ if (is_mac) {
"Resources",
]
sources = includes_common +
includes_mac +
gypi_paths.autogen_cpp_includes +
gypi_paths2.includes_capi +
gypi_paths.autogen_capi_includes +
gypi_paths2.libcef_sources_common +
gypi_paths.autogen_library_side
sources = libcef_sources_common + includes_mac
deps = [
deps = libcef_deps_common + [
":cef_framework_angle_binaries",
":cef_framework_resources",
":cef_framework_swiftshader_binaries",
":libcef_static",
":libcef_test_support",
]
configs += [
":libcef_autogen_config",
":libcef_includes_config",
]
# We don't link the framework so just use the path from the main executable.
@ -1586,20 +1629,13 @@ if (is_mac) {
# Necessary because the libcef_test_support target is testonly.
testonly = true
sources = includes_common +
gypi_paths.autogen_cpp_includes +
gypi_paths2.includes_capi +
gypi_paths.autogen_capi_includes +
gypi_paths2.libcef_sources_common +
gypi_paths.autogen_library_side
sources = libcef_sources_common
deps = [
":libcef_static",
":libcef_test_support",
]
deps = libcef_deps_common
configs += [
":libcef_autogen_config",
":libcef_includes_config",
":pdb_larger_than_4gb",
]

34
cef_api_versions.json Normal file
View File

@ -0,0 +1,34 @@
{
"hashes": {
"13300": {
"comment": "Added January 07, 2025.",
"linux": "f0b073047a026b83e911ba60aa1a83f036d31b0e",
"mac": "39c1f7df430aeaf39911147032b266416658c11d",
"universal": "dd40c0c97ba3f4a1f4ec53ff64d19fea30217d3d",
"windows": "4d97ebe2ed64b448b23625c6bd3943797ac3e137"
},
"13301": {
"comment": "Added January 07, 2025.",
"linux": "41f72b80f8a2d00ea8301cda42d37b8fdf0240a5",
"mac": "e44f5eb6d634f3d4353f52ff383bf213f3894bbd",
"universal": "f7edff150ad480bc2f5cfc85fd6bfa23fbc4a73f",
"windows": "130d2eed0662c065a1cee3c782a6d855c63d67e8"
},
"13302": {
"comment": "Added January 07, 2025.",
"linux": "2ef9e3f071838f2d7705d144cf66e0f5ae69b32f",
"mac": "ec74fb1f9aff97f55882dbb35ba979934c8ab1a7",
"universal": "d9c1eedf985ddcd4e9df05f7664b111462d45626",
"windows": "f4d05b712907d8d64df80029d9e2e8edbee814ac"
},
"13303": {
"comment": "Added January 07, 2025.",
"linux": "397ad962a3049dad4b36b356c8d108f78603de60",
"mac": "f7a5c733b8c3cd6fa3a284ce9b307566c6aa5860",
"universal": "91d5546d2b3f601ab2453f218a7bd69d2fd39b1b",
"windows": "b24722530b6b77bd1a633af5d72088225468eee2"
}
},
"last": "13303",
"min": "13300"
}

View File

@ -36,7 +36,6 @@
'include/base/internal/cef_thread_checker_impl.h',
'include/cef_api_hash.h',
'include/cef_base.h',
'include/cef_version.h',
'include/internal/cef_export.h',
'include/internal/cef_ptr.h',
'include/internal/cef_string_wrappers.h',
@ -44,6 +43,8 @@
'include/internal/cef_types_wrappers.h',
],
'includes_common_capi': [
'include/cef_id_mappers.h',
'include/cef_version_info.h',
'include/internal/cef_dump_without_crashing_internal.h',
'include/internal/cef_logging_internal.h',
'include/internal/cef_string.h',
@ -483,6 +484,7 @@
'tests/ceftests/resources/net/data/ssl/certificates/root_ca_cert.pem',
],
'ceftests_sources_common': [
'tests/ceftests/api_version_unittest.cc',
'tests/ceftests/audio_output_unittest.cc',
'tests/ceftests/browser_info_map_unittest.cc',
'tests/ceftests/certificate_error_unittest.cc',

View File

@ -69,6 +69,20 @@ list(APPEND CEF_COMPILER_DEFINES
option(USE_SANDBOX "Enable or disable use of the sandbox." ON)
# Optionally configure the CEF API version by adding `-D api_version=XXXXX` to the
# cmake command-line where XXXXX is the desired version number. For background see
# https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
if(DEFINED api_version)
string(LENGTH "${api_version}" length)
if (NOT length EQUAL 5 OR NOT api_version MATCHES "^[0-9]+$")
message(FATAL_ERROR "Expected a 5 digit number for api_version, got '${api_version}'")
endif()
list(APPEND CEF_COMPILER_DEFINES
CEF_API_VERSION=${api_version}
)
endif()
#
# Linux configuration.
#

View File

@ -85,7 +85,10 @@
#endif
#else // !USING_CHROMIUM_INCLUDES
#if !defined(GENERATING_CEF_API_HASH)
#include "include/cef_config.h"
#endif
// The following is substantially similar to the Chromium implementation.
// If the Chromium implementation diverges the below implementation should be

View File

@ -44,62 +44,54 @@ extern "C" {
#endif
///
// All ref-counted framework structures must include this structure first.
/// All ref-counted framework structures must include this structure first.
///
typedef struct _cef_base_ref_counted_t {
///
// Size of the data structure.
/// Size of the data structure.
///
size_t size;
///
// Called to increment the reference count for the object. Should be called
// for every new copy of a pointer to a given object.
/// Called to increment the reference count for the object. Should be called
/// for every new copy of a pointer to a given object.
///
void(CEF_CALLBACK* add_ref)(struct _cef_base_ref_counted_t* self);
///
// Called to decrement the reference count for the object. If the reference
// count falls to 0 the object should self-delete. Returns true (1) if the
// resulting reference count is 0.
/// Called to decrement the reference count for the object. If the reference
/// count falls to 0 the object should self-delete. Returns true (1) if the
/// resulting reference count is 0.
///
int(CEF_CALLBACK* release)(struct _cef_base_ref_counted_t* self);
///
// Returns true (1) if the current reference count is 1.
/// Returns true (1) if the current reference count is 1.
///
int(CEF_CALLBACK* has_one_ref)(struct _cef_base_ref_counted_t* self);
///
// Returns true (1) if the current reference count is at least 1.
/// Returns true (1) if the current reference count is at least 1.
///
int(CEF_CALLBACK* has_at_least_one_ref)(struct _cef_base_ref_counted_t* self);
} cef_base_ref_counted_t;
///
// All scoped framework structures must include this structure first.
/// All scoped framework structures must include this structure first.
///
typedef struct _cef_base_scoped_t {
///
// Size of the data structure.
/// Size of the data structure.
///
size_t size;
///
// Called to delete this object. May be NULL if the object is not owned.
/// Called to delete this object. May be NULL if the object is not owned.
///
void(CEF_CALLBACK* del)(struct _cef_base_scoped_t* self);
} cef_base_scoped_t;
// Check that the structure |s|, which is defined with a size_t member at the
// top, is large enough to contain the specified member |f|.
#define CEF_MEMBER_EXISTS(s, f) \
((intptr_t) & \
((s)->f) - (intptr_t)(s) + sizeof((s)->f) <= *reinterpret_cast<size_t*>(s))
#define CEF_MEMBER_MISSING(s, f) (!CEF_MEMBER_EXISTS(s, f) || !((s)->f))
#ifdef __cplusplus
}
#endif

View File

@ -27,45 +27,124 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_api_hash_header.py tool.
// Versions are managed using the version_manager.py tool. For usage details
// see https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
//
#ifndef CEF_INCLUDE_API_HASH_H_
#define CEF_INCLUDE_API_HASH_H_
#ifndef CEF_INCLUDE_CEF_API_HASH_H_
#define CEF_INCLUDE_CEF_API_HASH_H_
#include "include/internal/cef_export.h"
// The API hash is created 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 "e52a54bfb4cfc13366fe52766756180fc7d3d1b2"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "ce7bfedc905e90407eb975eebf2f419a347b27cd"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "8bb21c09270905fe64b8c31f744e0cbf7bc39ff5"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "a8198f66f731c8ac91bba1e45847807bffca7b01"
#if !defined(GENERATING_CEF_API_HASH)
#include "include/cef_api_versions.h"
#endif
// Experimental CEF API. Experimental API is unversioned, meaning that it is
// excluded (compiled out) when clients explicitly set the CEF_API_VERSION
// value in their project configuration. Experimental API is not back/forward
// compatible with different CEF versions.
#define CEF_API_VERSION_EXPERIMENTAL 999999
// Placeholder for the next CEF version currently under development. This is a
// temporary value that must be replaced with the actual next version number
// (output of running `version_manager.py -n`) prior to upstream merge. As an
// added reminder, use of this value will cause version_manager.py to fail when
// computing hashes for explicit API versions. When adding new API consider
// using CEF_API_VERSION_EXPERIMENTAL instead.
#if !defined(CEF_API_VERSION_NEXT)
#define CEF_API_VERSION_NEXT 999998
#endif
// Shorter versions of the above for convenience use in comparison macros.
#define CEF_NEXT CEF_API_VERSION_NEXT
#define CEF_EXPERIMENTAL CEF_API_VERSION_EXPERIMENTAL
// API version that will be compiled client-side. The experimental (unversioned)
// API is selected by default. Clients can set the CEF_API_VERSION value in
// their project configuration to configure an explicit API version. Unlike
// the experimental API, explicit API versions are back/forward compatible with
// a specific range of CEF versions.
#if !defined(CEF_API_VERSION)
#define CEF_API_VERSION CEF_API_VERSION_EXPERIMENTAL
#endif
#if !defined(GENERATING_CEF_API_HASH)
#if CEF_API_VERSION < CEF_API_VERSION_MIN || \
(CEF_API_VERSION > CEF_API_VERSION_LAST && CEF_API_VERSION != CEF_NEXT && \
CEF_API_VERSION != CEF_EXPERIMENTAL)
#error Building with unsupported CEF_API_VERSION value
#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)
// 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)
#if defined(BUILDING_CEF_SHARED)
#define _CEF_AV_LT(v) 1
#define _CEF_AV_GE(v) 1
#else // !defined(BUILDING_CEF_SHARED)
#define _CEF_AV_CMP(v, op) (CEF_API_VERSION op v)
#define _CEF_AV_LT(v) _CEF_AV_CMP(v, <)
#define _CEF_AV_GE(v) _CEF_AV_CMP(v, >=)
#endif // !defined(BUILDING_CEF_SHARED)
///
/// API was added in the specified version.
///
#define CEF_API_ADDED(v) _CEF_AV_GE(v)
///
/// API was removed in the specified version.
///
#define CEF_API_REMOVED(v) _CEF_AV_LT(v)
///
/// API exists only in the specified version range.
///
#define CEF_API_RANGE(va, vr) (_CEF_AV_GE(va) && _CEF_AV_LT(vr))
#ifdef __cplusplus
extern "C" {
#endif
///
// Returns CEF API hashes for the libcef library. The returned string is owned
// by the library and should not be freed. The |entry| parameter describes which
// hash value will be returned:
// 0 - CEF_API_HASH_PLATFORM
// 1 - CEF_API_HASH_UNIVERSAL
// 2 - CEF_COMMIT_HASH (from cef_version.h)
/// Configures the CEF API version and returns API hashes for the libcef
/// library. The returned string is owned by the library and should not be
/// freed. The |version| parameter should be CEF_API_VERSION and any changes to
/// this value will be ignored after the first call to this method. The |entry|
/// parameter describes which hash value will be returned:
///
CEF_EXPORT const char* cef_api_hash(int entry);
/// 0 - CEF_API_HASH_PLATFORM
/// 1 - CEF_API_HASH_UNIVERSAL
/// 2 - CEF_COMMIT_HASH (from cef_version.h)
///
CEF_EXPORT const char* cef_api_hash(int version, int entry);
///
/// Returns the CEF API version that was configured by the first call to
/// cef_api_hash().
///
CEF_EXPORT int cef_api_version();
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_API_HASH_H_
#endif // CEF_INCLUDE_CEF_API_HASH_H_

View File

@ -1022,17 +1022,21 @@ class CefBrowserHost : public virtual CefBaseRefCounted {
virtual void ExitFullscreen(bool will_cause_resize) = 0;
///
/// Returns true if a Chrome command is supported and enabled. Values for
/// |command_id| can be found in the cef_command_ids.h file. This method can
/// only be called on the UI thread. Only used with Chrome style.
/// Returns true if a Chrome command is supported and enabled. Use the
/// cef_id_for_command_id_name() function for version-safe mapping of command
/// IDC names from cef_command_ids.h to version-specific numerical
/// |command_id| values. This method can only be called on the UI thread. Only
/// used with Chrome style.
///
/*--cef()--*/
virtual bool CanExecuteChromeCommand(int command_id) = 0;
///
/// Execute a Chrome command. Values for |command_id| can be found in the
/// cef_command_ids.h file. |disposition| provides information about the
/// intended command target. Only used with Chrome style.
/// Execute a Chrome command. Use the cef_id_for_command_id_name()
/// function for version-safe mapping of command IDC names from
/// cef_command_ids.h to version-specific numerical |command_id| values.
/// |disposition| provides information about the intended command target. Only
/// used with Chrome style.
///
/*--cef()--*/
virtual void ExecuteChromeCommand(

View File

@ -50,12 +50,13 @@ class CefCommandHandler : public virtual CefBaseRefCounted {
public:
///
/// Called to execute a Chrome command triggered via menu selection or
/// keyboard shortcut. Values for |command_id| can be found in the
/// cef_command_ids.h file. |disposition| provides information about the
/// intended command target. Return true if the command was handled or false
/// for the default implementation. For context menu commands this will be
/// called after CefContextMenuHandler::OnContextMenuCommand. Only used with
/// Chrome style.
/// keyboard shortcut. Use the cef_id_for_command_id_name()
/// function for version-safe mapping of command IDC names from
/// cef_command_ids.h to version-specific numerical |command_id| values.
/// |disposition| provides information about the intended command target.
/// Return true if the command was handled or false for the default
/// implementation. For context menu commands this will be called after
/// CefContextMenuHandler::OnContextMenuCommand. Only used with Chrome style.
///
/*--cef()--*/
virtual bool OnChromeCommand(CefRefPtr<CefBrowser> browser,
@ -65,9 +66,11 @@ class CefCommandHandler : public virtual CefBaseRefCounted {
}
///
/// Called to check if a Chrome app menu item should be visible. Values for
/// |command_id| can be found in the cef_command_ids.h file. Only called for
/// menu items that would be visible by default. Only used with Chrome style.
/// Called to check if a Chrome app menu item should be visible. Use the
/// cef_id_for_command_id_name() function for version-safe mapping of command
/// IDC names from cef_command_ids.h to version-specific numerical
/// |command_id| values. Only called for menu items that would be visible by
/// default. Only used with Chrome style.
///
/*--cef()--*/
virtual bool IsChromeAppMenuItemVisible(CefRefPtr<CefBrowser> browser,
@ -76,9 +79,11 @@ class CefCommandHandler : public virtual CefBaseRefCounted {
}
///
/// Called to check if a Chrome app menu item should be enabled. Values for
/// |command_id| can be found in the cef_command_ids.h file. Only called for
/// menu items that would be enabled by default. Only used with Chrome style.
/// Called to check if a Chrome app menu item should be enabled. Use the
/// cef_id_for_command_id_name() function for version-safe mapping of command
/// IDC names from cef_command_ids.h to version-specific numerical
/// |command_id| values. Only called for menu items that would be enabled by
/// default. Only used with Chrome style.
///
/*--cef()--*/
virtual bool IsChromeAppMenuItemEnabled(CefRefPtr<CefBrowser> browser,

89
include/cef_id_mappers.h Normal file
View File

@ -0,0 +1,89 @@
// Copyright (c) 2025 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CEF_INCLUDE_CEF_ID_MAPPERS_H_
#define CEF_INCLUDE_CEF_ID_MAPPERS_H_
#pragma once
///
/// Helper for declaring a static IDR variable.
///
#define CEF_DECLARE_PACK_RESOURCE_ID(name) \
static const int name = cef_id_for_pack_resource_name(#name)
///
/// Helper for declaring a static IDS variable.
///
#define CEF_DECLARE_PACK_STRING_ID(name) \
static const int name = cef_id_for_pack_string_name(#name)
///
/// Helper for declaring a static IDC variable.
///
#define CEF_DECLARE_COMMAND_ID(name) \
static const int name = cef_id_for_command_id_name(#name)
#ifdef __cplusplus
extern "C" {
#endif
#include "include/internal/cef_export.h"
///
/// Returns the numeric ID value for an IDR |name| from cef_pack_resources.h or
/// -1 if |name| is unrecognized by the current CEF/Chromium build. This
/// function provides version-safe mapping of resource IDR names to
/// version-specific numeric ID values. Numeric ID values are likely to change
/// across CEF/Chromium versions but names generally remain the same.
///
CEF_EXPORT int cef_id_for_pack_resource_name(const char* name);
///
/// Returns the numeric ID value for an IDS |name| from cef_pack_strings.h or -1
/// if |name| is unrecognized by the current CEF/Chromium build. This function
/// provides version-safe mapping of string IDS names to version-specific
/// numeric ID values. Numeric ID values are likely to change across
/// CEF/Chromium versions but names generally remain the same.
///
CEF_EXPORT int cef_id_for_pack_string_name(const char* name);
///
/// Returns the numeric ID value for an IDC |name| from cef_command_ids.h or -1
/// if |name| is unrecognized by the current CEF/Chromium build. This function
/// provides version-safe mapping of command IDC names to version-specific
/// numeric ID values. Numeric ID values are likely to change across
/// CEF/Chromium versions but names generally remain the same.
///
CEF_EXPORT int cef_id_for_command_id_name(const char* name);
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_CEF_ID_MAPPERS_H_

View File

@ -61,16 +61,19 @@ class CefResourceBundle : public virtual CefBaseRefCounted {
///
/// Returns the localized string for the specified |string_id| or an empty
/// string if the value is not found. Include cef_pack_strings.h for a listing
/// of valid string ID values.
/// string if the value is not found. Use the cef_id_for_pack_string_name()
/// function for version-safe mapping of string IDS names from
/// cef_pack_strings.h to version-specific numerical |string_id| values.
///
/*--cef()--*/
virtual CefString GetLocalizedString(int string_id) = 0;
///
/// Returns a CefBinaryValue containing the decompressed contents of the
/// specified scale independent |resource_id| or NULL if not found. Include
/// cef_pack_resources.h for a listing of valid resource ID values.
/// specified scale independent |resource_id| or NULL if not found. Use the
/// cef_id_for_pack_resource_name() function for version-safe mapping of
/// resource IDR names from cef_pack_resources.h to version-specific numerical
/// |resource_id| values.
///
/*--cef()--*/
virtual CefRefPtr<CefBinaryValue> GetDataResource(int resource_id) = 0;
@ -79,8 +82,10 @@ class CefResourceBundle : public virtual CefBaseRefCounted {
/// Returns a CefBinaryValue containing the decompressed contents of the
/// specified |resource_id| nearest the scale factor |scale_factor| or NULL if
/// not found. Use a |scale_factor| value of SCALE_FACTOR_NONE for scale
/// independent resources or call GetDataResource instead.Include
/// cef_pack_resources.h for a listing of valid resource ID values.
/// independent resources or call GetDataResource instead. Use the
/// cef_id_for_pack_resource_name() function for version-safe mapping of
/// resource IDR names from cef_pack_resources.h to version-specific numerical
/// |resource_id| values.
///
/*--cef()--*/
virtual CefRefPtr<CefBinaryValue> GetDataResourceForScale(

View File

@ -53,8 +53,10 @@ class CefResourceBundleHandler : public virtual CefBaseRefCounted {
///
/// Called to retrieve a localized translation for the specified |string_id|.
/// To provide the translation set |string| to the translation string and
/// return true. To use the default translation return false. Include
/// cef_pack_strings.h for a listing of valid string ID values.
/// return true. To use the default translation return false. Use the
/// cef_id_for_pack_string_name() function for version-safe mapping of string
/// IDS names from cef_pack_strings.h to version-specific numerical
/// |string_id| values.
///
/*--cef()--*/
virtual bool GetLocalizedString(int string_id, CefString& string) = 0;
@ -64,8 +66,9 @@ class CefResourceBundleHandler : public virtual CefBaseRefCounted {
/// To provide the resource data set |data| and |data_size| to the data
/// pointer and size respectively and return true. To use the default resource
/// data return false. The resource data will not be copied and must remain
/// resident in memory. Include cef_pack_resources.h for a listing of valid
/// resource ID values.
/// resident in memory. Use the cef_id_for_pack_resource_name() function for
/// version-safe mapping of resource IDR names from cef_pack_resources.h to
/// version-specific numerical |resource_id| values.
///
/*--cef()--*/
virtual bool GetDataResource(int resource_id,
@ -77,8 +80,10 @@ class CefResourceBundleHandler : public virtual CefBaseRefCounted {
/// factor |scale_factor|. To provide the resource data set |data| and
/// |data_size| to the data pointer and size respectively and return true. To
/// use the default resource data return false. The resource data will not be
/// copied and must remain resident in memory. Include cef_pack_resources.h
/// for a listing of valid resource ID values.
/// copied and must remain resident in memory. Use the
/// cef_id_for_pack_resource_name() function for version-safe mapping of
/// resource IDR names from cef_pack_resources.h to version-specific numerical
/// |resource_id| values.
///
/*--cef()--*/
virtual bool GetDataResourceForScale(int resource_id,

View File

@ -0,0 +1,62 @@
// Copyright (c) 2024 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CEF_INCLUDE_CEF_VERSION_INFO_H_
#define CEF_INCLUDE_CEF_VERSION_INFO_H_
#include "include/internal/cef_export.h"
#if !defined(GENERATING_CEF_API_HASH)
#include "include/cef_version.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
///
/// Returns CEF version information for the libcef library. The |entry|
/// parameter describes which version component will be returned:
///
/// 0 - CEF_VERSION_MAJOR
/// 1 - CEF_VERSION_MINOR
/// 2 - CEF_VERSION_PATCH
/// 3 - CEF_COMMIT_NUMBER
/// 4 - CHROME_VERSION_MAJOR
/// 5 - CHROME_VERSION_MINOR
/// 6 - CHROME_VERSION_BUILD
/// 7 - CHROME_VERSION_PATCH
///
CEF_EXPORT int cef_version_info(int entry);
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_CEF_VERSION_INFO_H_

View File

@ -36,9 +36,9 @@
#if defined(COMPILER_MSVC)
#ifdef BUILDING_CEF_SHARED
#if defined(BUILDING_CEF_SHARED)
#define CEF_EXPORT __declspec(dllexport)
#elif USING_CEF_SHARED
#elif defined(USING_CEF_SHARED)
#define CEF_EXPORT __declspec(dllimport)
#else
#define CEF_EXPORT

File diff suppressed because it is too large Load Diff

View File

@ -39,8 +39,8 @@
// be included from unit test targets.
//
#ifndef CEF_INCLUDE_TEST_CEF_TEST_H_
#define CEF_INCLUDE_TEST_CEF_TEST_H_
#ifndef CEF_INCLUDE_TEST_CEF_TRANSLATOR_TEST_H_
#define CEF_INCLUDE_TEST_CEF_TRANSLATOR_TEST_H_
#pragma once
#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
@ -805,4 +805,4 @@ class CefTranslatorTestScopedClientChild
virtual int GetOtherValue() = 0;
};
#endif // CEF_INCLUDE_TEST_CEF_TEST_H_
#endif // CEF_INCLUDE_TEST_CEF_TRANSLATOR_TEST_H_

View File

@ -0,0 +1,54 @@
// Copyright (c) 2024 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_COMMON_API_VERSION_UTIL_H_
#define CEF_LIBCEF_COMMON_API_VERSION_UTIL_H_
#pragma once
#include "base/logging.h"
#include "base/notreached.h"
#include "cef/include/cef_api_hash.h"
#define _CEF_RA_CMP(v, op) (cef_api_version() op v)
#define _CEF_RA_LT(v) _CEF_RA_CMP(v, <)
#define _CEF_RA_GE(v) _CEF_RA_CMP(v, >=)
#define _CEF_RA_CHECK(check) \
check << __func__ << " called for invalid API version " << cef_api_version()
// Helpers for fatally asserting (with [[noreturn]]) that the configured
// CEF API version matches expectations.
// Assert that the specified version-related condition is true.
#define CEF_API_ASSERT(condition) _CEF_RA_CHECK(LOG_IF(FATAL, (condition)))
// Annotate should-be unreachable version-related code.
#define CEF_API_NOTREACHED() _CEF_RA_CHECK(NOTREACHED())
// Assert that API was added in the specified version.
// Pair with CEF_API_ADDED usage in CEF header files.
#define CEF_API_REQUIRE_ADDED(v) CEF_API_ASSERT(_CEF_RA_LT(v))
// Assert that API was removed in the specified version.
// Pair with CEF_API_REMOVED usage in CEF header files.
#define CEF_API_REQUIRE_REMOVED(v) CEF_API_ASSERT(_CEF_RA_GE(v))
// Assert that API exists only in the specified version range.
// Pair with CEF_API_RANGE usage in CEF header files.
#define CEF_API_REQUIRE_RANGE(va, vr) \
CEF_API_ASSERT(_CEF_RA_LT(va) || _CEF_RA_GE(vr))
// Helpers for testing the configured CEF API version in conditionals.
// True if API was added in the specified version.
#define CEF_API_IS_ADDED(v) _CEF_RA_GE(v)
// True if API was removed in the specified version.
#define CEF_API_IS_REMOVED(v) _CEF_RA_LT(v)
// True if API exists only in the specified version range.
#define CEF_API_IS_RANGE(va, vr) (_CEF_RA_GE(va) && _CEF_RA_LT(vr))
#endif // CEF_LIBCEF_COMMON_API_VERSION_UTIL_H_

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,8 @@
#include "cef/include/test/cef_translator_test.h"
namespace {
class CefTranslatorTestRefPtrLibraryImpl
: public CefTranslatorTestRefPtrLibrary {
public:
@ -18,19 +20,22 @@ class CefTranslatorTestRefPtrLibraryImpl
void SetValue(int value) override { value_ = value; }
protected:
private:
int value_;
private:
IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryImpl);
};
} // namespace
// static
CefRefPtr<CefTranslatorTestRefPtrLibrary>
CefTranslatorTestRefPtrLibrary::Create(int value) {
return new CefTranslatorTestRefPtrLibraryImpl(value);
}
namespace {
class CefTranslatorTestRefPtrLibraryChildImpl
: public CefTranslatorTestRefPtrLibraryChild {
public:
@ -50,20 +55,23 @@ class CefTranslatorTestRefPtrLibraryChildImpl
void SetOtherValue(int value) override { other_value_ = value; }
protected:
private:
int value_;
int other_value_;
private:
IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildImpl);
};
} // namespace
// static
CefRefPtr<CefTranslatorTestRefPtrLibraryChild>
CefTranslatorTestRefPtrLibraryChild::Create(int value, int other_value) {
return new CefTranslatorTestRefPtrLibraryChildImpl(value, other_value);
}
namespace {
class CefTranslatorTestRefPtrLibraryChildChildImpl
: public CefTranslatorTestRefPtrLibraryChildChild {
public:
@ -91,15 +99,16 @@ class CefTranslatorTestRefPtrLibraryChildChildImpl
void SetOtherOtherValue(int value) override { other_other_value_ = value; }
protected:
private:
int value_;
int other_value_;
int other_other_value_;
private:
IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildChildImpl);
};
} // namespace
// static
CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild>
CefTranslatorTestRefPtrLibraryChildChild::Create(int value,
@ -109,6 +118,8 @@ CefTranslatorTestRefPtrLibraryChildChild::Create(int value,
other_other_value);
}
namespace {
class CefTranslatorTestScopedLibraryImpl
: public CefTranslatorTestScopedLibrary {
public:
@ -123,10 +134,12 @@ class CefTranslatorTestScopedLibraryImpl
void SetValue(int value) override { value_ = value; }
protected:
private:
int value_;
};
} // namespace
// static
CefOwnPtr<CefTranslatorTestScopedLibrary>
CefTranslatorTestScopedLibrary::Create(int value) {
@ -134,6 +147,8 @@ CefTranslatorTestScopedLibrary::Create(int value) {
new CefTranslatorTestScopedLibraryImpl(value));
}
namespace {
class CefTranslatorTestScopedLibraryChildImpl
: public CefTranslatorTestScopedLibraryChild {
public:
@ -153,11 +168,13 @@ class CefTranslatorTestScopedLibraryChildImpl
void SetOtherValue(int value) override { other_value_ = value; }
protected:
private:
int value_;
int other_value_;
};
} // namespace
// static
CefOwnPtr<CefTranslatorTestScopedLibraryChild>
CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) {
@ -165,6 +182,8 @@ CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) {
new CefTranslatorTestScopedLibraryChildImpl(value, other_value));
}
namespace {
class CefTranslatorTestScopedLibraryChildChildImpl
: public CefTranslatorTestScopedLibraryChildChild {
public:
@ -192,12 +211,14 @@ class CefTranslatorTestScopedLibraryChildChildImpl
void SetOtherOtherValue(int value) override { other_other_value_ = value; }
protected:
private:
int value_;
int other_value_;
int other_other_value_;
};
} // namespace
// static
CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>
CefTranslatorTestScopedLibraryChildChild::Create(int value,
@ -208,6 +229,8 @@ CefTranslatorTestScopedLibraryChildChild::Create(int value,
other_other_value));
}
namespace {
class CefTranslatorTestImpl : public CefTranslatorTest {
public:
CefTranslatorTestImpl() = default;
@ -595,6 +618,8 @@ class CefTranslatorTestImpl : public CefTranslatorTest {
IMPLEMENT_REFCOUNTING(CefTranslatorTestImpl);
};
} // namespace
// static
CefRefPtr<CefTranslatorTest> CefTranslatorTest::Create() {
return new CefTranslatorTestImpl();

View File

@ -11,4 +11,7 @@ declare_args() {
# FOR OTHER CHROMIUM/CEF BUILD CONFIGURATIONS AS ITS USE MAY HAVE SIGNIFICANT
# PERFORMANCE AND/OR SECURITY IMPLICATIONS.
is_cef_sandbox_build = false
# Optionally configure the CEF API version. This impacts wrapper-side only.
cef_api_version = ""
}

View File

@ -23,4 +23,7 @@ class CefBaseRefCountedCppToC
CefBaseRefCountedCppToC();
};
constexpr auto CefBaseRefCountedCppToC_Wrap = CefBaseRefCountedCppToC::Wrap;
constexpr auto CefBaseRefCountedCppToC_Unwrap = CefBaseRefCountedCppToC::Unwrap;
#endif // CEF_LIBCEF_DLL_CPPTOC_BASE_REF_COUNTED_CPPTOC_H_

View File

@ -22,4 +22,17 @@ class CefBaseScopedCppToC : public CefCppToCScoped<CefBaseScopedCppToC,
CefBaseScopedCppToC();
};
constexpr auto CefBaseScopedCppToC_WrapOwn = CefBaseScopedCppToC::WrapOwn;
constexpr auto CefBaseScopedCppToC_WrapRaw = CefBaseScopedCppToC::WrapRaw;
constexpr auto CefBaseScopedCppToC_UnwrapOwn = CefBaseScopedCppToC::UnwrapOwn;
constexpr auto CefBaseScopedCppToC_UnwrapRaw = CefBaseScopedCppToC::UnwrapRaw;
constexpr auto CefBaseScopedCppToC_GetWrapper = CefBaseScopedCppToC::GetWrapper;
inline cef_base_scoped_t* CefBaseScopedCppToC_WrapRawAndRelease(
CefRawPtr<CefBaseScoped> c) {
auto [ownerPtr, structPtr] = CefBaseScopedCppToC_WrapRaw(c);
ownerPtr.release();
return structPtr;
}
#endif // CEF_LIBCEF_DLL_CPPTOC_BASE_CPPTOC_H_

View File

@ -45,7 +45,8 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
}
// Cast our structure to the wrapper structure type.
WrapperStruct* wrapperStruct = GetWrapperStruct(s);
WrapperStruct* wrapperStruct =
GetWrapperStruct(s, /*require_exact_type=*/false);
// If the type does not match this object then we need to unwrap as the
// derived type.
@ -68,8 +69,6 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
static CefRefPtr<BaseName> Get(StructName* s) {
DCHECK(s);
WrapperStruct* wrapperStruct = GetWrapperStruct(s);
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->object_;
}
@ -122,13 +121,21 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
StructName struct_;
};
static WrapperStruct* GetWrapperStruct(StructName* s) {
static WrapperStruct* GetWrapperStruct(StructName* s,
bool require_exact_type = true) {
// Offset using the WrapperStruct size instead of individual member sizes
// to avoid problems due to platform/compiler differences in structure
// padding.
return reinterpret_cast<WrapperStruct*>(
auto* wrapperStruct = reinterpret_cast<WrapperStruct*>(
reinterpret_cast<char*>(s) -
(sizeof(WrapperStruct) - sizeof(StructName)));
if (require_exact_type) {
// Verify that the wrapper offset was calculated correctly.
CHECK_EQ(kWrapperType, wrapperStruct->type_);
}
return wrapperStruct;
}
// Unwrap as the derived type.
@ -152,9 +159,6 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
WrapperStruct* wrapperStruct =
GetWrapperStruct(reinterpret_cast<StructName*>(base));
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
wrapperStruct->wrapper_->AddRef();
}
@ -166,9 +170,6 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
WrapperStruct* wrapperStruct =
GetWrapperStruct(reinterpret_cast<StructName*>(base));
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->wrapper_->Release();
}
@ -180,9 +181,6 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
WrapperStruct* wrapperStruct =
GetWrapperStruct(reinterpret_cast<StructName*>(base));
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->wrapper_->HasOneRef();
}
@ -195,9 +193,6 @@ class CefCppToCRefCounted : public CefBaseRefCounted {
WrapperStruct* wrapperStruct =
GetWrapperStruct(reinterpret_cast<StructName*>(base));
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->wrapper_->HasAtLeastOneRef();
}

View File

@ -6,6 +6,8 @@
#define CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_
#pragma once
#include <utility>
#include "include/base/cef_logging.h"
#include "include/capi/cef_base_capi.h"
#include "include/cef_base.h"
@ -52,17 +54,18 @@ class CefCppToCScoped : public CefBaseScoped {
// For example:
//
// void MyMethod(MyType* obj) {
// CefOwnPtr<MyTypeCppToC> MyTypeWrapper = MyTypeCppToC::WrapRaw(obj);
// my_method(MyTypeWrapper->GetStruct());
// [MyTypeWrapper, MyTypeStruct] = MyTypeCppToC::WrapRaw(obj);
// my_method(MyTypeStruct);
// // MyTypeWrapper is deleted when MyMethod() goes out of scope.
// }
//
// void my_method(my_type_t* struct) {
// // Access |struct| here but you can't delete it.
// }
static CefOwnPtr<ClassName> WrapRaw(CefRawPtr<BaseName> c) {
static std::pair<CefOwnPtr<CefBaseScoped>, StructName*> WrapRaw(
CefRawPtr<BaseName> c) {
if (!c) {
return CefOwnPtr<ClassName>();
return std::make_pair(nullptr, nullptr);
}
// Wrap our object with the CefCppToC class.
@ -70,7 +73,9 @@ class CefCppToCScoped : public CefBaseScoped {
wrapper->Initialize(c, false);
// Return the owned wrapper object.
return CefOwnPtr<ClassName>(wrapper);
CefOwnPtr<ClassName> wrapperPtr(wrapper);
auto* wrapperStruct = wrapperPtr->GetStruct();
return std::make_pair(std::move(wrapperPtr), wrapperStruct);
}
// Retrieve the underlying object instance for a structure reference passed
@ -87,7 +92,8 @@ class CefCppToCScoped : public CefBaseScoped {
}
// Cast our structure to the wrapper structure type.
WrapperStruct* wrapperStruct = GetWrapperStruct(s);
WrapperStruct* wrapperStruct =
GetWrapperStruct(s, /*require_exact_type=*/false);
// If the type does not match this object then we need to unwrap as the
// derived type.
@ -96,8 +102,8 @@ class CefCppToCScoped : public CefBaseScoped {
}
// We should own the underlying object currently.
DCHECK(wrapperStruct->wrapper_->owned_);
DCHECK(wrapperStruct->object_);
CHECK(wrapperStruct->wrapper_->owned_);
CHECK(wrapperStruct->object_);
// We're giving up ownership of the underlying object. Clear the pointer so
// it doesn't get deleted.
@ -123,7 +129,8 @@ class CefCppToCScoped : public CefBaseScoped {
}
// Cast our structure to the wrapper structure type.
WrapperStruct* wrapperStruct = GetWrapperStruct(s);
WrapperStruct* wrapperStruct =
GetWrapperStruct(s, /*require_exact_type=*/false);
// If the type does not match this object then we need to unwrap as the
// derived type.
@ -137,12 +144,10 @@ class CefCppToCScoped : public CefBaseScoped {
// Retrieve the same side wrapper associated with the structure. Ownership
// does not change.
static ClassName* GetWrapper(StructName* s) {
static CefBaseScoped* GetWrapper(StructName* s) {
DCHECK(s);
WrapperStruct* wrapperStruct = GetWrapperStruct(s);
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return static_cast<ClassName*>(wrapperStruct->wrapper_);
return wrapperStruct->wrapper_;
}
// Retrieve the underlying object instance from our own structure reference
@ -151,8 +156,6 @@ class CefCppToCScoped : public CefBaseScoped {
static BaseName* Get(StructName* s) {
DCHECK(s);
WrapperStruct* wrapperStruct = GetWrapperStruct(s);
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->object_;
}
@ -196,13 +199,21 @@ class CefCppToCScoped : public CefBaseScoped {
}
}
static WrapperStruct* GetWrapperStruct(StructName* s) {
static WrapperStruct* GetWrapperStruct(StructName* s,
bool require_exact_type = true) {
// Offset using the WrapperStruct size instead of individual member sizes
// to avoid problems due to platform/compiler differences in structure
// padding.
return reinterpret_cast<WrapperStruct*>(
auto* wrapperStruct = reinterpret_cast<WrapperStruct*>(
reinterpret_cast<char*>(s) -
(sizeof(WrapperStruct) - sizeof(StructName)));
if (require_exact_type) {
// Verify that the wrapper offset was calculated correctly.
CHECK_EQ(kWrapperType, wrapperStruct->type_);
}
return wrapperStruct;
}
// Unwrap as the derived type.
@ -219,11 +230,9 @@ class CefCppToCScoped : public CefBaseScoped {
WrapperStruct* wrapperStruct =
GetWrapperStruct(reinterpret_cast<StructName*>(base));
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
// Should only be deleting wrappers that own the underlying object.
DCHECK(wrapperStruct->wrapper_->owned_);
CHECK(wrapperStruct->wrapper_->owned_);
delete wrapperStruct->wrapper_;
}

View File

@ -23,4 +23,7 @@ class CefBaseRefCountedCToCpp
CefBaseRefCountedCToCpp();
};
constexpr auto CefBaseRefCountedCToCpp_Wrap = CefBaseRefCountedCToCpp::Wrap;
constexpr auto CefBaseRefCountedCToCpp_Unwrap = CefBaseRefCountedCToCpp::Unwrap;
#endif // CEF_LIBCEF_DLL_CTOCPP_BASE_REF_COUNTED_CTOCPP_H_

View File

@ -22,4 +22,8 @@ class CefBaseScopedCToCpp : public CefCToCppScoped<CefBaseScopedCToCpp,
CefBaseScopedCToCpp();
};
constexpr auto CefBaseScopedCToCpp_Wrap = CefBaseScopedCToCpp::Wrap;
constexpr auto CefBaseScopedCToCpp_UnwrapOwn = CefBaseScopedCToCpp::UnwrapOwn;
constexpr auto CefBaseScopedCToCpp_UnwrapRaw = CefBaseScopedCToCpp::UnwrapRaw;
#endif // CEF_LIBCEF_DLL_CTOCPP_BASE_SCOPED_CTOCPP_H_

View File

@ -8,6 +8,7 @@
#include "include/base/cef_logging.h"
#include "include/capi/cef_base_capi.h"
#include "include/cef_api_hash.h"
#include "include/cef_base.h"
#include "libcef_dll/wrapper_types.h"
@ -45,8 +46,6 @@ class CefCToCppRefCounted : public BaseName {
// If returning the structure across the DLL boundary use Unwrap() instead.
StructName* GetStruct() const {
WrapperStruct* wrapperStruct = GetWrapperStruct(this);
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->struct_;
}
@ -55,7 +54,8 @@ class CefCToCppRefCounted : public BaseName {
// from the other side.
struct WrapperStruct;
static WrapperStruct* GetWrapperStruct(const BaseName* obj);
static WrapperStruct* GetWrapperStruct(const BaseName* obj,
bool require_exact_type = true);
// Unwrap as the derived type.
static StructName* UnwrapDerived(CefWrapperType type, BaseName* c);
@ -119,6 +119,18 @@ CefRefPtr<BaseName> CefCToCppRefCounted<ClassName, BaseName, StructName>::Wrap(
return nullptr;
}
const auto size = reinterpret_cast<cef_base_ref_counted_t*>(s)->size;
if (size != sizeof(StructName)) {
LOG(FATAL) << "Cannot wrap struct with invalid base.size value (got "
<< size << ", expected " << sizeof(StructName)
<< ") at API version "
#if defined(WRAPPING_CEF_SHARED)
<< CEF_API_VERSION;
#else
<< cef_api_version();
#endif
}
// Wrap their structure with the CefCToCppRefCounted object.
WrapperStruct* wrapperStruct = new WrapperStruct;
wrapperStruct->type_ = kWrapperType;
@ -140,7 +152,8 @@ StructName* CefCToCppRefCounted<ClassName, BaseName, StructName>::Unwrap(
return nullptr;
}
WrapperStruct* wrapperStruct = GetWrapperStruct(c.get());
WrapperStruct* wrapperStruct =
GetWrapperStruct(c.get(), /*require_exact_type=*/false);
// If the type does not match this object then we need to unwrap as the
// derived type.
@ -160,8 +173,6 @@ bool CefCToCppRefCounted<ClassName, BaseName, StructName>::Release() const {
UnderlyingRelease();
if (ref_count_.Release()) {
WrapperStruct* wrapperStruct = GetWrapperStruct(this);
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
delete wrapperStruct;
return true;
}
@ -171,12 +182,20 @@ bool CefCToCppRefCounted<ClassName, BaseName, StructName>::Release() const {
template <class ClassName, class BaseName, class StructName>
typename CefCToCppRefCounted<ClassName, BaseName, StructName>::WrapperStruct*
CefCToCppRefCounted<ClassName, BaseName, StructName>::GetWrapperStruct(
const BaseName* obj) {
const BaseName* obj,
bool require_exact_type) {
// Offset using the WrapperStruct size instead of individual member sizes to
// avoid problems due to platform/compiler differences in structure padding.
return reinterpret_cast<WrapperStruct*>(
auto* wrapperStruct = reinterpret_cast<WrapperStruct*>(
reinterpret_cast<char*>(const_cast<BaseName*>(obj)) -
(sizeof(WrapperStruct) - sizeof(ClassName)));
if (require_exact_type) {
// Verify that the wrapper offset was calculated correctly.
CHECK_EQ(kWrapperType, wrapperStruct->type_);
}
return wrapperStruct;
}
#endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_

View File

@ -8,6 +8,7 @@
#include "include/base/cef_logging.h"
#include "include/capi/cef_base_capi.h"
#include "include/cef_api_hash.h"
#include "include/cef_base.h"
#include "libcef_dll/wrapper_types.h"
@ -75,8 +76,6 @@ class CefCToCppScoped : public BaseName {
// If returning the structure across the DLL boundary use Unwrap() instead.
StructName* GetStruct() const {
WrapperStruct* wrapperStruct = GetWrapperStruct(this);
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
return wrapperStruct->struct_;
}
@ -85,7 +84,8 @@ class CefCToCppScoped : public BaseName {
// from the other side.
struct WrapperStruct;
static WrapperStruct* GetWrapperStruct(const BaseName* obj);
static WrapperStruct* GetWrapperStruct(const BaseName* obj,
bool require_exact_type = true);
// Unwrap as the derived type.
static StructName* UnwrapDerivedOwn(CefWrapperType type,
@ -107,7 +107,19 @@ template <class ClassName, class BaseName, class StructName>
CefOwnPtr<BaseName> CefCToCppScoped<ClassName, BaseName, StructName>::Wrap(
StructName* s) {
if (!s) {
return CefOwnPtr<BaseName>();
return nullptr;
}
const auto size = reinterpret_cast<cef_base_ref_counted_t*>(s)->size;
if (size != sizeof(StructName)) {
LOG(FATAL) << "Cannot wrap struct with invalid base.size value (got "
<< size << ", expected " << sizeof(StructName)
<< ") at API version "
#if defined(WRAPPING_CEF_SHARED)
<< CEF_API_VERSION;
#else
<< cef_api_version();
#endif
}
// Wrap their structure with the CefCToCpp object.
@ -125,7 +137,8 @@ StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapOwn(
return nullptr;
}
WrapperStruct* wrapperStruct = GetWrapperStruct(c.get());
WrapperStruct* wrapperStruct =
GetWrapperStruct(c.get(), /*require_exact_type=*/false);
// If the type does not match this object then we need to unwrap as the
// derived type.
@ -156,7 +169,8 @@ StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapRaw(
return nullptr;
}
WrapperStruct* wrapperStruct = GetWrapperStruct(c);
WrapperStruct* wrapperStruct =
GetWrapperStruct(c, /*require_exact_type=*/false);
// If the type does not match this object then we need to unwrap as the
// derived type.
@ -173,8 +187,6 @@ NO_SANITIZE("cfi-icall")
void CefCToCppScoped<ClassName, BaseName, StructName>::operator delete(
void* ptr) {
WrapperStruct* wrapperStruct = GetWrapperStruct(static_cast<BaseName*>(ptr));
// Verify that the wrapper offset was calculated correctly.
DCHECK_EQ(kWrapperType, wrapperStruct->type_);
// May be NULL if UnwrapOwn() was called.
cef_base_scoped_t* base =
@ -194,12 +206,20 @@ void CefCToCppScoped<ClassName, BaseName, StructName>::operator delete(
template <class ClassName, class BaseName, class StructName>
typename CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct*
CefCToCppScoped<ClassName, BaseName, StructName>::GetWrapperStruct(
const BaseName* obj) {
const BaseName* obj,
bool require_exact_type) {
// Offset using the WrapperStruct size instead of individual member sizes to
// avoid problems due to platform/compiler differences in structure padding.
return reinterpret_cast<WrapperStruct*>(
auto* wrapperStruct = reinterpret_cast<WrapperStruct*>(
reinterpret_cast<char*>(const_cast<BaseName*>(obj)) -
(sizeof(WrapperStruct) - sizeof(ClassName)));
if (require_exact_type) {
// Verify that the wrapper offset was calculated correctly.
CHECK_EQ(kWrapperType, wrapperStruct->type_);
}
return wrapperStruct;
}
#endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_

View File

@ -4,15 +4,24 @@
//
#include <cstddef>
#include <map>
#include <string_view>
#include "include/base/cef_build.h"
#include "include/cef_api_hash.h"
#include "include/cef_version.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "cef/include/base/cef_build.h"
#include "cef/include/cef_api_hash.h"
#include "cef/include/cef_id_mappers.h"
#include "cef/include/cef_version_info.h"
#if defined(OS_WIN)
#include "include/internal/cef_win.h"
#include "cef/include/internal/cef_win.h"
#endif
namespace {
int g_version = -1;
}
CEF_EXPORT int cef_version_info(int entry) {
switch (entry) {
case 0:
@ -36,19 +45,117 @@ CEF_EXPORT int cef_version_info(int entry) {
}
}
CEF_EXPORT const char* cef_api_hash(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;
// Initialize on the first successful lookup.
if (!hash) {
for (size_t i = 0; i < kApiVersionHashesSize; ++i) {
if (version == kApiVersionHashes[i].version) {
hash = &kApiVersionHashes[i];
break;
}
}
if (hash) {
g_version = version;
}
}
if (!hash) {
LOG(ERROR) << "Request for unsupported CEF API version " << version;
return nullptr;
}
if (version != g_version) {
LOG(ERROR) << "CEF API version cannot be configured multiple times";
return nullptr;
}
switch (entry) {
case 0:
return CEF_API_HASH_PLATFORM;
return hash->platform;
case 1:
return CEF_API_HASH_UNIVERSAL;
return hash->universal;
case 2:
return CEF_COMMIT_HASH;
default:
return NULL;
return nullptr;
}
}
CEF_EXPORT int cef_api_version() {
return g_version;
}
#include "cef/libcef_dll/cef_pack_resources.inc"
CEF_EXPORT int cef_id_for_pack_resource_name(const char* name) {
static base::NoDestructor<std::map<std::string_view, int>> string_to_id_map;
// 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;
}
}
const auto& it = string_to_id_map->find(name);
if (it != string_to_id_map->end()) {
return it->second;
}
LOG(WARNING) << __func__ << " called with unsupported value " << name;
return -1;
}
#include "cef/libcef_dll/cef_pack_strings.inc"
CEF_EXPORT int cef_id_for_pack_string_name(const char* name) {
static base::NoDestructor<std::map<std::string_view, int>> string_to_id_map;
// 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;
}
}
const auto& it = string_to_id_map->find(name);
if (it != string_to_id_map->end()) {
return it->second;
}
LOG(WARNING) << __func__ << " called with unsupported value " << name;
return -1;
}
#include "cef/libcef_dll/cef_command_ids.inc"
CEF_EXPORT int cef_id_for_command_id_name(const char* name) {
static base::NoDestructor<std::map<std::string_view, int>> string_to_id_map;
// 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;
}
}
const auto& it = string_to_id_map->find(name);
if (it != string_to_id_map->end()) {
return it->second;
}
LOG(WARNING) << __func__ << " called with unsupported value " << name;
return -1;
}
#if defined(OS_WIN)
#if defined(ARCH_CPU_32_BITS)

View File

@ -19,12 +19,9 @@ int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
int nCmdShow) {
CHECK(wWinMain && hInstance);
const char* api_hash = cef_api_hash(0);
if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
// The libcef API hash does not match the current header API hash.
DCHECK(false);
return 0;
}
const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);
CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<
"API hashes for libcef and libcef_dll_wrapper do not match.";
return cef_run_winmain_with_preferred_stack_size(wWinMain, hInstance,
lpCmdLine, nCmdShow);
@ -33,12 +30,9 @@ int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) {
CHECK(main);
const char* api_hash = cef_api_hash(0);
if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
// The libcef API hash does not match the current header API hash.
DCHECK(false);
return 0;
}
const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);
CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<
"API hashes for libcef and libcef_dll_wrapper do not match.";
return cef_run_main_with_preferred_stack_size(main, argc, argv);
}

View File

@ -88,7 +88,7 @@ index 4aaba212926f4..e8aadb2c97fe9 100644
}
diff --git chrome/browser/ui/BUILD.gn chrome/browser/ui/BUILD.gn
index 977b3222c8f7c..ee71bf3a1a463 100644
index 977b3222c8f7c..e5d36a4e5921e 100644
--- chrome/browser/ui/BUILD.gn
+++ chrome/browser/ui/BUILD.gn
@@ -8,6 +8,7 @@ import("//build/config/compiler/compiler.gni")
@ -118,18 +118,21 @@ index 977b3222c8f7c..ee71bf3a1a463 100644
"//chrome:resources",
"//chrome:strings",
"//chrome/app:chrome_dll_resources",
@@ -699,6 +705,10 @@ static_library("ui") {
@@ -699,6 +705,13 @@ static_library("ui") {
deps += [ "//components/plus_addresses/resources:vector_icons" ]
}
+ if (enable_cef) {
+ deps += [ "//cef:cef_resources" ]
+ deps += [
+ "//cef:cef_resources",
+ "//cef:make_version_header",
+ ]
+ }
+
# TODO(crbug.com/41437292): Remove this circular dependency.
# Any circular includes must depend on the target "//chrome/browser:browser_public_dependencies".
# These are all-platform circular includes.
@@ -5487,6 +5497,7 @@ static_library("ui") {
@@ -5487,6 +5500,7 @@ static_library("ui") {
if (enable_printing) {
deps += [
"//components/printing/browser",

View File

@ -13,8 +13,8 @@
#include "include/base/cef_callback.h"
#include "include/cef_browser.h"
#include "include/cef_command_ids.h"
#include "include/cef_frame.h"
#include "include/cef_id_mappers.h"
#include "include/cef_parser.h"
#include "include/cef_shared_process_message_builder.h"
#include "include/cef_ssl_status.h"
@ -318,6 +318,32 @@ bool IsAllowedToolbarButton(cef_chrome_toolbar_button_type_t button_type) {
}
bool IsAllowedAppMenuCommandId(int command_id) {
// Version-safe static declarations of IDC variables using names from
// cef_command_ids.h.
CEF_DECLARE_COMMAND_ID(IDC_NEW_WINDOW);
CEF_DECLARE_COMMAND_ID(IDC_NEW_INCOGNITO_WINDOW);
CEF_DECLARE_COMMAND_ID(IDC_ZOOM_MENU);
CEF_DECLARE_COMMAND_ID(IDC_ZOOM_PLUS);
CEF_DECLARE_COMMAND_ID(IDC_ZOOM_NORMAL);
CEF_DECLARE_COMMAND_ID(IDC_ZOOM_MINUS);
CEF_DECLARE_COMMAND_ID(IDC_FULLSCREEN);
CEF_DECLARE_COMMAND_ID(IDC_PRINT);
CEF_DECLARE_COMMAND_ID(IDC_FIND);
CEF_DECLARE_COMMAND_ID(IDC_FIND_NEXT);
CEF_DECLARE_COMMAND_ID(IDC_FIND_PREVIOUS);
CEF_DECLARE_COMMAND_ID(IDC_MORE_TOOLS_MENU);
CEF_DECLARE_COMMAND_ID(IDC_CLEAR_BROWSING_DATA);
CEF_DECLARE_COMMAND_ID(IDC_MANAGE_EXTENSIONS);
CEF_DECLARE_COMMAND_ID(IDC_PERFORMANCE);
CEF_DECLARE_COMMAND_ID(IDC_TASK_MANAGER);
CEF_DECLARE_COMMAND_ID(IDC_DEV_TOOLS);
CEF_DECLARE_COMMAND_ID(IDC_EDIT_MENU);
CEF_DECLARE_COMMAND_ID(IDC_CUT);
CEF_DECLARE_COMMAND_ID(IDC_COPY);
CEF_DECLARE_COMMAND_ID(IDC_PASTE);
CEF_DECLARE_COMMAND_ID(IDC_OPTIONS);
CEF_DECLARE_COMMAND_ID(IDC_EXIT);
// Only the commands in this array will be allowed.
static const int kAllowedCommandIds[] = {
IDC_NEW_WINDOW,
@ -361,6 +387,28 @@ bool IsAllowedAppMenuCommandId(int command_id) {
}
bool IsAllowedContextMenuCommandId(int command_id) {
// Version-safe static declarations of IDC variables using names from
// cef_command_ids.h.
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_CUSTOM_FIRST);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_CUSTOM_LAST);
CEF_DECLARE_COMMAND_ID(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST);
CEF_DECLARE_COMMAND_ID(IDC_EXTENSIONS_CONTEXT_CUSTOM_LAST);
CEF_DECLARE_COMMAND_ID(IDC_BACK);
CEF_DECLARE_COMMAND_ID(IDC_FORWARD);
CEF_DECLARE_COMMAND_ID(IDC_RELOAD);
CEF_DECLARE_COMMAND_ID(IDC_RELOAD_BYPASSING_CACHE);
CEF_DECLARE_COMMAND_ID(IDC_RELOAD_CLEARING_CACHE);
CEF_DECLARE_COMMAND_ID(IDC_STOP);
CEF_DECLARE_COMMAND_ID(IDC_PRINT);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_CUT);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_COPY);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_PASTE);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_DELETE);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_SELECTALL);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_UNDO);
CEF_DECLARE_COMMAND_ID(IDC_CONTENT_CONTEXT_REDO);
// Allow commands added by web content.
if (command_id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
command_id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {

View File

@ -7,7 +7,7 @@
#include "include/cef_app.h"
#import "include/cef_application_mac.h"
#include "include/cef_command_ids.h"
#import "include/cef_id_mappers.h"
#import "include/wrapper/cef_library_loader.h"
#include "tests/cefclient/browser/main_context_impl.h"
#include "tests/cefclient/browser/resource.h"
@ -404,6 +404,24 @@ void RemoveMenuItem(NSMenu* menu, SEL action_selector) {
//
// This implementation is based on Chromium's AppController class.
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item {
// Version-safe static declarations of IDC variables using names from
// cef_command_ids.h.
CEF_DECLARE_COMMAND_ID(IDC_OPEN_FILE);
CEF_DECLARE_COMMAND_ID(IDC_NEW_TAB);
CEF_DECLARE_COMMAND_ID(IDC_FOCUS_LOCATION);
CEF_DECLARE_COMMAND_ID(IDC_FOCUS_SEARCH);
CEF_DECLARE_COMMAND_ID(IDC_SHOW_HISTORY);
CEF_DECLARE_COMMAND_ID(IDC_SHOW_BOOKMARK_MANAGER);
CEF_DECLARE_COMMAND_ID(IDC_CLEAR_BROWSING_DATA);
CEF_DECLARE_COMMAND_ID(IDC_SHOW_DOWNLOADS);
CEF_DECLARE_COMMAND_ID(IDC_IMPORT_SETTINGS);
CEF_DECLARE_COMMAND_ID(IDC_MANAGE_EXTENSIONS);
CEF_DECLARE_COMMAND_ID(IDC_HELP_PAGE_VIA_MENU);
CEF_DECLARE_COMMAND_ID(IDC_OPTIONS);
CEF_DECLARE_COMMAND_ID(IDC_NEW_WINDOW);
CEF_DECLARE_COMMAND_ID(IDC_TASK_MANAGER);
CEF_DECLARE_COMMAND_ID(IDC_NEW_INCOGNITO_WINDOW);
SEL action = [item action];
BOOL enable = NO;
// Whether opening a new browser window is allowed.
@ -413,37 +431,26 @@ void RemoveMenuItem(NSMenu* menu, SEL action_selector) {
// no key window.
if (action == @selector(commandDispatch:) ||
action == @selector(commandDispatchUsingKeyModifiers:)) {
switch ([item tag]) {
const auto tag = [item tag];
if (tag == IDC_OPEN_FILE || tag == IDC_NEW_TAB ||
tag == IDC_FOCUS_LOCATION || tag == IDC_FOCUS_SEARCH ||
tag == IDC_SHOW_HISTORY || tag == IDC_SHOW_BOOKMARK_MANAGER ||
tag == IDC_CLEAR_BROWSING_DATA || tag == IDC_SHOW_DOWNLOADS ||
tag == IDC_IMPORT_SETTINGS || tag == IDC_MANAGE_EXTENSIONS ||
tag == IDC_HELP_PAGE_VIA_MENU || tag == IDC_OPTIONS) {
// Browser-level items that open in new tabs or perform an action in a
// current tab should not open if there's a window- or app-modal dialog.
case IDC_OPEN_FILE:
case IDC_NEW_TAB:
case IDC_FOCUS_LOCATION:
case IDC_FOCUS_SEARCH:
case IDC_SHOW_HISTORY:
case IDC_SHOW_BOOKMARK_MANAGER:
case IDC_CLEAR_BROWSING_DATA:
case IDC_SHOW_DOWNLOADS:
case IDC_IMPORT_SETTINGS:
case IDC_MANAGE_EXTENSIONS:
case IDC_HELP_PAGE_VIA_MENU:
case IDC_OPTIONS:
enable = canOpenNewBrowser && ![self keyWindowIsModal];
break;
} else if (tag == IDC_NEW_WINDOW) {
// Browser-level items that open in new windows: allow the user to open
// a new window even if there's a window-modal dialog.
case IDC_NEW_WINDOW:
enable = canOpenNewBrowser;
break;
case IDC_TASK_MANAGER:
} else if (tag == IDC_TASK_MANAGER) {
enable = YES;
break;
case IDC_NEW_INCOGNITO_WINDOW:
} else if (tag == IDC_NEW_INCOGNITO_WINDOW) {
enable = canOpenNewBrowser;
break;
default:
} else {
enable = ![self keyWindowIsModal];
break;
}
} else if ([self respondsToSelector:action]) {
// All other selectors that this class implements.
@ -469,12 +476,16 @@ void RemoveMenuItem(NSMenu* menu, SEL action_selector) {
}
}
// Version-safe static declarations of IDC variables using names from
// cef_command_ids.h.
CEF_DECLARE_COMMAND_ID(IDC_FIND);
CEF_DECLARE_COMMAND_ID(IDC_FIND_NEXT);
CEF_DECLARE_COMMAND_ID(IDC_FIND_PREVIOUS);
// Handle specific commands where we want to make the last active browser
// frontmost and then re-execute the command.
switch ([sender tag]) {
case IDC_FIND:
case IDC_FIND_NEXT:
case IDC_FIND_PREVIOUS:
const auto tag = [sender tag];
if (tag == IDC_FIND || tag == IDC_FIND_NEXT || tag == IDC_FIND_PREVIOUS) {
if (id window = [self getActiveBrowserNSWindow]) {
[window makeKeyAndOrderFront:nil];
if ([window respondsToSelector:@selector(commandDispatch:)]) {
@ -482,9 +493,6 @@ void RemoveMenuItem(NSMenu* menu, SEL action_selector) {
return;
}
}
break;
default:
break;
}
LOG(INFO) << "Unhandled commandDispatch: for tag " << [sender tag];

View File

@ -0,0 +1,868 @@
// Copyright (c) 2024 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include <memory>
#include "include/test/cef_api_version_test.h"
#include "tests/ceftests/test_handler.h"
#include "tests/gtest/include/gtest/gtest.h"
namespace {
template <typename T>
static int GetValue(T& obj) {
#if CEF_API_REMOVED(13301)
return obj->GetValue();
#elif CEF_API_RANGE(13301, 13302)
return obj->GetValueV1();
#elif CEF_API_ADDED(13302)
return obj->GetValueV2();
#endif
}
CefRefPtr<CefApiVersionTestRefPtrLibrary> CreateRefPtrLibrary(int val) {
#if CEF_API_ADDED(13301)
return CefApiVersionTestRefPtrLibrary::Create(val);
#else
auto obj = CefApiVersionTestRefPtrLibrary::Create();
obj->SetValue(val);
return obj;
#endif
}
CefRefPtr<CefApiVersionTestRefPtrLibraryChild> CreateRefPtrLibraryChild(
int val1,
int val2) {
#if CEF_API_ADDED(13301)
return CefApiVersionTestRefPtrLibraryChild::Create(val1, val2);
#else
auto obj = CefApiVersionTestRefPtrLibraryChild::Create();
obj->SetValue(val1);
obj->SetOtherValue(val2);
return obj;
#endif
}
#if CEF_API_REMOVED(13301)
CefRefPtr<CefApiVersionTestRefPtrLibraryChildChild>
#elif CEF_API_RANGE(13301, 13302)
CefRefPtr<CefApiVersionTestRefPtrLibraryChildChildV1>
#elif CEF_API_ADDED(13302)
CefRefPtr<CefApiVersionTestRefPtrLibraryChildChildV2>
#endif
CreateRefPtrLibraryChildChild(int val1, int val2, int val3) {
#if CEF_API_REMOVED(13301)
auto obj = CefApiVersionTestRefPtrLibraryChildChild::Create();
obj->SetValue(val1);
obj->SetOtherValue(val2);
obj->SetOtherOtherValue(val3);
return obj;
#elif CEF_API_RANGE(13301, 13302)
return CefApiVersionTestRefPtrLibraryChildChildV1::Create(val1, val2, val3);
#elif CEF_API_ADDED(13302)
return CefApiVersionTestRefPtrLibraryChildChildV2::Create(val1, val2, val3);
#endif
}
} // namespace
// Test getting/setting library-side RefPtr types.
TEST(ApiVersionTest, RefPtrLibrary) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
CefRefPtr<CefApiVersionTestRefPtrLibrary> test_obj =
CreateRefPtrLibrary(kTestVal);
EXPECT_EQ(kTestVal, GetValue(test_obj));
int retval = obj->SetRefPtrLibrary(test_obj);
EXPECT_EQ(kTestVal, retval);
EXPECT_EQ(kTestVal, GetValue(test_obj));
const int kTestVal2 = 30;
CefRefPtr<CefApiVersionTestRefPtrLibrary> test_obj2 =
obj->GetRefPtrLibrary(kTestVal2);
EXPECT_EQ(kTestVal2, GetValue(test_obj2));
int retval2 = obj->SetRefPtrLibrary(test_obj2);
EXPECT_EQ(kTestVal2, retval2);
EXPECT_EQ(kTestVal2, GetValue(test_obj2));
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
EXPECT_TRUE(test_obj->HasOneRef());
EXPECT_TRUE(test_obj2->HasOneRef());
}
// Test getting/setting inherited library-side RefPtr types.
TEST(ApiVersionTest, RefPtrLibraryInherit) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
const int kTestVal2 = 40;
auto test_obj = CreateRefPtrLibraryChild(kTestVal, kTestVal2);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
int retval = obj->SetRefPtrLibrary(test_obj);
EXPECT_EQ(kTestVal, retval);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
EXPECT_EQ(kTestVal, obj->SetChildRefPtrLibrary(test_obj));
auto parent = obj->SetChildRefPtrLibraryAndReturnParent(test_obj);
EXPECT_EQ(kTestVal, GetValue(parent));
parent = nullptr;
const int kTestVal3 = 100;
auto test_obj2 =
CreateRefPtrLibraryChildChild(kTestVal, kTestVal2, kTestVal3);
EXPECT_EQ(kTestVal, GetValue(test_obj2));
EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
int retval2 = obj->SetRefPtrLibrary(test_obj2);
EXPECT_EQ(kTestVal, retval2);
EXPECT_EQ(kTestVal, GetValue(test_obj2));
EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
EXPECT_EQ(kTestVal, obj->SetChildRefPtrLibrary(test_obj2));
auto parent2 = obj->SetChildRefPtrLibraryAndReturnParent(test_obj2);
EXPECT_EQ(kTestVal, GetValue(parent2));
parent2 = nullptr;
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
EXPECT_TRUE(test_obj->HasOneRef());
EXPECT_TRUE(test_obj2->HasOneRef());
}
// Test getting/setting library-side RefPtr list types.
TEST(ApiVersionTest, RefPtrLibraryList) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kVal1 = 34;
const int kVal2 = 10;
CefRefPtr<CefApiVersionTestRefPtrLibrary> val1 = CreateRefPtrLibrary(kVal1);
CefRefPtr<CefApiVersionTestRefPtrLibrary> val2 =
CreateRefPtrLibraryChild(kVal2, 0);
std::vector<CefRefPtr<CefApiVersionTestRefPtrLibrary>> list;
list.push_back(val1);
list.push_back(val2);
EXPECT_TRUE(obj->SetRefPtrLibraryList(list, kVal1, kVal2));
list.clear();
EXPECT_TRUE(obj->GetRefPtrLibraryListByRef(list, kVal1, kVal2));
EXPECT_EQ(2U, list.size());
EXPECT_EQ(kVal1, GetValue(list[0]));
EXPECT_EQ(kVal2, GetValue(list[1]));
list.clear();
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
EXPECT_TRUE(val1->HasOneRef());
EXPECT_TRUE(val2->HasOneRef());
}
namespace {
class ApiVersionTestRefPtrClient : public CefApiVersionTestRefPtrClient {
public:
explicit ApiVersionTestRefPtrClient(int val) : val_(val) {}
int GetValueLegacy() override { return val_legacy_; }
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int GetValueExp() override { return val_exp_; }
#endif
#if CEF_API_REMOVED(13301)
int GetValue() override { return val_; }
#elif CEF_API_RANGE(13301, 13302)
int GetValueV1() override { return val_; }
#elif CEF_API_ADDED(13302)
int GetValueV2() override { return val_; }
#endif
private:
const int val_;
int val_legacy_ = -1;
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int val_exp_ = -1;
#endif
IMPLEMENT_REFCOUNTING(ApiVersionTestRefPtrClient);
DISALLOW_COPY_AND_ASSIGN(ApiVersionTestRefPtrClient);
};
#if CEF_API_REMOVED(13302)
class ApiVersionTestRefPtrClientChild
: public CefApiVersionTestRefPtrClientChild {
public:
ApiVersionTestRefPtrClientChild(int val, int other_val)
: val_(val), other_val_(other_val) {}
int GetValueLegacy() override { return val_legacy_; }
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int GetValueExp() override { return val_exp_; }
#endif
#if CEF_API_REMOVED(13301)
int GetValue() override { return val_; }
#elif CEF_API_RANGE(13301, 13302)
int GetValueV1() override { return val_; }
#elif CEF_API_ADDED(13302)
int GetValueV2() override { return val_; }
#endif
#if CEF_API_REMOVED(13301)
int GetOtherValue() override { return other_val_; }
#else
int GetOtherValueV1() override { return other_val_; }
#endif
private:
const int val_;
const int other_val_;
int val_legacy_ = -1;
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int val_exp_ = -1;
#endif
IMPLEMENT_REFCOUNTING(ApiVersionTestRefPtrClientChild);
DISALLOW_COPY_AND_ASSIGN(ApiVersionTestRefPtrClientChild);
};
using ApiVersionTestRefPtrClientChildType = ApiVersionTestRefPtrClientChild;
#else // CEF_API_ADDED(13302)
class ApiVersionTestRefPtrClientChildV2
: public CefApiVersionTestRefPtrClientChildV2 {
public:
ApiVersionTestRefPtrClientChildV2(int val, int other_val)
: val_(val), other_val_(other_val) {}
int GetValueLegacy() override { return val_legacy_; }
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int GetValueExp() override { return val_exp_; }
#endif
#if CEF_API_REMOVED(13301)
int GetValue() override { return val_; }
#elif CEF_API_RANGE(13301, 13302)
int GetValueV1() override { return val_; }
#elif CEF_API_ADDED(13302)
int GetValueV2() override { return val_; }
#endif
int GetOtherValue() override { return other_val_; }
#if CEF_API_ADDED(13303)
int GetAnotherValue() override { return another_val_; }
#endif
private:
const int val_;
const int other_val_;
#if CEF_API_ADDED(13303)
int another_val_ = -1;
#endif
int val_legacy_ = -1;
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int val_exp_ = -1;
#endif
IMPLEMENT_REFCOUNTING(ApiVersionTestRefPtrClientChildV2);
DISALLOW_COPY_AND_ASSIGN(ApiVersionTestRefPtrClientChildV2);
};
using ApiVersionTestRefPtrClientChildType = ApiVersionTestRefPtrClientChildV2;
#endif // CEF_API_ADDED(13302)
template <typename T>
static int GetOtherValue(T& obj) {
#if CEF_API_REMOVED(13301)
// ApiVersionTestRefPtrClientChild
return obj->GetOtherValue();
#elif CEF_API_RANGE(13301, 13302)
// ApiVersionTestRefPtrClientChild
return obj->GetOtherValueV1();
#elif CEF_API_ADDED(13302)
// ApiVersionTestRefPtrClientChildV2
return obj->GetOtherValue();
#endif
}
} // namespace
// Test getting/setting client-side RefPtr types.
TEST(ApiVersionTest, RefPtrClient) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
CefRefPtr<ApiVersionTestRefPtrClient> test_obj =
new ApiVersionTestRefPtrClient(kTestVal);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal, obj->SetRefPtrClient(test_obj.get()));
CefRefPtr<CefApiVersionTestRefPtrClient> handler =
obj->SetRefPtrClientAndReturn(test_obj.get());
EXPECT_EQ(test_obj.get(), handler.get());
EXPECT_EQ(kTestVal, GetValue(handler));
handler = nullptr;
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
EXPECT_TRUE(test_obj->HasOneRef());
}
// Test getting/setting inherited client-side RefPtr types.
TEST(ApiVersionTest, RefPtrClientInherit) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
const int kTestVal2 = 86;
CefRefPtr<ApiVersionTestRefPtrClientChildType> test_obj =
new ApiVersionTestRefPtrClientChildType(kTestVal, kTestVal2);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, GetOtherValue(test_obj));
int retval = obj->SetRefPtrClient(test_obj);
EXPECT_EQ(kTestVal, retval);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, GetOtherValue(test_obj));
EXPECT_EQ(kTestVal, obj->SetChildRefPtrClient(test_obj));
CefRefPtr<CefApiVersionTestRefPtrClient> handler =
obj->SetChildRefPtrClientAndReturnParent(test_obj);
EXPECT_EQ(kTestVal, GetValue(handler));
EXPECT_EQ(test_obj.get(), handler.get());
handler = nullptr;
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
EXPECT_TRUE(test_obj->HasOneRef());
}
// Test getting/setting client-side RefPtr list types.
TEST(ApiVersionTest, RefPtrClientList) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kVal1 = 34;
const int kVal2 = 10;
CefRefPtr<CefApiVersionTestRefPtrClient> val1 =
new ApiVersionTestRefPtrClient(kVal1);
CefRefPtr<CefApiVersionTestRefPtrClient> val2 =
new ApiVersionTestRefPtrClientChildType(kVal2, 0);
std::vector<CefRefPtr<CefApiVersionTestRefPtrClient>> list;
list.push_back(val1);
list.push_back(val2);
EXPECT_TRUE(obj->SetRefPtrClientList(list, kVal1, kVal2));
list.clear();
EXPECT_TRUE(obj->GetRefPtrClientListByRef(list, val1, val2));
EXPECT_EQ(2U, list.size());
EXPECT_EQ(kVal1, GetValue(list[0]));
EXPECT_EQ(val1.get(), list[0].get());
EXPECT_EQ(kVal2, GetValue(list[1]));
EXPECT_EQ(val2.get(), list[1].get());
list.clear();
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
EXPECT_TRUE(val1->HasOneRef());
EXPECT_TRUE(val2->HasOneRef());
}
namespace {
CefOwnPtr<CefApiVersionTestScopedLibrary> CreateScopedLibrary(int val) {
#if CEF_API_ADDED(13301)
return CefApiVersionTestScopedLibrary::Create(val);
#else
auto obj = CefApiVersionTestScopedLibrary::Create();
obj->SetValue(val);
return obj;
#endif
}
CefOwnPtr<CefApiVersionTestScopedLibraryChild> CreateScopedLibraryChild(
int val1,
int val2) {
#if CEF_API_ADDED(13301)
return CefApiVersionTestScopedLibraryChild::Create(val1, val2);
#else
auto obj = CefApiVersionTestScopedLibraryChild::Create();
obj->SetValue(val1);
obj->SetOtherValue(val2);
return obj;
#endif
}
#if CEF_API_REMOVED(13301)
CefOwnPtr<CefApiVersionTestScopedLibraryChildChild>
#elif CEF_API_RANGE(13301, 13302)
CefOwnPtr<CefApiVersionTestScopedLibraryChildChildV1>
#elif CEF_API_ADDED(13302)
CefOwnPtr<CefApiVersionTestScopedLibraryChildChildV2>
#endif
CreateScopedLibraryChildChild(int val1, int val2, int val3) {
#if CEF_API_REMOVED(13301)
auto obj = CefApiVersionTestScopedLibraryChildChild::Create();
obj->SetValue(val1);
obj->SetOtherValue(val2);
obj->SetOtherOtherValue(val3);
return obj;
#elif CEF_API_RANGE(13301, 13302)
return CefApiVersionTestScopedLibraryChildChildV1::Create(val1, val2, val3);
#elif CEF_API_ADDED(13302)
return CefApiVersionTestScopedLibraryChildChildV2::Create(val1, val2, val3);
#endif
}
} // namespace
// Test getting/setting library-side OwnPtr types.
TEST(ApiVersionTest, OwnPtrLibrary) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
CefOwnPtr<CefApiVersionTestScopedLibrary> test_obj =
CreateScopedLibrary(kTestVal);
EXPECT_TRUE(test_obj.get());
EXPECT_EQ(kTestVal, GetValue(test_obj));
int retval = obj->SetOwnPtrLibrary(std::move(test_obj));
EXPECT_EQ(kTestVal, retval);
EXPECT_FALSE(test_obj.get());
const int kTestVal2 = 30;
CefOwnPtr<CefApiVersionTestScopedLibrary> test_obj2 =
obj->GetOwnPtrLibrary(kTestVal2);
EXPECT_TRUE(test_obj2.get());
EXPECT_EQ(kTestVal2, GetValue(test_obj2));
int retval2 = obj->SetOwnPtrLibrary(std::move(test_obj2));
EXPECT_EQ(kTestVal2, retval2);
EXPECT_FALSE(test_obj2.get());
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting inherited library-side OwnPtr types.
TEST(ApiVersionTest, OwnPtrLibraryInherit) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
const int kTestVal2 = 40;
auto test_obj = CreateScopedLibraryChild(kTestVal, kTestVal2);
EXPECT_TRUE(test_obj.get());
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
int retval = obj->SetOwnPtrLibrary(std::move(test_obj));
EXPECT_EQ(kTestVal, retval);
EXPECT_FALSE(test_obj.get());
test_obj = CreateScopedLibraryChild(kTestVal, kTestVal2);
EXPECT_TRUE(test_obj.get());
EXPECT_EQ(kTestVal, obj->SetChildOwnPtrLibrary(std::move(test_obj)));
EXPECT_FALSE(test_obj.get());
test_obj = CreateScopedLibraryChild(kTestVal, kTestVal2);
EXPECT_TRUE(test_obj.get());
CefOwnPtr<CefApiVersionTestScopedLibrary> test_obj_parent =
obj->SetChildOwnPtrLibraryAndReturnParent(std::move(test_obj));
EXPECT_FALSE(test_obj.get());
EXPECT_TRUE(test_obj_parent.get());
EXPECT_EQ(kTestVal, GetValue(test_obj_parent));
test_obj_parent.reset(nullptr);
const int kTestVal3 = 100;
auto test_obj2 =
CreateScopedLibraryChildChild(kTestVal, kTestVal2, kTestVal3);
EXPECT_EQ(kTestVal, GetValue(test_obj2));
EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
int retval2 = obj->SetOwnPtrLibrary(std::move(test_obj2));
EXPECT_EQ(kTestVal, retval2);
EXPECT_FALSE(test_obj2.get());
test_obj2 = CreateScopedLibraryChildChild(kTestVal, kTestVal2, kTestVal3);
EXPECT_EQ(kTestVal, obj->SetChildOwnPtrLibrary(std::move(test_obj2)));
EXPECT_FALSE(test_obj2.get());
test_obj2 = CreateScopedLibraryChildChild(kTestVal, kTestVal2, kTestVal3);
test_obj_parent =
obj->SetChildOwnPtrLibraryAndReturnParent(std::move(test_obj2));
EXPECT_FALSE(test_obj2.get());
EXPECT_TRUE(test_obj_parent.get());
EXPECT_EQ(kTestVal, GetValue(test_obj_parent));
test_obj_parent.reset(nullptr);
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
namespace {
class ApiVersionTestScopedClient : public CefApiVersionTestScopedClient {
public:
ApiVersionTestScopedClient(int val, TrackCallback* got_delete)
: val_(val), got_delete_(got_delete) {}
~ApiVersionTestScopedClient() override { got_delete_->yes(); }
int GetValueLegacy() override { return val_legacy_; }
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int GetValueExp() override { return val_exp_; }
#endif
#if CEF_API_REMOVED(13301)
int GetValue() override { return val_; }
#elif CEF_API_RANGE(13301, 13302)
int GetValueV1() override { return val_; }
#elif CEF_API_ADDED(13302)
int GetValueV2() override { return val_; }
#endif
private:
const int val_;
int val_legacy_ = -1;
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int val_exp_ = -1;
#endif
TrackCallback* got_delete_;
DISALLOW_COPY_AND_ASSIGN(ApiVersionTestScopedClient);
};
#if CEF_API_REMOVED(13302)
class ApiVersionTestScopedClientChild
: public CefApiVersionTestScopedClientChild {
public:
ApiVersionTestScopedClientChild(int val,
int other_val,
TrackCallback* got_delete)
: val_(val), other_val_(other_val), got_delete_(got_delete) {}
~ApiVersionTestScopedClientChild() override { got_delete_->yes(); }
int GetValueLegacy() override { return val_legacy_; }
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int GetValueExp() override { return val_exp_; }
#endif
#if CEF_API_REMOVED(13301)
int GetValue() override { return val_; }
#elif CEF_API_RANGE(13301, 13302)
int GetValueV1() override { return val_; }
#elif CEF_API_ADDED(13302)
int GetValueV2() override { return val_; }
#endif
#if CEF_API_REMOVED(13301)
int GetOtherValue() override { return other_val_; }
#else
int GetOtherValueV1() override { return other_val_; }
#endif
private:
const int val_;
const int other_val_;
int val_legacy_ = -1;
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int val_exp_ = -1;
#endif
TrackCallback* got_delete_;
DISALLOW_COPY_AND_ASSIGN(ApiVersionTestScopedClientChild);
};
using ApiVersionTestScopedClientChildType = ApiVersionTestScopedClientChild;
#else // CEF_API_ADDED(13302)
class ApiVersionTestScopedClientChildV2
: public CefApiVersionTestScopedClientChildV2 {
public:
ApiVersionTestScopedClientChildV2(int val,
int other_val,
TrackCallback* got_delete)
: val_(val), other_val_(other_val), got_delete_(got_delete) {}
~ApiVersionTestScopedClientChildV2() override { got_delete_->yes(); }
int GetValueLegacy() override { return val_legacy_; }
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int GetValueExp() override { return val_exp_; }
#endif
#if CEF_API_REMOVED(13301)
int GetValue() override { return val_; }
#elif CEF_API_RANGE(13301, 13302)
int GetValueV1() override { return val_; }
#elif CEF_API_ADDED(13302)
int GetValueV2() override { return val_; }
#endif
int GetOtherValue() override { return other_val_; }
#if CEF_API_ADDED(13303)
int GetAnotherValue() override { return another_val_; }
#endif
private:
const int val_;
const int other_val_;
#if CEF_API_ADDED(13303)
int another_val_ = -1;
#endif
int val_legacy_ = -1;
#if CEF_API_ADDED(CEF_EXPERIMENTAL)
int val_exp_ = -1;
#endif
TrackCallback* got_delete_;
DISALLOW_COPY_AND_ASSIGN(ApiVersionTestScopedClientChildV2);
};
using ApiVersionTestScopedClientChildType = ApiVersionTestScopedClientChildV2;
#endif // CEF_API_ADDED(13302)
} // namespace
// Test getting/setting client-side OwnPtr types.
TEST(ApiVersionTest, OwnPtrClient) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
TrackCallback got_delete;
CefOwnPtr<CefApiVersionTestScopedClient> test_obj(
new ApiVersionTestScopedClient(kTestVal, &got_delete));
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal, obj->SetOwnPtrClient(std::move(test_obj)));
EXPECT_FALSE(test_obj.get());
EXPECT_TRUE(got_delete);
got_delete.reset();
test_obj =
std::make_unique<ApiVersionTestScopedClient>(kTestVal, &got_delete);
CefOwnPtr<CefApiVersionTestScopedClient> handler =
obj->SetOwnPtrClientAndReturn(std::move(test_obj));
EXPECT_FALSE(test_obj.get());
EXPECT_TRUE(handler.get());
EXPECT_FALSE(got_delete);
EXPECT_EQ(kTestVal, GetValue(handler));
handler.reset(nullptr);
EXPECT_TRUE(got_delete);
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting inherited client-side OwnPtr types.
TEST(ApiVersionTest, OwnPtrClientInherit) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
const int kTestVal2 = 86;
TrackCallback got_delete;
CefOwnPtr<ApiVersionTestScopedClientChildType> test_obj(
new ApiVersionTestScopedClientChildType(kTestVal, kTestVal2,
&got_delete));
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, GetOtherValue(test_obj));
EXPECT_EQ(kTestVal, obj->SetOwnPtrClient(std::move(test_obj)));
EXPECT_FALSE(test_obj.get());
EXPECT_TRUE(got_delete);
got_delete.reset();
test_obj = std::make_unique<ApiVersionTestScopedClientChildType>(
kTestVal, kTestVal2, &got_delete);
EXPECT_EQ(kTestVal, obj->SetChildOwnPtrClient(std::move(test_obj)));
EXPECT_FALSE(test_obj.get());
EXPECT_TRUE(got_delete);
got_delete.reset();
test_obj = std::make_unique<ApiVersionTestScopedClientChildType>(
kTestVal, kTestVal2, &got_delete);
CefOwnPtr<CefApiVersionTestScopedClient> handler(
obj->SetChildOwnPtrClientAndReturnParent(std::move(test_obj)));
EXPECT_EQ(kTestVal, GetValue(handler));
EXPECT_FALSE(test_obj.get());
EXPECT_FALSE(got_delete);
handler.reset(nullptr);
EXPECT_TRUE(got_delete);
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting library-side RawPtr types.
TEST(ApiVersionTest, RawPtrLibrary) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
auto test_obj = CreateScopedLibrary(kTestVal);
EXPECT_EQ(kTestVal, GetValue(test_obj));
int retval = obj->SetRawPtrLibrary(test_obj.get());
EXPECT_EQ(kTestVal, retval);
EXPECT_EQ(kTestVal, GetValue(test_obj));
const int kTestVal2 = 30;
auto test_obj2 = obj->GetOwnPtrLibrary(kTestVal2);
EXPECT_EQ(kTestVal2, GetValue(test_obj2));
int retval2 = obj->SetRawPtrLibrary(test_obj2.get());
EXPECT_EQ(kTestVal2, retval2);
EXPECT_EQ(kTestVal2, GetValue(test_obj2));
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting inherited library-side RawPtr types.
TEST(ApiVersionTest, RawPtrLibraryInherit) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
const int kTestVal2 = 40;
auto test_obj = CreateScopedLibraryChild(kTestVal, kTestVal2);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
int retval = obj->SetRawPtrLibrary(test_obj.get());
EXPECT_EQ(kTestVal, retval);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
EXPECT_EQ(kTestVal, obj->SetChildRawPtrLibrary(test_obj.get()));
const int kTestVal3 = 100;
auto test_obj2 =
CreateScopedLibraryChildChild(kTestVal, kTestVal2, kTestVal3);
EXPECT_EQ(kTestVal, GetValue(test_obj2));
EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
int retval2 = obj->SetRawPtrLibrary(test_obj2.get());
EXPECT_EQ(kTestVal, retval2);
EXPECT_EQ(kTestVal, GetValue(test_obj2));
EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
EXPECT_EQ(kTestVal, obj->SetChildRawPtrLibrary(test_obj2.get()));
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting library-side RawPtr list types.
TEST(ApiVersionTest, RawPtrLibraryList) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kVal1 = 34;
const int kVal2 = 10;
auto val1 = CreateScopedLibrary(kVal1);
auto val2 = CreateScopedLibraryChild(kVal2, 0);
std::vector<CefRawPtr<CefApiVersionTestScopedLibrary>> list;
list.push_back(val1.get());
list.push_back(val2.get());
EXPECT_TRUE(obj->SetRawPtrLibraryList(list, kVal1, kVal2));
list.clear();
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting client-side RawPtr types.
TEST(ApiVersionTest, RawPtrClient) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
TrackCallback got_delete;
CefOwnPtr<ApiVersionTestScopedClient> test_obj(
new ApiVersionTestScopedClient(kTestVal, &got_delete));
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal, obj->SetRawPtrClient(test_obj.get()));
EXPECT_FALSE(got_delete);
test_obj.reset(nullptr);
EXPECT_TRUE(got_delete);
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting inherited client-side RawPtr types.
TEST(ApiVersionTest, RawPtrClientInherit) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kTestVal = 12;
const int kTestVal2 = 86;
TrackCallback got_delete;
CefOwnPtr<ApiVersionTestScopedClientChildType> test_obj(
new ApiVersionTestScopedClientChildType(kTestVal, kTestVal2,
&got_delete));
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, GetOtherValue(test_obj));
int retval = obj->SetRawPtrClient(test_obj.get());
EXPECT_EQ(kTestVal, retval);
EXPECT_EQ(kTestVal, GetValue(test_obj));
EXPECT_EQ(kTestVal2, GetOtherValue(test_obj));
EXPECT_FALSE(got_delete);
EXPECT_EQ(kTestVal, obj->SetChildRawPtrClient(test_obj.get()));
EXPECT_FALSE(got_delete);
test_obj.reset(nullptr);
EXPECT_TRUE(got_delete);
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}
// Test getting/setting client-side RawPtr list types.
TEST(ApiVersionTest, RawPtrClientList) {
CefRefPtr<CefApiVersionTest> obj = CefApiVersionTest::Create();
const int kVal1 = 34;
const int kVal2 = 10;
TrackCallback got_delete1, got_delete2;
CefOwnPtr<CefApiVersionTestScopedClient> val1(
new ApiVersionTestScopedClient(kVal1, &got_delete1));
CefOwnPtr<CefApiVersionTestScopedClient> val2(
new ApiVersionTestScopedClientChildType(kVal2, 0, &got_delete2));
std::vector<CefRawPtr<CefApiVersionTestScopedClient>> list;
list.push_back(val1.get());
list.push_back(val2.get());
EXPECT_TRUE(obj->SetRawPtrClientList(list, kVal1, kVal2));
list.clear();
EXPECT_FALSE(got_delete1);
val1.reset(nullptr);
EXPECT_TRUE(got_delete1);
EXPECT_FALSE(got_delete2);
val2.reset(nullptr);
EXPECT_TRUE(got_delete2);
// Only one reference to the object should exist.
EXPECT_TRUE(obj->HasOneRef());
}

View File

@ -3,7 +3,6 @@
// can be found in the LICENSE file.
#include "include/base/cef_callback.h"
#include "include/cef_pack_resources.h"
#include "include/cef_request_context_handler.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_stream_resource_handler.h"

View File

@ -18,6 +18,7 @@
#endif
#include "include/base/cef_callback.h"
#include "include/cef_api_hash.h"
#include "include/cef_app.h"
#include "include/cef_task.h"
#include "include/cef_thread.h"
@ -136,6 +137,10 @@ class ScopedPlatformSetup final {
int main(int argc, char* argv[]) {
int exit_code;
#if CEF_API_VERSION != CEF_EXPERIMENTAL
printf("Running with configured CEF API version %d\n", CEF_API_VERSION);
#endif
#if defined(OS_WIN) && defined(ARCH_CPU_32_BITS)
// Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
// stack size. This function must be called at the top of the executable entry

View File

@ -3,7 +3,7 @@
// can be found in the LICENSE file.
#include "include/cef_api_hash.h"
#include "include/cef_version.h"
#include "include/cef_version_info.h"
#include "tests/gtest/include/gtest/gtest.h"
TEST(VersionTest, VersionInfo) {
@ -18,7 +18,7 @@ TEST(VersionTest, VersionInfo) {
}
TEST(VersionTest, ApiHash) {
EXPECT_STREQ(CEF_API_HASH_PLATFORM, cef_api_hash(0));
EXPECT_STREQ(CEF_API_HASH_UNIVERSAL, cef_api_hash(1));
EXPECT_STREQ(CEF_COMMIT_HASH, cef_api_hash(2));
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_COMMIT_HASH, cef_api_hash(CEF_API_VERSION, 2));
}

View File

@ -3,7 +3,6 @@
// can be found in the LICENSE file.
#include "include/base/cef_callback.h"
#include "include/cef_pack_strings.h"
#include "include/views/cef_panel.h"
#include "include/views/cef_panel_delegate.h"
#include "include/views/cef_scroll_view.h"

View File

@ -3,7 +3,6 @@
// can be found in the LICENSE file.
#include "include/base/cef_callback.h"
#include "include/cef_pack_strings.h"
#include "include/views/cef_textfield.h"
#include "include/views/cef_textfield_delegate.h"
#include "include/wrapper/cef_closure_task.h"

View File

@ -4,16 +4,16 @@
from __future__ import absolute_import
from __future__ import print_function
from clang_util import clang_eval
from file_util import *
import hashlib
import itertools
import os
import re
import shutil
import string
import sys
import textwrap
import time
import itertools
import hashlib
from version_util import EXP_VERSION
# Determines string type for python 2 and python 3.
if sys.version_info[0] == 3:
@ -22,93 +22,172 @@ else:
string_type = basestring
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'
find = '#ifdef __cplusplus\nextern "C" {'
pos = content.find(find)
assert pos > 0, filename
content = content[0:pos] + tag + content[pos:]
defines = [
# Makes sure CEF_EXPORT is defined.
'USING_CEF_SHARED',
# 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):]
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
class cef_api_hash:
""" CEF API hash calculator """
def __init__(self, headerdir, debugdir=None, verbose=False):
def __init__(self, headerdir, verbose=False):
if headerdir is None or len(headerdir) == 0:
raise AssertionError("headerdir is not specified")
self.__headerdir = headerdir
self.__debugdir = debugdir
self.__verbose = verbose
self.__debug_enabled = not (self.__debugdir is
None) and len(self.__debugdir) > 0
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 = {
# List of includes_win_capi from cef_paths2.gypi.
"windows": [
"internal/cef_app_win.h",
"internal/cef_types_win.h",
],
# List of includes_mac_capi from cef_paths2.gypi.
"mac": [
"internal/cef_types_mac.h",
],
# List of includes_linux_capi from cef_paths2.gypi.
"linux": [
"internal/cef_types_linux.h",
]
"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)
}
self.included_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)
# List of include/ and include/internal/ files from cef_paths2.gypi.
self.excluded_files = [
# includes_common
"cef_api_hash.h",
"cef_base.h",
"cef_version.h",
"internal/cef_export.h",
"internal/cef_ptr.h",
"internal/cef_string_wrappers.h",
"internal/cef_time_wrappers.h",
"internal/cef_types_wrappers.h",
# includes_win
"cef_sandbox_win.h",
"internal/cef_win.h",
# includes_mac
"cef_application_mac.h",
"cef_sandbox_mac.h",
"internal/cef_mac.h",
# includes_linux
"internal/cef_linux.h",
]
self.filecontents = {}
self.filecontentobjs = {}
def calculate(self):
filenames = [
filename for filename in self.__get_filenames()
if not filename in self.excluded_files
]
objects = []
for filename in filenames:
# Cache values that will not change between calls to calculate().
for filename in self.filenames:
if self.__verbose:
print("Processing " + filename + "...")
assert not filename in self.filecontents, filename
assert not filename in self.filecontentobjs, filename
content = read_file(os.path.join(self.__headerdir, filename), True)
platforms = list([
p for p in self.platforms if self.__is_platform_filename(filename, p)
])
content_objects = None
# Parse cef_string.h happens in special case: grab only defined CEF_STRING_TYPE_xxx declaration
content_objects = None
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
else:
content_objects = self.__parse_objects(content)
for o in content_objects:
o["text"] = self.__prepare_text(o["text"])
o["platforms"] = platforms
o["filename"] = filename
objects.append(o)
if not content_objects is None:
self.__prepare_objects(filename, content_objects)
self.filecontentobjs[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
objects = []
for filename in self.filenames:
if self.__verbose:
print("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_objects = self.__parse_objects(content)
self.__prepare_objects(filename, content_objects)
else:
content_objects = self.filecontentobjs.get(filename, None)
assert not content_objects is None, filename
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"])
if self.__debug_enabled:
if debug_enabled:
namelen = max([len(o["name"]) for o in objects])
filenamelen = max([len(o["filename"]) for o in objects])
dumpsig = []
@ -116,14 +195,14 @@ class cef_api_hash:
dumpsig.append(
format(o["name"], str(namelen) + "s") + "|" + format(
o["filename"], "" + str(filenamelen) + "s") + "|" + o["text"])
self.__write_debug_file("objects.txt", dumpsig)
self.__write_debug_file(debug_dir, "objects.txt", dumpsig)
revisions = {}
for platform in itertools.chain(["universal"], self.platforms):
sig = self.__get_final_sig(objects, platform)
if self.__debug_enabled:
self.__write_debug_file(platform + ".sig", sig)
if debug_enabled:
self.__write_debug_file(debug_dir, platform + ".sig", sig)
revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest()
revisions[platform] = revstr
@ -152,7 +231,8 @@ class cef_api_hash:
# enums
for m in re.finditer(
r"\ntypedef\s+?enum\s+?\{.*?\}\s+?(\w+)\s*?;", content, flags=re.DOTALL):
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)
@ -163,11 +243,20 @@ class cef_api_hash:
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,
r"\n\s*?#\s*?define\s+?(CEF_STRING_TYPE_\w+)\s+?.*?\n",
content,
flags=0):
object = {
"name": m.group(1),
@ -191,35 +280,20 @@ class cef_api_hash:
return "\n".join(sig)
def __get_filenames(self):
def __get_filenames(self, cef_dir, paths, excluded_files):
""" Returns file names to be processed, relative to headerdir """
headers = [
os.path.join(self.__headerdir, filename)
for filename in self.included_files
filenames = [
os.path.relpath(os.path.join(cef_dir, filename),
self.__headerdir).replace('\\', '/').lower()
for filename in paths
]
capi_dir = os.path.join(self.__headerdir, "capi")
headers = itertools.chain(headers, get_files(os.path.join(capi_dir, "*.h")))
if len(excluded_files) == 0:
return filenames
# Also include capi sub-directories.
for root, dirs, files in os.walk(capi_dir):
for name in dirs:
headers = itertools.chain(headers,
get_files(os.path.join(root, name, "*.h")))
headers = itertools.chain(
headers, get_files(os.path.join(self.__headerdir, "internal", "*.h")))
for v in self.platform_files.values():
headers = itertools.chain(headers,
[os.path.join(self.__headerdir, f) for f in v])
normalized = [
os.path.relpath(filename, self.__headerdir) for filename in headers
return [
filename for filename in filenames if not filename in excluded_files
]
normalized = [f.replace('\\', '/').lower() for f in normalized]
return list(set(normalized))
def __is_platform_filename(self, filename, platform):
if platform == "universal":
@ -235,9 +309,9 @@ class cef_api_hash:
listed = True
return not listed
def __write_debug_file(self, filename, content):
make_dir(self.__debugdir)
outfile = os.path.join(self.__debugdir, filename)
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):
@ -282,14 +356,16 @@ if __name__ == "__main__":
c_start_time = time.time()
calc = cef_api_hash(options.cppheaderdir, options.debugdir, options.verbose)
revisions = calc.calculate()
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

View File

@ -3,6 +3,7 @@
# can be found in the LICENSE file.
from __future__ import absolute_import
import bisect
from date_util import *
from file_util import *
import os
@ -12,11 +13,26 @@ import string
import sys
import textwrap
import time
from version_util import version_as_numeric, version_as_variable
_NOTIFY_CONTEXT = None
_NOTIFY_CONTEXT_LAST = None
def set_notify_context(context):
global _NOTIFY_CONTEXT
_NOTIFY_CONTEXT = context
def notify(msg):
""" Display a message. """
sys.stdout.write(' NOTE: ' + msg + '\n')
global _NOTIFY_CONTEXT_LAST
if not _NOTIFY_CONTEXT is None and _NOTIFY_CONTEXT != _NOTIFY_CONTEXT_LAST:
print('In %s:' % _NOTIFY_CONTEXT)
_NOTIFY_CONTEXT_LAST = _NOTIFY_CONTEXT
print(' NOTE: ' + msg)
def wrap_text(text, indent='', maxchars=80, listitem=False):
@ -44,25 +60,28 @@ def is_base_class(clsname):
return clsname == 'CefBaseRefCounted' or clsname == 'CefBaseScoped'
def get_capi_file_name(cppname):
def get_capi_file_name(cppname, versions=False):
""" Convert a C++ header file name to a C API header file name. """
return cppname[:-2] + '_capi.h'
return cppname[:-2] + ('_capi_versions.h' if versions else '_capi.h')
def get_capi_name(cppname, isclassname, prefix=None):
def get_capi_name(cppname, isclassname, prefix=None, version=None):
""" Convert a C++ CamelCaps name to a C API underscore name. """
result = ''
lastchr = ''
for chr in cppname:
# add an underscore if the current character is an upper case letter
# and the last character was a lower case letter
if len(result) > 0 and not chr.isdigit() \
# and the last character was a lower case letter or number.
if len(result) > 0 and chr.isalpha() \
and chr.upper() == chr \
and not lastchr.upper() == lastchr:
and lastchr.isalnum() and lastchr.lower() == lastchr:
result += '_'
result += chr.lower()
lastchr = chr
if isclassname and not version is None:
result += '_%d' % version
if isclassname:
result += '_t'
@ -259,7 +278,10 @@ def format_translation_changes(old, new):
return result
def format_translation_includes(header, body):
def format_translation_includes(header,
body,
with_versions=False,
other_includes=None):
""" Return the necessary list of includes based on the contents of the
body.
"""
@ -269,47 +291,187 @@ def format_translation_includes(header, body):
if body.find('std::min') > 0 or body.find('std::max') > 0:
result += '#include <algorithm>\n'
if body.find('cef_api_hash(') > 0:
result += '#include "include/cef_api_hash.h"\n'
paths = set()
if body.find('cef_api_hash(') > 0 or body.find('cef_api_version(') > 0:
paths.add('include/cef_api_hash.h')
if body.find('template_util::has_valid_size(') > 0:
result += '#include "libcef_dll/template_util.h"\n'
paths.add('libcef_dll/template_util.h')
# identify what CppToC classes are being used
p = re.compile(r'([A-Za-z0-9_]{1,})CppToC')
list = sorted(set(p.findall(body)))
for item in list:
search = ((True, True, r'([A-Za-z0-9_]{1,})_[0-9]{1,}_CppToC'),
(True, False, r'([A-Za-z0-9_]{1,})CppToC'),
(False, True, r'([A-Za-z0-9_]{1,})_[0-9]{1,}_CToCpp'),
(False, False, r'([A-Za-z0-9_]{1,})CToCpp'))
for cpptoc, versioned, regex in search:
# identify what classes are being used
p = re.compile(regex)
items = set(p.findall(body))
for item in items:
if item == 'Cef':
continue
if not versioned and item[-1] == '_':
# skip versioned names that are picked up by the unversioned regex
continue
directory = ''
if not is_base_class(item):
cls = header.get_class(item)
if cls is None:
raise Exception('Class does not exist: ' + item)
dir = cls.get_file_directory()
if not dir is None:
directory = dir + '/'
result += '#include "libcef_dll/cpptoc/'+directory+ \
get_capi_name(item[3:], False)+'_cpptoc.h"\n'
# identify what CToCpp classes are being used
p = re.compile(r'([A-Za-z0-9_]{1,})CToCpp')
list = sorted(set(p.findall(body)))
for item in list:
directory = ''
if not is_base_class(item):
cls = header.get_class(item)
dir = cls.get_file_directory()
if not dir is None:
directory = dir + '/'
result += '#include "libcef_dll/ctocpp/'+directory+ \
get_capi_name(item[3:], False)+'_ctocpp.h"\n'
type = 'cpptoc' if cpptoc else 'ctocpp'
paths.add('libcef_dll/' + type + '/'+directory+ \
get_capi_name(item[3:], False)+'_' + type + '.h')
if body.find('shutdown_checker') > 0:
result += '#include "libcef_dll/shutdown_checker.h"\n'
paths.add('libcef_dll/shutdown_checker.h')
if body.find('transfer_') > 0:
result += '#include "libcef_dll/transfer_util.h"\n'
paths.add('libcef_dll/transfer_util.h')
if not other_includes is None:
paths.update(other_includes)
if len(paths) > 0:
if len(result) > 0:
result += '\n'
paths = sorted(list(paths))
result += '\n'.join(['#include "%s"' % p for p in paths]) + '\n'
return result
def format_notreached(library_side, msg, default_retval='', indent=' '):
if library_side:
return 'NOTREACHED() << __func__ << ' + msg + ';'
return 'CHECK(false) << __func__ << ' + msg + ';\n' + \
indent + 'return%s;' % ((' ' + default_retval) if len(default_retval) > 0 else '')
def _has_version_added(attribs):
return 'added' in attribs
def _has_version_removed(attribs):
return 'removed' in attribs
def _has_version(attribs):
return _has_version_added(attribs) or _has_version_removed(attribs)
def get_version_check(attribs):
assert _has_version(attribs)
added = attribs.get('added', None)
if not added is None:
added = version_as_variable(added)
removed = attribs.get('removed', None)
if not removed is None:
removed = version_as_variable(removed)
if not added is None and not removed is None:
return 'CEF_API_RANGE(%s, %s)' % (added, removed)
elif not added is None:
return 'CEF_API_ADDED(%s)' % added
return 'CEF_API_REMOVED(%s)' % removed
def _get_version_attrib(attribs, key):
value = attribs.get(key, None)
if not value is None:
return version_as_numeric(value)
# Unversioned is always the first value.
return 0
def _get_version_added(attribs):
""" Returns a numeric 'added' value used for sorting purposes. """
return _get_version_attrib(attribs, 'added')
def _get_version_removed(attribs):
""" Returns a numeric 'removed' value used for sorting purposes. """
return _get_version_attrib(attribs, 'removed')
def get_version_surround(obj, long=False):
""" Returns (pre,post) strings for a version check. """
version_check = obj.get_version_check() if obj.has_version() else None
# Don't duplicate the surrounding class version check for a virtual method.
if not version_check is None and \
isinstance(obj, obj_function) and isinstance(obj.parent, obj_class) and \
obj.parent.has_version() and obj.parent.get_version_check() == version_check:
version_check = None
if not version_check is None:
return ('#if %s\n' % version_check, ('#endif // %s\n' % version_check)
if long else '#endif\n')
return ('', '')
def get_clsname(cls, version):
name = cls.get_name()
if not version is None:
# Select the appropriate version for this class.
closest_version = cls.get_closest_version(version)
if closest_version is None:
raise Exception('Cannot find version <= %d for %s' % (version, name))
return '%s_%d_' % (name, closest_version)
return name
def _version_order_funcs(funcs, max_version=None):
""" Applies version-based ordering to a list of funcs. """
versions = {0: []}
for func in funcs:
if func.has_version():
added = func.get_version_added()
if not added in versions:
versions[added] = [func]
else:
versions[added].append(func)
else:
# Unversioned funcs.
versions[0].append(func)
result = []
for version in sorted(versions.keys()):
if not max_version is None and version > max_version:
break
result.extend(versions[version])
return result
def _get_all_versions(funcs):
# Using a set to ensure uniqueness.
versions = set({0})
for func in funcs:
if func.has_version():
versions.add(func.get_version_added())
versions.add(func.get_version_removed())
return versions
def _find_closest_not_greater(lst, target):
assert isinstance(lst, list), lst
assert isinstance(target, int), target
idx = bisect.bisect_right(lst, target) - 1
if idx < 0:
return None
return lst[idx]
def str_to_dict(str):
""" Convert a string to a dictionary. If the same key has multiple values
the values will be stored in a list. """
@ -357,6 +519,13 @@ def dict_to_str(dict):
return ','.join(str)
# 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')
# regex for matching comment-formatted attributes
_cre_attrib = r'/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/'
# regex for matching class and function names
@ -747,13 +916,18 @@ class obj_header:
res.append(cls)
return res
def get_class(self, classname, defined_structs=None):
def get_class(self, classname):
""" Return the specified class or None if not found. """
for cls in self.classes:
if cls.get_name() == classname:
return cls
elif not defined_structs is None:
defined_structs.append(cls.get_capi_name())
return None
def get_capi_class(self, classname):
""" Return the specified class or None if not found. """
for cls in self.classes:
if cls.get_capi_name() == classname:
return cls
return None
def get_class_names(self):
@ -856,6 +1030,8 @@ class obj_class:
self.includes = includes
self.forward_declares = forward_declares
self._validate_attribs()
# extract typedefs
p = re.compile(
r'\n' + _cre_space + r'typedef' + _cre_space + _cre_typedef + r';',
@ -895,13 +1071,19 @@ class obj_class:
# build the virtual function objects
self.virtualfuncs = []
self.has_versioned_funcs = False
for attrib, retval, argval, vfmod in list:
comment = get_comment(body, retval + '(' + argval + ')')
validate_comment(filename, retval, comment)
if not self.has_versioned_funcs and _has_version(attrib):
self.has_versioned_funcs = True
self.virtualfuncs.append(
obj_function_virtual(self, attrib, retval, argval, comment,
vfmod.strip()))
self.virtualfuncs_ordered = None
self.allversions = None
def __repr__(self):
result = '/* ' + dict_to_str(
self.attribs) + ' */ class ' + self.name + "\n{"
@ -930,15 +1112,21 @@ class obj_class:
result += "\n};\n"
return result
def _validate_attribs(self):
for key in self.attribs.keys():
if not key in CLASS_ATTRIB_KEYS:
raise Exception('Invalid attribute key \"%s\" for class %s' %
(key, self.get_name()))
def get_file_name(self):
""" Return the C++ header file name. Includes the directory component,
if any. """
return self.filename
def get_capi_file_name(self):
def get_capi_file_name(self, versions=False):
""" Return the CAPI header file name. Includes the directory component,
if any. """
return get_capi_file_name(self.filename)
return get_capi_file_name(self.filename, versions)
def get_file_directory(self):
""" Return the file directory component, if any. """
@ -947,21 +1135,44 @@ class obj_class:
return self.filename[:pos]
return None
def get_name(self):
def get_name(self, version=None):
""" Return the class name. """
if not version is None:
# Select the appropriate version for this class.
closest_version = self.get_closest_version(version)
if closest_version is None:
raise Exception('Cannot find version <= %d for %s' % (version,
self.name))
return '%s_%d_' % (self.name, closest_version)
return self.name
def get_capi_name(self):
def get_capi_name(self, version=None, first_version=False):
""" Return the CAPI structure name for this class. """
return get_capi_name(self.name, True)
# Select the appropriate version for this class.
if first_version:
version = self.get_first_version()
elif not version is None:
closest_version = self.get_closest_version(version)
if closest_version is None:
raise Exception('Cannot find version <= %d for %s' % (version,
self.name))
version = closest_version
return get_capi_name(self.name, True, version=version)
def get_parent_name(self):
""" Return the parent class name. """
return self.parent_name
def get_parent_capi_name(self):
def get_parent_capi_name(self, version=None):
""" Return the CAPI structure name for the parent class. """
return get_capi_name(self.parent_name, True)
if not version is None:
# Select the appropriate version for the parent class.
if is_base_class(self.parent_name):
version = None
else:
parent_cls = self.parent.get_class(self.parent_name)
version = parent_cls.get_closest_version(version)
return get_capi_name(self.parent_name, True, version=version)
def has_parent(self, parent_name):
""" Returns true if this class has the specified class anywhere in its
@ -1043,8 +1254,17 @@ class obj_class:
""" Return the array of static function objects. """
return self.staticfuncs
def get_virtual_funcs(self):
def get_virtual_funcs(self, version_order=False, version=None):
""" Return the array of virtual function objects. """
if version_order and self.has_versioned_funcs:
if version is None:
# Cache the ordering result for future use.
if self.virtualfuncs_ordered is None:
self.virtualfuncs_ordered = _version_order_funcs(self.virtualfuncs)
return self.virtualfuncs_ordered
# Need to order each time to apply the max version.
return _version_order_funcs(self.virtualfuncs, version)
return self.virtualfuncs
def get_types(self, list):
@ -1078,6 +1298,75 @@ class obj_class:
""" Returns true if the class is implemented by the client. """
return self.attribs['source'] == 'client'
def has_version(self):
""" Returns true if the class has an associated version. """
return _has_version(self.attribs)
def has_version_added(self):
""" Returns true if the class has an associated 'added' version. """
return _has_version_added(self.attribs)
def get_version_added(self):
""" Returns the associated 'added' version. """
return _get_version_added(self.attribs)
def has_version_removed(self):
""" Returns true if the class has an associated 'removed' version. """
return _has_version_removed(self.attribs)
def get_version_removed(self):
""" Returns the associated 'removed' version. """
return _get_version_removed(self.attribs)
def removed_at_version(self, version):
""" Returns true if this class is removed at the specified version. """
return self.has_version_removed() and self.get_version_removed() <= version
def exists_at_version(self, version):
""" Returns true if this class exists at the specified version. """
if self.has_version_added() and self.get_version_added() > version:
return False
return not self.removed_at_version(version)
def get_version_check(self):
""" Returns the #if check for the associated version. """
return get_version_check(self.attribs)
def get_all_versions(self):
""" Returns all distinct versions of this class. """
if not self.allversions is None:
return self.allversions
# Using a set to ensure uniqueness.
versions = set()
# Versions from class inheritance.
if not is_base_class(self.parent_name):
versions.update(
self.parent.get_class(self.parent_name).get_all_versions())
# Versions from virtual methods.
versions.update(_get_all_versions(self.virtualfuncs))
versions = list(versions)
# Clamp to class versions, if specified.
if self.has_version_added():
versions = [x for x in versions if x >= self.get_version_added()]
if self.has_version_removed():
versions = [x for x in versions if x < self.get_version_removed()]
self.allversions = sorted(versions)
return self.allversions
def get_first_version(self):
""" Returns the first version. """
return self.get_all_versions()[0]
def get_closest_version(self, version):
""" Returns the closest version to |version| that is not greater, or None. """
return _find_closest_not_greater(self.get_all_versions(), version)
class obj_typedef:
""" Class representing a typedef statement. """
@ -1099,9 +1388,9 @@ class obj_typedef:
""" Return the C++ header file name. """
return self.filename
def get_capi_file_name(self):
def get_capi_file_name(self, versions=False):
""" Return the CAPI header file name. """
return get_capi_file_name(self.filename)
return get_capi_file_name(self.filename, versions)
def get_alias(self):
""" Return the alias. """
@ -1131,6 +1420,8 @@ class obj_function:
self.name = self.retval.remove_name()
self.comment = comment
self._validate_attribs()
# build the argument objects
self.arguments = []
arglist = argval.split(',')
@ -1163,13 +1454,19 @@ class obj_function:
def __repr__(self):
return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto()
def _validate_attribs(self):
for key in self.attribs.keys():
if not key in FUNCTION_ATTRIB_KEYS:
raise Exception('Invalid attribute key \"%s\" for %s' %
(key, self.get_qualified_name()))
def get_file_name(self):
""" Return the C++ header file name. """
return self.filename
def get_capi_file_name(self):
def get_capi_file_name(self, versions=False):
""" Return the CAPI header file name. """
return get_capi_file_name(self.filename)
return get_capi_file_name(self.filename, versions)
def get_name(self):
""" Return the function name. """
@ -1186,9 +1483,7 @@ class obj_function:
def get_capi_name(self, prefix=None):
""" Return the CAPI function name. """
if 'capi_name' in self.attribs:
return self.attribs['capi_name']
return get_capi_name(self.name, False, prefix)
return get_capi_name(self.get_attrib('capi_name', self.name), False, prefix)
def get_comment(self):
""" Return the function comment as an array of lines. """
@ -1202,7 +1497,7 @@ class obj_function:
""" Return true if the specified attribute exists. """
return name in self.attribs
def get_attrib(self, name):
def get_attrib(self, name, default=None):
""" Return the first or only value for specified attribute. """
if name in self.attribs:
if isinstance(self.attribs[name], list):
@ -1211,7 +1506,7 @@ class obj_function:
else:
# the value is a string
return self.attribs[name]
return None
return default
def get_attrib_list(self, name):
""" Return all values for specified attribute as a list. """
@ -1237,10 +1532,15 @@ class obj_function:
for cls in self.arguments:
cls.get_types(list)
def get_capi_parts(self, defined_structs=[], isimpl=False, prefix=None):
def get_capi_parts(self,
defined_structs=[],
isimpl=False,
prefix=None,
version=None,
version_finder=None):
""" Return the parts of the C API function definition. """
retval = ''
dict = self.retval.get_type().get_capi(defined_structs)
dict = self.retval.get_type().get_capi(defined_structs, version_finder)
if dict['format'] == 'single':
retval = dict['value']
@ -1249,7 +1549,7 @@ class obj_function:
if isinstance(self, obj_function_virtual):
# virtual functions get themselves as the first argument
str = 'struct _' + self.parent.get_capi_name() + '* self'
str = 'struct _' + self.parent.get_capi_name(version=version) + '* self'
if isinstance(self, obj_function_virtual) and self.is_const():
# const virtual functions get const self pointers
str = 'const ' + str
@ -1260,7 +1560,7 @@ class obj_function:
if len(self.arguments) > 0:
for cls in self.arguments:
type = cls.get_type()
dict = type.get_capi(defined_structs)
dict = type.get_capi(defined_structs, version_finder)
if dict['format'] == 'single':
args.append(dict['value'])
elif dict['format'] == 'multi-arg':
@ -1276,9 +1576,15 @@ class obj_function:
return {'retval': retval, 'name': name, 'args': args}
def get_capi_proto(self, defined_structs=[], isimpl=False, prefix=None):
def get_capi_proto(self,
defined_structs=[],
isimpl=False,
prefix=None,
version=None,
version_finder=None):
""" Return the prototype of the C API function. """
parts = self.get_capi_parts(defined_structs, isimpl, prefix)
parts = self.get_capi_parts(defined_structs, isimpl, prefix, version,
version_finder)
result = parts['retval']+' '+parts['name']+ \
'('+', '.join(parts['args'])+')'
return result
@ -1336,6 +1642,14 @@ class obj_function:
return other_is_library_side == this_is_library_side
def has_version(self):
""" Returns true if the class has an associated version. """
return _has_version(self.attribs)
def get_version_check(self):
""" Returns the #if check for the associated version. """
return get_version_check(self.attribs)
class obj_function_static(obj_function):
""" Class representing a static function. """
@ -1377,6 +1691,34 @@ class obj_function_virtual(obj_function):
""" Returns true if the method declaration is const. """
return self.isconst
def has_version_added(self):
""" Returns true if a 'added' value was specified. """
return _has_version_added(self.attribs)
def get_version_added(self):
""" Returns the numeric 'added' value, or 0 if unspecified.
Used for sorting purposes only. """
return _get_version_added(self.attribs)
def has_version_removed(self):
""" Returns true if a 'removed' value was specified. """
return _has_version_removed(self.attribs)
def get_version_removed(self):
""" Returns the numeric 'removed' value, or 0 if unspecified.
Used for sorting purposes only. """
return _get_version_removed(self.attribs)
def removed_at_version(self, version):
""" Returns true if this function is removed at the specified version. """
return self.has_version_removed() and self.get_version_removed() <= version
def exists_at_version(self, version):
""" Returns true if this function exists at the specified version. """
if self.has_version_added() and self.get_version_added() > version:
return False
return not self.removed_at_version(version)
class obj_argument:
""" Class representing a function argument. """
@ -1907,12 +2249,15 @@ class obj_analysis:
""" Return the *Ptr type structure name. """
return self.result_value[:-1]
def get_result_ptr_type(self, defined_structs=[]):
def get_result_ptr_type(self, defined_structs=[], version_finder=None):
""" Return the *Ptr type. """
result = ''
if not self.result_value[:-1] in defined_structs:
name = self.result_value[:-1]
if not version_finder is None:
name = version_finder(name)
if not name in defined_structs:
result += 'struct _'
result += self.result_value
result += name + self.result_value[-1]
if self.is_byref() or self.is_byaddr():
result += '*'
return result
@ -1951,16 +2296,22 @@ class obj_analysis:
return True
return False
def get_result_struct_type(self, defined_structs=[]):
def get_result_struct_type(self, defined_structs=[], version_finder=None):
""" Return the structure or enumeration type. """
result = ''
name = self.result_value
is_enum = self.is_result_struct_enum()
if not is_enum:
if self.is_const():
result += 'const '
if not self.result_value in defined_structs:
result += 'struct _'
result += self.result_value
if not version_finder is None:
name = version_finder(name)
result += name
if not is_enum:
result += '*'
return result
@ -2026,7 +2377,7 @@ class obj_analysis:
""" Return the vector structure or basic type name. """
return self.result_value[0]['result_value']
def get_result_vector_type(self, defined_structs=[]):
def get_result_vector_type(self, defined_structs=[], version_finder=None):
""" Return the vector type. """
if not self.has_name():
raise Exception('Cannot use vector as a return type')
@ -2048,9 +2399,15 @@ class obj_analysis:
result['value'] = str
elif type == 'refptr' or type == 'ownptr' or type == 'rawptr':
str = ''
if not value[:-1] in defined_structs:
# remove the * suffix
name = value[:-1]
if not version_finder is None:
name = version_finder(name)
if not name in defined_structs:
str += 'struct _'
str += value
str += name + value[-1]
if self.is_const():
str += ' const'
str += '*'
@ -2087,16 +2444,16 @@ class obj_analysis:
return {'value': 'cef_string_multimap_t', 'format': 'multi'}
raise Exception('Only mappings of strings to strings are supported')
def get_capi(self, defined_structs=[]):
def get_capi(self, defined_structs=[], version_finder=None):
""" Format the value for the C API. """
result = ''
format = 'single'
if self.is_result_simple():
result += self.get_result_simple_type()
elif self.is_result_ptr():
result += self.get_result_ptr_type(defined_structs)
result += self.get_result_ptr_type(defined_structs, version_finder)
elif self.is_result_struct():
result += self.get_result_struct_type(defined_structs)
result += self.get_result_struct_type(defined_structs, version_finder)
elif self.is_result_string():
result += self.get_result_string_type()
elif self.is_result_map():
@ -2106,7 +2463,7 @@ class obj_analysis:
else:
raise Exception('Unsupported map type')
elif self.is_result_vector():
resdict = self.get_result_vector_type(defined_structs)
resdict = self.get_result_vector_type(defined_structs, version_finder)
if resdict['format'] != 'single':
format = resdict['format']
result += resdict['value']

View File

@ -7,6 +7,7 @@ from __future__ import print_function
from file_util import *
import git_util as git
import os
from version_util import read_version_last, version_parse, VERSIONS_JSON_FILE
class VersionFormatter:
@ -46,15 +47,18 @@ class VersionFormatter:
if not bool(self._chrome_version):
file_path = os.path.join(self.src_path, 'chrome', 'VERSION')
assert os.path.isfile(file_path), file_path
read_version_file(file_path, self._chrome_version)
assert read_version_file(file_path, self._chrome_version), file_path
return self._chrome_version
def get_chrome_major_version(self):
return self.get_chrome_version_components()['MAJOR']
def get_cef_version_components(self):
""" Returns CEF version components. """
if not bool(self._cef_version):
file_path = os.path.join(self.cef_path, 'VERSION.in')
assert os.path.isfile(file_path), file_path
read_version_file(file_path, self._cef_version)
assert read_version_file(file_path, self._cef_version), file_path
return self._cef_version
def get_cef_commit_components(self):
@ -75,11 +79,11 @@ class VersionFormatter:
# branch since branching from origin/master.
hashes = git.get_branch_hashes(self.cef_path)
for hash in hashes:
# Determine if the API hash file was modified by the commit.
# Determine if the API versions file was modified by the commit.
found = False
files = git.get_changed_files(self.cef_path, hash)
for file in files:
if file.find('cef_api_hash.h') >= 0:
if file.find(VERSIONS_JSON_FILE) >= 0:
found = True
break
@ -89,6 +93,14 @@ class VersionFormatter:
else:
bugfix += 1
last_version = read_version_last(
os.path.join(self.cef_path, VERSIONS_JSON_FILE))
if not last_version is None:
major, revision = version_parse(last_version)
if major == int(self.get_chrome_major_version()) and revision > minor:
# Override the computed minor version with the last specified API version.
minor = revision
self._branch_version = {'MINOR': minor, 'PATCH': bugfix}
return self._branch_version
@ -149,8 +161,8 @@ 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_version.h) (release branch
# only).
# the CEF_API_HASH_UNIVERSAL 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
# (release branch only).
@ -186,9 +198,15 @@ class VersionFormatter:
# if we can get the name of the branch we are on (may be just "HEAD").
cef_branch_name = git.get_branch_name(self.cef_path).split('/')[-1]
cef_minor = cef_patch = 0
if cef_branch_name != 'HEAD' and cef_branch_name != 'master':
cef_branch = self.get_cef_branch_version_components()
cef_minor = cef_branch['MINOR']
cef_patch = cef_branch['PATCH']
self._version_parts = {'MAJOR': int(chrome_major), 'MINOR': 0, 'PATCH': 0}
self._version_string = '%s.0.0-%s.%s+%s+%s' % \
(chrome_major, cef_branch_name, cef_commit['NUMBER'],
self._version_string = '%s.%d.%d-%s.%s+%s+%s' % \
(chrome_major, cef_minor, cef_patch, cef_branch_name, cef_commit['NUMBER'],
cef_commit_hash, chrome_version_part)
else:
cef_branch = self.get_cef_branch_version_components()

View File

@ -10,22 +10,66 @@ import sys
# Script directory.
script_dir = os.path.dirname(__file__)
root_dir = os.path.join(script_dir, os.pardir)
cef_dir = os.path.join(script_dir, os.pardir)
src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
llvm_bin_dir = os.path.join(src_dir,
'third_party/llvm-build/Release+Asserts/bin')
if sys.platform == 'win32':
# Force use of the clang-format version bundled with depot_tools.
clang_format_exe = 'clang-format.bat'
clang_exe = os.path.join(llvm_bin_dir, 'clang-cl.exe')
else:
clang_format_exe = 'clang-format'
clang_exe = os.path.join(llvm_bin_dir, 'clang')
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), \
root_dir, file_contents.encode('utf-8'))
cef_dir, file_contents.encode('utf-8'))
if result['err'] != '':
print("clang-format error: %s" % result['err'])
sys.stderr.write("clang-format error: %s\n" % result['err'])
if result['out'] != '':
output = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
output = output.replace("\r", "")
return output
return None
def clang_format_inplace(file_name):
result = exec_cmd("%s -i %s" % (clang_format_exe, file_name), cef_dir)
if result['err'] != '':
sys.stderr.write("clang-format error: %s\n" % result['err'])
return False
return True
def clang_eval(file_name,
file_contents,
defines=[],
includes=[],
as_cpp=True,
verbose=False):
lang = 'c++' if as_cpp else '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'
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))
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)
return None
if result['out'] != '':
output = result['out']
if sys.platform == 'win32':

View File

@ -3,19 +3,22 @@
# can be found in the LICENSE file.
from __future__ import absolute_import
import codecs
import fnmatch
from glob import iglob
from io import open
import json
import os
import fnmatch
import shutil
import sys
import time
def read_file(name, normalize=True):
def read_file(path, normalize=True):
""" Read a file. """
if os.path.isfile(path):
try:
with open(name, 'r', encoding='utf-8') as f:
with open(path, 'r', encoding='utf-8') as f:
# read the data
data = f.read()
if normalize:
@ -24,14 +27,21 @@ def read_file(name, normalize=True):
return data
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to read file ' + name + ': ' + strerror)
sys.stderr.write('ERROR: Failed to read file ' + path + ': ' + strerror)
raise
return None
def write_file(name, data):
def write_file(path, data, overwrite=True, quiet=True):
""" Write a file. """
if not overwrite and os.path.exists(path):
return False
if not quiet:
print('Writing file %s' % path)
try:
with open(name, 'w', encoding='utf-8', newline='\n') as f:
with open(path, 'w', encoding='utf-8', newline='\n') as f:
# write the data
if sys.version_info.major == 2:
f.write(data.decode('utf-8'))
@ -39,57 +49,67 @@ def write_file(name, data):
f.write(data)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to write file ' + name + ': ' + strerror)
sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
raise
return True
def path_exists(name):
def path_exists(path):
""" Returns true if the path currently exists. """
return os.path.exists(name)
return os.path.exists(path)
def write_file_if_changed(name, data):
def write_file_if_changed(path, data, quiet=True):
""" Write a file if the contents have changed. Returns True if the file was written. """
if path_exists(name):
old_contents = read_file(name)
if path_exists(path):
old_contents = read_file(path)
assert not old_contents is None, path
else:
old_contents = ''
if (data != old_contents):
write_file(name, data)
write_file(path, data, quiet=quiet)
return True
return False
def backup_file(name):
def backup_file(path):
""" Rename the file to a name that includes the current time stamp. """
move_file(name, name + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
move_file(path, path + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
def copy_file(src, dst, quiet=True):
""" Copy a file. """
if not os.path.isfile(src):
return False
try:
shutil.copy2(src, dst)
if not quiet:
sys.stdout.write('Transferring ' + src + ' file.\n')
shutil.copy2(src, dst)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to copy file from ' + src + ' to ' + dst + ': ' +
strerror)
sys.stderr.write('ERROR: Failed to copy file from ' + src + ' to ' + dst +
': ' + strerror)
raise
return True
def move_file(src, dst, quiet=True):
""" Move a file. """
if not os.path.isfile(src):
return False
try:
shutil.move(src, dst)
if not quiet:
sys.stdout.write('Moving ' + src + ' file.\n')
print('Moving ' + src + ' file.')
shutil.move(src, dst)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to move file from ' + src + ' to ' + dst + ': ' +
strerror)
sys.stderr.write('ERROR: Failed to move file from ' + src + ' to ' + dst +
': ' + strerror)
raise
return True
def copy_files(src_glob, dst_folder, quiet=True):
@ -102,56 +122,62 @@ def copy_files(src_glob, dst_folder, quiet=True):
copy_file(fname, dst, quiet)
def remove_file(name, quiet=True):
def remove_file(path, quiet=True):
""" Remove the specified file. """
try:
if path_exists(name):
os.remove(name)
if path_exists(path):
if not quiet:
sys.stdout.write('Removing ' + name + ' file.\n')
print('Removing ' + path + ' file.')
os.remove(path)
return True
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to remove file ' + name + ': ' + strerror)
sys.stderr.write('ERROR: Failed to remove file ' + path + ': ' + strerror)
raise
return False
def copy_dir(src, dst, quiet=True):
""" Copy a directory tree. """
try:
remove_dir(dst, quiet)
shutil.copytree(src, dst)
if not quiet:
sys.stdout.write('Transferring ' + src + ' directory.\n')
print('Transferring ' + src + ' directory.')
shutil.copytree(src, dst)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to copy directory from ' + src + ' to ' + dst +
': ' + strerror)
sys.stderr.write('ERROR: Failed to copy directory from ' + src + ' to ' +
dst + ': ' + strerror)
raise
def remove_dir(name, quiet=True):
def remove_dir(path, quiet=True):
""" Remove the specified directory. """
try:
if path_exists(name):
shutil.rmtree(name)
if path_exists(path):
if not quiet:
sys.stdout.write('Removing ' + name + ' directory.\n')
print('Removing ' + path + ' directory.')
shutil.rmtree(path)
return True
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to remove directory ' + name + ': ' + strerror)
sys.stderr.write('ERROR: Failed to remove directory ' + path + ': ' +
strerror)
raise
return False
def make_dir(name, quiet=True):
def make_dir(path, quiet=True):
""" Create the specified directory. """
try:
if not path_exists(name):
if not path_exists(path):
if not quiet:
sys.stdout.write('Creating ' + name + ' directory.\n')
os.makedirs(name)
print('Creating ' + path + ' directory.')
os.makedirs(path)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('Failed to create directory ' + name + ': ' + strerror)
sys.stderr.write('ERROR: Failed to create directory ' + path + ': ' +
strerror)
raise
@ -180,13 +206,17 @@ def get_files_recursive(directory, pattern):
yield filename
def read_version_file(file, args):
def read_version_file(path, args):
""" Read and parse a version file (key=value pairs, one per line). """
lines = read_file(file).split("\n")
contents = read_file(path)
if contents is None:
return False
lines = contents.split("\n")
for line in lines:
parts = line.split('=', 1)
if len(parts) == 2:
args[parts[0]] = parts[1]
return True
def eval_file(src):
@ -199,3 +229,48 @@ def normalize_path(path):
if sys.platform == 'win32':
return path.replace('\\', '/')
return path
def read_json_file(path):
""" Read and parse a JSON file. Returns a list/dictionary or None. """
if os.path.isfile(path):
try:
with codecs.open(path, 'r', encoding='utf-8') as fp:
return json.load(fp)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('ERROR: Failed to read file ' + path + ': ' + strerror)
raise
return None
def _bytes_encoder(z):
if isinstance(z, bytes):
return str(z, 'utf-8')
else:
type_name = z.__class__.__name__
raise TypeError(f"Object of type {type_name} is not serializable")
def write_json_file(path, data, overwrite=True, quiet=True):
""" Serialize and write a JSON file. Returns True on success. """
if not overwrite and os.path.exists(path):
return False
if not quiet:
print('Writing file %s' % path)
try:
with open(path, 'w', encoding='utf-8') as fp:
json.dump(
data,
fp,
ensure_ascii=False,
indent=2,
sort_keys=True,
default=_bytes_encoder)
except IOError as e:
(errno, strerror) = e.args
sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
raise
return True

View File

@ -28,8 +28,8 @@ else:
print('Unknown operating system platform')
sys.exit()
print("\nGenerating CEF version header file...")
cmd = [sys.executable, 'tools/make_version_header.py', 'include/cef_version.h']
print("\nGenerating CEF translated files...")
cmd = [sys.executable, 'tools/version_manager.py', '-u', '--fast-check']
RunAction(cef_dir, cmd)
print("\nPatching build configuration and source files for CEF...")

View File

@ -26,85 +26,80 @@ def is_ancestor(path='.', commit1='HEAD', commit2='master'):
return result['ret'] == 0
def get_hash(path='.', branch='HEAD'):
""" Returns the git hash for the specified branch/tag/hash. """
cmd = "%s rev-parse %s" % (git_exe, branch)
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['out'] != '':
return result['out'].strip()
return 'Unknown'
out = result['out'].strip()
if sys.platform == 'win32':
# Convert to Unix line endings.
out = out.replace('\r\n', '\n')
return out
return None
def get_hash(path='.', branch='HEAD'):
""" Returns the git hash for the specified branch/tag/hash. """
cmd = "rev-parse %s" % branch
result = exec_git_cmd(cmd, path)
return 'Unknown' if result is None else result
def get_branch_name(path='.', branch='HEAD'):
""" Returns the branch name for the specified branch/tag/hash. """
# Returns the branch name if not in detached HEAD state, else an empty string
# or "HEAD".
cmd = "%s rev-parse --abbrev-ref %s" % (git_exe, branch)
result = exec_cmd(cmd, path)
if result['out'] != '':
name = result['out'].strip()
if len(name) > 0 and name != 'HEAD':
return name
cmd = "rev-parse --abbrev-ref %s" % branch
result = exec_git_cmd(cmd, path)
if result is None:
return 'Unknown'
if result != 'HEAD':
return result
# Returns a value like "(HEAD, origin/3729, 3729)".
# Ubuntu 14.04 uses Git version 1.9.1 which does not support %D (which
# provides the same output but without the parentheses).
cmd = "%s log -n 1 --pretty=%%d %s" % (git_exe, branch)
result = exec_cmd(cmd, path)
if result['out'] != '':
return result['out'].strip()[1:-1].split(', ')[-1]
return 'Unknown'
cmd = "log -n 1 --pretty=%%d %s" % branch
result = exec_git_cmd(cmd, path)
return 'Unknown' if result is None else result[1:-1].split(', ')[-1]
def get_url(path='.'):
""" Returns the origin url for the specified path. """
cmd = "%s config --get remote.origin.url" % git_exe
result = exec_cmd(cmd, path)
if result['out'] != '':
return result['out'].strip()
return 'Unknown'
cmd = "config --get remote.origin.url"
result = exec_git_cmd(cmd, path)
return 'Unknown' if result is None else result
def get_commit_number(path='.', branch='HEAD'):
""" Returns the number of commits in the specified branch/tag/hash. """
cmd = "%s rev-list --count %s" % (git_exe, branch)
result = exec_cmd(cmd, path)
if result['out'] != '':
return result['out'].strip()
return '0'
cmd = "rev-list --count %s" % (branch)
result = exec_git_cmd(cmd, path)
return '0' if result is None else result
def get_changed_files(path, hash):
""" Retrieves the list of changed files. """
if hash == 'unstaged':
cmd = "%s diff --name-only" % git_exe
cmd = "diff --name-only"
elif hash == 'staged':
cmd = "%s diff --name-only --cached" % git_exe
cmd = "diff --name-only --cached"
else:
cmd = "%s diff-tree --no-commit-id --name-only -r %s" % (git_exe, hash)
result = exec_cmd(cmd, path)
if result['out'] != '':
files = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
files = files.replace('\r\n', '\n')
return files.strip().split("\n")
return []
cmd = "diff-tree --no-commit-id --name-only -r %s" % hash
result = exec_git_cmd(cmd, path)
return [] if result is None else result.split("\n")
def get_branch_hashes(path='.', branch='HEAD', ref='origin/master'):
""" Returns an ordered list of hashes for commits that have been applied since
branching from ref. """
cmd = "%s cherry %s %s" % (git_exe, ref, branch)
result = exec_cmd(cmd, path)
if result['out'] != '':
hashes = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
hashes = hashes.replace('\r\n', '\n')
# Remove the "+ " or "- " prefix.
return [line[2:] for line in hashes.strip().split('\n')]
cmd = "cherry %s %s" % (ref, branch)
result = exec_git_cmd(cmd, path)
if result is None:
return []
# Remove the "+ " or "- " prefix.
return [line[2:] for line in result.split('\n')]
def write_indented_output(output):

View File

@ -87,8 +87,11 @@ else:
print('Unknown operating system platform')
sys.exit()
_QUIET = False
def msg(msg):
if not _QUIET:
print('NOTE: ' + msg)
@ -591,12 +594,16 @@ def LinuxSysrootExists(cpu):
return os.path.isdir(os.path.join(sysroot_root, sysroot_name))
def GetAllPlatformConfigs(build_args):
def GetAllPlatformConfigs(build_args, quiet=False):
"""
Return a map of directory name to GN args for the current platform.
"""
result = {}
if quiet:
global _QUIET
_QUIET = True
# Merged args without validation.
args = GetMergedArgs(build_args)

View File

@ -1,95 +0,0 @@
# Copyright (c) 2019 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.
from __future__ import absolute_import
from cef_api_hash import cef_api_hash
from cef_parser import get_copyright
from file_util import *
import os
import sys
def make_api_hash_header(cpp_header_dir):
# calculate api hashes
api_hash_calculator = cef_api_hash(cpp_header_dir, verbose=False)
api_hash = api_hash_calculator.calculate()
result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_api_hash_header.py tool.
//
#ifndef CEF_INCLUDE_API_HASH_H_
#define CEF_INCLUDE_API_HASH_H_
#include "include/internal/cef_export.h"
// The API hash is created 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 "$UNIVERSAL$"
#if defined(OS_WIN)
#define CEF_API_HASH_PLATFORM "$WINDOWS$"
#elif defined(OS_MAC)
#define CEF_API_HASH_PLATFORM "$MAC$"
#elif defined(OS_LINUX)
#define CEF_API_HASH_PLATFORM "$LINUX$"
#endif
#ifdef __cplusplus
extern "C" {
#endif
///
// Returns CEF API hashes for the libcef library. The returned string is owned
// by the library and should not be freed. The |entry| parameter describes which
// hash value will be returned:
// 0 - CEF_API_HASH_PLATFORM
// 1 - CEF_API_HASH_UNIVERSAL
// 2 - CEF_COMMIT_HASH (from cef_version.h)
///
CEF_EXPORT const char* cef_api_hash(int entry);
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_API_HASH_H_
"""
# Substitute hash values for placeholders.
for platform, value in api_hash.items():
result = result.replace('$%s$' % platform.upper(), value)
return result
def write_api_hash_header(output, cpp_header_dir):
output = os.path.abspath(output)
result = make_api_hash_header(cpp_header_dir)
ret = write_file_if_changed(output, result)
# Also write to |cpp_header_dir| if a different path from |output|, since we
# need to commit the hash header for cef_version.py to correctly calculate the
# version number based on git history.
header_path = os.path.abspath(
os.path.join(cpp_header_dir, os.path.basename(output)))
if (output != header_path):
write_file_if_changed(header_path, result)
return ret
def main(argv):
if len(argv) < 3:
print(("Usage:\n %s <output_filename> <cpp_header_dir>" % argv[0]))
sys.exit(-1)
write_api_hash_header(argv[1], argv[2])
if '__main__' == __name__:
main(sys.argv)

View File

@ -0,0 +1,130 @@
# Copyright (c) 2024 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.
from __future__ import absolute_import
from cef_parser import get_copyright
from file_util import write_file_if_changed
from version_util import read_version_files
import os
import sys
def make_api_versions_header(json):
result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_api_versions_header.py tool. Versions
// are managed using the version_manager.py tool. For usage details see
// https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
//
#ifndef CEF_INCLUDE_CEF_API_VERSIONS_H_
#define CEF_INCLUDE_CEF_API_VERSIONS_H_
#include "include/base/cef_build.h"
"""
for version, hashes in json['hashes'].items():
version_part = """
// $COMMENT$
#define CEF_API_VERSION_$VER$ $VER$
#define CEF_API_HASH_$VER$_UNIVERSAL "$UNIVERSAL$"
#if defined(OS_WIN)
#define CEF_API_HASH_$VER$_PLATFORM "$WINDOWS$"
#elif defined(OS_MAC)
#define CEF_API_HASH_$VER$_PLATFORM "$MAC$"
#elif defined(OS_LINUX)
#define CEF_API_HASH_$VER$_PLATFORM "$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)
result += version_part
result += \
"""
// Oldest supported CEF version.
#define CEF_API_VERSION_MIN CEF_API_VERSION_$MIN$
// Newest supported CEF version.
#define CEF_API_VERSION_LAST CEF_API_VERSION_$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) + \
"""//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_api_versions_header.py tool.
//
namespace {
struct ApiVersionHash {
int version;
const char* const universal;
const char* const platform;
};
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)
result += \
"""
};
const size_t kApiVersionHashesSize = std::size(kApiVersionHashes);
} // namespace
"""
return result
def write_api_versions(out_header_file, out_inc_file, json):
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)
sys.exit(1)
retval1 = 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)
sys.exit(1)
retval2 = write_file_if_changed(out_file, result)
return retval1 or retval2
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])
sys.exit(-1)
json, initialized = \
read_version_files(argv[3], argv[4], True, combine=True)
if not write_api_versions(argv[1], argv[2], json):
print('Nothing done')
if '__main__' == __name__:
main(sys.argv)

View File

@ -8,33 +8,41 @@ from cef_parser import *
def make_capi_global_funcs(funcs, defined_names, translate_map, indent):
result = ''
first = True
for func in funcs:
comment = func.get_comment()
if first or len(comment) > 0:
result += '\n' + format_comment(comment, indent, translate_map)
pre, post = get_version_surround(func)
result += '\n' + pre
if len(comment) > 0:
result += format_comment(comment, indent, translate_map)
if func.get_retval().get_type().is_result_string():
result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
result += indent + 'CEF_EXPORT ' + func.get_capi_proto(defined_names) + ';\n'
if first:
first = False
result += indent + 'CEF_EXPORT ' + func.get_capi_proto(
defined_names) + ';\n' + post
return result
def make_capi_member_funcs(funcs, defined_names, translate_map, indent):
result = ''
first = True
for func in funcs:
comment = func.get_comment()
if first or len(comment) > 0:
result += '\n' + format_comment(comment, indent, translate_map)
pre, post = get_version_surround(func)
result += '\n' + pre
if len(comment) > 0:
result += format_comment(comment, indent, translate_map)
if func.get_retval().get_type().is_result_string():
result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
parts = func.get_capi_parts()
result += indent+parts['retval']+' (CEF_CALLBACK *'+parts['name']+ \
')('+', '.join(parts['args'])+');\n'
if first:
first = False
result += indent + parts['retval'] + ' (CEF_CALLBACK *' + parts['name'] + \
')(' + ', '.join(parts['args']) + ');\n'
if len(post) > 0 and func.has_version_removed():
if func.has_version_added():
result += '#elif ' + get_version_check({
'added': func.get_attrib('removed')
})
else:
result += '#else'
result += '\n' + indent + 'uintptr_t ' + parts['name'] + '_removed;\n'
result += post
return result
@ -61,13 +69,16 @@ def make_capi_header(header, filename):
#define $GUARD$
#pragma once
#if defined(BUILDING_CEF_SHARED)
#error This file cannot be included DLL-side
#endif
"""
# Protect against incorrect use of test headers.
if filename.startswith('test/'):
result += \
"""#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \\
!defined(UNIT_TEST)
"""#if !defined(WRAPPING_CEF_SHARED) && !defined(UNIT_TEST)
#error This file can be included for unit tests only
#endif
@ -78,7 +89,7 @@ def make_capi_header(header, filename):
# identify all includes and forward declarations
translated_includes = set([])
internal_includes = set([])
all_declares = set([])
all_declares = {}
for cls in classes:
includes = cls.get_includes()
for include in includes:
@ -87,7 +98,7 @@ def make_capi_header(header, filename):
# translated CEF API headers.
raise Exception('Disallowed include of %s.h from %s' % (include,
filename))
elif include.startswith('internal/'):
elif include.startswith('internal/') or include == 'cef_api_hash':
# internal/ headers may be C or C++. Include them as-is.
internal_includes.add(include)
else:
@ -97,7 +108,10 @@ def make_capi_header(header, filename):
declare_cls = header.get_class(declare)
if declare_cls is None:
raise Exception('Unknown class: %s' % declare)
all_declares.add(declare_cls.get_capi_name())
capi_name = declare_cls.get_capi_name()
if not capi_name in all_declares:
all_declares[capi_name] = declare_cls.get_version_check() \
if declare_cls.has_version() else None
# output translated includes
if len(translated_includes) > 0:
@ -122,22 +136,39 @@ extern "C" {
"""
# output forward declarations
if len(all_declares) > 0:
sorted_declares = sorted(all_declares)
if bool(all_declares):
sorted_declares = sorted(all_declares.keys())
for declare in sorted_declares:
cls_version_check = all_declares[declare]
if not cls_version_check is None:
result += '#if ' + cls_version_check + '\n'
result += 'struct _' + declare + ';\n'
if not cls_version_check is None:
result += '#endif\n'
# output classes
for cls in classes:
pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += '\n' + pre
comment = cls.get_comment()
add_comment = []
if comment[-1] != '':
add_comment.append('')
add_comment.append('NOTE: This struct is allocated %s-side.' % \
('client' if cls.is_client_side() else 'DLL'))
add_comment.append('')
# virtual functions are inside the structure
classname = cls.get_capi_name()
result += '\n' + format_comment(cls.get_comment(), '', translate_map)
result += '\n' + format_comment(comment + add_comment, '', translate_map)
result += 'typedef struct _'+classname+' {\n'+\
' ///\n'+\
' /// Base structure.\n'+\
' ///\n'+\
' '+cls.get_parent_capi_name()+' base;\n'
funcs = cls.get_virtual_funcs()
funcs = cls.get_virtual_funcs(version_order=True)
result += make_capi_member_funcs(funcs, defined_names, translate_map, ' ')
result += '} ' + classname + ';\n\n'
@ -149,6 +180,8 @@ extern "C" {
result += make_capi_global_funcs(funcs, defined_names, translate_map,
'') + '\n'
result += post
# output global functions
funcs = header.get_funcs(filename)
if len(funcs) > 0:

View File

@ -0,0 +1,189 @@
# Copyright (c) 2024 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.
from __future__ import absolute_import
from cef_parser import *
import functools
def _version_finder(header, name):
cls = header.get_capi_class(name)
if not cls is None:
return cls.get_capi_name(first_version=True)
return name
def make_capi_global_funcs(version, version_finder, funcs, defined_names):
result = ''
for func in funcs:
result += 'CEF_EXPORT ' + func.get_capi_proto(
defined_names, version=version, version_finder=version_finder) + ';\n'
return result
def make_capi_member_funcs(version, version_finder, funcs, defined_names,
translate_map, indent):
result = ''
for func in funcs:
parts = func.get_capi_parts(version=version, version_finder=version_finder)
if func.removed_at_version(version):
result += indent + 'uintptr_t ' + parts['name'] + '_removed;\n'
else:
result += indent + parts['retval'] + ' (CEF_CALLBACK *' + parts['name'] + \
')(' + ', '.join(parts['args']) + ');\n'
return result
def make_capi_versions_header(header, filename):
# structure names that have already been defined
defined_names = header.get_defined_structs()
# map of strings that will be changed in C++ comments
translate_map = header.get_capi_translations()
# header string
result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
// $hash=$$HASH$$$
//
#ifndef $GUARD$
#define $GUARD$
#pragma once
#if !defined(BUILDING_CEF_SHARED)
#error This file can be included DLL-side only
#endif
"""
classes = header.get_classes(filename)
# identify all includes and forward declarations
translated_includes = set()
internal_includes = set()
all_declares = set()
for cls in classes:
includes = cls.get_includes()
for include in includes:
if include.startswith('base/'):
# base/ headers are C++. They should not be included by
# translated CEF API headers.
raise Exception('Disallowed include of %s.h from %s' % (include,
filename))
elif include.startswith('internal/') or include == 'cef_api_hash':
# internal/ headers may be C or C++. Include them as-is.
internal_includes.add(include)
else:
translated_includes.add(include)
declares = cls.get_forward_declares()
for declare in declares:
declare_cls = header.get_class(declare)
if declare_cls is None:
raise Exception('Unknown class: %s' % declare)
for version in declare_cls.get_all_versions():
all_declares.add(declare_cls.get_capi_name(version=version))
# output translated includes
if len(translated_includes) > 0:
sorted_includes = sorted(translated_includes)
for include in sorted_includes:
suffix = '_versions' if not include in ('cef_base',) else ''
result += '#include "include/capi/' + include + '_capi' + suffix + '.h"\n'
else:
result += '#include "include/capi/cef_base_capi.h"\n'
# output internal includes
if len(internal_includes) > 0:
sorted_includes = sorted(internal_includes)
for include in sorted_includes:
result += '#include "include/' + include + '.h"\n'
result += \
"""
#ifdef __cplusplus
extern "C" {
#endif
"""
# output forward declarations
if bool(all_declares):
for declare in sorted(all_declares):
result += 'struct _' + declare + ';\n'
result += '\n'
version_finder = functools.partial(_version_finder, header)
# output classes
for cls in classes:
for version in cls.get_all_versions():
# virtual functions are inside the structure
classname = cls.get_capi_name(version=version)
result += 'typedef struct _'+classname+' {\n'+\
' '+cls.get_parent_capi_name(version=version)+' base;\n'
funcs = cls.get_virtual_funcs(version_order=True, version=version)
result += make_capi_member_funcs(version, version_finder, funcs,
defined_names, translate_map, ' ')
result += '} ' + classname + ';\n\n'
defined_names.append(classname)
# static functions become global
funcs = cls.get_static_funcs()
if len(funcs) > 0:
result += make_capi_global_funcs(version, version_finder, funcs,
defined_names) + '\n'
# output global functions
funcs = header.get_funcs(filename)
if len(funcs) > 0:
result += make_capi_global_funcs(None, version_finder, funcs,
defined_names) + '\n'
# footer string
result += \
"""#ifdef __cplusplus
}
#endif
#endif // $GUARD$
"""
# add the guard string
guard = 'CEF_INCLUDE_CAPI_' + \
filename.replace('/', '_').replace('.', '_capi_versions_').upper() + '_'
result = result.replace('$GUARD$', guard)
return result
def write_capi_versions_header(header, header_dir, filename):
file = get_capi_file_name(os.path.join(header_dir, filename), versions=True)
newcontents = make_capi_versions_header(header, filename)
return (file, newcontents)
# test the module
if __name__ == "__main__":
import sys
# verify that the correct number of command-line arguments are provided
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile>\n')
sys.exit()
# create the header object
header = obj_header()
header.add_file(sys.argv[1])
# dump the result to stdout
filename = os.path.split(sys.argv[1])[1]
sys.stdout.write(make_capi_versions_header(header, filename))

View File

@ -20,8 +20,6 @@ def make_cpptoc_header(header, clsname):
defname += get_capi_name(clsname[3:], False)
defname = defname.upper()
capiname = cls.get_capi_name()
result = get_copyright()
result += '#ifndef CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_\n'+ \
@ -41,9 +39,11 @@ def make_cpptoc_header(header, clsname):
#endif
"""
with_versions = dllside
# include the headers for this class
result += '\n#include "include/'+cls.get_file_name()+'"\n' \
'#include "include/capi/'+cls.get_capi_file_name()+'"\n'
'#include "include/capi/'+cls.get_capi_file_name(versions=with_versions)+'"\n'
# include headers for any forward declared classes that are not in the same file
declares = cls.get_forward_declares()
@ -51,7 +51,7 @@ def make_cpptoc_header(header, clsname):
dcls = header.get_class(declare)
if dcls.get_file_name() != cls.get_file_name():
result += '#include "include/'+dcls.get_file_name()+'"\n' \
'#include "include/capi/'+dcls.get_capi_file_name()+'"\n'
'#include "include/capi/'+dcls.get_capi_file_name(versions=with_versions)+'"\n'
base_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False
@ -63,20 +63,79 @@ def make_cpptoc_header(header, clsname):
template_class = 'CefCppToCRefCounted'
result += '#include "libcef_dll/cpptoc/' + template_file + '"'
result += '\n\n// Wrap a C++ class with a C structure.\n'
if with_versions:
pre = post = ''
else:
pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += '\n\n' + pre.strip()
result += '\n\n'
versions = cls.get_all_versions() if with_versions else (None,)
for version in versions:
result += '// Wrap a C++ class with a C structure%s.\n' % \
('' if version is None else ' at API version %d' % version)
if dllside:
result += '// This class may be instantiated and accessed DLL-side only.\n'
else:
result += '// This class may be instantiated and accessed wrapper-side only.\n'
result += 'class '+clsname+'CppToC\n'+ \
' : public ' + template_class + '<'+clsname+'CppToC, '+clsname+', '+capiname+'> {\n'+ \
capiname = cls.get_capi_name(version=version)
if version is None:
typename = clsname + 'CppToC'
else:
typename = clsname + '_%d_CppToC' % version
result += 'class '+typename+'\n'+ \
' : public ' + template_class + '<'+typename+', '+clsname+', '+capiname+'> {\n'+ \
' public:\n'+ \
' '+clsname+'CppToC();\n'+ \
' virtual ~'+clsname+'CppToC();\n'+ \
' '+typename+'();\n'+ \
' virtual ~'+typename+'();\n'+ \
'};\n\n'
typename = clsname + 'CppToC'
if len(versions) > 1:
result += '// Helpers to return objects at the globally configured API version.\n'
structname = cls.get_capi_name(version=versions[0])
if base_scoped:
result += structname + '* ' + typename + '_WrapOwn(CefOwnPtr<' + clsname + '> c);\n' + \
'std::pair<CefOwnPtr<CefBaseScoped>, '+ structname + '*> ' + typename + '_WrapRaw(CefRawPtr<' + clsname + '> c);\n' + \
'CefOwnPtr<' + clsname + '> ' + typename + '_UnwrapOwn('+ structname + '* s);\n' + \
'CefRawPtr<' + clsname + '> ' + typename + '_UnwrapRaw('+ structname + '* s);\n' + \
'CefBaseScoped* ' + typename + '_GetWrapper('+ structname + '* s);\n\n'
else:
result += structname + '* ' + typename + '_Wrap(CefRefPtr<' + clsname + '> c);\n' + \
'CefRefPtr<' + clsname + '> ' + typename + '_Unwrap('+ structname + '* s);\n\n'
else:
if versions[0] is None:
targetname = clsname + 'CppToC'
structname = cls.get_capi_name()
else:
targetname = clsname + '_%d_CppToC' % versions[0]
structname = cls.get_capi_name(version=versions[0])
if base_scoped:
result += 'constexpr auto ' + typename + '_WrapOwn = ' + targetname + '::WrapOwn;\n' + \
'constexpr auto ' + typename + '_WrapRaw = ' + targetname + '::WrapRaw;\n' + \
'constexpr auto ' + typename + '_UnwrapOwn = ' + targetname + '::UnwrapOwn;\n' + \
'constexpr auto ' + typename + '_UnwrapRaw = ' + targetname + '::UnwrapRaw;\n' + \
'constexpr auto ' + typename + '_GetWrapper = ' + targetname + '::GetWrapper;\n\n'
else:
result += 'constexpr auto ' + typename + '_Wrap = ' + targetname + '::Wrap;\n' + \
'constexpr auto ' + typename + '_Unwrap = ' + targetname + '::Unwrap;\n\n'
if base_scoped:
result += 'inline ' + structname + '* ' + typename + '_WrapRawAndRelease(CefRawPtr<' + clsname + '> c) {\n' + \
' auto [ownerPtr, structPtr] = ' + typename + '_WrapRaw(c);\n' + \
' ownerPtr.release();\n' + \
' return structPtr;\n' + \
'}\n\n'
if len(post) > 0:
result += post + '\n'
result += '#endif // CEF_LIBCEF_DLL_CPPTOC_' + defname + '_CPPTOC_H_'
return result

View File

@ -4,6 +4,8 @@
from __future__ import absolute_import
from cef_parser import *
import copy
import functools
def make_cpptoc_impl_proto(name, func, parts):
@ -16,27 +18,37 @@ def make_cpptoc_impl_proto(name, func, parts):
return proto
def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names):
def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names,
version, version_finder):
notify(name + ' has manual edits')
# retrieve the C API prototype parts
parts = func.get_capi_parts(defined_names, True)
parts = func.get_capi_parts(
defined_names, True, version=version, version_finder=version_finder)
changes = format_translation_changes(impl, parts)
if len(changes) > 0:
notify(name + ' prototype changed')
return make_cpptoc_impl_proto(
name, func, parts) + '{' + changes + impl['body'] + '\n}\n\n'
return make_cpptoc_impl_proto(name, func,
parts) + '{' + changes + impl['body'] + '\n}\n'
def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped,
version, version_finder):
if not version is None and isinstance(func, obj_function_virtual) and \
not func.exists_at_version(version):
raise Exception(
'Attempting to generate non-existing function %s at version %d' %
(name, version))
# Special handling for the cef_shutdown global function.
is_cef_shutdown = name == 'cef_shutdown' and isinstance(
func.parent, obj_header)
# retrieve the C API prototype parts
parts = func.get_capi_parts(defined_names, True)
parts = func.get_capi_parts(
defined_names, True, version=version, version_finder=version_finder)
result = make_cpptoc_impl_proto(name, func, parts) + ' {'
if isinstance(func.parent, obj_class) and \
@ -219,31 +231,31 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
elif arg_type == 'refptr_same' or arg_type == 'refptr_diff':
ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_same':
params.append(ptr_class + 'CppToC::Unwrap(' + arg_name + ')')
params.append(ptr_class + 'CppToC_Unwrap(' + arg_name + ')')
else:
params.append(ptr_class + 'CToCpp::Wrap(' + arg_name + ')')
params.append(ptr_class + 'CToCpp_Wrap(' + arg_name + ')')
elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same':
ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'ownptr_same':
params.append(ptr_class + 'CppToC::UnwrapOwn(' + arg_name + ')')
params.append(ptr_class + 'CppToC_UnwrapOwn(' + arg_name + ')')
else:
params.append(ptr_class + 'CppToC::UnwrapRaw(' + arg_name + ')')
params.append(ptr_class + 'CppToC_UnwrapRaw(' + arg_name + ')')
elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff':
ptr_class = arg.get_type().get_ptr_type()
result += comment+\
'\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp::Wrap('+arg_name+'));'
'\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp_Wrap('+arg_name+'));'
if arg_type == 'ownptr_diff':
params.append('std::move(' + arg_name + 'Ptr)')
else:
params.append(arg_name + 'Ptr.get()')
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
ptr_class = ptr_class_u = arg.get_type().get_ptr_type()
if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CppToC::Unwrap(*' + arg_name + ')'
assign = ptr_class + 'CppToC_Unwrap(*' + arg_name + ')'
else:
assign = ptr_class + 'CToCpp::Wrap(*' + arg_name + ')'
assign = ptr_class + 'CToCpp_Wrap(*' + arg_name + ')'
result += comment+\
'\n CefRefPtr<'+ptr_class+'> '+arg_name+'Ptr;'\
'\n CefRefPtr<'+ptr_class_u+'> '+arg_name+'Ptr;'\
'\n if ('+arg_name+' && *'+arg_name+') {'\
'\n '+arg_name+'Ptr = '+assign+';'\
'\n }'\
@ -273,10 +285,10 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
assign = arg_name + '[i]?true:false'
elif arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])'
elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])'
result += comment+\
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\
'\n if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\
@ -296,13 +308,13 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
else:
ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_vec_same_byref_const':
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + '[i])'
elif arg_type == 'refptr_vec_diff_byref_const':
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i])'
elif arg_type == 'rawptr_vec_same_byref_const':
assign = ptr_class + 'CppToC::UnwrapRaw(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_UnwrapRaw(' + arg_name + '[i])'
elif arg_type == 'rawptr_vec_diff_byref_const':
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i]).release()'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + '[i]).release()'
result += comment+\
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\
'\n if ('+arg_name+'Count > 0) {'\
@ -334,13 +346,16 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
if isinstance(func.parent, obj_class):
# virtual and static class methods
if isinstance(func, obj_function_virtual):
ptr_class = cls.get_name()
if not version_finder is None:
ptr_class = version_finder(ptr_class, as_cpp=True)
if cls.get_name() == func.parent.get_name():
# virtual method for the current class
result += func.parent.get_name() + 'CppToC::Get(self)->'
# virtual method called for the current class
result += ptr_class + 'CppToC::Get(self)->'
else:
# virtual method for a parent class
result += cls.get_name(
) + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->'
# virtual method called for a parent class
result += ptr_class + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(self))->'
else:
result += func.parent.get_name() + '::'
result += func.get_name() + '('
@ -382,9 +397,9 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'Ptr)'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'Ptr)'
else:
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'Ptr)'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'Ptr)'
result += comment+\
'\n if ('+arg_name+') {'\
'\n if ('+arg_name+'Ptr.get()) {'\
@ -413,10 +428,10 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
assign = arg_name + 'List[i]'
elif arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'List[i])'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'List[i])'
elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'List[i])'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'List[i])'
result += comment+\
'\n if ('+arg_name+'Count && '+arg_name+') {'\
'\n *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\
@ -452,80 +467,121 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
result += '\n return _retval.DetachToUserFree();'
elif retval_type == 'refptr_same':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CppToC::Wrap(_retval);'
result += '\n return ' + ptr_class + 'CppToC_Wrap(_retval);'
elif retval_type == 'refptr_diff':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CToCpp::Unwrap(_retval);'
result += '\n return ' + ptr_class + 'CToCpp_Unwrap(_retval);'
elif retval_type == 'ownptr_same':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CppToC::WrapOwn(std::move(_retval));'
result += '\n return ' + ptr_class + 'CppToC_WrapOwn(std::move(_retval));'
elif retval_type == 'ownptr_diff':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CToCpp::UnwrapOwn(std::move(_retval));'
result += '\n return ' + ptr_class + 'CToCpp_UnwrapOwn(std::move(_retval));'
else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name))
if len(result) != result_len:
result += '\n'
result += '}\n\n'
result += '}\n'
return result
def make_cpptoc_function_impl(cls, funcs, existing, prefixname, defined_names,
base_scoped):
def make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
defined_names, base_scoped, version,
version_finder):
impl = ''
customized = False
for func in funcs:
if not prefixname is None:
name = prefixname + '_' + func.get_capi_name()
else:
if not version is None and isinstance(func, obj_function_virtual) and \
not func.exists_at_version(version):
continue
name = func.get_capi_name()
if not prefixname is None:
name = prefixname + '_' + name
if not suffixname is None:
name += '_' + suffixname
if version is None:
pre, post = get_version_surround(func, long=True)
else:
pre = post = ''
value = get_next_function_impl(existing, name)
if not value is None \
and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
# an implementation exists that was not auto-generated
impl += make_cpptoc_function_impl_existing(cls, name, func, value,
defined_names)
customized = True
impl += pre + make_cpptoc_function_impl_existing(
cls, name, func, value, defined_names, version,
version_finder) + post + '\n'
else:
impl += make_cpptoc_function_impl_new(cls, name, func, defined_names,
base_scoped)
impl += pre + make_cpptoc_function_impl_new(
cls, name, func, defined_names, base_scoped, version,
version_finder) + post + '\n'
return impl
if not customized and impl.find('// COULD NOT IMPLEMENT') >= 0:
customized = True
return (impl, customized)
def make_cpptoc_virtual_function_impl(header, cls, existing, prefixname,
defined_names, base_scoped):
funcs = []
funcs.extend(cls.get_virtual_funcs())
suffixname, defined_names, base_scoped,
version, version_finder):
# don't modify the original list
funcs = copy.copy(cls.get_virtual_funcs(version=version))
cur_cls = cls
while True:
parent_name = cur_cls.get_parent_name()
if is_base_class(parent_name):
break
else:
parent_cls = header.get_class(parent_name, defined_names)
parent_cls = header.get_class(parent_name)
if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name)
funcs.extend(parent_cls.get_virtual_funcs())
cur_cls = header.get_class(parent_name, defined_names)
defined_names.append(parent_cls.get_capi_name(version))
funcs.extend(parent_cls.get_virtual_funcs(version=version))
cur_cls = header.get_class(parent_name)
defined_names.append(cur_cls.get_capi_name(version))
return make_cpptoc_function_impl(cls, funcs, existing, prefixname,
defined_names, base_scoped)
return make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
defined_names, base_scoped, version,
version_finder)
def make_cpptoc_virtual_function_assignment_block(funcs, offset, prefixname):
def make_cpptoc_virtual_function_assignment_block(cls, offset, prefixname,
suffixname, version):
impl = ''
funcs = cls.get_virtual_funcs(version_order=True, version=version)
for func in funcs:
name = func.get_capi_name()
impl += ' GetStruct()->' + offset + name + ' = ' + prefixname + '_' + name + ';\n'
# should only include methods directly declared in the current class
assert func.parent.get_name() == cls.get_name(), func.get_name()
if version is None:
pre, post = get_version_surround(func)
else:
if func.removed_at_version(version):
continue
pre = post = ''
name = oname = func.get_capi_name()
if not prefixname is None:
name = prefixname + '_' + name
if not suffixname is None:
name += '_' + suffixname
impl += pre + ' GetStruct()->' + offset + oname + ' = ' + name + ';\n' + post
return impl
def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
defined_names):
impl = make_cpptoc_virtual_function_assignment_block(cls.get_virtual_funcs(),
'', prefixname)
def make_cpptoc_virtual_function_assignment(header, cls, prefixname, suffixname,
defined_names, version,
version_finder):
impl = make_cpptoc_virtual_function_assignment_block(cls, '', prefixname,
suffixname, version)
cur_cls = cls
offset = ''
@ -535,17 +591,19 @@ def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
if is_base_class(parent_name):
break
else:
parent_cls = header.get_class(parent_name, defined_names)
parent_cls = header.get_class(parent_name)
if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name)
defined_names.append(parent_cls.get_capi_name(version))
impl += make_cpptoc_virtual_function_assignment_block(
parent_cls.get_virtual_funcs(), offset, prefixname)
cur_cls = header.get_class(parent_name, defined_names)
parent_cls, offset, prefixname, suffixname, version)
cur_cls = header.get_class(parent_name)
defined_names.append(cur_cls.get_capi_name(version))
return impl
def make_cpptoc_unwrap_derived(header, cls, base_scoped):
def make_cpptoc_unwrap_derived(header, cls, base_scoped, version):
# identify all classes that derive from cls
derived_classes = []
cur_clsname = cls.get_name()
@ -561,39 +619,193 @@ def make_cpptoc_unwrap_derived(header, cls, base_scoped):
if base_scoped:
impl = ['', '']
for clsname in derived_classes:
impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return '+clsname+'CppToC::UnwrapOwn(reinterpret_cast<'+\
get_capi_name(clsname, True)+'*>(s));\n'+\
' }\n'
impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return '+clsname+'CppToC::UnwrapRaw(reinterpret_cast<'+\
get_capi_name(clsname, True)+'*>(s));\n'+\
' }\n'
derived_cls = header.get_class(clsname)
if version is None:
capiname = derived_cls.get_capi_name()
pre, post = get_version_surround(derived_cls)
else:
if not derived_cls.exists_at_version(version):
continue
capiname = derived_cls.get_capi_name(first_version=True)
pre = post = ''
impl[0] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return '+clsname+'CppToC_UnwrapOwn(reinterpret_cast<'+capiname+'*>(s));\n'+\
' }\n' + post
impl[1] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return '+clsname+'CppToC_UnwrapRaw(reinterpret_cast<'+capiname+'*>(s));\n'+\
' }\n' + post
else:
impl = ''
for clsname in derived_classes:
impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return '+clsname+'CppToC::Unwrap(reinterpret_cast<'+\
get_capi_name(clsname, True)+'*>(s));\n'+\
' }\n'
derived_cls = header.get_class(clsname)
if version is None:
capiname = derived_cls.get_capi_name()
pre, post = get_version_surround(derived_cls)
else:
if not derived_cls.exists_at_version(version):
continue
capiname = derived_cls.get_capi_name(first_version=True)
pre = post = ''
impl += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return '+clsname+'CppToC_Unwrap(reinterpret_cast<'+capiname+'*>(s));\n'+\
' }\n' + post
return impl
def make_cpptoc_version_wrappers(header, cls, base_scoped, versions):
assert len(versions) > 0
clsname = cls.get_name()
typename = clsname + 'CppToC'
structname = cls.get_capi_name(version=versions[0])
rversions = sorted(versions, reverse=True)
notreached = format_notreached(
True,
'" called with invalid version " << version',
default_retval='nullptr')
impl = ''
if base_scoped:
impl += structname + '* ' + typename + '_WrapOwn(CefOwnPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c));\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::WrapOwn(std::move(c)));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
'std::pair<CefOwnPtr<CefBaseScoped>, '+ structname + '*> ' + typename + '_WrapRaw(CefRawPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n'
else:
impl += ' auto [ownPtr, structPtr] = ' + clsname + '_' + vstr + '_CppToC::WrapRaw(std::move(c));\n' + \
' return std::make_pair(std::move(ownPtr), reinterpret_cast<' + structname + '*>(structPtr));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
'CefOwnPtr<' + clsname + '> ' + typename + '_UnwrapOwn('+ structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapOwn(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
'CefRawPtr<' + clsname + '> ' + typename + '_UnwrapRaw('+ structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::UnwrapRaw(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
'CefBaseScoped* ' + typename + '_GetWrapper('+ structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::GetWrapper(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n'
else:
impl += structname + '* ' + typename + '_Wrap(CefRefPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Wrap(c);\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CppToC::Wrap(c));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
'CefRefPtr<' + clsname + '> ' + typename + '_Unwrap('+ structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CppToC::Unwrap(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n'
return impl + '\n'
def _version_finder(header, version, name, as_cpp=False):
assert version is None or isinstance(version, int), version
assert name[-1] != '*', name
if as_cpp:
cls = header.get_class(name)
if cls is None:
return name
return cls.get_name(version=version)
cls = header.get_capi_class(name)
if not cls is None:
return cls.get_capi_name(first_version=True)
return name
def make_cpptoc_class_impl(header, clsname, impl):
# structure names that have already been defined
defined_names = header.get_defined_structs()
# retrieve the class and populate the defined names
cls = header.get_class(clsname, defined_names)
cls = header.get_class(clsname)
if cls is None:
raise Exception('Class does not exist: ' + clsname)
capiname = cls.get_capi_name()
prefixname = get_capi_name(clsname[3:], False)
# retrieve the existing virtual function implementations
existing = get_function_impls(impl, 'CEF_CALLBACK')
base_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False
if base_scoped:
@ -601,80 +813,143 @@ def make_cpptoc_class_impl(header, clsname, impl):
else:
template_class = 'CefCppToCRefCounted'
# generate virtual functions
virtualimpl = make_cpptoc_virtual_function_impl(
header, cls, existing, prefixname, defined_names, base_scoped)
if len(virtualimpl) > 0:
virtualimpl = '\nnamespace {\n\n// MEMBER FUNCTIONS - Body may be edited by hand.\n\n' + virtualimpl + '} // namespace'
# the current class is already defined for static functions
defined_names.append(cls.get_capi_name())
with_versions = cls.is_library_side()
versions = list(cls.get_all_versions()) if with_versions else (None,)
# retrieve the existing static function implementations
existing = get_function_impls(impl, 'CEF_EXPORT')
existing_static = get_function_impls(impl, 'CEF_EXPORT')
# retrieve the existing virtual function implementations
existing_virtual = get_function_impls(impl, 'CEF_CALLBACK')
staticout = virtualout = ''
customized = False
first = True
idx = 0
for version in versions:
version_finder = functools.partial(_version_finder, header,
version) if with_versions else None
defined_names.append(cls.get_capi_name(version=version))
if first:
first = False
# generate static functions
staticimpl = make_cpptoc_function_impl(cls,
cls.get_static_funcs(), existing, None,
defined_names, base_scoped)
staticimpl, scustomized = make_cpptoc_function_impl(
cls,
cls.get_static_funcs(), existing_static, None, None, defined_names,
base_scoped, version, version_finder)
if len(staticimpl) > 0:
staticimpl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
staticout += '// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
if scustomized:
customized = True
resultingimpl = staticimpl + virtualimpl
if len(versions) > 1:
staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n'
staticout += make_cpptoc_version_wrappers(header, cls, base_scoped,
versions)
comment = '' if version is None else (' FOR VERSION %d' % version)
suffixname = str(version) if (len(versions) > 1 and version > 0) else None
# generate virtual functions
virtualimpl, vcustomized = make_cpptoc_virtual_function_impl(
header, cls, existing_virtual, prefixname, suffixname, defined_names,
base_scoped, version, version_finder)
if len(virtualimpl) > 0:
virtualout += 'namespace {\n\n// MEMBER FUNCTIONS' + comment + ' - Body may be edited by hand.\n\n' + \
virtualimpl + '} // namespace\n\n'
if vcustomized:
customized = True
# any derived classes can be unwrapped
unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped)
unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped,
version)
capiname = cls.get_capi_name(version=version)
typename = cls.get_name(version=version) + 'CppToC'
const = '// CONSTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
typename+'::'+typename+'() {\n'
if not version is None:
if idx < len(versions) - 1:
condition = 'version < %d || version >= %d' % (version, versions[idx
+ 1])
else:
condition = 'version < %d' % version
const += ' const int version = cef_api_version();\n' + \
' LOG_IF(FATAL, ' + condition + ') << __func__ << " called with invalid version " << version;\n\n'
const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CppToC::'+clsname+'CppToC() {\n'
const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
defined_names)
suffixname, defined_names,
version, version_finder)
const += '}\n\n'+ \
'// DESTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CppToC::~'+clsname+'CppToC() {\n'
'// DESTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
typename+'::~'+typename+'() {\n'
if not cls.has_attrib('no_debugct_check') and not base_scoped:
const += ' shutdown_checker::AssertNotShutdown();\n'
const += '}\n\n'
# determine what includes are required by identifying what translation
# classes are being used
includes = format_translation_includes(header, const + resultingimpl +
(unwrapderived[0]
if base_scoped else unwrapderived))
# build the final output
result = get_copyright()
result += includes + '\n' + resultingimpl + '\n'
parent_sig = template_class + '<' + clsname + 'CppToC, ' + clsname + ', ' + capiname + '>'
parent_sig = template_class + '<' + typename + ', ' + clsname + ', ' + capiname + '>'
notreached = format_notreached(
with_versions,
'" called with unexpected class type " << type',
default_retval='nullptr')
if base_scoped:
const += 'template<> CefOwnPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, '+capiname+'* s) {\n' + \
unwrapderived[0] + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return CefOwnPtr<'+clsname+'>();\n'+ \
' ' + notreached + '\n'+ \
'}\n\n' + \
'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \
unwrapderived[1] + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
' ' + notreached + '\n'+ \
'}\n\n'
else:
const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\n' + \
unwrapderived + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
' ' + notreached + '\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
clsname) + ';'
clsname) + ';\n\n'
result += '\n\n' + const
virtualout += const
idx += 1
return result
out = staticout + virtualout
# determine what includes are required by identifying what translation
# classes are being used
includes = format_translation_includes(
header,
out + (unwrapderived[0] if base_scoped else unwrapderived),
with_versions=with_versions)
# build the final output
result = get_copyright()
result += includes + '\n'
if with_versions:
pre = post = ''
else:
pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += pre + '\n'
result += out + '\n'
if len(post) > 0:
result += post + '\n'
return (result, customized)
def make_cpptoc_global_impl(header, impl):
@ -684,34 +959,36 @@ def make_cpptoc_global_impl(header, impl):
# retrieve the existing global function implementations
existing = get_function_impls(impl, 'CEF_EXPORT')
version_finder = functools.partial(_version_finder, header, None)
# generate global functions
impl = make_cpptoc_function_impl(None,
header.get_funcs(), existing, None,
defined_names, False)
impl, customized = make_cpptoc_function_impl(None,
header.get_funcs(), existing,
None, None, defined_names, False,
None, version_finder)
if len(impl) > 0:
impl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + impl
includes = ''
# include required headers for global functions
filenames = []
paths = set()
for func in header.get_funcs():
filename = func.get_file_name()
if not filename in filenames:
includes += '#include "include/'+func.get_file_name()+'"\n' \
'#include "include/capi/'+func.get_capi_file_name()+'"\n'
filenames.append(filename)
paths.add('include/' + func.get_file_name())
paths.add('include/capi/' + func.get_capi_file_name(versions=True))
# determine what includes are required by identifying what translation
# classes are being used
includes += format_translation_includes(header, impl)
includes += format_translation_includes(
header, impl, with_versions=True, other_includes=paths)
# build the final output
result = get_copyright()
result += includes + '\n' + impl
return result
return (result, customized)
def write_cpptoc_impl(header, clsname, dir):
@ -725,16 +1002,22 @@ def write_cpptoc_impl(header, clsname, dir):
dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_cpptoc.cc')
set_notify_context(file)
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
if clsname is None:
newcontents = make_cpptoc_global_impl(header, oldcontents)
newcontents, customized = make_cpptoc_global_impl(header, oldcontents)
else:
newcontents = make_cpptoc_class_impl(header, clsname, oldcontents)
return (file, newcontents)
newcontents, customized = make_cpptoc_class_impl(header, clsname,
oldcontents)
set_notify_context(None)
return (file, newcontents, customized)
# test the module

View File

@ -6,22 +6,25 @@ from __future__ import absolute_import
from cef_parser import *
def make_function_body_block(cls):
def make_function_body_block(cls, with_versions):
impl = ' // ' + cls.get_name() + ' methods.\n'
funcs = cls.get_virtual_funcs()
for func in funcs:
impl += ' ' + func.get_cpp_proto()
if cls.is_client_side():
impl += ' override;\n'
if func.parent.get_name() != cls.get_name():
# skip methods that are not directly declared in the current class
continue
if with_versions:
pre = post = ''
else:
impl += ' override;\n'
pre, post = get_version_surround(func)
impl += pre + ' ' + func.get_cpp_proto() + ' override;\n' + post
return impl
def make_function_body(header, cls):
impl = make_function_body_block(cls)
def make_function_body(header, cls, with_versions):
impl = make_function_body_block(cls, with_versions)
cur_cls = cls
while True:
@ -34,7 +37,7 @@ def make_function_body(header, cls):
raise Exception('Class does not exist: ' + parent_name)
if len(impl) > 0:
impl += '\n'
impl += make_function_body_block(parent_cls)
impl += make_function_body_block(parent_cls, with_versions)
cur_cls = header.get_class(parent_name)
return impl
@ -54,8 +57,6 @@ def make_ctocpp_header(header, clsname):
defname += get_capi_name(clsname[3:], False)
defname = defname.upper()
capiname = cls.get_capi_name()
result = get_copyright()
result += '#ifndef CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_\n'+ \
@ -75,8 +76,10 @@ def make_ctocpp_header(header, clsname):
#endif
"""
with_versions = clientside
# build the function body
func_body = make_function_body(header, cls)
func_body = make_function_body(header, cls, with_versions)
# include standard headers
if func_body.find('std::map') > 0 or func_body.find('std::multimap') > 0:
@ -86,7 +89,7 @@ def make_ctocpp_header(header, clsname):
# include the headers for this class
result += '\n#include "include/'+cls.get_file_name()+'"'+ \
'\n#include "include/capi/'+cls.get_capi_file_name()+'"\n'
'\n#include "include/capi/'+cls.get_capi_file_name(versions=with_versions)+'"\n'
# include headers for any forward declared classes that are not in the same file
declares = cls.get_forward_declares()
@ -94,7 +97,7 @@ def make_ctocpp_header(header, clsname):
dcls = header.get_class(declare)
if dcls.get_file_name() != cls.get_file_name():
result += '#include "include/'+dcls.get_file_name()+'"\n' \
'#include "include/capi/'+dcls.get_capi_file_name()+'"\n'
'#include "include/capi/'+dcls.get_capi_file_name(versions=with_versions)+'"\n'
base_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False
@ -106,22 +109,67 @@ def make_ctocpp_header(header, clsname):
template_class = 'CefCToCppRefCounted'
result += '#include "libcef_dll/ctocpp/' + template_file + '"'
result += '\n\n// Wrap a C structure with a C++ class.\n'
if with_versions:
pre = post = ''
else:
pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += '\n\n' + pre.strip()
result += '\n\n'
versions = cls.get_all_versions() if with_versions else (None,)
for version in versions:
result += '// Wrap a C structure with a C++ class%s.\n' % \
('' if version is None else ' at API version %d' % version)
if clientside:
result += '// This class may be instantiated and accessed DLL-side only.\n'
else:
result += '// This class may be instantiated and accessed wrapper-side only.\n'
result += 'class '+clsname+'CToCpp\n'+ \
' : public ' + template_class + '<'+clsname+'CToCpp, '+clsname+', '+capiname+'> {\n'+ \
capiname = cls.get_capi_name(version=version)
if version is None:
typename = clsname + 'CToCpp'
else:
typename = clsname + '_%d_CToCpp' % version
result += 'class '+typename+'\n'+ \
' : public ' + template_class + '<'+typename+', '+clsname+', '+capiname+'> {\n'+ \
' public:\n'+ \
' '+clsname+'CToCpp();\n'+ \
' virtual ~'+clsname+'CToCpp();\n\n'
' '+typename+'();\n'+ \
' virtual ~'+typename+'();\n\n'
result += func_body
result += '};\n\n'
typename = clsname + 'CToCpp'
if len(versions) > 1:
result += '// Helpers to return objects at the globally configured API version.\n'
structname = cls.get_capi_name(version=versions[0])
if base_scoped:
result += 'CefOwnPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s);\n' + \
structname + '* ' + typename + '_UnwrapOwn(CefOwnPtr<' + clsname + '> c);\n' + \
structname + '* ' + typename + '_UnwrapRaw(CefRawPtr<' + clsname + '> c);\n\n'
else:
result += 'CefRefPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s);\n' + \
structname + '* ' + typename + '_Unwrap(CefRefPtr<' + clsname + '> c);\n\n'
else:
if versions[0] is None:
targetname = clsname + 'CToCpp'
else:
targetname = clsname + '_%d_CToCpp' % versions[0]
if base_scoped:
result += 'constexpr auto ' + typename + '_Wrap = ' + targetname + '::Wrap;\n' + \
'constexpr auto ' + typename + '_UnwrapOwn = ' + targetname + '::UnwrapOwn;\n' + \
'constexpr auto ' + typename + '_UnwrapRaw = ' + targetname + '::UnwrapRaw;\n\n'
else:
result += 'constexpr auto ' + typename + '_Wrap = ' + targetname + '::Wrap;\n' + \
'constexpr auto ' + typename + '_Unwrap = ' + targetname + '::Unwrap;\n\n'
if len(post) > 0:
result += post + '\n'
result += '#endif // CEF_LIBCEF_DLL_CTOCPP_' + defname + '_CTOCPP_H_'
return result

View File

@ -4,6 +4,7 @@
from __future__ import absolute_import
from cef_parser import *
import functools
def make_ctocpp_impl_proto(clsname, name, func, parts):
@ -25,42 +26,31 @@ def make_ctocpp_impl_proto(clsname, name, func, parts):
return proto
def make_ctocpp_function_impl_existing(clsname, name, func, impl):
notify(name + ' has manual edits')
def make_ctocpp_function_impl_existing(cls, name, func, impl, version):
clsname = None if cls is None else cls.get_name(version=version)
notify_name = name if clsname is None else '%sCToCpp::%s' % (clsname, name)
notify(notify_name + ' has manual edits')
# retrieve the C++ prototype parts
parts = func.get_cpp_parts(True)
changes = format_translation_changes(impl, parts)
if len(changes) > 0:
notify(name + ' prototype changed')
notify(notify_name + ' prototype changed')
return make_ctocpp_impl_proto(clsname, name, func, parts)+'{'+ \
changes+impl['body']+'\n}\n\n'
changes+impl['body']+'\n}\n'
def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
def make_ctocpp_function_impl_new(cls, name, func, base_scoped, version,
version_finder):
# Special handling for the CefShutdown global function.
is_cef_shutdown = name == 'CefShutdown' and isinstance(
func.parent, obj_header)
# build the C++ prototype
parts = func.get_cpp_parts(True)
result = make_ctocpp_impl_proto(clsname, name, func, parts) + ' {'
if isinstance(func.parent, obj_class) and \
not func.parent.has_attrib('no_debugct_check') and \
not base_scoped:
result += '\n shutdown_checker::AssertNotShutdown();\n'
if isinstance(func, obj_function_virtual):
# determine how the struct should be referenced
if clsname == func.parent.get_name():
result += '\n ' + get_capi_name(clsname,
True) + '* _struct = GetStruct();'
else:
result += '\n '+func.parent.get_capi_name()+'* _struct = reinterpret_cast<'+\
func.parent.get_capi_name()+'*>(GetStruct());'
clsname = None if cls is None else cls.get_name(version=version)
notify_name = name if clsname is None else '%sCToCpp::%s' % (clsname, name)
invalid = []
@ -83,23 +73,43 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if len(retval_default) > 0:
retval_default = ' ' + retval_default
# build the C++ prototype
parts = func.get_cpp_parts(True)
result = make_ctocpp_impl_proto(clsname, name, func, parts) + ' {'
is_virtual = isinstance(func, obj_function_virtual)
if is_virtual and not version is None and not func.exists_at_version(version):
notreached = format_notreached(
True,
'" should not be called at version %d"' % version,
default_retval=retval_default.strip())
result += '\n // AUTO-GENERATED CONTENT' + \
'\n ' + notreached + \
'\n}\n'
return result
if isinstance(func.parent, obj_class) and \
not func.parent.has_attrib('no_debugct_check') and \
not base_scoped:
result += '\n shutdown_checker::AssertNotShutdown();\n'
if is_virtual:
# determine how the struct should be referenced
if cls.get_name() == func.parent.get_name():
result += '\n auto* _struct = GetStruct();'
else:
result += '\n auto* _struct = reinterpret_cast<'+\
func.parent.get_capi_name(version=version)+'*>(GetStruct());'
# add API hash check
if func.has_attrib('api_hash_check'):
result += '\n const char* api_hash = cef_api_hash(0);'\
'\n if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {'\
'\n // The libcef API hash does not match the current header API hash.'\
'\n DCHECK(false);'\
'\n return'+retval_default+';'\
'\n }\n'
if isinstance(func, obj_function_virtual):
# add the structure size check
result += '\n if (CEF_MEMBER_MISSING(_struct, ' + func.get_capi_name() + ')) {'\
'\n return' + retval_default + ';\n'\
'\n }\n'
result += '\n const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);'\
'\n CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<'\
'\n "API hashes for libcef and libcef_dll_wrapper do not match.";\n'
if len(invalid) > 0:
notify(name + ' could not be autogenerated')
notify(notify_name + ' could not be autogenerated')
# code could not be auto-generated
result += '\n // BEGIN DELETE BEFORE MODIFYING'
result += '\n // AUTO-GENERATED CONTENT'
@ -209,38 +219,39 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
params.append(arg_name + '.GetWritableStruct()')
elif arg_type == 'refptr_same':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CToCpp::Unwrap(' + arg_name + ')')
params.append(ptr_class + 'CToCpp_Unwrap(' + arg_name + ')')
elif arg_type == 'ownptr_same':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CToCpp::UnwrapOwn(std::move(' + arg_name +
'))')
params.append(ptr_class + 'CToCpp_UnwrapOwn(std::move(' + arg_name + '))')
elif arg_type == 'rawptr_same':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + ')')
params.append(ptr_class + 'CToCpp_UnwrapRaw(' + arg_name + ')')
elif arg_type == 'refptr_diff':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CppToC::Wrap(' + arg_name + ')')
params.append(ptr_class + 'CppToC_Wrap(' + arg_name + ')')
elif arg_type == 'ownptr_diff':
ptr_class = arg.get_type().get_ptr_type()
params.append(ptr_class + 'CppToC::WrapOwn(std::move(' + arg_name + '))')
params.append(ptr_class + 'CppToC_WrapOwn(std::move(' + arg_name + '))')
elif arg_type == 'rawptr_diff':
ptr_class = arg.get_type().get_ptr_type()
result += comment+\
'\n CefOwnPtr<'+ptr_class+'CppToC> '+arg_name+'Ptr('+ptr_class+'CppToC::WrapRaw('+arg_name+'));'
params.append(arg_name + 'Ptr->GetStruct()')
'\n auto ['+arg_name+'Ptr, '+arg_name+'Struct] = '+ptr_class+'CppToC_WrapRaw('+arg_name+');'
params.append(arg_name + 'Struct')
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
ptr_struct = arg.get_type().get_result_ptr_type_root()
if not version_finder is None:
ptr_struct = version_finder(ptr_struct)
if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + ')'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + ')'
else:
assign = ptr_class + 'CppToC::Wrap(' + arg_name + ')'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + ')'
result += comment+\
'\n '+ptr_struct+'* '+arg_name+'Struct = NULL;'\
'\n if ('+arg_name+'.get()) {'\
'\n '+arg_name+'Struct = '+assign+';'\
'\n }'\
'\n '+ptr_struct+'* '+arg_name+'Orig = '+arg_name+'Struct;'
'\n auto* '+arg_name+'Orig = '+arg_name+'Struct;'
params.append('&' + arg_name + 'Struct')
elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
result += comment+\
@ -270,12 +281,15 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if not version_finder is None:
vec_type = version_finder(vec_type)
if arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + '[i])'
elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + '[i])'
else:
assign = arg_name + '[i]'
result += comment+\
@ -301,18 +315,21 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if not version_finder is None:
vec_type = version_finder(vec_type)
if arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const':
assign = arg_name + '[i]'
else:
ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_vec_same_byref_const':
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + '[i])'
elif arg_type == 'refptr_vec_diff_byref_const':
assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
assign = ptr_class + 'CppToC_Wrap(' + arg_name + '[i])'
elif arg_type == 'rawptr_vec_same_byref_const':
assign = ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + '[i])'
assign = ptr_class + 'CToCpp_UnwrapRaw(' + arg_name + '[i])'
elif arg_type == 'rawptr_vec_diff_byref_const':
assign = ptr_class + 'CppToC::WrapRaw(' + arg_name + '[i]).release()->GetStruct()'
assign = ptr_class + 'CppToC_WrapRawAndRelease(' + arg_name + '[i])'
result += comment+\
'\n const size_t '+arg_name+'Count = '+arg_name+'.size();'\
'\n '+vec_type+'* '+arg_name+'List = NULL;'\
@ -348,8 +365,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
result += 'cef_string_userfree_t'
elif retval_type == 'refptr_same' or retval_type == 'refptr_diff' or \
retval_type == 'ownptr_same' or retval_type == 'ownptr_diff':
ptr_struct = retval.get_type().get_result_ptr_type_root()
result += ptr_struct + '*'
result += 'auto*'
else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name))
@ -390,11 +406,10 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
'\n }'
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
ptr_struct = arg.get_type().get_result_ptr_type_root()
if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'Struct)'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + 'Struct)'
else:
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'Struct)'
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + 'Struct)'
result += comment+\
'\n if ('+arg_name+'Struct) {'\
'\n if ('+arg_name+'Struct != '+arg_name+'Orig) {'\
@ -442,13 +457,13 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'List[i])'
assign = ptr_class + 'CToCpp_Wrap(' + arg_name + 'List[i])'
elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type()
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'List[i])'
assign = ptr_class + 'CppToC_Unwrap(' + arg_name + 'List[i])'
elif arg_type == 'bool_vec_byref':
assign = arg_name + 'List[i]?true:false'
else:
@ -468,7 +483,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if arg_type == 'rawptr_vec_diff_byref_const':
result += '\n if ('+arg_name+'Count > 0) {'\
'\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
'\n delete '+ptr_class+'CppToC::GetWrapper('+arg_name+'List[i]);'\
'\n delete '+ptr_class+'CppToC_GetWrapper('+arg_name+'List[i]);'\
'\n }'\
'\n }'
result += '\n if ('+arg_name+'List) {'\
@ -497,43 +512,59 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
'\n return _retvalStr;'
elif retval_type == 'refptr_same' or retval_type == 'ownptr_same':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CToCpp::Wrap(_retval);'
result += '\n return ' + ptr_class + 'CToCpp_Wrap(_retval);'
elif retval_type == 'refptr_diff':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CppToC::Unwrap(_retval);'
result += '\n return ' + ptr_class + 'CppToC_Unwrap(_retval);'
elif retval_type == 'ownptr_diff':
ptr_class = retval.get_type().get_ptr_type()
result += '\n return ' + ptr_class + 'CppToC::UnwrapOwn(_retval);'
result += '\n return ' + ptr_class + 'CppToC_UnwrapOwn(_retval);'
else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name))
if len(result) != result_len:
result += '\n'
result += '}\n\n'
result += '}\n'
return result
def make_ctocpp_function_impl(clsname, funcs, existing, base_scoped):
def make_ctocpp_function_impl(cls, funcs, existing, base_scoped, version,
version_finder):
impl = ''
customized = False
for func in funcs:
name = func.get_name()
value = get_next_function_impl(existing, name)
if version is None:
pre, post = get_version_surround(func, long=True)
else:
pre = post = ''
if not value is None \
and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
# an implementation exists that was not auto-generated
impl += make_ctocpp_function_impl_existing(clsname, name, func, value)
customized = True
impl += pre + make_ctocpp_function_impl_existing(cls, name, func, value,
version) + post + '\n'
else:
impl += make_ctocpp_function_impl_new(clsname, name, func, base_scoped)
impl += pre + make_ctocpp_function_impl_new(
cls, name, func, base_scoped, version, version_finder) + post + '\n'
return impl
if not customized and impl.find('// COULD NOT IMPLEMENT') >= 0:
customized = True
return (impl, customized)
def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
impl = make_ctocpp_function_impl(cls.get_name(),
cls.get_virtual_funcs(), existing,
base_scoped)
def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped,
version, version_finder):
impl, customized = make_ctocpp_function_impl(
cls,
cls.get_virtual_funcs(), existing, base_scoped, version, version_finder)
cur_cls = cls
while True:
@ -544,18 +575,28 @@ def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
parent_cls = header.get_class(parent_name)
if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name)
impl += make_ctocpp_function_impl(cls.get_name(),
parent_cls.get_virtual_funcs(),
existing, base_scoped)
pimpl, pcustomized = make_ctocpp_function_impl(
cls,
parent_cls.get_virtual_funcs(), existing, base_scoped, version,
version_finder)
impl += pimpl
if pcustomized and not customized:
customized = True
cur_cls = header.get_class(parent_name)
return impl
return (impl, customized)
def make_ctocpp_unwrap_derived(header, cls, base_scoped):
def make_ctocpp_unwrap_derived(header, cls, base_scoped, version):
# identify all classes that derive from cls
derived_classes = []
clsname = cls.get_name()
if version is None:
capiname = cls.get_capi_name()
else:
capiname = cls.get_capi_name(version=version)
allclasses = header.get_classes()
for cur_cls in allclasses:
if cur_cls.get_name() == clsname:
@ -568,34 +609,156 @@ def make_ctocpp_unwrap_derived(header, cls, base_scoped):
if base_scoped:
impl = ['', '']
for clsname in derived_classes:
impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
clsname+'CToCpp::UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\
' }\n'
impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
clsname+'CToCpp::UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c))));\n'+\
' }\n'
derived_cls = header.get_class(clsname)
if version is None:
pre, post = get_version_surround(derived_cls)
else:
if not derived_cls.exists_at_version(version):
continue
pre = post = ''
impl[0] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+capiname+'*>('+\
clsname+'CToCpp_UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\
' }\n' + post
impl[1] += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+capiname+'*>('+\
clsname+'CToCpp_UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c))));\n'+\
' }\n' + post
else:
impl = ''
for clsname in derived_classes:
impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
clsname+'CToCpp::Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\
' }\n'
derived_cls = header.get_class(clsname)
if version is None:
pre, post = get_version_surround(derived_cls)
else:
if not derived_cls.exists_at_version(version):
continue
pre = post = ''
impl += pre + ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
' return reinterpret_cast<'+capiname+'*>('+\
clsname+'CToCpp_Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\
' }\n' + post
return impl
def make_ctocpp_version_wrappers(header, cls, base_scoped, versions):
assert len(versions) > 0
clsname = cls.get_name()
typename = clsname + 'CToCpp'
structname = cls.get_capi_name(version=versions[0])
rversions = sorted(versions, reverse=True)
notreached = format_notreached(
True,
'" called with invalid version " << version',
default_retval='nullptr')
impl = ''
if base_scoped:
impl += 'CefOwnPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
structname + '* ' + typename + '_UnwrapOwn(CefOwnPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::UnwrapOwn(std::move(c));\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CToCpp::UnwrapOwn(std::move(c)));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
structname + '* ' + typename + '_UnwrapRaw(CefRawPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::UnwrapRaw(std::move(c));\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CToCpp::UnwrapRaw(std::move(c)));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n'
else:
impl += 'CefRefPtr<' + clsname + '> ' + typename + '_Wrap(' + structname + '* s) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(s);\n'
else:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Wrap(reinterpret_cast<' + cls.get_capi_name(
version) + '*>(s));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n\n' + \
structname + '* ' + typename + '_Unwrap(CefRefPtr<' + clsname + '> c) {\n' + \
' const int version = cef_api_version();\n'
for version in rversions:
vstr = str(version)
impl += ' if (version >= ' + vstr + ') {\n'
if versions[0] == version:
impl += ' return ' + clsname + '_' + vstr + '_CToCpp::Unwrap(c);\n'
else:
impl += ' return reinterpret_cast<' + structname + '*>(' + clsname + '_' + vstr + '_CToCpp::Unwrap(c));\n'
impl += ' }\n'
impl += ' ' + notreached + '\n'+ \
'}\n'
return impl + '\n'
def _version_finder(header, version, name):
assert version is None or isinstance(version, int), version
# normalize ptr values
if name[-1] == '*':
name = name[0:-1]
suffix = '*'
else:
suffix = ''
cls = header.get_capi_class(name)
if not cls is None:
name = cls.get_capi_name(first_version=True)
return name + suffix
def make_ctocpp_class_impl(header, clsname, impl):
cls = header.get_class(clsname)
if cls is None:
raise Exception('Class does not exist: ' + clsname)
capiname = cls.get_capi_name()
# retrieve the existing virtual function implementations
existing = get_function_impls(impl, clsname + 'CToCpp::')
base_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False
if base_scoped:
@ -603,75 +766,135 @@ def make_ctocpp_class_impl(header, clsname, impl):
else:
template_class = 'CefCToCppRefCounted'
# generate virtual functions
virtualimpl = make_ctocpp_virtual_function_impl(header, cls, existing,
base_scoped)
if len(virtualimpl) > 0:
virtualimpl = '\n// VIRTUAL METHODS - Body may be edited by hand.\n\n' + virtualimpl
with_versions = cls.is_client_side()
versions = list(cls.get_all_versions()) if with_versions else (None,)
# retrieve the existing static function implementations
existing = get_function_impls(impl, clsname + '::')
existing_static = get_function_impls(impl, clsname + '::')
staticout = virtualout = ''
customized = False
first = True
idx = 0
for version in versions:
version_finder = functools.partial(_version_finder, header,
version) if with_versions else None
if first:
first = False
# generate static functions
staticimpl = make_ctocpp_function_impl(clsname,
cls.get_static_funcs(), existing,
base_scoped)
staticimpl, scustomized = make_ctocpp_function_impl(
cls,
cls.get_static_funcs(), existing_static, base_scoped, version,
version_finder)
if len(staticimpl) > 0:
staticimpl = '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
staticout += '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
if scustomized:
customized = True
resultingimpl = staticimpl + virtualimpl
if len(versions) > 1:
staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n'
staticout += make_ctocpp_version_wrappers(header, cls, base_scoped,
versions)
comment = '' if version is None else (' FOR VERSION %d' % version)
typename = cls.get_name(version=version) + 'CToCpp'
# retrieve the existing virtual function implementations
existing_virtual = get_function_impls(impl, typename + '::')
# generate virtual functions
virtualimpl, vcustomized = make_ctocpp_virtual_function_impl(
header, cls, existing_virtual, base_scoped, version, version_finder)
if len(virtualimpl) > 0:
virtualout += '\n// VIRTUAL METHODS' + comment + ' - Body may be edited by hand.\n\n' + virtualimpl
if vcustomized:
customized = True
# any derived classes can be unwrapped
unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped)
unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped,
version)
const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CToCpp::'+clsname+'CToCpp() {\n'+ \
'}\n\n'+ \
'// DESTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CToCpp::~'+clsname+'CToCpp() {\n'
capiname = cls.get_capi_name(version=version)
const = '// CONSTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
typename+'::'+typename+'() {\n'
if not version is None:
if idx < len(versions) - 1:
condition = 'version < %d || version >= %d' % (version, versions[idx
+ 1])
else:
condition = 'version < %d' % version
const += ' const int version = cef_api_version();\n' + \
' LOG_IF(FATAL, ' + condition + ') << __func__ << " called with invalid version " << version;\n'
const += '}\n\n'+ \
'// DESTRUCTOR' + comment + ' - Do not edit by hand.\n\n'+ \
typename+'::~'+typename+'() {\n'
if not cls.has_attrib('no_debugct_check') and not base_scoped:
const += ' shutdown_checker::AssertNotShutdown();\n'
const += '}\n\n'
# determine what includes are required by identifying what translation
# classes are being used
includes = format_translation_includes(header, const + resultingimpl +
(unwrapderived[0]
if base_scoped else unwrapderived))
# build the final output
result = get_copyright()
result += includes + '\n' + resultingimpl + '\n'
parent_sig = template_class + '<' + clsname + 'CToCpp, ' + clsname + ', ' + capiname + '>'
parent_sig = template_class + '<' + typename + ', ' + clsname + ', ' + capiname + '>'
notreached = format_notreached(
with_versions,
'" called with unexpected class type " << type',
default_retval='nullptr')
if base_scoped:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<'+clsname+'> c) {\n'+ \
unwrapderived[0] + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
' ' + notreached + '\n'+ \
'}\n\n' + \
'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<'+clsname+'> c) {\n'+ \
unwrapderived[1] + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
' ' + notreached + '\n'+ \
'}\n\n'
else:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \
unwrapderived + \
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \
' return nullptr;\n'+ \
' ' + notreached + '\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
clsname) + ';'
clsname) + ';\n\n'
result += const
virtualout += const
idx += 1
return result
out = staticout + virtualout
# determine what includes are required by identifying what translation
# classes are being used
includes = format_translation_includes(
header,
out + (unwrapderived[0] if base_scoped else unwrapderived),
with_versions=with_versions)
# build the final output
result = get_copyright()
result += includes + '\n'
if with_versions:
pre = post = ''
else:
pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += pre + '\n'
result += out + '\n'
if len(post) > 0:
result += post + '\n'
return (result, customized)
def make_ctocpp_global_impl(header, impl):
@ -679,31 +902,31 @@ def make_ctocpp_global_impl(header, impl):
existing = get_function_impls(impl, 'CEF_GLOBAL')
# generate static functions
impl = make_ctocpp_function_impl(None, header.get_funcs(), existing, False)
impl, customized = make_ctocpp_function_impl(None,
header.get_funcs(), existing,
False, None, None)
if len(impl) > 0:
impl = '\n// GLOBAL METHODS - Body may be edited by hand.\n\n' + impl
includes = ''
# include required headers for global functions
filenames = []
paths = set()
for func in header.get_funcs():
filename = func.get_file_name()
if not filename in filenames:
includes += '#include "include/'+func.get_file_name()+'"\n' \
'#include "include/capi/'+func.get_capi_file_name()+'"\n'
filenames.append(filename)
paths.add('include/' + func.get_file_name())
paths.add('include/capi/' + func.get_capi_file_name())
# determine what includes are required by identifying what translation
# classes are being used
includes += format_translation_includes(header, impl)
includes += format_translation_includes(header, impl, other_includes=paths)
# build the final output
result = get_copyright()
result += includes + '\n// Define used to facilitate parsing.\n#define CEF_GLOBAL\n\n' + impl
return result
return (result, customized)
def write_ctocpp_impl(header, clsname, dir):
@ -717,16 +940,22 @@ def write_ctocpp_impl(header, clsname, dir):
dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_ctocpp.cc')
set_notify_context(file)
if path_exists(file):
oldcontents = read_file(file)
else:
oldcontents = ''
if clsname is None:
newcontents = make_ctocpp_global_impl(header, oldcontents)
newcontents, customized = make_ctocpp_global_impl(header, oldcontents)
else:
newcontents = make_ctocpp_class_impl(header, clsname, oldcontents)
return (file, newcontents)
newcontents, customized = make_ctocpp_class_impl(header, clsname,
oldcontents)
set_notify_context(None)
return (file, newcontents, customized)
# test the module

View File

@ -6,6 +6,7 @@ from __future__ import absolute_import
from __future__ import print_function
from bazel_util import bazel_substitute, bazel_last_error, bazel_set_quiet
from cef_version import VersionFormatter
from clang_util import clang_format_inplace
from date_util import *
from exec_util import exec_cmd
from file_util import *
@ -226,7 +227,12 @@ def transfer_doxyfile(dst_dir, quiet):
sys.stdout.write('Creating Doxyfile file.\n')
def transfer_gypi_files(src_dir, gypi_paths, gypi_path_prefix, dst_dir, quiet):
def transfer_gypi_files(src_dir,
gypi_paths,
gypi_path_prefix,
dst_dir,
quiet,
format=False):
""" Transfer files from one location to another. """
for path in gypi_paths:
src = os.path.join(src_dir, path)
@ -235,6 +241,11 @@ def transfer_gypi_files(src_dir, gypi_paths, gypi_path_prefix, dst_dir, quiet):
make_dir(dst_path, quiet)
copy_file(src, dst, quiet)
# Apply clang-format for C/C++ files.
if format and os.path.splitext(dst)[1][1:] in ('c', 'cc', 'cpp', 'h'):
print(dst)
clang_format_inplace(dst)
def extract_toolchain_cmd(build_dir,
exe_name,
@ -925,17 +936,19 @@ if mode == 'standard' or mode == 'minimal':
transfer_gypi_files(cef_dir, cef_paths2['includes_wrapper'], \
'include/', include_dir, options.quiet)
transfer_gypi_files(cef_dir, cef_paths['autogen_cpp_includes'], \
'include/', include_dir, options.quiet)
'include/', include_dir, options.quiet, format=True)
transfer_gypi_files(cef_dir, cef_paths['autogen_capi_includes'], \
'include/', include_dir, options.quiet)
'include/', include_dir, options.quiet, format=True)
# Transfer generated include files.
generated_includes = [
'cef_api_versions.h',
'cef_color_ids.h',
'cef_command_ids.h',
'cef_config.h',
'cef_pack_resources.h',
'cef_pack_strings.h',
'cef_version.h',
]
for include in generated_includes:
# Debug and Release build should be the same so grab whichever exists.
@ -953,7 +966,7 @@ if mode == 'standard' or mode == 'minimal':
transfer_gypi_files(cef_dir, cef_paths2['libcef_dll_wrapper_sources_common'], \
'libcef_dll/', libcef_dll_dir, options.quiet)
transfer_gypi_files(cef_dir, cef_paths['autogen_client_side'], \
'libcef_dll/', libcef_dll_dir, options.quiet)
'libcef_dll/', libcef_dll_dir, options.quiet, format=True)
if mode == 'standard' or mode == 'minimal':
# transfer additional files

View File

@ -37,6 +37,13 @@ def make_gypi_file(header):
result += " 'include/capi/" + get_capi_file_name(filename) + "',\n"
result += " ],\n"
# capi version includes
result += " 'autogen_capi_versions_includes': [\n"
for filename in filenames:
result += " 'include/capi/" + get_capi_file_name(
filename, versions=True) + "',\n"
result += " ],\n"
classes = sorted(header.get_class_names())
# library side includes

View File

@ -10,7 +10,8 @@ import os
# Other headers that export C API functions.
OTHER_HEADERS = [
'cef_api_hash.h',
'cef_version.h',
'cef_id_mappers.h',
'cef_version_info.h',
'internal/cef_dump_without_crashing_internal.h',
'internal/cef_logging_internal.h',
'internal/cef_string_list.h',
@ -37,12 +38,11 @@ def make_libcef_dll_dylib_impl_parts(name, retval, args):
declare = 'decltype(&%s) %s;\n' % (name, name)
init = ' INIT_ENTRY(%s);' % name
init = 'INIT_ENTRY(%s);\n' % name
impl = """NO_SANITIZE("cfi-icall") %s %s(%s) {
%sg_libcef_pointers.%s(%s);
}
""" % (retval, name, ', '.join(args), 'return '
if retval != 'void' else '', name, arg_names)
@ -70,9 +70,10 @@ def make_libcef_dll_dylib_impl(header):
# Include required headers for global functions.
for func in header.get_funcs():
declare, init, impl = make_libcef_dll_dylib_impl_func(func)
ptr_declare += declare
ptr_init += init
ptr_impl += impl
pre, post = get_version_surround(func)
ptr_declare += pre + declare + post
ptr_init += pre + init + post
ptr_impl += pre + impl + post + '\n'
filename = func.get_file_name()
if not filename in filenames:
@ -85,9 +86,13 @@ def make_libcef_dll_dylib_impl(header):
funcs = cls.get_static_funcs()
for func in funcs:
declare, init, impl = make_libcef_dll_dylib_impl_func(func)
ptr_declare += declare
ptr_init += init
ptr_impl += impl
pre1, post1 = get_version_surround(func)
pre2, post2 = get_version_surround(cls)
pre = pre1 + pre2
post = post1 + post2
ptr_declare += pre + declare + post
ptr_init += pre + init + post
ptr_impl += pre + impl + post + '\n'
if len(funcs) > 0:
filename = cls.get_file_name()
@ -106,7 +111,7 @@ def make_libcef_dll_dylib_impl(header):
func['name'], func['retval'], func['args'])
ptr_declare += declare
ptr_init += init
ptr_impl += impl
ptr_impl += impl + '\n'
includes.append('#include "include/%s"' % other)
@ -202,7 +207,9 @@ if __name__ == "__main__":
# Create the header object. Should match the logic in translator.py.
header = obj_header()
header.set_root_directory(cpp_header_dir)
excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
excluded_files = [
'cef_api_hash.h', 'cef_application_mac.h', 'cef_version_info.h'
]
header.add_directory(cpp_header_dir, excluded_files)
header.add_directory(os.path.join(cpp_header_dir, 'test'))
header.add_directory(os.path.join(cpp_header_dir, 'views'))

View File

@ -16,7 +16,7 @@ import string
import sys
def MakeFileSegment(input, all_names):
def _make_pack_header_segment(input, ids):
result = """
// ---------------------------------------------------------------------------
@ -26,8 +26,93 @@ def MakeFileSegment(input, all_names):
filename = os.path.split(input)[1]
result = result.replace('$FILE$', filename)
for name, id in ids.items():
result += "\n#define %s %s" % (name, id)
return result
def make_pack_header(output, all_files):
# header string
result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file is generated by the make_pack_header.py tool.
//
#ifndef $GUARD$
#define $GUARD$
#pragma once"""
# generate the file segments
for file, ids in all_files.items():
result += _make_pack_header_segment(file, ids)
# footer string
result += \
"""
#endif // $GUARD$
"""
# add the guard string
filename = os.path.split(output)[1]
guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
result = result.replace('$GUARD$', guard)
return result
def _get_cpp_var_name(output):
filename_no_ext = os.path.splitext(os.path.split(output)[1])[0]
# Convert to CamelCase after removing the 'cef_' prefix.
parts = filename_no_ext.split('_')[1:]
return "".join([p[0].upper() + p[1:] for p in parts])
def make_pack_inc(output, all_files):
var = 'IdNames' + _get_cpp_var_name(output)
result = get_copyright(full=False, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file was generated by the make_pack_header.py tool.
//
namespace {
struct $var$ {
int id;
const char* const name;
};
const $var$ k$var$[] = {""".replace('$var$', var)
for file, ids in all_files.items():
result += '\n // From %s:' % file
for name, id in ids.items():
result += '\n {%s, "%s"},' % (id, name)
result += \
"""
};
const size_t k$var$Size = std::size(k$var$);
} // namespace
""".replace('$var$', var)
return result
def _get_defines(input, all_names):
contents = read_file(input)
ids = {}
# Format for Windows builds with resource whitelisting enabled [1]:
# #define IDR_RESOURCE_NAME (::ui::WhitelistedResource<12345>(), 12345)
# Format for other builds:
@ -50,54 +135,48 @@ def MakeFileSegment(input, all_names):
else:
all_names[name] = 1
result += "\n#define %s %s" % (name, id)
ids[name] = id
return result
return ids
def MakeFile(output, input):
# header string
result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
//
// This file is generated by the make_pack_header.py tool.
//
#ifndef $GUARD$
#define $GUARD$
#pragma once"""
def write_pack_header(out_header_file, out_inc_file, inputs):
# sort the input files by name
input = sorted(input, key=lambda path: os.path.split(path)[1])
inputs = sorted(inputs, key=lambda path: os.path.split(path)[1])
all_names = {}
all_files = {}
# generate the file segments
for file in input:
result += MakeFileSegment(file, all_names)
for file in inputs:
filename = os.path.split(file)[1]
assert not filename in all_files, filename
all_files[filename] = _get_defines(file, all_names)
# footer string
result += \
"""
out_file = os.path.abspath(out_header_file)
result = make_pack_header(out_file, all_files)
if not bool(result):
sys.stderr.write('Failed to create %s\n' % out_file)
sys.exit(1)
retval1 = write_file_if_changed(out_file, result)
#endif // $GUARD$
"""
out_file = os.path.abspath(out_inc_file)
result = make_pack_inc(out_file, all_files)
if not bool(result):
sys.stderr.write('Failed to create %s\n' % out_file)
sys.exit(1)
retval2 = write_file_if_changed(out_file, result)
# add the guard string
filename = os.path.split(output)[1]
guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
result = result.replace('$GUARD$', guard)
write_file_if_changed(output, result)
return retval1 #or retval2
def main(argv):
if len(argv) < 3:
print(("Usage:\n %s <output_filename> <input_file1> [input_file2] ... " %
argv[0]))
if len(argv) < 4:
print(
"Usage:\n %s <output_header_file> <output_inc_file> <input_file1> [input_file2] ... "
% argv[0])
sys.exit(-1)
MakeFile(argv[1], argv[2:])
write_pack_header(argv[1], argv[2], argv[3:])
if '__main__' == __name__:

View File

@ -1,2 +0,0 @@
@echo off
python3.bat tools\make_version_header.py include\cef_version.h

View File

@ -12,9 +12,6 @@ import sys
def make_version_header(header):
if not git.is_checkout('.'):
raise Exception('Not a valid checkout')
result = get_copyright(full=True, translator=False) + \
"""//
// ---------------------------------------------------------------------------
@ -41,33 +38,6 @@ def make_version_header(header):
#define DO_MAKE_STRING(p) #p
#define MAKE_STRING(p) DO_MAKE_STRING(p)
#ifndef APSTUDIO_HIDDEN_SYMBOLS
#include "include/internal/cef_export.h"
#ifdef __cplusplus
extern "C" {
#endif
// Returns CEF version information for the libcef library. The |entry|
// parameter describes which version component will be returned:
// 0 - CEF_VERSION_MAJOR
// 1 - CEF_VERSION_MINOR
// 2 - CEF_VERSION_PATCH
// 3 - CEF_COMMIT_NUMBER
// 4 - CHROME_VERSION_MAJOR
// 5 - CHROME_VERSION_MINOR
// 6 - CHROME_VERSION_BUILD
// 7 - CHROME_VERSION_PATCH
///
CEF_EXPORT int cef_version_info(int entry);
#ifdef __cplusplus
}
#endif
#endif // APSTUDIO_HIDDEN_SYMBOLS
#endif // CEF_INCLUDE_CEF_VERSION_H_
"""

View File

@ -1,2 +0,0 @@
#!/bin/sh
python3 tools/make_version_header.py include/cef_version.h

View File

@ -43,7 +43,9 @@ if __name__ == "__main__":
# create the header object
header = obj_header()
excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
excluded_files = [
'cef_api_hash.h', 'cef_application_mac.h', 'cef_version_info.h'
]
header.add_directory(sys.argv[1], excluded_files)
# dump the result to stdout

View File

@ -285,10 +285,6 @@ follows.
void CefClassCToCpp::Function(cpp_params)
{
// Structure Verification
if (CEF_MEMBER_MISSING(struct_, function))
return;
// Parameter Verification (Optional)
// Verify the C++ parameter values.
// ...
@ -309,10 +305,6 @@ follows.
cpp_retval CefClassCToCpp::Function(cpp_params)
{
// Structure Verification
if (CEF_MEMBER_MISSING(struct_, function))
return default_retval; // Configured or defaulted automatically.
// Parameter Verification (Optional)
// Verify the C++ parameter values.
// ...

View File

@ -3,111 +3,66 @@
# can be found in the LICENSE file.
from __future__ import absolute_import
import sys
from cef_parser import *
from cef_parser import obj_header
from cef_version import VersionFormatter
from clang_util import clang_format
from file_util import *
import hashlib
from make_api_hash_header import *
from make_capi_header import *
from make_cpptoc_header import *
from make_cpptoc_impl import *
from make_ctocpp_header import *
from make_ctocpp_impl import *
from make_gypi_file import *
from make_libcef_dll_dylib_impl import *
from make_wrapper_types_header import *
from make_capi_header import write_capi_header
from make_capi_versions_header import write_capi_versions_header
from make_cpptoc_header import write_cpptoc_header
from make_cpptoc_impl import write_cpptoc_impl
from make_ctocpp_header import write_ctocpp_header
from make_ctocpp_impl import write_ctocpp_impl
from make_gypi_file import write_gypi_file
from make_libcef_dll_dylib_impl import write_libcef_dll_dylib_impl
from make_wrapper_types_header import write_wrapper_types_header
from optparse import OptionParser
import sys
# cannot be loaded as a module
if __name__ != "__main__":
sys.stderr.write('This file cannot be loaded as a module!')
sys.exit()
FILE_HEADER = """#
# This file was generated by the CEF translator tool and should not edited
# by hand.
#
# $hash=$$HASH$$$
#
# parse command-line options
disc = """
This utility generates files for the CEF C++ to C API translation layer.
"""
parser = OptionParser(description=disc)
parser.add_option(
'--root-dir',
dest='rootdir',
metavar='DIR',
help='CEF root directory [required]')
parser.add_option(
'--backup',
action='store_true',
dest='backup',
default=False,
help='create a backup of modified files')
parser.add_option(
'--force',
action='store_true',
dest='force',
default=False,
help='force rewrite of the file')
parser.add_option(
'-c',
'--classes',
dest='classes',
action='append',
help='only translate the specified classes')
parser.add_option(
'-q',
'--quiet',
action='store_true',
dest='quiet',
default=False,
help='do not output detailed status information')
(options, args) = parser.parse_args()
# the rootdir option is required
if options.rootdir is None:
parser.print_help(sys.stdout)
sys.exit()
# determine the paths
root_dir = os.path.abspath(options.rootdir)
cpp_header_dir = os.path.join(root_dir, 'include')
cpp_header_test_dir = os.path.join(cpp_header_dir, 'test')
cpp_header_views_dir = os.path.join(cpp_header_dir, 'views')
capi_header_dir = os.path.join(cpp_header_dir, 'capi')
api_hash_header = os.path.join(cpp_header_dir, 'cef_api_hash.h')
libcef_dll_dir = os.path.join(root_dir, 'libcef_dll')
cpptoc_global_impl = os.path.join(libcef_dll_dir, 'libcef_dll.cc')
ctocpp_global_impl = os.path.join(libcef_dll_dir, 'wrapper',
'libcef_dll_wrapper.cc')
wrapper_types_header = os.path.join(libcef_dll_dir, 'wrapper_types.h')
cpptoc_dir = os.path.join(libcef_dll_dir, 'cpptoc')
ctocpp_dir = os.path.join(libcef_dll_dir, 'ctocpp')
gypi_file = os.path.join(root_dir, 'cef_paths.gypi')
libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper',
'libcef_dll_dylib.cc')
# make sure the header directory exists
if not path_exists(cpp_header_dir):
sys.stderr.write('Directory ' + cpp_header_dir + ' does not exist.')
sys.exit()
# create the header object
if not options.quiet:
sys.stdout.write('Parsing C++ headers from ' + cpp_header_dir + '...\n')
header = obj_header()
# add include files to be processed
header.set_root_directory(cpp_header_dir)
excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
header.add_directory(cpp_header_dir, excluded_files)
header.add_directory(cpp_header_test_dir)
header.add_directory(cpp_header_views_dir)
# Track the number of files that were written.
writect = 0
def _write_version():
return FILE_HEADER + VersionFormatter().get_version_string()
def update_file(file, newcontents):
def _write_gitignore(gitignore, gitignore_file, root_dir):
contents = FILE_HEADER
in_file = gitignore_file + '.in'
if os.path.isfile(in_file):
contents += read_file(in_file)
# Include ourselves in generated files.
gitignore.append(gitignore_file)
root_dir_len = len(root_dir)
contents += '\n'.join(
[p[root_dir_len:].replace('\\', '/') for p in sorted(gitignore)])
return contents
def _update_file(file, newcontents, customized, force, clean, backup,
gitignore):
""" Replaces the contents of |file| with |newcontents| if necessary. """
if clean:
if not customized:
return 1 if remove_file(file, quiet=False) else 0
print('File %s has customizations and will not be removed' % file)
return 0
if not customized and not gitignore is None:
gitignore.append(file)
oldcontents = ''
oldhash = ''
@ -122,7 +77,7 @@ def update_file(file, newcontents):
hash_end = "$"
hash_token = "$$HASH$$"
if not options.force and path_exists(file):
if not force and path_exists(file):
oldcontents = read_file(file)
# Extract the existing hash.
@ -137,106 +92,264 @@ def update_file(file, newcontents):
if oldhash == newhash:
# Pre-formatted contents have not changed.
return
return 0
newcontents = newcontents.replace(hash_token, newhash, 1)
# Apply clang-format for C/C++ files.
if os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'):
# Apply clang-format for C/C++ files. This is slow, so we only do it for
# customized files.
if customized and os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'):
result = clang_format(file, newcontents)
if result != None:
newcontents = result
else:
raise Exception("Call to clang-format failed")
raise Exception("Call to clang-format failed for %s" % file)
if options.backup and oldcontents != '':
if backup and oldcontents != '':
backup_file(file)
filedir = os.path.split(file)[0]
if not os.path.isdir(filedir):
make_dir(filedir)
print('Writing file %s' % file)
write_file(file, newcontents)
global writect
writect += 1
return 1
# output the C API header
if not options.quiet:
sys.stdout.write('In C API header directory ' + capi_header_dir + '...\n')
filenames = sorted(header.get_file_names())
for filename in filenames:
if not options.quiet:
sys.stdout.write('Generating ' + filename + ' C API header...\n')
update_file(*write_capi_header(header, capi_header_dir, filename))
def translate(cef_dir,
force=False,
clean=False,
backup=False,
verbose=False,
selected_classes=None):
# determine the paths
root_dir = os.path.abspath(cef_dir)
cpp_header_dir = os.path.join(root_dir, 'include')
cpp_header_test_dir = os.path.join(cpp_header_dir, 'test')
cpp_header_views_dir = os.path.join(cpp_header_dir, 'views')
capi_header_dir = os.path.join(cpp_header_dir, 'capi')
libcef_dll_dir = os.path.join(root_dir, 'libcef_dll')
cpptoc_global_impl = os.path.join(libcef_dll_dir, 'libcef_dll.cc')
ctocpp_global_impl = os.path.join(libcef_dll_dir, 'wrapper',
'libcef_dll_wrapper.cc')
wrapper_types_header = os.path.join(libcef_dll_dir, 'wrapper_types.h')
cpptoc_dir = os.path.join(libcef_dll_dir, 'cpptoc')
ctocpp_dir = os.path.join(libcef_dll_dir, 'ctocpp')
gypi_file = os.path.join(root_dir, 'cef_paths.gypi')
libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper',
'libcef_dll_dylib.cc')
version_file = os.path.join(root_dir, 'VERSION.stamp')
gitignore_file = os.path.join(root_dir, '.gitignore')
# output the wrapper types header
if not options.quiet:
sys.stdout.write('Generating wrapper types header...\n')
update_file(*write_wrapper_types_header(header, wrapper_types_header))
# make sure the header directory exists
if not path_exists(cpp_header_dir):
sys.stderr.write('ERROR: Directory ' + cpp_header_dir +
' does not exist.\n')
sys.exit(1)
# build the list of classes to parse
allclasses = header.get_class_names()
if not options.classes is None:
for cls in options.classes:
# create the header object
if verbose:
print('Parsing C++ headers from ' + cpp_header_dir + '...')
header = obj_header()
# add include files to be processed
header.set_root_directory(cpp_header_dir)
excluded_files = [
'cef_api_hash.h', 'cef_application_mac.h', 'cef_version_info.h'
]
header.add_directory(cpp_header_dir, excluded_files)
header.add_directory(cpp_header_test_dir)
header.add_directory(cpp_header_views_dir)
# Track the number of files that were written.
writect = 0
# Track files that are not customized.
gitignore = []
debug_string = ''
try:
# output the C API header
if verbose:
print('In C API header directory ' + capi_header_dir + '...')
filenames = sorted(header.get_file_names())
for filename in filenames:
if verbose:
print('Generating ' + filename + ' C API headers...')
debug_string = 'CAPI header for ' + filename
writect += _update_file(*write_capi_header(header, capi_header_dir,
filename), False, force, clean,
backup, gitignore)
debug_string = 'CAPI versions header for ' + filename
writect += _update_file(*write_capi_versions_header(
header, capi_header_dir, filename), False, force, clean, backup,
gitignore)
# output the wrapper types header
if verbose:
print('Generating wrapper types header...')
debug_string = 'wrapper types header'
writect += _update_file(*write_wrapper_types_header(
header, wrapper_types_header), False, force, clean, backup, gitignore)
# build the list of classes to parse
allclasses = header.get_class_names()
if not selected_classes is None:
for cls in selected_classes:
if not cls in allclasses:
sys.stderr.write('ERROR: Unknown class: ' + cls)
sys.exit()
classes = options.classes
else:
sys.stderr.write('ERROR: Unknown class: %s\n' % cls)
sys.exit(1)
classes = selected_classes
else:
classes = allclasses
classes = sorted(classes)
classes = sorted(classes)
# output CppToC global file
if not options.quiet:
sys.stdout.write('Generating CppToC global implementation...\n')
update_file(*write_cpptoc_impl(header, None, cpptoc_global_impl))
# output CppToC global file
if verbose:
print('Generating CppToC global implementation...')
debug_string = 'CppToC global implementation'
writect += _update_file(*write_cpptoc_impl(
header, None, cpptoc_global_impl), force, clean, backup, gitignore)
# output CToCpp global file
if not options.quiet:
sys.stdout.write('Generating CToCpp global implementation...\n')
update_file(*write_ctocpp_impl(header, None, ctocpp_global_impl))
# output CToCpp global file
if verbose:
print('Generating CToCpp global implementation...')
debug_string = 'CToCpp global implementation'
writect += _update_file(*write_ctocpp_impl(
header, None, ctocpp_global_impl), force, clean, backup, gitignore)
# output CppToC class files
if not options.quiet:
sys.stdout.write('In CppToC directory ' + cpptoc_dir + '...\n')
for cls in classes:
if not options.quiet:
sys.stdout.write('Generating ' + cls + 'CppToC class header...\n')
update_file(*write_cpptoc_header(header, cls, cpptoc_dir))
if not options.quiet:
sys.stdout.write('Generating ' + cls + 'CppToC class implementation...\n')
update_file(*write_cpptoc_impl(header, cls, cpptoc_dir))
# output CppToC class files
if verbose:
print('In CppToC directory ' + cpptoc_dir + '...')
for cls in classes:
if verbose:
print('Generating ' + cls + 'CppToC class header...')
debug_string = 'CppToC class header for ' + cls
writect += _update_file(*write_cpptoc_header(header, cls, cpptoc_dir),
False, force, clean, backup, gitignore)
# output CppToC class files
if not options.quiet:
sys.stdout.write('In CToCpp directory ' + ctocpp_dir + '...\n')
for cls in classes:
if not options.quiet:
sys.stdout.write('Generating ' + cls + 'CToCpp class header...\n')
update_file(*write_ctocpp_header(header, cls, ctocpp_dir))
if not options.quiet:
sys.stdout.write('Generating ' + cls + 'CToCpp class implementation...\n')
update_file(*write_ctocpp_impl(header, cls, ctocpp_dir))
if verbose:
print('Generating ' + cls + 'CppToC class implementation...')
debug_string = 'CppToC class implementation for ' + cls
writect += _update_file(*write_cpptoc_impl(header, cls, cpptoc_dir),
force, clean, backup, gitignore)
# output the gypi file
if not options.quiet:
sys.stdout.write('Generating ' + gypi_file + ' file...\n')
update_file(*write_gypi_file(header, gypi_file))
# output CppToC class files
if verbose:
print('In CToCpp directory ' + ctocpp_dir + '...')
for cls in classes:
if verbose:
print('Generating ' + cls + 'CToCpp class header...')
debug_string = 'CToCpp class header for ' + cls
writect += _update_file(*write_ctocpp_header(header, cls, ctocpp_dir),
False, force, clean, backup, gitignore)
if verbose:
print('Generating ' + cls + 'CToCpp class implementation...')
debug_string = 'CToCpp class implementation for ' + cls
writect += _update_file(*write_ctocpp_impl(header, cls, ctocpp_dir),
force, clean, backup, gitignore)
# output the libcef dll dylib file
if not options.quiet:
sys.stdout.write('Generating ' + libcef_dll_dylib_impl + ' file...\n')
update_file(*write_libcef_dll_dylib_impl(header, libcef_dll_dylib_impl))
# output the gypi file
if verbose:
print('Generating ' + gypi_file + ' file...')
debug_string = gypi_file
writect += _update_file(*write_gypi_file(header, gypi_file), False, force,
clean, backup, gitignore)
# Update the API hash header file if necessary. This must be done last because
# it reads files that were potentially written by proceeding operations.
if not options.quiet:
sys.stdout.write('Generating API hash header...\n')
if write_api_hash_header(api_hash_header, cpp_header_dir):
writect += 1
# output the libcef dll dylib file
if verbose:
print('Generating ' + libcef_dll_dylib_impl + ' file...')
debug_string = libcef_dll_dylib_impl
writect += _update_file(*write_libcef_dll_dylib_impl(
header, libcef_dll_dylib_impl), False, force, clean, backup, gitignore)
if not options.quiet:
sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n')
# output the VERSION.stamp file that triggers cef_version.h regen at build time
if verbose:
print('Generating ' + version_file + ' file...')
debug_string = version_file
writect += _update_file(version_file,
_write_version(), False, force, clean, backup,
gitignore)
# output the top-level .gitignore file that lists uncustomized files
if verbose:
print('Generating ' + gitignore_file + ' file...')
debug_string = gitignore_file
writect += _update_file(gitignore_file,
_write_gitignore(gitignore, gitignore_file,
root_dir), False, force, clean,
backup, None)
except (AssertionError, Exception) as e:
sys.stderr.write('ERROR: while processing %s\n' % debug_string)
raise
if verbose or writect > 0:
print('Done translating - %s %d files.' % ('Removed'
if clean else 'Wrote', writect))
return writect
if __name__ == "__main__":
from optparse import OptionParser
# parse command-line options
disc = """
This utility generates files for the CEF C++ to C API translation layer.
"""
parser = OptionParser(description=disc)
parser.add_option(
'--root-dir',
dest='rootdir',
metavar='DIR',
help='CEF root directory [required]')
parser.add_option(
'--backup',
action='store_true',
dest='backup',
default=False,
help='create a backup of modified files')
parser.add_option(
'--force',
action='store_true',
dest='force',
default=False,
help='force rewrite of the file')
parser.add_option(
'--clean',
action='store_true',
dest='clean',
default=False,
help='clean all files without custom modifications')
parser.add_option(
'-c',
'--classes',
dest='classes',
action='append',
help='only translate the specified classes')
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
default=False,
help='output detailed status information')
(options, args) = parser.parse_args()
# the rootdir option is required
if options.rootdir is None:
parser.print_help(sys.stdout)
sys.exit()
if translate(options.rootdir, options.force, options.clean, options.backup,
options.verbose, options.classes) == 0:
if not options.verbose:
print('Nothing to do.')
elif not options.clean:
print('WARNING: You must run version_manager.py to update API hashes.')

549
tools/version_manager.py Normal file
View File

@ -0,0 +1,549 @@
# Copyright (c) 2024 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.
from __future__ import absolute_import
from __future__ import print_function
from cef_api_hash import cef_api_hash
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
from git_util import exec_git_cmd
import os
import sys
from translator import translate
from version_util import *
def get_next_api_revision(api_versions_file, major_version):
""" Returns the next available API revision for |major_version|.
"""
json = read_json_file(api_versions_file)
if not bool(json):
return 0
assert 'last' in json, api_versions_file
last_version, last_revision = version_parse(json['last'])
if major_version < last_version:
sys.stderr.write(
'ERROR: Cannot add new API versions on old branches/checkouts '
'(found %d, expected >= %d)\b' % (major_version, last_version))
return -1
if major_version == last_version:
# Increment the revision for the current major version.
new_revision = last_revision + 1
assert new_revision <= 99, new_revision
return new_revision
# Reset the revision for a new 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)
if not next_allowed:
# Next usage is banned with explicit API versions.
assert not api_version 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
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):
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())
else:
hashes['comment'] = 'Added %s.' % 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
def compute_next_api_verson(api_versions_file):
""" Computes the next available API version number.
"""
major_version = int(VersionFormatter().get_chrome_major_version())
next_revision = get_next_api_revision(api_versions_file, major_version)
if next_revision < 0:
return None
return version_make(major_version, next_revision)
def git_grep_next(cef_dir):
cmd = "grep --no-color -n -E (CEF_NEXT|CEF_NEXT)|=next -- :!include/cef_api_hash.h *.h"
return exec_git_cmd(cmd, cef_dir)
def find_next_usage(cpp_header_dir):
cef_dir = os.path.abspath(os.path.join(cpp_header_dir, os.pardir))
result = git_grep_next(cef_dir)
if result is None:
return False
sys.stderr.write('ERROR: NEXT usage found in CEF headers:\n\n' + result +
'\n\nFix manually or run with --replace-next.\n')
return True
def replace_next_usage(file, linenums, as_variable, as_metadata):
assert len(linenums) > 0
contents = read_file(file)
if contents is None:
sys.stderr.write('ERROR: Failed to read file %s\n' % file)
return 0
lines = contents.split('\n')
changect = 0
messages = []
for num in linenums:
idx = num - 1
if idx < 0 or idx >= len(lines):
sys.stderr.write('ERROR: Invalid line number %d in file %s\n' % (num,
file))
return 0
line = lines[idx]
replaced = False
if line.find('CEF_NEXT') >= 0:
line = line.replace('CEF_NEXT', as_variable)
replaced = True
if line.find('=next') >= 0:
line = line.replace('=next', '=' + as_metadata)
replaced = True
if replaced:
lines[idx] = line
changect += 1
else:
messages.append(
'WARNING: No NEXT instances found on line number %d' % num)
if changect > 0 and write_file(file, '\n'.join(lines)):
messages.append('Replaced %d of %d NEXT instances' % (changect,
len(linenums)))
else:
changect = 0
if len(messages) > 0:
print('For file %s:' % file)
for msg in messages:
print(' %s' % msg)
print()
return changect
def find_replace_next_usage(cpp_header_dir, next_version):
cef_dir = os.path.abspath(os.path.join(cpp_header_dir, os.pardir))
result = git_grep_next(cef_dir)
if result is None:
return 0
print('Attempting to replace NEXT usage with %s in CEF headers:\n' %
next_version)
print(result + '\n')
as_variable = version_as_variable(next_version)
as_metadata = version_as_metadata(next_version)
files = {}
# Parse values like:
# include/test/cef_translator_test.h:879:#if CEF_API_ADDED(CEF_NEXT)
# include/test/cef_translator_test.h:883: /*--cef(added=next)--*/
for line in result.split('\n'):
parts = line.split(':', maxsplit=2)
name = parts[0]
linenum = int(parts[1])
if not name in files:
files[name] = [linenum]
else:
files[name].append(linenum)
for file, linenums in files.items():
if replace_next_usage(
os.path.join(cef_dir, file), linenums, as_variable,
as_metadata) != len(linenums):
sys.stderr.write('ERROR: Failed to replace all NEXT usage in %s\n' % file)
return 1
# Sanity-check that all instances were fixed.
if find_next_usage(cpp_header_dir):
return 1
print('All NEXT instances successfully replaced.')
return 0
def exec_apply(cpp_header_dir, api_versions_file, api_untracked_file,
next_version, debug_dir, apply_next, verbose):
""" Updates untracked API hashes if necessary.
Saves the hash for the next API version if |apply_next| is true.
"""
json_versions, json_untracked, initialized = \
read_version_files(api_versions_file, api_untracked_file, True)
if initialized:
# Also need to generate hashes for the first version.
apply_next = True
json_versions['min'] = next_version
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):
sys.stderr.write('ERROR: Failed to process %s\n' % label)
return 1
if version in json_untracked['hashes'] and same_api_hashes(
hashes, json_untracked['hashes'][version]):
print('Hashes for %s are unchanged.' % label)
else:
untracked_changed = True
print('Updating hashes for %s.' % label)
json_untracked['hashes'][version] = hashes
next_changed = apply_next
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):
sys.stderr.write('ERROR: Failed to process %s\n' % next_label)
return 1
last_version = json_versions.get('last', None)
if not last_version is None and last_version in json_versions['hashes']:
if same_api_hashes(hashes, json_versions['hashes'][last_version]):
print('Hashes for last %s are unchanged.' % version_label(last_version))
next_changed = False
if next_changed:
print('Adding hashes for %s.' % next_label)
json_versions['last'] = next_version
json_versions['hashes'][next_version] = hashes
if NEXT_VERSION in json_untracked['hashes'] and not \
same_api_hashes(hashes, json_untracked['hashes'][NEXT_VERSION]):
print('NOTE: Additional versions are available to generate.')
write_versions = next_changed or not os.path.isfile(api_versions_file)
write_untracked = untracked_changed or not os.path.isfile(api_untracked_file)
if not write_versions and not write_untracked:
print('No hash updates required.')
return -1
if write_versions and not write_json_file(
api_versions_file, json_versions, quiet=False):
return 1
if write_untracked and not write_json_file(
api_untracked_file, json_untracked, quiet=False):
return 1
return 0
def exec_check(cpp_header_dir, api_versions_file, api_untracked_file, debug_dir,
fast_check, force_update, skip_untracked, verbose):
""" 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)
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:
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'):
if key in json_versions:
version = json_versions[key]
assert version in json_versions['hashes'], version
versions.append(version)
len_versioned_checked += 1
else:
versions.extend(keys)
len_versioned_checked = len_versioned_existing
if not json_untracked is 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:
print('No hashes to check.')
return 0
write_versions = False
write_untracked = False
for version in versions:
untracked = version in UNTRACKED_VERSIONS
if untracked:
stored_hashes = json_untracked['hashes'][version]
else:
stored_hashes = json_versions['hashes'][version]
label = version_label(version)
computed_hashes = compute_api_hashes(cpp_header_dir, version, True,
debug_dir, verbose)
if not bool(computed_hashes):
sys.stderr.write('ERROR: Failed to process %s\n' % label)
return 1
if not same_api_hashes(computed_hashes, stored_hashes):
if force_update:
print('Updating hashes for %s' % label)
if untracked:
json_untracked['hashes'][version] = computed_hashes
write_untracked = True
else:
json_versions['hashes'][version] = computed_hashes
write_versions = True
else:
sys.stderr.write('ERROR: Hashes for %s do not match!\n' % label)
if untracked:
len_untracked_failed += 1
else:
len_versioned_failed += 1
len_failed = len_untracked_failed + len_versioned_failed
if len_failed == 0:
if write_versions and not write_json_file(
api_versions_file, json_versions, quiet=False):
return 1
if write_untracked and not write_json_file(
api_untracked_file, json_untracked, quiet=False):
return 1
if write_versions:
print('WARNING: This change can break back/forward binary compatibility.')
else:
sys.stderr.write('ERROR: %d hashes checked and failed\n' % len_failed)
print('%d hashes checked and match (%d/%d versioned, %d/%d untracked).' %
(len(versions) - len_failed,
len_versioned_checked - len_versioned_failed, len_versioned_existing,
len_untracked_checked - len_untracked_failed, len_untracked_existing))
return 0 if len_failed == 0 else 1
if __name__ == "__main__":
from optparse import OptionParser
desc = """
This utility manages CEF API versions.
"""
epilog = """
Call this utility without arguments after modifying header files in the CEF
include/ directory. Translated files will be updated if necessary.
If translated files have changed, or when running with -u, unversioned API
hashes (next and experimental) will be checked and potentially updated.
If translated files have changed, or when running with -c, versioned and
unversioned API hashes will be checked. Any changes to versioned API hashes
can break back/forward binary compatibility and are considered an error.
API under development will use placeholder values like CEF_NEXT, added=next,
removed=next in CEF header files. This utility can replace those placeholders
with an actual new version and generate the associated versioned API hashes.
Run with -n to output the next available API version.
Run with -a to apply the next available API version.
For complete usage details see
https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
"""
class CustomParser(OptionParser):
def format_epilog(self, formatter):
return self.epilog
parser = CustomParser(description=desc, epilog=epilog)
parser.add_option(
'--debug-dir',
dest='debugdir',
metavar='DIR',
help='intermediate directory for easy debugging')
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
default=False,
help='output detailed status information')
parser.add_option(
'-u',
'--update',
action='store_true',
dest='update',
default=False,
help='update next and unversioned API hashes')
parser.add_option(
'-n',
'--next',
action='store_true',
dest='next',
default=False,
help='output the next available API version')
parser.add_option(
'-a',
'--apply-next',
action='store_true',
dest='apply',
default=False,
help='add a hash for the next available API version')
parser.add_option(
'-c',
'--check',
action='store_true',
dest='check',
default=False,
help='check hashes for existing API versions')
parser.add_option(
'--fast-check',
action='store_true',
dest='fastcheck',
default=False,
help=
'only check minimum, last, next and experimental API hashes (use with -u, -a or -c)'
)
parser.add_option(
'--replace-next',
action='store_true',
dest='replacenext',
default=False,
help='replace NEXT usage in CEF headers (use with -a)')
parser.add_option(
'--replace-next-version',
dest='replacenextversion',
metavar='VERSION',
help='replace NEXT usage with this value (use with --replace-next)')
parser.add_option(
'--force-update',
action='store_true',
dest='forceupdate',
default=False,
help='force update all API hashes (use with -c)')
(options, args) = parser.parse_args()
script_dir = os.path.dirname(__file__)
cef_dir = os.path.abspath(os.path.join(script_dir, os.pardir))
cpp_header_dir = os.path.join(cef_dir, 'include')
if not os.path.isdir(cpp_header_dir):
sys.stderr.write(
'ERROR: Missing %s directory is required\n' % cpp_header_dir)
sys.exit(1)
api_versions_file = os.path.join(cef_dir, VERSIONS_JSON_FILE)
api_untracked_file = os.path.join(cef_dir, UNTRACKED_JSON_FILE)
mode_ct = options.update + options.next + options.apply + options.check
if mode_ct > 1:
sys.stderr.write(
'ERROR: Choose a single execution mode (-u, -n, -a or -c)\n')
parser.print_help(sys.stdout)
sys.exit(1)
next_version = compute_next_api_verson(api_versions_file)
if next_version is None:
sys.exit(1)
if options.next:
print(next_version)
sys.exit(0)
will_apply_next = options.apply or not os.path.isfile(api_versions_file)
if will_apply_next:
if options.replacenext:
replace_version = options.replacenextversion
if replace_version is None:
replace_version = next_version
elif not version_valid_for_next(replace_version, next_version):
sys.stderr.write('ERROR: Invalid value for --replace-next-version\n')
sys.exit(1)
result = find_replace_next_usage(cpp_header_dir, replace_version)
if result != 0:
sys.exit(result)
elif find_next_usage(cpp_header_dir):
sys.exit(1)
changed = translate(cef_dir, verbose=options.verbose) > 0
skip_untracked = False
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:
# Apply failed.
sys.exit(1)
elif not options.check:
print('Nothing to do.')
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))

154
tools/version_util.py Normal file
View File

@ -0,0 +1,154 @@
# Copyright (c) 2024 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.
from __future__ import absolute_import
from __future__ import print_function
from file_util import read_json_file
# Experimental version. Always the last value.
EXP_VERSION = '999999'
EXP_NAME = 'EXPERIMENTAL'
# Next version. Always the next to last value.
NEXT_VERSION = '999998'
NEXT_NAME = 'NEXT'
UNTRACKED_VERSIONS = (EXP_VERSION, NEXT_VERSION)
UNTRACKED_NAMES = (EXP_NAME, NEXT_NAME)
VERSIONS_JSON_FILE = 'cef_api_versions.json'
UNTRACKED_JSON_FILE = 'cef_api_untracked.json'
def version_make(major_version, revision):
""" Make a tracked version from components. """
# 9999 is reserved for untracked placeholder values. This allows for ~898 years
# of Chromium major versions at the current (end of 2024) rate of 11 per year.
# If this breaks for you please file an issue via Ouija board and/or psychic medium.
assert major_version > 0 and major_version < 9999, major_version
assert revision >= 0 and revision <= 99, revision
if major_version < 1000:
return '%03d%02d' % (major_version, revision)
return '%d%02d' % (major_version, revision)
def version_tracked(version):
""" Returns true if version is in tracked format. """
return (len(version) == 5 or len(version) == 6) and version.isnumeric() and \
not version in UNTRACKED_VERSIONS
def version_parse(version):
""" Parse a tracked version into components. """
assert version_tracked(version), version
split = 3 if len(version) == 5 else 4
return (int(version[0:split]), int(version[split:]))
def version_valid(version):
""" Returns true if version is valid. """
# Untracked versions must be referenced by name instead of number.
return version in UNTRACKED_NAMES or version_tracked(version)
def version_valid_for_next(version, ref_version, allow_exp=True):
""" Returns true if version is valid as a replacement for NEXT. """
version = version.upper()
if allow_exp and version == EXP_NAME:
return True
# Must be valid and not NEXT.
if not version_valid(version) or version == NEXT_NAME:
return False
# Must be >= ref_version.
if version_as_numeric(version) < int(ref_version):
return False
# Must have the same major version number as ref_version.
return version_parse(version)[0] == version_parse(ref_version)[0]
def read_version_last(api_versions_file):
json_versions = read_json_file(api_versions_file)
if not bool(json_versions):
return None
assert 'last' in json_versions, api_versions_file
return json_versions['last']
def read_version_files(api_versions_file,
api_untracked_file,
initialize,
combine=False):
initialized = False
if combine:
initialize = True
json_versions = read_json_file(api_versions_file)
if not bool(json_versions):
if initialize:
json_versions = {
'hashes': {},
}
initialized = True
else:
json_version = None
else:
assert 'hashes' in json_versions, api_versions_file
assert 'last' in json_versions, api_versions_file
assert 'min' in json_versions, api_versions_file
json_untracked = read_json_file(api_untracked_file)
if not bool(json_untracked):
if initialize:
json_untracked = {
'hashes': {},
}
else:
json_untracked = None
else:
assert 'hashes' in json_untracked, api_untracked_file
for version in json_untracked['hashes']:
assert version in UNTRACKED_VERSIONS, api_untracked_file
if combine:
if bool(json_untracked['hashes']):
json_versions['hashes'].update(json_untracked['hashes'])
return (json_versions, initialized)
return (json_versions, json_untracked, initialized)
def version_label(version):
if version == EXP_VERSION or version == EXP_NAME:
return 'experimental version'
if version == NEXT_VERSION or version == NEXT_NAME:
return 'next version'
return 'version ' + version
def version_as_numeric(version):
""" Returns version as a numeric value. """
version = version.upper()
assert version_valid(version), version
if version == EXP_NAME:
version = EXP_VERSION
elif version == NEXT_NAME:
version = NEXT_VERSION
return int(version)
def version_as_variable(version):
""" Returns version as a variable for use in C/C++ files. """
version = version.upper()
assert version_valid(version), version
if not version.isnumeric():
return 'CEF_' + version
return version
def version_as_metadata(version):
""" Returns version as metadata for comments in C++ header files. """
version = version.upper()
assert version_valid(version), version
return version.lower()