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 = [ deps = [
":make_version_header",
"//components/crash/core/common", # crash_keys "//components/crash/core/common", # crash_keys
# Required by chrome_switches.cc # 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_helpers_impl.cc",
"libcef/browser/test/test_server_impl.cc", "libcef/browser/test/test_server_impl.cc",
"libcef/browser/test/test_server_impl.h", "libcef/browser/test/test_server_impl.h",
"libcef/common/test/api_version_test_impl.cc",
"libcef/common/test/translator_test_impl.cc", "libcef/common/test/translator_test_impl.cc",
] ]
@ -451,6 +454,10 @@ source_set("libcef_test_support") {
# Support for UI input events. # Support for UI input events.
"//ui/views:test_support", "//ui/views:test_support",
] ]
configs += [
":libcef_includes_config",
]
} }
@ -758,6 +765,7 @@ source_set("libcef_static") {
"libcef/browser/xml_reader_impl.h", "libcef/browser/xml_reader_impl.h",
"libcef/browser/zip_reader_impl.cc", "libcef/browser/zip_reader_impl.cc",
"libcef/browser/zip_reader_impl.h", "libcef/browser/zip_reader_impl.h",
"libcef/common/api_version_util.h",
"libcef/common/app_manager.cc", "libcef/common/app_manager.cc",
"libcef/common/app_manager.h", "libcef/common/app_manager.h",
"libcef/common/base_impl.cc", "libcef/common/base_impl.cc",
@ -1159,6 +1167,10 @@ config("libcef_dll_wrapper_config") {
if (is_mac) { if (is_mac) {
cflags_objcc = [ "-std=c++17" ] cflags_objcc = [ "-std=c++17" ]
} }
if (cef_api_version != "") {
defines = [ "CEF_API_VERSION=$cef_api_version" ]
}
} }
# libcef_dll_wrapper target. # libcef_dll_wrapper target.
@ -1245,16 +1257,16 @@ grit("cef_resources") {
# Helper for generating pack header files. # Helper for generating pack header files.
template("make_pack_header") { template("make_pack_header") {
assert(defined(invoker.header)) assert(defined(invoker.header))
assert(defined(invoker.inc))
assert(defined(invoker.inputs)) assert(defined(invoker.inputs))
action("make_pack_header_${target_name}") { action("make_pack_header_${target_name}") {
script = "tools/make_pack_header.py" script = "tools/make_pack_header.py"
inputs = invoker.inputs inputs = invoker.inputs
outputs = [ invoker.header ] outputs = [ invoker.header, invoker.inc ]
args = rebase_path(outputs, root_build_dir) + args = rebase_path(outputs + inputs, root_build_dir)
rebase_path(inputs, root_build_dir)
if (defined(invoker.deps)) { if (defined(invoker.deps)) {
deps = invoker.deps deps = invoker.deps
@ -1265,6 +1277,7 @@ template("make_pack_header") {
# Generate cef_pack_resources.h. # Generate cef_pack_resources.h.
make_pack_header("resources") { make_pack_header("resources") {
header = "$root_out_dir/includes/cef/include/cef_pack_resources.h" header = "$root_out_dir/includes/cef/include/cef_pack_resources.h"
inc = "$root_gen_dir/cef/libcef_dll/cef_pack_resources.inc"
inputs = [ inputs = [
"$root_gen_dir/base/tracing/protos/grit/tracing_proto_resources.h", "$root_gen_dir/base/tracing/protos/grit/tracing_proto_resources.h",
"$root_gen_dir/cef/grit/cef_resources.h", "$root_gen_dir/cef/grit/cef_resources.h",
@ -1331,6 +1344,7 @@ make_pack_header("resources") {
# Generate cef_pack_strings.h. # Generate cef_pack_strings.h.
make_pack_header("strings") { make_pack_header("strings") {
header = "$root_out_dir/includes/cef/include/cef_pack_strings.h" header = "$root_out_dir/includes/cef/include/cef_pack_strings.h"
inc = "$root_gen_dir/cef/libcef_dll/cef_pack_strings.inc"
inputs = [ inputs = [
"$root_gen_dir/cef/grit/cef_strings.h", "$root_gen_dir/cef/grit/cef_strings.h",
"$root_gen_dir/chrome/grit/branded_strings.h", "$root_gen_dir/chrome/grit/branded_strings.h",
@ -1374,26 +1388,39 @@ make_pack_header("strings") {
# Generate cef_command_ids.h. # Generate cef_command_ids.h.
make_pack_header("command_ids") { make_pack_header("command_ids") {
header = "$root_out_dir/includes/cef/include/cef_command_ids.h" header = "$root_out_dir/includes/cef/include/cef_command_ids.h"
inc = "$root_gen_dir/cef/libcef_dll/cef_command_ids.inc"
inputs = [ inputs = [
"//chrome/app/chrome_command_ids.h", "//chrome/app/chrome_command_ids.h",
] ]
} }
# Generate cef_api_hash.h. # Generate cef_api_versions.h.
action("make_api_hash_header") { action("make_api_versions_header") {
script = "tools/make_api_hash_header.py" 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 = [
inputs = gypi_paths2.includes_common_capi + "cef_api_versions.json",
gypi_paths2.includes_linux_capi + "cef_api_untracked.json",
gypi_paths2.includes_mac_capi + ]
gypi_paths2.includes_win_capi + outputs = [
gypi_paths2.includes_capi + "$root_out_dir/includes/cef/include/cef_api_versions.h",
gypi_paths.autogen_capi_includes "$root_gen_dir/cef/libcef_dll/cef_api_versions.inc",
include_dir = [ "include" ] ]
outputs = [ "$root_out_dir/includes/cef/include/cef_api_hash.h" ]
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 # 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_resources",
":make_pack_header_strings", ":make_pack_header_strings",
":make_pack_header_command_ids", ":make_pack_header_command_ids",
":make_api_hash_header", ":make_api_versions_header",
":make_version_header",
":make_config_header", ":make_config_header",
":make_colorids_header", ":make_colorids_header",
] ]
@ -1447,6 +1475,28 @@ group("cef_make_headers") {
# libcef dll/framework target. # 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) { if (is_mac) {
cef_framework_name = "Chromium Embedded Framework" cef_framework_name = "Chromium Embedded Framework"
@ -1530,24 +1580,17 @@ if (is_mac) {
"Resources", "Resources",
] ]
sources = includes_common + sources = libcef_sources_common + includes_mac
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
deps = [ deps = libcef_deps_common + [
":cef_framework_angle_binaries", ":cef_framework_angle_binaries",
":cef_framework_resources", ":cef_framework_resources",
":cef_framework_swiftshader_binaries", ":cef_framework_swiftshader_binaries",
":libcef_static",
":libcef_test_support",
] ]
configs += [ configs += [
":libcef_autogen_config", ":libcef_autogen_config",
":libcef_includes_config",
] ]
# We don't link the framework so just use the path from the main executable. # 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. # Necessary because the libcef_test_support target is testonly.
testonly = true testonly = true
sources = includes_common + sources = libcef_sources_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
deps = [ deps = libcef_deps_common
":libcef_static",
":libcef_test_support",
]
configs += [ configs += [
":libcef_autogen_config", ":libcef_autogen_config",
":libcef_includes_config",
":pdb_larger_than_4gb", ":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/base/internal/cef_thread_checker_impl.h',
'include/cef_api_hash.h', 'include/cef_api_hash.h',
'include/cef_base.h', 'include/cef_base.h',
'include/cef_version.h',
'include/internal/cef_export.h', 'include/internal/cef_export.h',
'include/internal/cef_ptr.h', 'include/internal/cef_ptr.h',
'include/internal/cef_string_wrappers.h', 'include/internal/cef_string_wrappers.h',
@ -44,6 +43,8 @@
'include/internal/cef_types_wrappers.h', 'include/internal/cef_types_wrappers.h',
], ],
'includes_common_capi': [ 'includes_common_capi': [
'include/cef_id_mappers.h',
'include/cef_version_info.h',
'include/internal/cef_dump_without_crashing_internal.h', 'include/internal/cef_dump_without_crashing_internal.h',
'include/internal/cef_logging_internal.h', 'include/internal/cef_logging_internal.h',
'include/internal/cef_string.h', 'include/internal/cef_string.h',
@ -483,6 +484,7 @@
'tests/ceftests/resources/net/data/ssl/certificates/root_ca_cert.pem', 'tests/ceftests/resources/net/data/ssl/certificates/root_ca_cert.pem',
], ],
'ceftests_sources_common': [ 'ceftests_sources_common': [
'tests/ceftests/api_version_unittest.cc',
'tests/ceftests/audio_output_unittest.cc', 'tests/ceftests/audio_output_unittest.cc',
'tests/ceftests/browser_info_map_unittest.cc', 'tests/ceftests/browser_info_map_unittest.cc',
'tests/ceftests/certificate_error_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) 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. # Linux configuration.
# #

View File

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

View File

@ -44,62 +44,54 @@ extern "C" {
#endif #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 { typedef struct _cef_base_ref_counted_t {
/// ///
// Size of the data structure. /// Size of the data structure.
/// ///
size_t size; size_t size;
/// ///
// Called to increment the reference count for the object. Should be called /// Called to increment the reference count for the object. Should be called
// for every new copy of a pointer to a given object. /// for every new copy of a pointer to a given object.
/// ///
void(CEF_CALLBACK* add_ref)(struct _cef_base_ref_counted_t* self); void(CEF_CALLBACK* add_ref)(struct _cef_base_ref_counted_t* self);
/// ///
// Called to decrement the reference count for the object. If the reference /// 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 /// count falls to 0 the object should self-delete. Returns true (1) if the
// resulting reference count is 0. /// resulting reference count is 0.
/// ///
int(CEF_CALLBACK* release)(struct _cef_base_ref_counted_t* self); 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); 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); int(CEF_CALLBACK* has_at_least_one_ref)(struct _cef_base_ref_counted_t* self);
} cef_base_ref_counted_t; } 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 { typedef struct _cef_base_scoped_t {
/// ///
// Size of the data structure. /// Size of the data structure.
/// ///
size_t size; 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); void(CEF_CALLBACK* del)(struct _cef_base_scoped_t* self);
} cef_base_scoped_t; } 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -27,45 +27,124 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// --------------------------------------------------------------------------- // Versions are managed using the version_manager.py tool. For usage details
// // see https://bitbucket.org/chromiumembedded/cef/wiki/ApiVersioning.md
// This file was generated by the make_api_hash_header.py tool.
// //
#ifndef CEF_INCLUDE_API_HASH_H_ #ifndef CEF_INCLUDE_CEF_API_HASH_H_
#define CEF_INCLUDE_API_HASH_H_ #define CEF_INCLUDE_CEF_API_HASH_H_
#include "include/internal/cef_export.h" #include "include/internal/cef_export.h"
// The API hash is created by analyzing CEF header files for C API type #if !defined(GENERATING_CEF_API_HASH)
// definitions. The hash value will change when header files are modified in a #include "include/cef_api_versions.h"
// 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"
#endif #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 #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/// ///
// Returns CEF API hashes for the libcef library. The returned string is owned /// Configures the CEF API version and returns API hashes for the libcef
// by the library and should not be freed. The |entry| parameter describes which /// library. The returned string is owned by the library and should not be
// hash value will be returned: /// freed. The |version| parameter should be CEF_API_VERSION and any changes to
// 0 - CEF_API_HASH_PLATFORM /// this value will be ignored after the first call to this method. The |entry|
// 1 - CEF_API_HASH_UNIVERSAL /// parameter describes which hash value will be returned:
// 2 - CEF_COMMIT_HASH (from cef_version.h)
/// ///
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 #ifdef __cplusplus
} }
#endif #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; virtual void ExitFullscreen(bool will_cause_resize) = 0;
/// ///
/// Returns true if a Chrome command is supported and enabled. Values for /// Returns true if a Chrome command is supported and enabled. Use the
/// |command_id| can be found in the cef_command_ids.h file. This method can /// cef_id_for_command_id_name() function for version-safe mapping of command
/// only be called on the UI thread. Only used with Chrome style. /// 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()--*/ /*--cef()--*/
virtual bool CanExecuteChromeCommand(int command_id) = 0; virtual bool CanExecuteChromeCommand(int command_id) = 0;
/// ///
/// Execute a Chrome command. Values for |command_id| can be found in the /// Execute a Chrome command. Use the cef_id_for_command_id_name()
/// cef_command_ids.h file. |disposition| provides information about the /// function for version-safe mapping of command IDC names from
/// intended command target. Only used with Chrome style. /// 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()--*/ /*--cef()--*/
virtual void ExecuteChromeCommand( virtual void ExecuteChromeCommand(

View File

@ -50,12 +50,13 @@ class CefCommandHandler : public virtual CefBaseRefCounted {
public: public:
/// ///
/// Called to execute a Chrome command triggered via menu selection or /// Called to execute a Chrome command triggered via menu selection or
/// keyboard shortcut. Values for |command_id| can be found in the /// keyboard shortcut. Use the cef_id_for_command_id_name()
/// cef_command_ids.h file. |disposition| provides information about the /// function for version-safe mapping of command IDC names from
/// intended command target. Return true if the command was handled or false /// cef_command_ids.h to version-specific numerical |command_id| values.
/// for the default implementation. For context menu commands this will be /// |disposition| provides information about the intended command target.
/// called after CefContextMenuHandler::OnContextMenuCommand. Only used with /// Return true if the command was handled or false for the default
/// Chrome style. /// implementation. For context menu commands this will be called after
/// CefContextMenuHandler::OnContextMenuCommand. Only used with Chrome style.
/// ///
/*--cef()--*/ /*--cef()--*/
virtual bool OnChromeCommand(CefRefPtr<CefBrowser> browser, 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 /// Called to check if a Chrome app menu item should be visible. Use the
/// |command_id| can be found in the cef_command_ids.h file. Only called for /// cef_id_for_command_id_name() function for version-safe mapping of command
/// menu items that would be visible by default. Only used with Chrome style. /// 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()--*/ /*--cef()--*/
virtual bool IsChromeAppMenuItemVisible(CefRefPtr<CefBrowser> browser, 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 /// Called to check if a Chrome app menu item should be enabled. Use the
/// |command_id| can be found in the cef_command_ids.h file. Only called for /// cef_id_for_command_id_name() function for version-safe mapping of command
/// menu items that would be enabled by default. Only used with Chrome style. /// 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()--*/ /*--cef()--*/
virtual bool IsChromeAppMenuItemEnabled(CefRefPtr<CefBrowser> browser, 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 /// 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 /// string if the value is not found. Use the cef_id_for_pack_string_name()
/// of valid string ID values. /// function for version-safe mapping of string IDS names from
/// cef_pack_strings.h to version-specific numerical |string_id| values.
/// ///
/*--cef()--*/ /*--cef()--*/
virtual CefString GetLocalizedString(int string_id) = 0; virtual CefString GetLocalizedString(int string_id) = 0;
/// ///
/// Returns a CefBinaryValue containing the decompressed contents of the /// Returns a CefBinaryValue containing the decompressed contents of the
/// specified scale independent |resource_id| or NULL if not found. Include /// specified scale independent |resource_id| or NULL if not found. Use the
/// cef_pack_resources.h for a listing of valid resource ID values. /// 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()--*/ /*--cef()--*/
virtual CefRefPtr<CefBinaryValue> GetDataResource(int resource_id) = 0; 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 /// Returns a CefBinaryValue containing the decompressed contents of the
/// specified |resource_id| nearest the scale factor |scale_factor| or NULL if /// 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 /// not found. Use a |scale_factor| value of SCALE_FACTOR_NONE for scale
/// independent resources or call GetDataResource instead.Include /// independent resources or call GetDataResource instead. Use the
/// cef_pack_resources.h for a listing of valid resource ID values. /// 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()--*/ /*--cef()--*/
virtual CefRefPtr<CefBinaryValue> GetDataResourceForScale( 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|. /// Called to retrieve a localized translation for the specified |string_id|.
/// To provide the translation set |string| to the translation string and /// To provide the translation set |string| to the translation string and
/// return true. To use the default translation return false. Include /// return true. To use the default translation return false. Use the
/// cef_pack_strings.h for a listing of valid string ID values. /// 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()--*/ /*--cef()--*/
virtual bool GetLocalizedString(int string_id, CefString& string) = 0; 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 /// 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 /// 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 /// 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 /// resident in memory. Use the cef_id_for_pack_resource_name() function for
/// resource ID values. /// version-safe mapping of resource IDR names from cef_pack_resources.h to
/// version-specific numerical |resource_id| values.
/// ///
/*--cef()--*/ /*--cef()--*/
virtual bool GetDataResource(int resource_id, 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 /// factor |scale_factor|. To provide the resource data set |data| and
/// |data_size| to the data pointer and size respectively and return true. To /// |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 /// 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 /// copied and must remain resident in memory. Use the
/// for a listing of valid resource ID values. /// 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()--*/ /*--cef()--*/
virtual bool GetDataResourceForScale(int resource_id, 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) #if defined(COMPILER_MSVC)
#ifdef BUILDING_CEF_SHARED #if defined(BUILDING_CEF_SHARED)
#define CEF_EXPORT __declspec(dllexport) #define CEF_EXPORT __declspec(dllexport)
#elif USING_CEF_SHARED #elif defined(USING_CEF_SHARED)
#define CEF_EXPORT __declspec(dllimport) #define CEF_EXPORT __declspec(dllimport)
#else #else
#define CEF_EXPORT #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. // be included from unit test targets.
// //
#ifndef CEF_INCLUDE_TEST_CEF_TEST_H_ #ifndef CEF_INCLUDE_TEST_CEF_TRANSLATOR_TEST_H_
#define CEF_INCLUDE_TEST_CEF_TEST_H_ #define CEF_INCLUDE_TEST_CEF_TRANSLATOR_TEST_H_
#pragma once #pragma once
#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \ #if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
@ -805,4 +805,4 @@ class CefTranslatorTestScopedClientChild
virtual int GetOtherValue() = 0; 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" #include "cef/include/test/cef_translator_test.h"
namespace {
class CefTranslatorTestRefPtrLibraryImpl class CefTranslatorTestRefPtrLibraryImpl
: public CefTranslatorTestRefPtrLibrary { : public CefTranslatorTestRefPtrLibrary {
public: public:
@ -18,19 +20,22 @@ class CefTranslatorTestRefPtrLibraryImpl
void SetValue(int value) override { value_ = value; } void SetValue(int value) override { value_ = value; }
protected: private:
int value_; int value_;
private:
IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryImpl); IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryImpl);
}; };
} // namespace
// static // static
CefRefPtr<CefTranslatorTestRefPtrLibrary> CefRefPtr<CefTranslatorTestRefPtrLibrary>
CefTranslatorTestRefPtrLibrary::Create(int value) { CefTranslatorTestRefPtrLibrary::Create(int value) {
return new CefTranslatorTestRefPtrLibraryImpl(value); return new CefTranslatorTestRefPtrLibraryImpl(value);
} }
namespace {
class CefTranslatorTestRefPtrLibraryChildImpl class CefTranslatorTestRefPtrLibraryChildImpl
: public CefTranslatorTestRefPtrLibraryChild { : public CefTranslatorTestRefPtrLibraryChild {
public: public:
@ -50,20 +55,23 @@ class CefTranslatorTestRefPtrLibraryChildImpl
void SetOtherValue(int value) override { other_value_ = value; } void SetOtherValue(int value) override { other_value_ = value; }
protected: private:
int value_; int value_;
int other_value_; int other_value_;
private:
IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildImpl); IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildImpl);
}; };
} // namespace
// static // static
CefRefPtr<CefTranslatorTestRefPtrLibraryChild> CefRefPtr<CefTranslatorTestRefPtrLibraryChild>
CefTranslatorTestRefPtrLibraryChild::Create(int value, int other_value) { CefTranslatorTestRefPtrLibraryChild::Create(int value, int other_value) {
return new CefTranslatorTestRefPtrLibraryChildImpl(value, other_value); return new CefTranslatorTestRefPtrLibraryChildImpl(value, other_value);
} }
namespace {
class CefTranslatorTestRefPtrLibraryChildChildImpl class CefTranslatorTestRefPtrLibraryChildChildImpl
: public CefTranslatorTestRefPtrLibraryChildChild { : public CefTranslatorTestRefPtrLibraryChildChild {
public: public:
@ -91,15 +99,16 @@ class CefTranslatorTestRefPtrLibraryChildChildImpl
void SetOtherOtherValue(int value) override { other_other_value_ = value; } void SetOtherOtherValue(int value) override { other_other_value_ = value; }
protected: private:
int value_; int value_;
int other_value_; int other_value_;
int other_other_value_; int other_other_value_;
private:
IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildChildImpl); IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildChildImpl);
}; };
} // namespace
// static // static
CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild> CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild>
CefTranslatorTestRefPtrLibraryChildChild::Create(int value, CefTranslatorTestRefPtrLibraryChildChild::Create(int value,
@ -109,6 +118,8 @@ CefTranslatorTestRefPtrLibraryChildChild::Create(int value,
other_other_value); other_other_value);
} }
namespace {
class CefTranslatorTestScopedLibraryImpl class CefTranslatorTestScopedLibraryImpl
: public CefTranslatorTestScopedLibrary { : public CefTranslatorTestScopedLibrary {
public: public:
@ -123,10 +134,12 @@ class CefTranslatorTestScopedLibraryImpl
void SetValue(int value) override { value_ = value; } void SetValue(int value) override { value_ = value; }
protected: private:
int value_; int value_;
}; };
} // namespace
// static // static
CefOwnPtr<CefTranslatorTestScopedLibrary> CefOwnPtr<CefTranslatorTestScopedLibrary>
CefTranslatorTestScopedLibrary::Create(int value) { CefTranslatorTestScopedLibrary::Create(int value) {
@ -134,6 +147,8 @@ CefTranslatorTestScopedLibrary::Create(int value) {
new CefTranslatorTestScopedLibraryImpl(value)); new CefTranslatorTestScopedLibraryImpl(value));
} }
namespace {
class CefTranslatorTestScopedLibraryChildImpl class CefTranslatorTestScopedLibraryChildImpl
: public CefTranslatorTestScopedLibraryChild { : public CefTranslatorTestScopedLibraryChild {
public: public:
@ -153,11 +168,13 @@ class CefTranslatorTestScopedLibraryChildImpl
void SetOtherValue(int value) override { other_value_ = value; } void SetOtherValue(int value) override { other_value_ = value; }
protected: private:
int value_; int value_;
int other_value_; int other_value_;
}; };
} // namespace
// static // static
CefOwnPtr<CefTranslatorTestScopedLibraryChild> CefOwnPtr<CefTranslatorTestScopedLibraryChild>
CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) { CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) {
@ -165,6 +182,8 @@ CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) {
new CefTranslatorTestScopedLibraryChildImpl(value, other_value)); new CefTranslatorTestScopedLibraryChildImpl(value, other_value));
} }
namespace {
class CefTranslatorTestScopedLibraryChildChildImpl class CefTranslatorTestScopedLibraryChildChildImpl
: public CefTranslatorTestScopedLibraryChildChild { : public CefTranslatorTestScopedLibraryChildChild {
public: public:
@ -192,12 +211,14 @@ class CefTranslatorTestScopedLibraryChildChildImpl
void SetOtherOtherValue(int value) override { other_other_value_ = value; } void SetOtherOtherValue(int value) override { other_other_value_ = value; }
protected: private:
int value_; int value_;
int other_value_; int other_value_;
int other_other_value_; int other_other_value_;
}; };
} // namespace
// static // static
CefOwnPtr<CefTranslatorTestScopedLibraryChildChild> CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>
CefTranslatorTestScopedLibraryChildChild::Create(int value, CefTranslatorTestScopedLibraryChildChild::Create(int value,
@ -208,6 +229,8 @@ CefTranslatorTestScopedLibraryChildChild::Create(int value,
other_other_value)); other_other_value));
} }
namespace {
class CefTranslatorTestImpl : public CefTranslatorTest { class CefTranslatorTestImpl : public CefTranslatorTest {
public: public:
CefTranslatorTestImpl() = default; CefTranslatorTestImpl() = default;
@ -595,6 +618,8 @@ class CefTranslatorTestImpl : public CefTranslatorTest {
IMPLEMENT_REFCOUNTING(CefTranslatorTestImpl); IMPLEMENT_REFCOUNTING(CefTranslatorTestImpl);
}; };
} // namespace
// static // static
CefRefPtr<CefTranslatorTest> CefTranslatorTest::Create() { CefRefPtr<CefTranslatorTest> CefTranslatorTest::Create() {
return new CefTranslatorTestImpl(); return new CefTranslatorTestImpl();

View File

@ -11,4 +11,7 @@ declare_args() {
# FOR OTHER CHROMIUM/CEF BUILD CONFIGURATIONS AS ITS USE MAY HAVE SIGNIFICANT # FOR OTHER CHROMIUM/CEF BUILD CONFIGURATIONS AS ITS USE MAY HAVE SIGNIFICANT
# PERFORMANCE AND/OR SECURITY IMPLICATIONS. # PERFORMANCE AND/OR SECURITY IMPLICATIONS.
is_cef_sandbox_build = false 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(); CefBaseRefCountedCppToC();
}; };
constexpr auto CefBaseRefCountedCppToC_Wrap = CefBaseRefCountedCppToC::Wrap;
constexpr auto CefBaseRefCountedCppToC_Unwrap = CefBaseRefCountedCppToC::Unwrap;
#endif // CEF_LIBCEF_DLL_CPPTOC_BASE_REF_COUNTED_CPPTOC_H_ #endif // CEF_LIBCEF_DLL_CPPTOC_BASE_REF_COUNTED_CPPTOC_H_

View File

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

View File

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

View File

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

View File

@ -22,4 +22,8 @@ class CefBaseScopedCToCpp : public CefCToCppScoped<CefBaseScopedCToCpp,
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_ #endif // CEF_LIBCEF_DLL_CTOCPP_BASE_SCOPED_CTOCPP_H_

View File

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

View File

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

View File

@ -4,15 +4,24 @@
// //
#include <cstddef> #include <cstddef>
#include <map>
#include <string_view>
#include "include/base/cef_build.h" #include "base/logging.h"
#include "include/cef_api_hash.h" #include "base/no_destructor.h"
#include "include/cef_version.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) #if defined(OS_WIN)
#include "include/internal/cef_win.h" #include "cef/include/internal/cef_win.h"
#endif #endif
namespace {
int g_version = -1;
}
CEF_EXPORT int cef_version_info(int entry) { CEF_EXPORT int cef_version_info(int entry) {
switch (entry) { switch (entry) {
case 0: 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) { switch (entry) {
case 0: case 0:
return CEF_API_HASH_PLATFORM; return hash->platform;
case 1: case 1:
return CEF_API_HASH_UNIVERSAL; return hash->universal;
case 2: case 2:
return CEF_COMMIT_HASH; return CEF_COMMIT_HASH;
default: 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(OS_WIN)
#if defined(ARCH_CPU_32_BITS) #if defined(ARCH_CPU_32_BITS)

View File

@ -19,12 +19,9 @@ int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
int nCmdShow) { int nCmdShow) {
CHECK(wWinMain && hInstance); CHECK(wWinMain && hInstance);
const char* api_hash = cef_api_hash(0); const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);
if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) { CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<
// The libcef API hash does not match the current header API hash. "API hashes for libcef and libcef_dll_wrapper do not match.";
DCHECK(false);
return 0;
}
return cef_run_winmain_with_preferred_stack_size(wWinMain, hInstance, return cef_run_winmain_with_preferred_stack_size(wWinMain, hInstance,
lpCmdLine, nCmdShow); lpCmdLine, nCmdShow);
@ -33,12 +30,9 @@ int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) { int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) {
CHECK(main); CHECK(main);
const char* api_hash = cef_api_hash(0); const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);
if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) { CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<
// The libcef API hash does not match the current header API hash. "API hashes for libcef and libcef_dll_wrapper do not match.";
DCHECK(false);
return 0;
}
return cef_run_main_with_preferred_stack_size(main, argc, argv); 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 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
+++ chrome/browser/ui/BUILD.gn +++ chrome/browser/ui/BUILD.gn
@@ -8,6 +8,7 @@ import("//build/config/compiler/compiler.gni") @@ -8,6 +8,7 @@ import("//build/config/compiler/compiler.gni")
@ -118,18 +118,21 @@ index 977b3222c8f7c..ee71bf3a1a463 100644
"//chrome:resources", "//chrome:resources",
"//chrome:strings", "//chrome:strings",
"//chrome/app:chrome_dll_resources", "//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" ] deps += [ "//components/plus_addresses/resources:vector_icons" ]
} }
+ if (enable_cef) { + if (enable_cef) {
+ deps += [ "//cef:cef_resources" ] + deps += [
+ "//cef:cef_resources",
+ "//cef:make_version_header",
+ ]
+ } + }
+ +
# TODO(crbug.com/41437292): Remove this circular dependency. # TODO(crbug.com/41437292): Remove this circular dependency.
# Any circular includes must depend on the target "//chrome/browser:browser_public_dependencies". # Any circular includes must depend on the target "//chrome/browser:browser_public_dependencies".
# These are all-platform circular includes. # These are all-platform circular includes.
@@ -5487,6 +5497,7 @@ static_library("ui") { @@ -5487,6 +5500,7 @@ static_library("ui") {
if (enable_printing) { if (enable_printing) {
deps += [ deps += [
"//components/printing/browser", "//components/printing/browser",

View File

@ -13,8 +13,8 @@
#include "include/base/cef_callback.h" #include "include/base/cef_callback.h"
#include "include/cef_browser.h" #include "include/cef_browser.h"
#include "include/cef_command_ids.h"
#include "include/cef_frame.h" #include "include/cef_frame.h"
#include "include/cef_id_mappers.h"
#include "include/cef_parser.h" #include "include/cef_parser.h"
#include "include/cef_shared_process_message_builder.h" #include "include/cef_shared_process_message_builder.h"
#include "include/cef_ssl_status.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) { 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. // Only the commands in this array will be allowed.
static const int kAllowedCommandIds[] = { static const int kAllowedCommandIds[] = {
IDC_NEW_WINDOW, IDC_NEW_WINDOW,
@ -361,6 +387,28 @@ bool IsAllowedAppMenuCommandId(int command_id) {
} }
bool IsAllowedContextMenuCommandId(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. // Allow commands added by web content.
if (command_id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST && if (command_id >= IDC_CONTENT_CONTEXT_CUSTOM_FIRST &&
command_id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) { command_id <= IDC_CONTENT_CONTEXT_CUSTOM_LAST) {

View File

@ -7,7 +7,7 @@
#include "include/cef_app.h" #include "include/cef_app.h"
#import "include/cef_application_mac.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" #import "include/wrapper/cef_library_loader.h"
#include "tests/cefclient/browser/main_context_impl.h" #include "tests/cefclient/browser/main_context_impl.h"
#include "tests/cefclient/browser/resource.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. // This implementation is based on Chromium's AppController class.
- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)item { - (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]; SEL action = [item action];
BOOL enable = NO; BOOL enable = NO;
// Whether opening a new browser window is allowed. // Whether opening a new browser window is allowed.
@ -413,37 +431,26 @@ void RemoveMenuItem(NSMenu* menu, SEL action_selector) {
// no key window. // no key window.
if (action == @selector(commandDispatch:) || if (action == @selector(commandDispatch:) ||
action == @selector(commandDispatchUsingKeyModifiers:)) { 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 // 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. // current tab should not open if there's a window- or app-modal dialog.
case IDC_OPEN_FILE: enable = canOpenNewBrowser && ![self keyWindowIsModal];
case IDC_NEW_TAB: } else if (tag == IDC_NEW_WINDOW) {
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;
// Browser-level items that open in new windows: allow the user to open // Browser-level items that open in new windows: allow the user to open
// a new window even if there's a window-modal dialog. // a new window even if there's a window-modal dialog.
case IDC_NEW_WINDOW: enable = canOpenNewBrowser;
enable = canOpenNewBrowser; } else if (tag == IDC_TASK_MANAGER) {
break; enable = YES;
case IDC_TASK_MANAGER: } else if (tag == IDC_NEW_INCOGNITO_WINDOW) {
enable = YES; enable = canOpenNewBrowser;
break; } else {
case IDC_NEW_INCOGNITO_WINDOW: enable = ![self keyWindowIsModal];
enable = canOpenNewBrowser;
break;
default:
enable = ![self keyWindowIsModal];
break;
} }
} else if ([self respondsToSelector:action]) { } else if ([self respondsToSelector:action]) {
// All other selectors that this class implements. // All other selectors that this class implements.
@ -469,22 +476,23 @@ 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 // Handle specific commands where we want to make the last active browser
// frontmost and then re-execute the command. // frontmost and then re-execute the command.
switch ([sender tag]) { const auto tag = [sender tag];
case IDC_FIND: if (tag == IDC_FIND || tag == IDC_FIND_NEXT || tag == IDC_FIND_PREVIOUS) {
case IDC_FIND_NEXT: if (id window = [self getActiveBrowserNSWindow]) {
case IDC_FIND_PREVIOUS: [window makeKeyAndOrderFront:nil];
if (id window = [self getActiveBrowserNSWindow]) { if ([window respondsToSelector:@selector(commandDispatch:)]) {
[window makeKeyAndOrderFront:nil]; [window commandDispatch:sender];
if ([window respondsToSelector:@selector(commandDispatch:)]) { return;
[window commandDispatch:sender];
return;
}
} }
break; }
default:
break;
} }
LOG(INFO) << "Unhandled commandDispatch: for tag " << [sender tag]; 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. // can be found in the LICENSE file.
#include "include/base/cef_callback.h" #include "include/base/cef_callback.h"
#include "include/cef_pack_resources.h"
#include "include/cef_request_context_handler.h" #include "include/cef_request_context_handler.h"
#include "include/wrapper/cef_closure_task.h" #include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_stream_resource_handler.h" #include "include/wrapper/cef_stream_resource_handler.h"

View File

@ -18,6 +18,7 @@
#endif #endif
#include "include/base/cef_callback.h" #include "include/base/cef_callback.h"
#include "include/cef_api_hash.h"
#include "include/cef_app.h" #include "include/cef_app.h"
#include "include/cef_task.h" #include "include/cef_task.h"
#include "include/cef_thread.h" #include "include/cef_thread.h"
@ -136,6 +137,10 @@ class ScopedPlatformSetup final {
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
int exit_code; 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) #if defined(OS_WIN) && defined(ARCH_CPU_32_BITS)
// Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB // 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 // 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. // can be found in the LICENSE file.
#include "include/cef_api_hash.h" #include "include/cef_api_hash.h"
#include "include/cef_version.h" #include "include/cef_version_info.h"
#include "tests/gtest/include/gtest/gtest.h" #include "tests/gtest/include/gtest/gtest.h"
TEST(VersionTest, VersionInfo) { TEST(VersionTest, VersionInfo) {
@ -18,7 +18,7 @@ TEST(VersionTest, VersionInfo) {
} }
TEST(VersionTest, ApiHash) { TEST(VersionTest, ApiHash) {
EXPECT_STREQ(CEF_API_HASH_PLATFORM, cef_api_hash(0)); EXPECT_STREQ(CEF_API_HASH_PLATFORM, cef_api_hash(CEF_API_VERSION, 0));
EXPECT_STREQ(CEF_API_HASH_UNIVERSAL, cef_api_hash(1)); EXPECT_STREQ(CEF_API_HASH_UNIVERSAL, cef_api_hash(CEF_API_VERSION, 1));
EXPECT_STREQ(CEF_COMMIT_HASH, cef_api_hash(2)); 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. // can be found in the LICENSE file.
#include "include/base/cef_callback.h" #include "include/base/cef_callback.h"
#include "include/cef_pack_strings.h"
#include "include/views/cef_panel.h" #include "include/views/cef_panel.h"
#include "include/views/cef_panel_delegate.h" #include "include/views/cef_panel_delegate.h"
#include "include/views/cef_scroll_view.h" #include "include/views/cef_scroll_view.h"

View File

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

View File

@ -4,16 +4,16 @@
from __future__ import absolute_import from __future__ import absolute_import
from __future__ import print_function from __future__ import print_function
from clang_util import clang_eval
from file_util import * from file_util import *
import hashlib
import itertools
import os import os
import re import re
import shutil
import string import string
import sys import sys
import textwrap
import time import time
import itertools from version_util import EXP_VERSION
import hashlib
# Determines string type for python 2 and python 3. # Determines string type for python 2 and python 3.
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
@ -22,93 +22,172 @@ else:
string_type = basestring 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: class cef_api_hash:
""" CEF API hash calculator """ """ 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: if headerdir is None or len(headerdir) == 0:
raise AssertionError("headerdir is not specified") raise AssertionError("headerdir is not specified")
self.__headerdir = headerdir self.__headerdir = headerdir
self.__debugdir = debugdir
self.__verbose = verbose self.__verbose = verbose
self.__debug_enabled = not (self.__debugdir is
None) and len(self.__debugdir) > 0
self.platforms = ["windows", "mac", "linux"] 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 = { self.platform_files = {
# List of includes_win_capi from cef_paths2.gypi. "windows":
"windows": [ self.__get_filenames(cef_dir, cef_paths2['includes_win_capi'],
"internal/cef_app_win.h", excluded_files),
"internal/cef_types_win.h", "mac":
], self.__get_filenames(cef_dir, cef_paths2['includes_mac_capi'],
# List of includes_mac_capi from cef_paths2.gypi. excluded_files),
"mac": [ "linux":
"internal/cef_types_mac.h", self.__get_filenames(cef_dir, cef_paths2['includes_linux_capi'],
], excluded_files)
# List of includes_linux_capi from cef_paths2.gypi.
"linux": [
"internal/cef_types_linux.h",
]
} }
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.filecontents = {}
self.excluded_files = [ self.filecontentobjs = {}
# 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",
]
def calculate(self): # Cache values that will not change between calls to calculate().
filenames = [ for filename in self.filenames:
filename for filename in self.__get_filenames()
if not filename in self.excluded_files
]
objects = []
for filename in filenames:
if self.__verbose: if self.__verbose:
print("Processing " + filename + "...") 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) content = read_file(os.path.join(self.__headerdir, filename), True)
platforms = list([ content_objects = None
p for p in self.platforms if self.__is_platform_filename(filename, p)
])
# Parse cef_string.h happens in special case: grab only defined CEF_STRING_TYPE_xxx declaration # 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": if filename == "internal/cef_string.h":
content_objects = self.__parse_string_type(content) 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: else:
content_objects = self.__parse_objects(content) content_objects = self.__parse_objects(content)
for o in content_objects: if not content_objects is None:
o["text"] = self.__prepare_text(o["text"]) self.__prepare_objects(filename, content_objects)
o["platforms"] = platforms self.filecontentobjs[filename] = content_objects
o["filename"] = filename
objects.append(o) 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 will be sorted including filename, to make stable universal hashes
objects = sorted(objects, key=lambda o: o["name"] + "@" + o["filename"]) 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]) namelen = max([len(o["name"]) for o in objects])
filenamelen = max([len(o["filename"]) for o in objects]) filenamelen = max([len(o["filename"]) for o in objects])
dumpsig = [] dumpsig = []
@ -116,14 +195,14 @@ class cef_api_hash:
dumpsig.append( dumpsig.append(
format(o["name"], str(namelen) + "s") + "|" + format( format(o["name"], str(namelen) + "s") + "|" + format(
o["filename"], "" + str(filenamelen) + "s") + "|" + o["text"]) o["filename"], "" + str(filenamelen) + "s") + "|" + o["text"])
self.__write_debug_file("objects.txt", dumpsig) self.__write_debug_file(debug_dir, "objects.txt", dumpsig)
revisions = {} revisions = {}
for platform in itertools.chain(["universal"], self.platforms): for platform in itertools.chain(["universal"], self.platforms):
sig = self.__get_final_sig(objects, platform) sig = self.__get_final_sig(objects, platform)
if self.__debug_enabled: if debug_enabled:
self.__write_debug_file(platform + ".sig", sig) self.__write_debug_file(debug_dir, platform + ".sig", sig)
revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest() revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest()
revisions[platform] = revstr revisions[platform] = revstr
@ -152,7 +231,8 @@ class cef_api_hash:
# enums # enums
for m in re.finditer( 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()} object = {"name": m.group(1), "text": m.group(0).strip()}
objects.append(object) objects.append(object)
@ -163,11 +243,20 @@ class cef_api_hash:
return objects 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): def __parse_string_type(self, content):
""" Grab defined CEF_STRING_TYPE_xxx """ """ Grab defined CEF_STRING_TYPE_xxx """
objects = [] objects = []
for m in re.finditer( 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): flags=0):
object = { object = {
"name": m.group(1), "name": m.group(1),
@ -191,35 +280,20 @@ class cef_api_hash:
return "\n".join(sig) 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 """ """ Returns file names to be processed, relative to headerdir """
headers = [ filenames = [
os.path.join(self.__headerdir, filename) os.path.relpath(os.path.join(cef_dir, filename),
for filename in self.included_files self.__headerdir).replace('\\', '/').lower()
for filename in paths
] ]
capi_dir = os.path.join(self.__headerdir, "capi") if len(excluded_files) == 0:
headers = itertools.chain(headers, get_files(os.path.join(capi_dir, "*.h"))) return filenames
# Also include capi sub-directories. return [
for root, dirs, files in os.walk(capi_dir): filename for filename in filenames if not filename in excluded_files
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
] ]
normalized = [f.replace('\\', '/').lower() for f in normalized]
return list(set(normalized))
def __is_platform_filename(self, filename, platform): def __is_platform_filename(self, filename, platform):
if platform == "universal": if platform == "universal":
@ -235,9 +309,9 @@ class cef_api_hash:
listed = True listed = True
return not listed return not listed
def __write_debug_file(self, filename, content): def __write_debug_file(self, debug_dir, filename, content):
make_dir(self.__debugdir) make_dir(debug_dir)
outfile = os.path.join(self.__debugdir, filename) outfile = os.path.join(debug_dir, filename)
dir = os.path.dirname(outfile) dir = os.path.dirname(outfile)
make_dir(dir) make_dir(dir)
if not isinstance(content, string_type): if not isinstance(content, string_type):
@ -282,14 +356,16 @@ if __name__ == "__main__":
c_start_time = time.time() c_start_time = time.time()
calc = cef_api_hash(options.cppheaderdir, options.debugdir, options.verbose) 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 c_completed_in = time.time() - c_start_time
print("{") if bool(revisions):
for k in sorted(revisions.keys()): print("{")
print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"") for k in sorted(revisions.keys()):
print("}") print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"")
print("}")
# print # print
# print 'Completed in: ' + str(c_completed_in) # print 'Completed in: ' + str(c_completed_in)
# print # print

View File

@ -3,6 +3,7 @@
# can be found in the LICENSE file. # can be found in the LICENSE file.
from __future__ import absolute_import from __future__ import absolute_import
import bisect
from date_util import * from date_util import *
from file_util import * from file_util import *
import os import os
@ -12,11 +13,26 @@ import string
import sys import sys
import textwrap import textwrap
import time 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): def notify(msg):
""" Display a message. """ """ 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): def wrap_text(text, indent='', maxchars=80, listitem=False):
@ -44,25 +60,28 @@ def is_base_class(clsname):
return clsname == 'CefBaseRefCounted' or clsname == 'CefBaseScoped' 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. """ """ 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. """ """ Convert a C++ CamelCaps name to a C API underscore name. """
result = '' result = ''
lastchr = '' lastchr = ''
for chr in cppname: for chr in cppname:
# add an underscore if the current character is an upper case letter # add an underscore if the current character is an upper case letter
# and the last character was a lower case letter # and the last character was a lower case letter or number.
if len(result) > 0 and not chr.isdigit() \ if len(result) > 0 and chr.isalpha() \
and chr.upper() == chr \ and chr.upper() == chr \
and not lastchr.upper() == lastchr: and lastchr.isalnum() and lastchr.lower() == lastchr:
result += '_' result += '_'
result += chr.lower() result += chr.lower()
lastchr = chr lastchr = chr
if isclassname and not version is None:
result += '_%d' % version
if isclassname: if isclassname:
result += '_t' result += '_t'
@ -259,7 +278,10 @@ def format_translation_changes(old, new):
return result 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 """ Return the necessary list of includes based on the contents of the
body. body.
""" """
@ -269,47 +291,187 @@ def format_translation_includes(header, body):
if body.find('std::min') > 0 or body.find('std::max') > 0: if body.find('std::min') > 0 or body.find('std::max') > 0:
result += '#include <algorithm>\n' result += '#include <algorithm>\n'
if body.find('cef_api_hash(') > 0: paths = set()
result += '#include "include/cef_api_hash.h"\n'
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: 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 search = ((True, True, r'([A-Za-z0-9_]{1,})_[0-9]{1,}_CppToC'),
p = re.compile(r'([A-Za-z0-9_]{1,})CppToC') (True, False, r'([A-Za-z0-9_]{1,})CppToC'),
list = sorted(set(p.findall(body))) (False, True, r'([A-Za-z0-9_]{1,})_[0-9]{1,}_CToCpp'),
for item in list: (False, False, r'([A-Za-z0-9_]{1,})CToCpp'))
directory = '' for cpptoc, versioned, regex in search:
if not is_base_class(item): # identify what classes are being used
cls = header.get_class(item) p = re.compile(regex)
dir = cls.get_file_directory() items = set(p.findall(body))
if not dir is None: for item in items:
directory = dir + '/' if item == 'Cef':
result += '#include "libcef_dll/cpptoc/'+directory+ \ continue
get_capi_name(item[3:], False)+'_cpptoc.h"\n' if not versioned and item[-1] == '_':
# skip versioned names that are picked up by the unversioned regex
# identify what CToCpp classes are being used continue
p = re.compile(r'([A-Za-z0-9_]{1,})CToCpp') directory = ''
list = sorted(set(p.findall(body))) if not is_base_class(item):
for item in list: cls = header.get_class(item)
directory = '' if cls is None:
if not is_base_class(item): raise Exception('Class does not exist: ' + item)
cls = header.get_class(item) dir = cls.get_file_directory()
dir = cls.get_file_directory() if not dir is None:
if not dir is None: directory = dir + '/'
directory = dir + '/' type = 'cpptoc' if cpptoc else 'ctocpp'
result += '#include "libcef_dll/ctocpp/'+directory+ \ paths.add('libcef_dll/' + type + '/'+directory+ \
get_capi_name(item[3:], False)+'_ctocpp.h"\n' get_capi_name(item[3:], False)+'_' + type + '.h')
if body.find('shutdown_checker') > 0: 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: 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 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): def str_to_dict(str):
""" Convert a string to a dictionary. If the same key has multiple values """ Convert a string to a dictionary. If the same key has multiple values
the values will be stored in a list. """ the values will be stored in a list. """
@ -357,6 +519,13 @@ def dict_to_str(dict):
return ','.join(str) 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 # regex for matching comment-formatted attributes
_cre_attrib = r'/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/' _cre_attrib = r'/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/'
# regex for matching class and function names # regex for matching class and function names
@ -747,13 +916,18 @@ class obj_header:
res.append(cls) res.append(cls)
return res return res
def get_class(self, classname, defined_structs=None): def get_class(self, classname):
""" Return the specified class or None if not found. """ """ Return the specified class or None if not found. """
for cls in self.classes: for cls in self.classes:
if cls.get_name() == classname: if cls.get_name() == classname:
return cls return cls
elif not defined_structs is None: return None
defined_structs.append(cls.get_capi_name())
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 return None
def get_class_names(self): def get_class_names(self):
@ -856,6 +1030,8 @@ class obj_class:
self.includes = includes self.includes = includes
self.forward_declares = forward_declares self.forward_declares = forward_declares
self._validate_attribs()
# extract typedefs # extract typedefs
p = re.compile( p = re.compile(
r'\n' + _cre_space + r'typedef' + _cre_space + _cre_typedef + r';', r'\n' + _cre_space + r'typedef' + _cre_space + _cre_typedef + r';',
@ -895,13 +1071,19 @@ class obj_class:
# build the virtual function objects # build the virtual function objects
self.virtualfuncs = [] self.virtualfuncs = []
self.has_versioned_funcs = False
for attrib, retval, argval, vfmod in list: for attrib, retval, argval, vfmod in list:
comment = get_comment(body, retval + '(' + argval + ')') comment = get_comment(body, retval + '(' + argval + ')')
validate_comment(filename, retval, comment) validate_comment(filename, retval, comment)
if not self.has_versioned_funcs and _has_version(attrib):
self.has_versioned_funcs = True
self.virtualfuncs.append( self.virtualfuncs.append(
obj_function_virtual(self, attrib, retval, argval, comment, obj_function_virtual(self, attrib, retval, argval, comment,
vfmod.strip())) vfmod.strip()))
self.virtualfuncs_ordered = None
self.allversions = None
def __repr__(self): def __repr__(self):
result = '/* ' + dict_to_str( result = '/* ' + dict_to_str(
self.attribs) + ' */ class ' + self.name + "\n{" self.attribs) + ' */ class ' + self.name + "\n{"
@ -930,15 +1112,21 @@ class obj_class:
result += "\n};\n" result += "\n};\n"
return result 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): def get_file_name(self):
""" Return the C++ header file name. Includes the directory component, """ Return the C++ header file name. Includes the directory component,
if any. """ if any. """
return self.filename 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, """ Return the CAPI header file name. Includes the directory component,
if any. """ if any. """
return get_capi_file_name(self.filename) return get_capi_file_name(self.filename, versions)
def get_file_directory(self): def get_file_directory(self):
""" Return the file directory component, if any. """ """ Return the file directory component, if any. """
@ -947,21 +1135,44 @@ class obj_class:
return self.filename[:pos] return self.filename[:pos]
return None return None
def get_name(self): def get_name(self, version=None):
""" Return the class name. """ """ 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 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 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): def get_parent_name(self):
""" Return the parent class name. """ """ Return the parent class name. """
return self.parent_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 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): def has_parent(self, parent_name):
""" Returns true if this class has the specified class anywhere in its """ 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 the array of static function objects. """
return self.staticfuncs 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. """ """ 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 return self.virtualfuncs
def get_types(self, list): def get_types(self, list):
@ -1078,6 +1298,75 @@ class obj_class:
""" Returns true if the class is implemented by the client. """ """ Returns true if the class is implemented by the client. """
return self.attribs['source'] == '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 obj_typedef:
""" Class representing a typedef statement. """ """ Class representing a typedef statement. """
@ -1099,9 +1388,9 @@ class obj_typedef:
""" Return the C++ header file name. """ """ Return the C++ header file name. """
return self.filename return self.filename
def get_capi_file_name(self): def get_capi_file_name(self, versions=False):
""" Return the CAPI header file name. """ """ 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): def get_alias(self):
""" Return the alias. """ """ Return the alias. """
@ -1131,6 +1420,8 @@ class obj_function:
self.name = self.retval.remove_name() self.name = self.retval.remove_name()
self.comment = comment self.comment = comment
self._validate_attribs()
# build the argument objects # build the argument objects
self.arguments = [] self.arguments = []
arglist = argval.split(',') arglist = argval.split(',')
@ -1163,13 +1454,19 @@ class obj_function:
def __repr__(self): def __repr__(self):
return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto() 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): def get_file_name(self):
""" Return the C++ header file name. """ """ Return the C++ header file name. """
return self.filename return self.filename
def get_capi_file_name(self): def get_capi_file_name(self, versions=False):
""" Return the CAPI header file name. """ """ 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): def get_name(self):
""" Return the function name. """ """ Return the function name. """
@ -1186,9 +1483,7 @@ class obj_function:
def get_capi_name(self, prefix=None): def get_capi_name(self, prefix=None):
""" Return the CAPI function name. """ """ Return the CAPI function name. """
if 'capi_name' in self.attribs: return get_capi_name(self.get_attrib('capi_name', self.name), False, prefix)
return self.attribs['capi_name']
return get_capi_name(self.name, False, prefix)
def get_comment(self): def get_comment(self):
""" Return the function comment as an array of lines. """ """ Return the function comment as an array of lines. """
@ -1202,7 +1497,7 @@ class obj_function:
""" Return true if the specified attribute exists. """ """ Return true if the specified attribute exists. """
return name in self.attribs 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. """ """ Return the first or only value for specified attribute. """
if name in self.attribs: if name in self.attribs:
if isinstance(self.attribs[name], list): if isinstance(self.attribs[name], list):
@ -1211,7 +1506,7 @@ class obj_function:
else: else:
# the value is a string # the value is a string
return self.attribs[name] return self.attribs[name]
return None return default
def get_attrib_list(self, name): def get_attrib_list(self, name):
""" Return all values for specified attribute as a list. """ """ Return all values for specified attribute as a list. """
@ -1237,10 +1532,15 @@ class obj_function:
for cls in self.arguments: for cls in self.arguments:
cls.get_types(list) 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. """ """ Return the parts of the C API function definition. """
retval = '' 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': if dict['format'] == 'single':
retval = dict['value'] retval = dict['value']
@ -1249,7 +1549,7 @@ class obj_function:
if isinstance(self, obj_function_virtual): if isinstance(self, obj_function_virtual):
# virtual functions get themselves as the first argument # 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(): if isinstance(self, obj_function_virtual) and self.is_const():
# const virtual functions get const self pointers # const virtual functions get const self pointers
str = 'const ' + str str = 'const ' + str
@ -1260,7 +1560,7 @@ class obj_function:
if len(self.arguments) > 0: if len(self.arguments) > 0:
for cls in self.arguments: for cls in self.arguments:
type = cls.get_type() type = cls.get_type()
dict = type.get_capi(defined_structs) dict = type.get_capi(defined_structs, version_finder)
if dict['format'] == 'single': if dict['format'] == 'single':
args.append(dict['value']) args.append(dict['value'])
elif dict['format'] == 'multi-arg': elif dict['format'] == 'multi-arg':
@ -1276,9 +1576,15 @@ class obj_function:
return {'retval': retval, 'name': name, 'args': args} 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. """ """ 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']+ \ result = parts['retval']+' '+parts['name']+ \
'('+', '.join(parts['args'])+')' '('+', '.join(parts['args'])+')'
return result return result
@ -1336,6 +1642,14 @@ class obj_function:
return other_is_library_side == this_is_library_side 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 obj_function_static(obj_function):
""" Class representing a static function. """ """ Class representing a static function. """
@ -1377,6 +1691,34 @@ class obj_function_virtual(obj_function):
""" Returns true if the method declaration is const. """ """ Returns true if the method declaration is const. """
return self.isconst 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 obj_argument:
""" Class representing a function argument. """ """ Class representing a function argument. """
@ -1907,12 +2249,15 @@ class obj_analysis:
""" Return the *Ptr type structure name. """ """ Return the *Ptr type structure name. """
return self.result_value[:-1] 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. """ """ Return the *Ptr type. """
result = '' 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 += 'struct _'
result += self.result_value result += name + self.result_value[-1]
if self.is_byref() or self.is_byaddr(): if self.is_byref() or self.is_byaddr():
result += '*' result += '*'
return result return result
@ -1951,16 +2296,22 @@ class obj_analysis:
return True return True
return False 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. """ """ Return the structure or enumeration type. """
result = '' result = ''
name = self.result_value
is_enum = self.is_result_struct_enum() is_enum = self.is_result_struct_enum()
if not is_enum: if not is_enum:
if self.is_const(): if self.is_const():
result += 'const ' result += 'const '
if not self.result_value in defined_structs: if not self.result_value in defined_structs:
result += 'struct _' result += 'struct _'
result += self.result_value if not version_finder is None:
name = version_finder(name)
result += name
if not is_enum: if not is_enum:
result += '*' result += '*'
return result return result
@ -2026,7 +2377,7 @@ class obj_analysis:
""" Return the vector structure or basic type name. """ """ Return the vector structure or basic type name. """
return self.result_value[0]['result_value'] 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. """ """ Return the vector type. """
if not self.has_name(): if not self.has_name():
raise Exception('Cannot use vector as a return type') raise Exception('Cannot use vector as a return type')
@ -2048,9 +2399,15 @@ class obj_analysis:
result['value'] = str result['value'] = str
elif type == 'refptr' or type == 'ownptr' or type == 'rawptr': elif type == 'refptr' or type == 'ownptr' or type == 'rawptr':
str = '' 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 += 'struct _'
str += value str += name + value[-1]
if self.is_const(): if self.is_const():
str += ' const' str += ' const'
str += '*' str += '*'
@ -2087,16 +2444,16 @@ class obj_analysis:
return {'value': 'cef_string_multimap_t', 'format': 'multi'} return {'value': 'cef_string_multimap_t', 'format': 'multi'}
raise Exception('Only mappings of strings to strings are supported') 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. """ """ Format the value for the C API. """
result = '' result = ''
format = 'single' format = 'single'
if self.is_result_simple(): if self.is_result_simple():
result += self.get_result_simple_type() result += self.get_result_simple_type()
elif self.is_result_ptr(): 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(): 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(): elif self.is_result_string():
result += self.get_result_string_type() result += self.get_result_string_type()
elif self.is_result_map(): elif self.is_result_map():
@ -2106,7 +2463,7 @@ class obj_analysis:
else: else:
raise Exception('Unsupported map type') raise Exception('Unsupported map type')
elif self.is_result_vector(): 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': if resdict['format'] != 'single':
format = resdict['format'] format = resdict['format']
result += resdict['value'] result += resdict['value']

View File

@ -7,6 +7,7 @@ from __future__ import print_function
from file_util import * from file_util import *
import git_util as git import git_util as git
import os import os
from version_util import read_version_last, version_parse, VERSIONS_JSON_FILE
class VersionFormatter: class VersionFormatter:
@ -46,15 +47,18 @@ class VersionFormatter:
if not bool(self._chrome_version): if not bool(self._chrome_version):
file_path = os.path.join(self.src_path, 'chrome', 'VERSION') file_path = os.path.join(self.src_path, 'chrome', 'VERSION')
assert os.path.isfile(file_path), file_path 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 return self._chrome_version
def get_chrome_major_version(self):
return self.get_chrome_version_components()['MAJOR']
def get_cef_version_components(self): def get_cef_version_components(self):
""" Returns CEF version components. """ """ Returns CEF version components. """
if not bool(self._cef_version): if not bool(self._cef_version):
file_path = os.path.join(self.cef_path, 'VERSION.in') file_path = os.path.join(self.cef_path, 'VERSION.in')
assert os.path.isfile(file_path), file_path 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 return self._cef_version
def get_cef_commit_components(self): def get_cef_commit_components(self):
@ -75,11 +79,11 @@ class VersionFormatter:
# branch since branching from origin/master. # branch since branching from origin/master.
hashes = git.get_branch_hashes(self.cef_path) hashes = git.get_branch_hashes(self.cef_path)
for hash in hashes: 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 found = False
files = git.get_changed_files(self.cef_path, hash) files = git.get_changed_files(self.cef_path, hash)
for file in files: for file in files:
if file.find('cef_api_hash.h') >= 0: if file.find(VERSIONS_JSON_FILE) >= 0:
found = True found = True
break break
@ -89,6 +93,14 @@ class VersionFormatter:
else: else:
bugfix += 1 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} self._branch_version = {'MINOR': minor, 'PATCH': bugfix}
return self._branch_version return self._branch_version
@ -149,8 +161,8 @@ class VersionFormatter:
# - "X" is the Chromium major version (e.g. 74). # - "X" is the Chromium major version (e.g. 74).
# - "Y" is an incremental number that starts at 0 when a release branch is # - "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 # 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 # the CEF_API_HASH_UNIVERSAL value behaves in cef_api_hash.h) (release
# only). # branch only).
# - "Z" is an incremental number that starts at 0 when a release branch is # - "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 # created and changes on each commit, with reset to 0 when "Y" changes
# (release branch only). # (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"). # 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_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_parts = {'MAJOR': int(chrome_major), 'MINOR': 0, 'PATCH': 0}
self._version_string = '%s.0.0-%s.%s+%s+%s' % \ self._version_string = '%s.%d.%d-%s.%s+%s+%s' % \
(chrome_major, cef_branch_name, cef_commit['NUMBER'], (chrome_major, cef_minor, cef_patch, cef_branch_name, cef_commit['NUMBER'],
cef_commit_hash, chrome_version_part) cef_commit_hash, chrome_version_part)
else: else:
cef_branch = self.get_cef_branch_version_components() cef_branch = self.get_cef_branch_version_components()

View File

@ -10,22 +10,66 @@ import sys
# Script directory. # Script directory.
script_dir = os.path.dirname(__file__) 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': if sys.platform == 'win32':
# Force use of the clang-format version bundled with depot_tools. # Force use of the clang-format version bundled with depot_tools.
clang_format_exe = 'clang-format.bat' clang_format_exe = 'clang-format.bat'
clang_exe = os.path.join(llvm_bin_dir, 'clang-cl.exe')
else: else:
clang_format_exe = 'clang-format' clang_format_exe = 'clang-format'
clang_exe = os.path.join(llvm_bin_dir, 'clang')
def clang_format(file_name, file_contents): def clang_format(file_name, file_contents):
# -assume-filename is necessary to find the .clang-format file and determine # -assume-filename is necessary to find the .clang-format file and determine
# the language when specifying contents via stdin. # the language when specifying contents via stdin.
result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name), \ result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name), \
root_dir, file_contents.encode('utf-8')) cef_dir, file_contents.encode('utf-8'))
if result['err'] != '': 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'] != '': if result['out'] != '':
output = result['out'] output = result['out']
if sys.platform == 'win32': if sys.platform == 'win32':

View File

@ -3,35 +3,45 @@
# can be found in the LICENSE file. # can be found in the LICENSE file.
from __future__ import absolute_import from __future__ import absolute_import
import codecs
import fnmatch
from glob import iglob from glob import iglob
from io import open from io import open
import json
import os import os
import fnmatch
import shutil import shutil
import sys import sys
import time import time
def read_file(name, normalize=True): def read_file(path, normalize=True):
""" Read a file. """ """ Read a file. """
try: if os.path.isfile(path):
with open(name, 'r', encoding='utf-8') as f: try:
# read the data with open(path, 'r', encoding='utf-8') as f:
data = f.read() # read the data
if normalize: data = f.read()
# normalize line endings if normalize:
data = data.replace("\r\n", "\n") # normalize line endings
return data data = data.replace("\r\n", "\n")
except IOError as e: return data
(errno, strerror) = e.args except IOError as e:
sys.stderr.write('Failed to read file ' + name + ': ' + strerror) (errno, strerror) = e.args
raise 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. """ """ Write a file. """
if not overwrite and os.path.exists(path):
return False
if not quiet:
print('Writing file %s' % path)
try: 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 # write the data
if sys.version_info.major == 2: if sys.version_info.major == 2:
f.write(data.decode('utf-8')) f.write(data.decode('utf-8'))
@ -39,57 +49,67 @@ def write_file(name, data):
f.write(data) f.write(data)
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to write file ' + name + ': ' + strerror) sys.stderr.write('ERROR: Failed to write file ' + path + ': ' + strerror)
raise raise
return True
def path_exists(name): def path_exists(path):
""" Returns true if the path currently exists. """ """ 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. """ """ Write a file if the contents have changed. Returns True if the file was written. """
if path_exists(name): if path_exists(path):
old_contents = read_file(name) old_contents = read_file(path)
assert not old_contents is None, path
else: else:
old_contents = '' old_contents = ''
if (data != old_contents): if (data != old_contents):
write_file(name, data) write_file(path, data, quiet=quiet)
return True return True
return False return False
def backup_file(name): def backup_file(path):
""" Rename the file to a name that includes the current time stamp. """ """ 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): def copy_file(src, dst, quiet=True):
""" Copy a file. """ """ Copy a file. """
if not os.path.isfile(src):
return False
try: try:
shutil.copy2(src, dst)
if not quiet: if not quiet:
sys.stdout.write('Transferring ' + src + ' file.\n') sys.stdout.write('Transferring ' + src + ' file.\n')
shutil.copy2(src, dst)
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to copy file from ' + src + ' to ' + dst + ': ' + sys.stderr.write('ERROR: Failed to copy file from ' + src + ' to ' + dst +
strerror) ': ' + strerror)
raise raise
return True
def move_file(src, dst, quiet=True): def move_file(src, dst, quiet=True):
""" Move a file. """ """ Move a file. """
if not os.path.isfile(src):
return False
try: try:
shutil.move(src, dst)
if not quiet: if not quiet:
sys.stdout.write('Moving ' + src + ' file.\n') print('Moving ' + src + ' file.')
shutil.move(src, dst)
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to move file from ' + src + ' to ' + dst + ': ' + sys.stderr.write('ERROR: Failed to move file from ' + src + ' to ' + dst +
strerror) ': ' + strerror)
raise raise
return True
def copy_files(src_glob, dst_folder, quiet=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) copy_file(fname, dst, quiet)
def remove_file(name, quiet=True): def remove_file(path, quiet=True):
""" Remove the specified file. """ """ Remove the specified file. """
try: try:
if path_exists(name): if path_exists(path):
os.remove(name)
if not quiet: if not quiet:
sys.stdout.write('Removing ' + name + ' file.\n') print('Removing ' + path + ' file.')
os.remove(path)
return True
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to remove file ' + name + ': ' + strerror) sys.stderr.write('ERROR: Failed to remove file ' + path + ': ' + strerror)
raise raise
return False
def copy_dir(src, dst, quiet=True): def copy_dir(src, dst, quiet=True):
""" Copy a directory tree. """ """ Copy a directory tree. """
try: try:
remove_dir(dst, quiet) remove_dir(dst, quiet)
shutil.copytree(src, dst)
if not quiet: if not quiet:
sys.stdout.write('Transferring ' + src + ' directory.\n') print('Transferring ' + src + ' directory.')
shutil.copytree(src, dst)
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to copy directory from ' + src + ' to ' + dst + sys.stderr.write('ERROR: Failed to copy directory from ' + src + ' to ' +
': ' + strerror) dst + ': ' + strerror)
raise raise
def remove_dir(name, quiet=True): def remove_dir(path, quiet=True):
""" Remove the specified directory. """ """ Remove the specified directory. """
try: try:
if path_exists(name): if path_exists(path):
shutil.rmtree(name)
if not quiet: if not quiet:
sys.stdout.write('Removing ' + name + ' directory.\n') print('Removing ' + path + ' directory.')
shutil.rmtree(path)
return True
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to remove directory ' + name + ': ' + strerror) sys.stderr.write('ERROR: Failed to remove directory ' + path + ': ' +
strerror)
raise raise
return False
def make_dir(name, quiet=True): def make_dir(path, quiet=True):
""" Create the specified directory. """ """ Create the specified directory. """
try: try:
if not path_exists(name): if not path_exists(path):
if not quiet: if not quiet:
sys.stdout.write('Creating ' + name + ' directory.\n') print('Creating ' + path + ' directory.')
os.makedirs(name) os.makedirs(path)
except IOError as e: except IOError as e:
(errno, strerror) = e.args (errno, strerror) = e.args
sys.stderr.write('Failed to create directory ' + name + ': ' + strerror) sys.stderr.write('ERROR: Failed to create directory ' + path + ': ' +
strerror)
raise raise
@ -180,13 +206,17 @@ def get_files_recursive(directory, pattern):
yield filename 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). """ """ 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: for line in lines:
parts = line.split('=', 1) parts = line.split('=', 1)
if len(parts) == 2: if len(parts) == 2:
args[parts[0]] = parts[1] args[parts[0]] = parts[1]
return True
def eval_file(src): def eval_file(src):
@ -199,3 +229,48 @@ def normalize_path(path):
if sys.platform == 'win32': if sys.platform == 'win32':
return path.replace('\\', '/') return path.replace('\\', '/')
return path 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') print('Unknown operating system platform')
sys.exit() sys.exit()
print("\nGenerating CEF version header file...") print("\nGenerating CEF translated files...")
cmd = [sys.executable, 'tools/make_version_header.py', 'include/cef_version.h'] cmd = [sys.executable, 'tools/version_manager.py', '-u', '--fast-check']
RunAction(cef_dir, cmd) RunAction(cef_dir, cmd)
print("\nPatching build configuration and source files for CEF...") 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 return result['ret'] == 0
def get_hash(path='.', branch='HEAD'): def exec_git_cmd(args, path='.'):
""" Returns the git hash for the specified branch/tag/hash. """ """ Executes a git command with the specified |args|. """
cmd = "%s rev-parse %s" % (git_exe, branch) cmd = "%s %s" % (git_exe, args)
result = exec_cmd(cmd, path) result = exec_cmd(cmd, path)
if result['out'] != '': if result['out'] != '':
return result['out'].strip() out = result['out'].strip()
return 'Unknown' 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'): def get_branch_name(path='.', branch='HEAD'):
""" Returns the branch name for the specified branch/tag/hash. """ """ Returns the branch name for the specified branch/tag/hash. """
# Returns the branch name if not in detached HEAD state, else an empty string # Returns the branch name if not in detached HEAD state, else an empty string
# or "HEAD". # or "HEAD".
cmd = "%s rev-parse --abbrev-ref %s" % (git_exe, branch) cmd = "rev-parse --abbrev-ref %s" % branch
result = exec_cmd(cmd, path) result = exec_git_cmd(cmd, path)
if result['out'] != '': if result is None:
name = result['out'].strip() return 'Unknown'
if len(name) > 0 and name != 'HEAD': if result != 'HEAD':
return name return result
# Returns a value like "(HEAD, origin/3729, 3729)". # Returns a value like "(HEAD, origin/3729, 3729)".
# Ubuntu 14.04 uses Git version 1.9.1 which does not support %D (which # Ubuntu 14.04 uses Git version 1.9.1 which does not support %D (which
# provides the same output but without the parentheses). # provides the same output but without the parentheses).
cmd = "%s log -n 1 --pretty=%%d %s" % (git_exe, branch) cmd = "log -n 1 --pretty=%%d %s" % branch
result = exec_cmd(cmd, path) result = exec_git_cmd(cmd, path)
if result['out'] != '': return 'Unknown' if result is None else result[1:-1].split(', ')[-1]
return result['out'].strip()[1:-1].split(', ')[-1]
return 'Unknown'
def get_url(path='.'): def get_url(path='.'):
""" Returns the origin url for the specified path. """ """ Returns the origin url for the specified path. """
cmd = "%s config --get remote.origin.url" % git_exe cmd = "config --get remote.origin.url"
result = exec_cmd(cmd, path) result = exec_git_cmd(cmd, path)
if result['out'] != '': return 'Unknown' if result is None else result
return result['out'].strip()
return 'Unknown'
def get_commit_number(path='.', branch='HEAD'): def get_commit_number(path='.', branch='HEAD'):
""" Returns the number of commits in the specified branch/tag/hash. """ """ Returns the number of commits in the specified branch/tag/hash. """
cmd = "%s rev-list --count %s" % (git_exe, branch) cmd = "rev-list --count %s" % (branch)
result = exec_cmd(cmd, path) result = exec_git_cmd(cmd, path)
if result['out'] != '': return '0' if result is None else result
return result['out'].strip()
return '0'
def get_changed_files(path, hash): def get_changed_files(path, hash):
""" Retrieves the list of changed files. """ """ Retrieves the list of changed files. """
if hash == 'unstaged': if hash == 'unstaged':
cmd = "%s diff --name-only" % git_exe cmd = "diff --name-only"
elif hash == 'staged': elif hash == 'staged':
cmd = "%s diff --name-only --cached" % git_exe cmd = "diff --name-only --cached"
else: else:
cmd = "%s diff-tree --no-commit-id --name-only -r %s" % (git_exe, hash) cmd = "diff-tree --no-commit-id --name-only -r %s" % hash
result = exec_cmd(cmd, path) result = exec_git_cmd(cmd, path)
if result['out'] != '': return [] if result is None else result.split("\n")
files = result['out']
if sys.platform == 'win32':
# Convert to Unix line endings.
files = files.replace('\r\n', '\n')
return files.strip().split("\n")
return []
def get_branch_hashes(path='.', branch='HEAD', ref='origin/master'): def get_branch_hashes(path='.', branch='HEAD', ref='origin/master'):
""" Returns an ordered list of hashes for commits that have been applied since """ Returns an ordered list of hashes for commits that have been applied since
branching from ref. """ branching from ref. """
cmd = "%s cherry %s %s" % (git_exe, ref, branch) cmd = "cherry %s %s" % (ref, branch)
result = exec_cmd(cmd, path) result = exec_git_cmd(cmd, path)
if result['out'] != '': if result is None:
hashes = result['out'] return []
if sys.platform == 'win32': # Remove the "+ " or "- " prefix.
# Convert to Unix line endings. return [line[2:] for line in result.split('\n')]
hashes = hashes.replace('\r\n', '\n')
# Remove the "+ " or "- " prefix.
return [line[2:] for line in hashes.strip().split('\n')]
return []
def write_indented_output(output): def write_indented_output(output):

View File

@ -87,9 +87,12 @@ else:
print('Unknown operating system platform') print('Unknown operating system platform')
sys.exit() sys.exit()
_QUIET = False
def msg(msg): def msg(msg):
print('NOTE: ' + msg) if not _QUIET:
print('NOTE: ' + msg)
def NameValueListToDict(name_value_list): def NameValueListToDict(name_value_list):
@ -591,12 +594,16 @@ def LinuxSysrootExists(cpu):
return os.path.isdir(os.path.join(sysroot_root, sysroot_name)) 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. Return a map of directory name to GN args for the current platform.
""" """
result = {} result = {}
if quiet:
global _QUIET
_QUIET = True
# Merged args without validation. # Merged args without validation.
args = GetMergedArgs(build_args) 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): def make_capi_global_funcs(funcs, defined_names, translate_map, indent):
result = '' result = ''
first = True
for func in funcs: for func in funcs:
comment = func.get_comment() comment = func.get_comment()
if first or len(comment) > 0: pre, post = get_version_surround(func)
result += '\n' + format_comment(comment, indent, translate_map) result += '\n' + pre
if len(comment) > 0:
result += format_comment(comment, indent, translate_map)
if func.get_retval().get_type().is_result_string(): 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 + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
result += indent + 'CEF_EXPORT ' + func.get_capi_proto(defined_names) + ';\n' result += indent + 'CEF_EXPORT ' + func.get_capi_proto(
if first: defined_names) + ';\n' + post
first = False
return result return result
def make_capi_member_funcs(funcs, defined_names, translate_map, indent): def make_capi_member_funcs(funcs, defined_names, translate_map, indent):
result = '' result = ''
first = True
for func in funcs: for func in funcs:
comment = func.get_comment() comment = func.get_comment()
if first or len(comment) > 0: pre, post = get_version_surround(func)
result += '\n' + format_comment(comment, indent, translate_map) result += '\n' + pre
if len(comment) > 0:
result += format_comment(comment, indent, translate_map)
if func.get_retval().get_type().is_result_string(): 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 + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
parts = func.get_capi_parts() parts = func.get_capi_parts()
result += indent+parts['retval']+' (CEF_CALLBACK *'+parts['name']+ \ result += indent + parts['retval'] + ' (CEF_CALLBACK *' + parts['name'] + \
')('+', '.join(parts['args'])+');\n' ')(' + ', '.join(parts['args']) + ');\n'
if first: if len(post) > 0 and func.has_version_removed():
first = False 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 return result
@ -61,13 +69,16 @@ def make_capi_header(header, filename):
#define $GUARD$ #define $GUARD$
#pragma once #pragma once
#if defined(BUILDING_CEF_SHARED)
#error This file cannot be included DLL-side
#endif
""" """
# Protect against incorrect use of test headers. # Protect against incorrect use of test headers.
if filename.startswith('test/'): if filename.startswith('test/'):
result += \ result += \
"""#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \\ """#if !defined(WRAPPING_CEF_SHARED) && !defined(UNIT_TEST)
!defined(UNIT_TEST)
#error This file can be included for unit tests only #error This file can be included for unit tests only
#endif #endif
@ -78,7 +89,7 @@ def make_capi_header(header, filename):
# identify all includes and forward declarations # identify all includes and forward declarations
translated_includes = set([]) translated_includes = set([])
internal_includes = set([]) internal_includes = set([])
all_declares = set([]) all_declares = {}
for cls in classes: for cls in classes:
includes = cls.get_includes() includes = cls.get_includes()
for include in includes: for include in includes:
@ -87,7 +98,7 @@ def make_capi_header(header, filename):
# translated CEF API headers. # translated CEF API headers.
raise Exception('Disallowed include of %s.h from %s' % (include, raise Exception('Disallowed include of %s.h from %s' % (include,
filename)) 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/ headers may be C or C++. Include them as-is.
internal_includes.add(include) internal_includes.add(include)
else: else:
@ -97,7 +108,10 @@ def make_capi_header(header, filename):
declare_cls = header.get_class(declare) declare_cls = header.get_class(declare)
if declare_cls is None: if declare_cls is None:
raise Exception('Unknown class: %s' % declare) 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 # output translated includes
if len(translated_includes) > 0: if len(translated_includes) > 0:
@ -122,22 +136,39 @@ extern "C" {
""" """
# output forward declarations # output forward declarations
if len(all_declares) > 0: if bool(all_declares):
sorted_declares = sorted(all_declares) sorted_declares = sorted(all_declares.keys())
for declare in sorted_declares: 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' result += 'struct _' + declare + ';\n'
if not cls_version_check is None:
result += '#endif\n'
# output classes # output classes
for cls in 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 # virtual functions are inside the structure
classname = cls.get_capi_name() 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'+\ result += 'typedef struct _'+classname+' {\n'+\
' ///\n'+\ ' ///\n'+\
' /// Base structure.\n'+\ ' /// Base structure.\n'+\
' ///\n'+\ ' ///\n'+\
' '+cls.get_parent_capi_name()+' base;\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 += make_capi_member_funcs(funcs, defined_names, translate_map, ' ')
result += '} ' + classname + ';\n\n' result += '} ' + classname + ';\n\n'
@ -149,6 +180,8 @@ extern "C" {
result += make_capi_global_funcs(funcs, defined_names, translate_map, result += make_capi_global_funcs(funcs, defined_names, translate_map,
'') + '\n' '') + '\n'
result += post
# output global functions # output global functions
funcs = header.get_funcs(filename) funcs = header.get_funcs(filename)
if len(funcs) > 0: 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 += get_capi_name(clsname[3:], False)
defname = defname.upper() defname = defname.upper()
capiname = cls.get_capi_name()
result = get_copyright() result = get_copyright()
result += '#ifndef CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_\n'+ \ result += '#ifndef CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_\n'+ \
@ -41,9 +39,11 @@ def make_cpptoc_header(header, clsname):
#endif #endif
""" """
with_versions = dllside
# include the headers for this class # include the headers for this class
result += '\n#include "include/'+cls.get_file_name()+'"\n' \ 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 # include headers for any forward declared classes that are not in the same file
declares = cls.get_forward_declares() declares = cls.get_forward_declares()
@ -51,7 +51,7 @@ def make_cpptoc_header(header, clsname):
dcls = header.get_class(declare) dcls = header.get_class(declare)
if dcls.get_file_name() != cls.get_file_name(): if dcls.get_file_name() != cls.get_file_name():
result += '#include "include/'+dcls.get_file_name()+'"\n' \ 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_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False base_scoped = True if base_class_name == 'CefBaseScoped' else False
@ -63,19 +63,78 @@ def make_cpptoc_header(header, clsname):
template_class = 'CefCppToCRefCounted' template_class = 'CefCppToCRefCounted'
result += '#include "libcef_dll/cpptoc/' + template_file + '"' result += '#include "libcef_dll/cpptoc/' + template_file + '"'
result += '\n\n// Wrap a C++ class with a C structure.\n'
if dllside: if with_versions:
result += '// This class may be instantiated and accessed DLL-side only.\n' pre = post = ''
else: else:
result += '// This class may be instantiated and accessed wrapper-side only.\n' pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += '\n\n' + pre.strip()
result += 'class '+clsname+'CppToC\n'+ \ result += '\n\n'
' : public ' + template_class + '<'+clsname+'CppToC, '+clsname+', '+capiname+'> {\n'+ \
' public:\n'+ \ versions = cls.get_all_versions() if with_versions else (None,)
' '+clsname+'CppToC();\n'+ \
' virtual ~'+clsname+'CppToC();\n'+ \ for version in versions:
'};\n\n' 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'
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'+ \
' '+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_' result += '#endif // CEF_LIBCEF_DLL_CPPTOC_' + defname + '_CPPTOC_H_'

View File

@ -4,6 +4,8 @@
from __future__ import absolute_import from __future__ import absolute_import
from cef_parser import * from cef_parser import *
import copy
import functools
def make_cpptoc_impl_proto(name, func, parts): def make_cpptoc_impl_proto(name, func, parts):
@ -16,27 +18,37 @@ def make_cpptoc_impl_proto(name, func, parts):
return proto 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') notify(name + ' has manual edits')
# retrieve the C API prototype parts # 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) changes = format_translation_changes(impl, parts)
if len(changes) > 0: if len(changes) > 0:
notify(name + ' prototype changed') notify(name + ' prototype changed')
return make_cpptoc_impl_proto( return make_cpptoc_impl_proto(name, func,
name, func, parts) + '{' + changes + impl['body'] + '\n}\n\n' 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. # Special handling for the cef_shutdown global function.
is_cef_shutdown = name == 'cef_shutdown' and isinstance( is_cef_shutdown = name == 'cef_shutdown' and isinstance(
func.parent, obj_header) func.parent, obj_header)
# retrieve the C API prototype parts # 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) + ' {' result = make_cpptoc_impl_proto(name, func, parts) + ' {'
if isinstance(func.parent, obj_class) and \ 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': elif arg_type == 'refptr_same' or arg_type == 'refptr_diff':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_same': if arg_type == 'refptr_same':
params.append(ptr_class + 'CppToC::Unwrap(' + arg_name + ')') params.append(ptr_class + 'CppToC_Unwrap(' + arg_name + ')')
else: 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': elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'ownptr_same': if arg_type == 'ownptr_same':
params.append(ptr_class + 'CppToC::UnwrapOwn(' + arg_name + ')') params.append(ptr_class + 'CppToC_UnwrapOwn(' + arg_name + ')')
else: 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': elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
result += comment+\ 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': if arg_type == 'ownptr_diff':
params.append('std::move(' + arg_name + 'Ptr)') params.append('std::move(' + arg_name + 'Ptr)')
else: else:
params.append(arg_name + 'Ptr.get()') params.append(arg_name + 'Ptr.get()')
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': 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': if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CppToC::Unwrap(*' + arg_name + ')' assign = ptr_class + 'CppToC_Unwrap(*' + arg_name + ')'
else: else:
assign = ptr_class + 'CToCpp::Wrap(*' + arg_name + ')' assign = ptr_class + 'CToCpp_Wrap(*' + arg_name + ')'
result += comment+\ result += comment+\
'\n CefRefPtr<'+ptr_class+'> '+arg_name+'Ptr;'\ '\n CefRefPtr<'+ptr_class_u+'> '+arg_name+'Ptr;'\
'\n if ('+arg_name+' && *'+arg_name+') {'\ '\n if ('+arg_name+' && *'+arg_name+') {'\
'\n '+arg_name+'Ptr = '+assign+';'\ '\n '+arg_name+'Ptr = '+assign+';'\
'\n }'\ '\n }'\
@ -273,10 +285,10 @@ def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
assign = arg_name + '[i]?true:false' assign = arg_name + '[i]?true:false'
elif arg_type == 'refptr_vec_same_byref': elif arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type() 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+\ result += comment+\
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\ '\n std::vector<'+vec_type+' > '+arg_name+'List;'\
'\n if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\ '\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: else:
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_vec_same_byref_const': 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': 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': 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': 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+\ result += comment+\
'\n std::vector<'+vec_type+' > '+arg_name+'List;'\ '\n std::vector<'+vec_type+' > '+arg_name+'List;'\
'\n if ('+arg_name+'Count > 0) {'\ '\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): if isinstance(func.parent, obj_class):
# virtual and static class methods # virtual and static class methods
if isinstance(func, obj_function_virtual): 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(): if cls.get_name() == func.parent.get_name():
# virtual method for the current class # virtual method called for the current class
result += func.parent.get_name() + 'CppToC::Get(self)->' result += ptr_class + 'CppToC::Get(self)->'
else: else:
# virtual method for a parent class # virtual method called for a parent class
result += cls.get_name( result += ptr_class + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name(
) + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->' version) + '*>(self))->'
else: else:
result += func.parent.get_name() + '::' result += func.parent.get_name() + '::'
result += func.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': elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_same_byref': if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'Ptr)' assign = ptr_class + 'CppToC_Wrap(' + arg_name + 'Ptr)'
else: else:
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'Ptr)' assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + 'Ptr)'
result += comment+\ result += comment+\
'\n if ('+arg_name+') {'\ '\n if ('+arg_name+') {'\
'\n if ('+arg_name+'Ptr.get()) {'\ '\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]' assign = arg_name + 'List[i]'
elif arg_type == 'refptr_vec_same_byref': elif arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type() 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+\ result += comment+\
'\n if ('+arg_name+'Count && '+arg_name+') {'\ '\n if ('+arg_name+'Count && '+arg_name+') {'\
'\n *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\ '\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();' result += '\n return _retval.DetachToUserFree();'
elif retval_type == 'refptr_same': elif retval_type == 'refptr_same':
ptr_class = retval.get_type().get_ptr_type() 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': elif retval_type == 'refptr_diff':
ptr_class = retval.get_type().get_ptr_type() 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': elif retval_type == 'ownptr_same':
ptr_class = retval.get_type().get_ptr_type() 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': elif retval_type == 'ownptr_diff':
ptr_class = retval.get_type().get_ptr_type() 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: else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name)) raise Exception('Unsupported return type %s in %s' % (retval_type, name))
if len(result) != result_len: if len(result) != result_len:
result += '\n' result += '\n'
result += '}\n\n' result += '}\n'
return result return result
def make_cpptoc_function_impl(cls, funcs, existing, prefixname, defined_names, def make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
base_scoped): defined_names, base_scoped, version,
version_finder):
impl = '' impl = ''
customized = False
for func in funcs: for func in funcs:
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: if not prefixname is None:
name = prefixname + '_' + func.get_capi_name() name = prefixname + '_' + name
if not suffixname is None:
name += '_' + suffixname
if version is None:
pre, post = get_version_surround(func, long=True)
else: else:
name = func.get_capi_name() pre = post = ''
value = get_next_function_impl(existing, name) value = get_next_function_impl(existing, name)
if not value is None \ if not value is None \
and value['body'].find('// AUTO-GENERATED CONTENT') < 0: and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
# an implementation exists that was not auto-generated # an implementation exists that was not auto-generated
impl += make_cpptoc_function_impl_existing(cls, name, func, value, customized = True
defined_names) impl += pre + make_cpptoc_function_impl_existing(
cls, name, func, value, defined_names, version,
version_finder) + post + '\n'
else: else:
impl += make_cpptoc_function_impl_new(cls, name, func, defined_names, impl += pre + make_cpptoc_function_impl_new(
base_scoped) 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, def make_cpptoc_virtual_function_impl(header, cls, existing, prefixname,
defined_names, base_scoped): suffixname, defined_names, base_scoped,
funcs = [] version, version_finder):
funcs.extend(cls.get_virtual_funcs()) # don't modify the original list
funcs = copy.copy(cls.get_virtual_funcs(version=version))
cur_cls = cls cur_cls = cls
while True: while True:
parent_name = cur_cls.get_parent_name() parent_name = cur_cls.get_parent_name()
if is_base_class(parent_name): if is_base_class(parent_name):
break break
else: else:
parent_cls = header.get_class(parent_name, defined_names) parent_cls = header.get_class(parent_name)
if parent_cls is None: if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name) raise Exception('Class does not exist: ' + parent_name)
funcs.extend(parent_cls.get_virtual_funcs()) defined_names.append(parent_cls.get_capi_name(version))
cur_cls = header.get_class(parent_name, defined_names) 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, return make_cpptoc_function_impl(cls, funcs, existing, prefixname, suffixname,
defined_names, base_scoped) 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 = '' impl = ''
funcs = cls.get_virtual_funcs(version_order=True, version=version)
for func in funcs: for func in funcs:
name = func.get_capi_name() # should only include methods directly declared in the current class
impl += ' GetStruct()->' + offset + name + ' = ' + prefixname + '_' + name + ';\n' 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 return impl
def make_cpptoc_virtual_function_assignment(header, cls, prefixname, def make_cpptoc_virtual_function_assignment(header, cls, prefixname, suffixname,
defined_names): defined_names, version,
impl = make_cpptoc_virtual_function_assignment_block(cls.get_virtual_funcs(), version_finder):
'', prefixname) impl = make_cpptoc_virtual_function_assignment_block(cls, '', prefixname,
suffixname, version)
cur_cls = cls cur_cls = cls
offset = '' offset = ''
@ -535,17 +591,19 @@ def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
if is_base_class(parent_name): if is_base_class(parent_name):
break break
else: else:
parent_cls = header.get_class(parent_name, defined_names) parent_cls = header.get_class(parent_name)
if parent_cls is None: if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name) raise Exception('Class does not exist: ' + parent_name)
defined_names.append(parent_cls.get_capi_name(version))
impl += make_cpptoc_virtual_function_assignment_block( impl += make_cpptoc_virtual_function_assignment_block(
parent_cls.get_virtual_funcs(), offset, prefixname) parent_cls, offset, prefixname, suffixname, version)
cur_cls = header.get_class(parent_name, defined_names) cur_cls = header.get_class(parent_name)
defined_names.append(cur_cls.get_capi_name(version))
return impl 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 # identify all classes that derive from cls
derived_classes = [] derived_classes = []
cur_clsname = cls.get_name() cur_clsname = cls.get_name()
@ -561,39 +619,193 @@ def make_cpptoc_unwrap_derived(header, cls, base_scoped):
if base_scoped: if base_scoped:
impl = ['', ''] impl = ['', '']
for clsname in derived_classes: for clsname in derived_classes:
impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ derived_cls = header.get_class(clsname)
' return '+clsname+'CppToC::UnwrapOwn(reinterpret_cast<'+\ if version is None:
get_capi_name(clsname, True)+'*>(s));\n'+\ capiname = derived_cls.get_capi_name()
' }\n' pre, post = get_version_surround(derived_cls)
impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ else:
' return '+clsname+'CppToC::UnwrapRaw(reinterpret_cast<'+\ if not derived_cls.exists_at_version(version):
get_capi_name(clsname, True)+'*>(s));\n'+\ continue
' }\n' 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: else:
impl = '' impl = ''
for clsname in derived_classes: for clsname in derived_classes:
impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ derived_cls = header.get_class(clsname)
' return '+clsname+'CppToC::Unwrap(reinterpret_cast<'+\ if version is None:
get_capi_name(clsname, True)+'*>(s));\n'+\ capiname = derived_cls.get_capi_name()
' }\n' 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 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): def make_cpptoc_class_impl(header, clsname, impl):
# structure names that have already been defined # structure names that have already been defined
defined_names = header.get_defined_structs() defined_names = header.get_defined_structs()
# retrieve the class and populate the defined names # retrieve the class and populate the defined names
cls = header.get_class(clsname, defined_names) cls = header.get_class(clsname)
if cls is None: if cls is None:
raise Exception('Class does not exist: ' + clsname) raise Exception('Class does not exist: ' + clsname)
capiname = cls.get_capi_name()
prefixname = get_capi_name(clsname[3:], False) 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_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False base_scoped = True if base_class_name == 'CefBaseScoped' else False
if base_scoped: if base_scoped:
@ -601,80 +813,143 @@ def make_cpptoc_class_impl(header, clsname, impl):
else: else:
template_class = 'CefCppToCRefCounted' template_class = 'CefCppToCRefCounted'
# generate virtual functions with_versions = cls.is_library_side()
virtualimpl = make_cpptoc_virtual_function_impl( versions = list(cls.get_all_versions()) if with_versions else (None,)
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())
# retrieve the existing static function implementations # retrieve the existing static function implementations
existing = get_function_impls(impl, 'CEF_EXPORT') existing_static = get_function_impls(impl, 'CEF_EXPORT')
# generate static functions # retrieve the existing virtual function implementations
staticimpl = make_cpptoc_function_impl(cls, existing_virtual = get_function_impls(impl, 'CEF_CALLBACK')
cls.get_static_funcs(), existing, None,
defined_names, base_scoped)
if len(staticimpl) > 0:
staticimpl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
resultingimpl = staticimpl + virtualimpl staticout = virtualout = ''
customized = False
first = True
idx = 0
# any derived classes can be unwrapped for version in versions:
unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped) version_finder = functools.partial(_version_finder, header,
version) if with_versions else None
defined_names.append(cls.get_capi_name(version=version))
const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \ if first:
clsname+'CppToC::'+clsname+'CppToC() {\n' first = False
const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
defined_names)
const += '}\n\n'+ \
'// DESTRUCTOR - Do not edit by hand.\n\n'+ \
clsname+'CppToC::~'+clsname+'CppToC() {\n'
if not cls.has_attrib('no_debugct_check') and not base_scoped: # generate static functions
const += ' shutdown_checker::AssertNotShutdown();\n' 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:
staticout += '// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
if scustomized:
customized = True
const += '}\n\n' 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,
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 += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
suffixname, defined_names,
version, version_finder)
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'
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] + \
' ' + notreached + '\n'+ \
'}\n\n' + \
'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \
unwrapderived[1] + \
' ' + notreached + '\n'+ \
'}\n\n'
else:
const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\n' + \
unwrapderived + \
' ' + notreached + '\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
clsname) + ';\n\n'
virtualout += const
idx += 1
out = staticout + virtualout
# determine what includes are required by identifying what translation # determine what includes are required by identifying what translation
# classes are being used # classes are being used
includes = format_translation_includes(header, const + resultingimpl + includes = format_translation_includes(
(unwrapderived[0] header,
if base_scoped else unwrapderived)) out + (unwrapderived[0] if base_scoped else unwrapderived),
with_versions=with_versions)
# build the final output # build the final output
result = get_copyright() result = get_copyright()
result += includes + '\n' + resultingimpl + '\n' result += includes + '\n'
parent_sig = template_class + '<' + clsname + 'CppToC, ' + clsname + ', ' + capiname + '>' if with_versions:
pre = post = ''
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'+ \
'}\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'+ \
'}\n\n'
else: else:
const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\n' + \ pre, post = get_version_surround(cls, long=True)
unwrapderived + \ if len(pre) > 0:
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \ result += pre + '\n'
' return nullptr;\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum( result += out + '\n'
clsname) + ';'
result += '\n\n' + const if len(post) > 0:
result += post + '\n'
return result return (result, customized)
def make_cpptoc_global_impl(header, impl): def make_cpptoc_global_impl(header, impl):
@ -684,34 +959,36 @@ def make_cpptoc_global_impl(header, impl):
# retrieve the existing global function implementations # retrieve the existing global function implementations
existing = get_function_impls(impl, 'CEF_EXPORT') existing = get_function_impls(impl, 'CEF_EXPORT')
version_finder = functools.partial(_version_finder, header, None)
# generate global functions # generate global functions
impl = make_cpptoc_function_impl(None, impl, customized = make_cpptoc_function_impl(None,
header.get_funcs(), existing, None, header.get_funcs(), existing,
defined_names, False) None, None, defined_names, False,
None, version_finder)
if len(impl) > 0: if len(impl) > 0:
impl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + impl impl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + impl
includes = '' includes = ''
# include required headers for global functions # include required headers for global functions
filenames = [] paths = set()
for func in header.get_funcs(): for func in header.get_funcs():
filename = func.get_file_name() filename = func.get_file_name()
if not filename in filenames: paths.add('include/' + func.get_file_name())
includes += '#include "include/'+func.get_file_name()+'"\n' \ paths.add('include/capi/' + func.get_capi_file_name(versions=True))
'#include "include/capi/'+func.get_capi_file_name()+'"\n'
filenames.append(filename)
# determine what includes are required by identifying what translation # determine what includes are required by identifying what translation
# classes are being used # 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 # build the final output
result = get_copyright() result = get_copyright()
result += includes + '\n' + impl result += includes + '\n' + impl
return result return (result, customized)
def write_cpptoc_impl(header, clsname, dir): 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())) 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') file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_cpptoc.cc')
set_notify_context(file)
if path_exists(file): if path_exists(file):
oldcontents = read_file(file) oldcontents = read_file(file)
else: else:
oldcontents = '' oldcontents = ''
if clsname is None: if clsname is None:
newcontents = make_cpptoc_global_impl(header, oldcontents) newcontents, customized = make_cpptoc_global_impl(header, oldcontents)
else: else:
newcontents = make_cpptoc_class_impl(header, clsname, oldcontents) newcontents, customized = make_cpptoc_class_impl(header, clsname,
return (file, newcontents) oldcontents)
set_notify_context(None)
return (file, newcontents, customized)
# test the module # test the module

View File

@ -6,22 +6,25 @@ from __future__ import absolute_import
from cef_parser 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' impl = ' // ' + cls.get_name() + ' methods.\n'
funcs = cls.get_virtual_funcs() funcs = cls.get_virtual_funcs()
for func in funcs: for func in funcs:
impl += ' ' + func.get_cpp_proto() if func.parent.get_name() != cls.get_name():
if cls.is_client_side(): # skip methods that are not directly declared in the current class
impl += ' override;\n' continue
if with_versions:
pre = post = ''
else: else:
impl += ' override;\n' pre, post = get_version_surround(func)
impl += pre + ' ' + func.get_cpp_proto() + ' override;\n' + post
return impl return impl
def make_function_body(header, cls): def make_function_body(header, cls, with_versions):
impl = make_function_body_block(cls) impl = make_function_body_block(cls, with_versions)
cur_cls = cls cur_cls = cls
while True: while True:
@ -34,7 +37,7 @@ def make_function_body(header, cls):
raise Exception('Class does not exist: ' + parent_name) raise Exception('Class does not exist: ' + parent_name)
if len(impl) > 0: if len(impl) > 0:
impl += '\n' 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) cur_cls = header.get_class(parent_name)
return impl return impl
@ -54,8 +57,6 @@ def make_ctocpp_header(header, clsname):
defname += get_capi_name(clsname[3:], False) defname += get_capi_name(clsname[3:], False)
defname = defname.upper() defname = defname.upper()
capiname = cls.get_capi_name()
result = get_copyright() result = get_copyright()
result += '#ifndef CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_\n'+ \ result += '#ifndef CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_\n'+ \
@ -75,8 +76,10 @@ def make_ctocpp_header(header, clsname):
#endif #endif
""" """
with_versions = clientside
# build the function body # build the function body
func_body = make_function_body(header, cls) func_body = make_function_body(header, cls, with_versions)
# include standard headers # include standard headers
if func_body.find('std::map') > 0 or func_body.find('std::multimap') > 0: 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 # include the headers for this class
result += '\n#include "include/'+cls.get_file_name()+'"'+ \ 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 # include headers for any forward declared classes that are not in the same file
declares = cls.get_forward_declares() declares = cls.get_forward_declares()
@ -94,7 +97,7 @@ def make_ctocpp_header(header, clsname):
dcls = header.get_class(declare) dcls = header.get_class(declare)
if dcls.get_file_name() != cls.get_file_name(): if dcls.get_file_name() != cls.get_file_name():
result += '#include "include/'+dcls.get_file_name()+'"\n' \ 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_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False base_scoped = True if base_class_name == 'CefBaseScoped' else False
@ -106,21 +109,66 @@ def make_ctocpp_header(header, clsname):
template_class = 'CefCToCppRefCounted' template_class = 'CefCToCppRefCounted'
result += '#include "libcef_dll/ctocpp/' + template_file + '"' result += '#include "libcef_dll/ctocpp/' + template_file + '"'
result += '\n\n// Wrap a C structure with a C++ class.\n'
if clientside: if with_versions:
result += '// This class may be instantiated and accessed DLL-side only.\n' pre = post = ''
else: else:
result += '// This class may be instantiated and accessed wrapper-side only.\n' pre, post = get_version_surround(cls, long=True)
if len(pre) > 0:
result += '\n\n' + pre.strip()
result += 'class '+clsname+'CToCpp\n'+ \ result += '\n\n'
' : public ' + template_class + '<'+clsname+'CToCpp, '+clsname+', '+capiname+'> {\n'+ \
' public:\n'+ \
' '+clsname+'CToCpp();\n'+ \
' virtual ~'+clsname+'CToCpp();\n\n'
result += func_body versions = cls.get_all_versions() if with_versions else (None,)
result += '};\n\n'
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'
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'+ \
' '+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_' result += '#endif // CEF_LIBCEF_DLL_CTOCPP_' + defname + '_CTOCPP_H_'

View File

@ -4,6 +4,7 @@
from __future__ import absolute_import from __future__ import absolute_import
from cef_parser import * from cef_parser import *
import functools
def make_ctocpp_impl_proto(clsname, name, func, parts): def make_ctocpp_impl_proto(clsname, name, func, parts):
@ -25,42 +26,31 @@ def make_ctocpp_impl_proto(clsname, name, func, parts):
return proto return proto
def make_ctocpp_function_impl_existing(clsname, name, func, impl): def make_ctocpp_function_impl_existing(cls, name, func, impl, version):
notify(name + ' has manual edits') 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 # retrieve the C++ prototype parts
parts = func.get_cpp_parts(True) parts = func.get_cpp_parts(True)
changes = format_translation_changes(impl, parts) changes = format_translation_changes(impl, parts)
if len(changes) > 0: if len(changes) > 0:
notify(name + ' prototype changed') notify(notify_name + ' prototype changed')
return make_ctocpp_impl_proto(clsname, name, func, parts)+'{'+ \ 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. # Special handling for the CefShutdown global function.
is_cef_shutdown = name == 'CefShutdown' and isinstance( is_cef_shutdown = name == 'CefShutdown' and isinstance(
func.parent, obj_header) func.parent, obj_header)
# build the C++ prototype clsname = None if cls is None else cls.get_name(version=version)
parts = func.get_cpp_parts(True) notify_name = name if clsname is None else '%sCToCpp::%s' % (clsname, name)
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());'
invalid = [] invalid = []
@ -83,23 +73,43 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if len(retval_default) > 0: if len(retval_default) > 0:
retval_default = ' ' + retval_default 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 # add API hash check
if func.has_attrib('api_hash_check'): if func.has_attrib('api_hash_check'):
result += '\n const char* api_hash = cef_api_hash(0);'\ result += '\n const char* api_hash = cef_api_hash(CEF_API_VERSION, 0);'\
'\n if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {'\ '\n CHECK(!strcmp(api_hash, CEF_API_HASH_PLATFORM)) <<'\
'\n // The libcef API hash does not match the current header API hash.'\ '\n "API hashes for libcef and libcef_dll_wrapper do not match.";\n'
'\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'
if len(invalid) > 0: if len(invalid) > 0:
notify(name + ' could not be autogenerated') notify(notify_name + ' could not be autogenerated')
# code could not be auto-generated # code could not be auto-generated
result += '\n // BEGIN DELETE BEFORE MODIFYING' result += '\n // BEGIN DELETE BEFORE MODIFYING'
result += '\n // AUTO-GENERATED CONTENT' 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()') params.append(arg_name + '.GetWritableStruct()')
elif arg_type == 'refptr_same': elif arg_type == 'refptr_same':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'ownptr_same':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'rawptr_same':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'refptr_diff':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'ownptr_diff':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'rawptr_diff':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
result += comment+\ result += comment+\
'\n CefOwnPtr<'+ptr_class+'CppToC> '+arg_name+'Ptr('+ptr_class+'CppToC::WrapRaw('+arg_name+'));' '\n auto ['+arg_name+'Ptr, '+arg_name+'Struct] = '+ptr_class+'CppToC_WrapRaw('+arg_name+');'
params.append(arg_name + 'Ptr->GetStruct()') params.append(arg_name + 'Struct')
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
ptr_struct = arg.get_type().get_result_ptr_type_root() 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': if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + ')' assign = ptr_class + 'CToCpp_Unwrap(' + arg_name + ')'
else: else:
assign = ptr_class + 'CppToC::Wrap(' + arg_name + ')' assign = ptr_class + 'CppToC_Wrap(' + arg_name + ')'
result += comment+\ result += comment+\
'\n '+ptr_struct+'* '+arg_name+'Struct = NULL;'\ '\n '+ptr_struct+'* '+arg_name+'Struct = NULL;'\
'\n if ('+arg_name+'.get()) {'\ '\n if ('+arg_name+'.get()) {'\
'\n '+arg_name+'Struct = '+assign+';'\ '\n '+arg_name+'Struct = '+assign+';'\
'\n }'\ '\n }'\
'\n '+ptr_struct+'* '+arg_name+'Orig = '+arg_name+'Struct;' '\n auto* '+arg_name+'Orig = '+arg_name+'Struct;'
params.append('&' + arg_name + 'Struct') params.append('&' + arg_name + 'Struct')
elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const': elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
result += comment+\ 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': arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
count_func = arg.get_attrib_count_func() count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root() 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': if arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type() 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: else:
assign = arg_name + '[i]' assign = arg_name + '[i]'
result += comment+\ 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': arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
count_func = arg.get_attrib_count_func() count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root() 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': if arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const':
assign = arg_name + '[i]' assign = arg_name + '[i]'
else: else:
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
if arg_type == 'refptr_vec_same_byref_const': 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': 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': 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': 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+\ result += comment+\
'\n const size_t '+arg_name+'Count = '+arg_name+'.size();'\ '\n const size_t '+arg_name+'Count = '+arg_name+'.size();'\
'\n '+vec_type+'* '+arg_name+'List = NULL;'\ '\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' result += 'cef_string_userfree_t'
elif retval_type == 'refptr_same' or retval_type == 'refptr_diff' or \ elif retval_type == 'refptr_same' or retval_type == 'refptr_diff' or \
retval_type == 'ownptr_same' or retval_type == 'ownptr_diff': retval_type == 'ownptr_same' or retval_type == 'ownptr_diff':
ptr_struct = retval.get_type().get_result_ptr_type_root() result += 'auto*'
result += ptr_struct + '*'
else: else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name)) 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 }' '\n }'
elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref': elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
ptr_class = arg.get_type().get_ptr_type() ptr_class = arg.get_type().get_ptr_type()
ptr_struct = arg.get_type().get_result_ptr_type_root()
if arg_type == 'refptr_same_byref': if arg_type == 'refptr_same_byref':
assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'Struct)' assign = ptr_class + 'CToCpp_Wrap(' + arg_name + 'Struct)'
else: else:
assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'Struct)' assign = ptr_class + 'CppToC_Unwrap(' + arg_name + 'Struct)'
result += comment+\ result += comment+\
'\n if ('+arg_name+'Struct) {'\ '\n if ('+arg_name+'Struct) {'\
'\n if ('+arg_name+'Struct != '+arg_name+'Orig) {'\ '\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 \ 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': arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
count_func = arg.get_attrib_count_func() count_func = arg.get_attrib_count_func()
vec_type = arg.get_type().get_result_vector_type_root()
if arg_type == 'refptr_vec_same_byref': if arg_type == 'refptr_vec_same_byref':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'refptr_vec_diff_byref':
ptr_class = arg.get_type().get_ptr_type() 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': elif arg_type == 'bool_vec_byref':
assign = arg_name + 'List[i]?true:false' assign = arg_name + 'List[i]?true:false'
else: else:
@ -468,7 +483,7 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
if arg_type == 'rawptr_vec_diff_byref_const': if arg_type == 'rawptr_vec_diff_byref_const':
result += '\n if ('+arg_name+'Count > 0) {'\ result += '\n if ('+arg_name+'Count > 0) {'\
'\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\ '\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 }'\
'\n }' '\n }'
result += '\n if ('+arg_name+'List) {'\ result += '\n if ('+arg_name+'List) {'\
@ -497,43 +512,59 @@ def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
'\n return _retvalStr;' '\n return _retvalStr;'
elif retval_type == 'refptr_same' or retval_type == 'ownptr_same': elif retval_type == 'refptr_same' or retval_type == 'ownptr_same':
ptr_class = retval.get_type().get_ptr_type() 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': elif retval_type == 'refptr_diff':
ptr_class = retval.get_type().get_ptr_type() 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': elif retval_type == 'ownptr_diff':
ptr_class = retval.get_type().get_ptr_type() 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: else:
raise Exception('Unsupported return type %s in %s' % (retval_type, name)) raise Exception('Unsupported return type %s in %s' % (retval_type, name))
if len(result) != result_len: if len(result) != result_len:
result += '\n' result += '\n'
result += '}\n\n' result += '}\n'
return result 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 = '' impl = ''
customized = False
for func in funcs: for func in funcs:
name = func.get_name() name = func.get_name()
value = get_next_function_impl(existing, 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 \ if not value is None \
and value['body'].find('// AUTO-GENERATED CONTENT') < 0: and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
# an implementation exists that was not auto-generated # 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: 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): def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped,
impl = make_ctocpp_function_impl(cls.get_name(), version, version_finder):
cls.get_virtual_funcs(), existing, impl, customized = make_ctocpp_function_impl(
base_scoped) cls,
cls.get_virtual_funcs(), existing, base_scoped, version, version_finder)
cur_cls = cls cur_cls = cls
while True: while True:
@ -544,18 +575,28 @@ def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
parent_cls = header.get_class(parent_name) parent_cls = header.get_class(parent_name)
if parent_cls is None: if parent_cls is None:
raise Exception('Class does not exist: ' + parent_name) raise Exception('Class does not exist: ' + parent_name)
impl += make_ctocpp_function_impl(cls.get_name(), pimpl, pcustomized = make_ctocpp_function_impl(
parent_cls.get_virtual_funcs(), cls,
existing, base_scoped) 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) 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 # identify all classes that derive from cls
derived_classes = [] derived_classes = []
clsname = cls.get_name() 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() allclasses = header.get_classes()
for cur_cls in allclasses: for cur_cls in allclasses:
if cur_cls.get_name() == clsname: if cur_cls.get_name() == clsname:
@ -568,34 +609,156 @@ def make_ctocpp_unwrap_derived(header, cls, base_scoped):
if base_scoped: if base_scoped:
impl = ['', ''] impl = ['', '']
for clsname in derived_classes: for clsname in derived_classes:
impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ derived_cls = header.get_class(clsname)
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\ if version is None:
clsname+'CToCpp::UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\ pre, post = get_version_surround(derived_cls)
' }\n' else:
impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ if not derived_cls.exists_at_version(version):
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\ continue
clsname+'CToCpp::UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c))));\n'+\ pre = post = ''
' }\n'
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: else:
impl = '' impl = ''
for clsname in derived_classes: for clsname in derived_classes:
impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\ derived_cls = header.get_class(clsname)
' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\ if version is None:
clsname+'CToCpp::Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\ pre, post = get_version_surround(derived_cls)
' }\n' 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 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): def make_ctocpp_class_impl(header, clsname, impl):
cls = header.get_class(clsname) cls = header.get_class(clsname)
if cls is None: if cls is None:
raise Exception('Class does not exist: ' + clsname) 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_class_name = header.get_base_class_name(clsname)
base_scoped = True if base_class_name == 'CefBaseScoped' else False base_scoped = True if base_class_name == 'CefBaseScoped' else False
if base_scoped: if base_scoped:
@ -603,75 +766,135 @@ def make_ctocpp_class_impl(header, clsname, impl):
else: else:
template_class = 'CefCToCppRefCounted' template_class = 'CefCToCppRefCounted'
# generate virtual functions with_versions = cls.is_client_side()
virtualimpl = make_ctocpp_virtual_function_impl(header, cls, existing, versions = list(cls.get_all_versions()) if with_versions else (None,)
base_scoped)
if len(virtualimpl) > 0:
virtualimpl = '\n// VIRTUAL METHODS - Body may be edited by hand.\n\n' + virtualimpl
# retrieve the existing static function implementations # retrieve the existing static function implementations
existing = get_function_impls(impl, clsname + '::') existing_static = get_function_impls(impl, clsname + '::')
# generate static functions staticout = virtualout = ''
staticimpl = make_ctocpp_function_impl(clsname, customized = False
cls.get_static_funcs(), existing, first = True
base_scoped) idx = 0
if len(staticimpl) > 0:
staticimpl = '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
resultingimpl = staticimpl + virtualimpl for version in versions:
version_finder = functools.partial(_version_finder, header,
version) if with_versions else None
# any derived classes can be unwrapped if first:
unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped) first = False
const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \ # generate static functions
clsname+'CToCpp::'+clsname+'CToCpp() {\n'+ \ staticimpl, scustomized = make_ctocpp_function_impl(
'}\n\n'+ \ cls,
'// DESTRUCTOR - Do not edit by hand.\n\n'+ \ cls.get_static_funcs(), existing_static, base_scoped, version,
clsname+'CToCpp::~'+clsname+'CToCpp() {\n' version_finder)
if len(staticimpl) > 0:
staticout += '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
if scustomized:
customized = True
if not cls.has_attrib('no_debugct_check') and not base_scoped: if len(versions) > 1:
const += ' shutdown_checker::AssertNotShutdown();\n' staticout += '// HELPER FUNCTIONS - Do not edit by hand.\n\n'
staticout += make_ctocpp_version_wrappers(header, cls, base_scoped,
versions)
const += '}\n\n' 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,
version)
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'
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] + \
' ' + notreached + '\n'+ \
'}\n\n' + \
'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<'+clsname+'> c) {\n'+ \
unwrapderived[1] + \
' ' + notreached + '\n'+ \
'}\n\n'
else:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \
unwrapderived + \
' ' + notreached + '\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
clsname) + ';\n\n'
virtualout += const
idx += 1
out = staticout + virtualout
# determine what includes are required by identifying what translation # determine what includes are required by identifying what translation
# classes are being used # classes are being used
includes = format_translation_includes(header, const + resultingimpl + includes = format_translation_includes(
(unwrapderived[0] header,
if base_scoped else unwrapderived)) out + (unwrapderived[0] if base_scoped else unwrapderived),
with_versions=with_versions)
# build the final output # build the final output
result = get_copyright() result = get_copyright()
result += includes + '\n' + resultingimpl + '\n' result += includes + '\n'
parent_sig = template_class + '<' + clsname + 'CToCpp, ' + clsname + ', ' + capiname + '>' if with_versions:
pre = post = ''
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'+ \
'}\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'+ \
'}\n\n'
else: else:
const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \ pre, post = get_version_surround(cls, long=True)
unwrapderived + \ if len(pre) > 0:
' DCHECK(false) << "Unexpected class type: " << type;\n'+ \ result += pre + '\n'
' return nullptr;\n'+ \
'}\n\n'
const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum( result += out + '\n'
clsname) + ';'
result += const if len(post) > 0:
result += post + '\n'
return result return (result, customized)
def make_ctocpp_global_impl(header, impl): 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') existing = get_function_impls(impl, 'CEF_GLOBAL')
# generate static functions # 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: if len(impl) > 0:
impl = '\n// GLOBAL METHODS - Body may be edited by hand.\n\n' + impl impl = '\n// GLOBAL METHODS - Body may be edited by hand.\n\n' + impl
includes = '' includes = ''
# include required headers for global functions # include required headers for global functions
filenames = [] paths = set()
for func in header.get_funcs(): for func in header.get_funcs():
filename = func.get_file_name() filename = func.get_file_name()
if not filename in filenames: paths.add('include/' + func.get_file_name())
includes += '#include "include/'+func.get_file_name()+'"\n' \ paths.add('include/capi/' + func.get_capi_file_name())
'#include "include/capi/'+func.get_capi_file_name()+'"\n'
filenames.append(filename)
# determine what includes are required by identifying what translation # determine what includes are required by identifying what translation
# classes are being used # classes are being used
includes += format_translation_includes(header, impl) includes += format_translation_includes(header, impl, other_includes=paths)
# build the final output # build the final output
result = get_copyright() result = get_copyright()
result += includes + '\n// Define used to facilitate parsing.\n#define CEF_GLOBAL\n\n' + impl 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): 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())) 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') file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_ctocpp.cc')
set_notify_context(file)
if path_exists(file): if path_exists(file):
oldcontents = read_file(file) oldcontents = read_file(file)
else: else:
oldcontents = '' oldcontents = ''
if clsname is None: if clsname is None:
newcontents = make_ctocpp_global_impl(header, oldcontents) newcontents, customized = make_ctocpp_global_impl(header, oldcontents)
else: else:
newcontents = make_ctocpp_class_impl(header, clsname, oldcontents) newcontents, customized = make_ctocpp_class_impl(header, clsname,
return (file, newcontents) oldcontents)
set_notify_context(None)
return (file, newcontents, customized)
# test the module # test the module

View File

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

View File

@ -37,6 +37,13 @@ def make_gypi_file(header):
result += " 'include/capi/" + get_capi_file_name(filename) + "',\n" result += " 'include/capi/" + get_capi_file_name(filename) + "',\n"
result += " ],\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()) classes = sorted(header.get_class_names())
# library side includes # library side includes

View File

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

View File

@ -16,7 +16,7 @@ import string
import sys import sys
def MakeFileSegment(input, all_names): def _make_pack_header_segment(input, ids):
result = """ result = """
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -26,8 +26,93 @@ def MakeFileSegment(input, all_names):
filename = os.path.split(input)[1] filename = os.path.split(input)[1]
result = result.replace('$FILE$', filename) 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) contents = read_file(input)
ids = {}
# Format for Windows builds with resource whitelisting enabled [1]: # Format for Windows builds with resource whitelisting enabled [1]:
# #define IDR_RESOURCE_NAME (::ui::WhitelistedResource<12345>(), 12345) # #define IDR_RESOURCE_NAME (::ui::WhitelistedResource<12345>(), 12345)
# Format for other builds: # Format for other builds:
@ -50,54 +135,48 @@ def MakeFileSegment(input, all_names):
else: else:
all_names[name] = 1 all_names[name] = 1
result += "\n#define %s %s" % (name, id) ids[name] = id
return result return ids
def MakeFile(output, input): def write_pack_header(out_header_file, out_inc_file, inputs):
# 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"""
# sort the input files by name # 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_names = {}
all_files = {}
# generate the file segments # generate the file segments
for file in input: for file in inputs:
result += MakeFileSegment(file, all_names) filename = os.path.split(file)[1]
assert not filename in all_files, filename
all_files[filename] = _get_defines(file, all_names)
# footer string out_file = os.path.abspath(out_header_file)
result += \ 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 return retval1 #or retval2
filename = os.path.split(output)[1]
guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
result = result.replace('$GUARD$', guard)
write_file_if_changed(output, result)
def main(argv): def main(argv):
if len(argv) < 3: if len(argv) < 4:
print(("Usage:\n %s <output_filename> <input_file1> [input_file2] ... " % print(
argv[0])) "Usage:\n %s <output_header_file> <output_inc_file> <input_file1> [input_file2] ... "
% argv[0])
sys.exit(-1) sys.exit(-1)
MakeFile(argv[1], argv[2:]) write_pack_header(argv[1], argv[2], argv[3:])
if '__main__' == __name__: 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): def make_version_header(header):
if not git.is_checkout('.'):
raise Exception('Not a valid checkout')
result = get_copyright(full=True, translator=False) + \ result = get_copyright(full=True, translator=False) + \
"""// """//
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -41,33 +38,6 @@ def make_version_header(header):
#define DO_MAKE_STRING(p) #p #define DO_MAKE_STRING(p) #p
#define MAKE_STRING(p) DO_MAKE_STRING(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_ #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 # create the header object
header = obj_header() 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) header.add_directory(sys.argv[1], excluded_files)
# dump the result to stdout # dump the result to stdout

View File

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

View File

@ -3,111 +3,66 @@
# can be found in the LICENSE file. # can be found in the LICENSE file.
from __future__ import absolute_import from __future__ import absolute_import
import sys from cef_parser import obj_header
from cef_parser import * from cef_version import VersionFormatter
from clang_util import clang_format from clang_util import clang_format
from file_util import * from file_util import *
import hashlib import hashlib
from make_api_hash_header import * from make_capi_header import write_capi_header
from make_capi_header import * from make_capi_versions_header import write_capi_versions_header
from make_cpptoc_header import * from make_cpptoc_header import write_cpptoc_header
from make_cpptoc_impl import * from make_cpptoc_impl import write_cpptoc_impl
from make_ctocpp_header import * from make_ctocpp_header import write_ctocpp_header
from make_ctocpp_impl import * from make_ctocpp_impl import write_ctocpp_impl
from make_gypi_file import * from make_gypi_file import write_gypi_file
from make_libcef_dll_dylib_impl import * from make_libcef_dll_dylib_impl import write_libcef_dll_dylib_impl
from make_wrapper_types_header import * from make_wrapper_types_header import write_wrapper_types_header
from optparse import OptionParser from optparse import OptionParser
import sys
# cannot be loaded as a module FILE_HEADER = """#
if __name__ != "__main__": # This file was generated by the CEF translator tool and should not edited
sys.stderr.write('This file cannot be loaded as a module!') # by hand.
sys.exit() #
# $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 def _write_version():
if options.rootdir is None: return FILE_HEADER + VersionFormatter().get_version_string()
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 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. """ """ 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 = '' oldcontents = ''
oldhash = '' oldhash = ''
@ -122,7 +77,7 @@ def update_file(file, newcontents):
hash_end = "$" hash_end = "$"
hash_token = "$$HASH$$" hash_token = "$$HASH$$"
if not options.force and path_exists(file): if not force and path_exists(file):
oldcontents = read_file(file) oldcontents = read_file(file)
# Extract the existing hash. # Extract the existing hash.
@ -137,106 +92,264 @@ def update_file(file, newcontents):
if oldhash == newhash: if oldhash == newhash:
# Pre-formatted contents have not changed. # Pre-formatted contents have not changed.
return return 0
newcontents = newcontents.replace(hash_token, newhash, 1) newcontents = newcontents.replace(hash_token, newhash, 1)
# Apply clang-format for C/C++ files. # Apply clang-format for C/C++ files. This is slow, so we only do it for
if os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'): # customized files.
if customized and os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'):
result = clang_format(file, newcontents) result = clang_format(file, newcontents)
if result != None: if result != None:
newcontents = result newcontents = result
else: 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) backup_file(file)
filedir = os.path.split(file)[0] filedir = os.path.split(file)[0]
if not os.path.isdir(filedir): if not os.path.isdir(filedir):
make_dir(filedir) make_dir(filedir)
print('Writing file %s' % file)
write_file(file, newcontents) write_file(file, newcontents)
return 1
global writect
writect += 1
# output the C API header def translate(cef_dir,
if not options.quiet: force=False,
sys.stdout.write('In C API header directory ' + capi_header_dir + '...\n') clean=False,
filenames = sorted(header.get_file_names()) backup=False,
for filename in filenames: verbose=False,
if not options.quiet: selected_classes=None):
sys.stdout.write('Generating ' + filename + ' C API header...\n') # determine the paths
update_file(*write_capi_header(header, capi_header_dir, filename)) 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 # make sure the header directory exists
if not options.quiet: if not path_exists(cpp_header_dir):
sys.stdout.write('Generating wrapper types header...\n') sys.stderr.write('ERROR: Directory ' + cpp_header_dir +
update_file(*write_wrapper_types_header(header, wrapper_types_header)) ' does not exist.\n')
sys.exit(1)
# build the list of classes to parse # create the header object
allclasses = header.get_class_names() if verbose:
if not options.classes is None: print('Parsing C++ headers from ' + cpp_header_dir + '...')
for cls in options.classes: header = obj_header()
if not cls in allclasses:
sys.stderr.write('ERROR: Unknown class: ' + cls)
sys.exit()
classes = options.classes
else:
classes = allclasses
classes = sorted(classes) # 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)
# output CppToC global file # Track the number of files that were written.
if not options.quiet: writect = 0
sys.stdout.write('Generating CppToC global implementation...\n')
update_file(*write_cpptoc_impl(header, None, cpptoc_global_impl))
# output CToCpp global file # Track files that are not customized.
if not options.quiet: gitignore = []
sys.stdout.write('Generating CToCpp global implementation...\n')
update_file(*write_ctocpp_impl(header, None, ctocpp_global_impl))
# output CppToC class files debug_string = ''
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 try:
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))
# output the gypi file # output the C API header
if not options.quiet: if verbose:
sys.stdout.write('Generating ' + gypi_file + ' file...\n') print('In C API header directory ' + capi_header_dir + '...')
update_file(*write_gypi_file(header, gypi_file)) 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 libcef dll dylib file # output the wrapper types header
if not options.quiet: if verbose:
sys.stdout.write('Generating ' + libcef_dll_dylib_impl + ' file...\n') print('Generating wrapper types header...')
update_file(*write_libcef_dll_dylib_impl(header, libcef_dll_dylib_impl)) debug_string = 'wrapper types header'
writect += _update_file(*write_wrapper_types_header(
header, wrapper_types_header), False, force, clean, backup, gitignore)
# Update the API hash header file if necessary. This must be done last because # build the list of classes to parse
# it reads files that were potentially written by proceeding operations. allclasses = header.get_class_names()
if not options.quiet: if not selected_classes is None:
sys.stdout.write('Generating API hash header...\n') for cls in selected_classes:
if write_api_hash_header(api_hash_header, cpp_header_dir): if not cls in allclasses:
writect += 1 sys.stderr.write('ERROR: Unknown class: %s\n' % cls)
sys.exit(1)
classes = selected_classes
else:
classes = allclasses
if not options.quiet: classes = sorted(classes)
sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n')
# 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 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 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)
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 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 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)
# 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)
# 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()