From 98cd08e8ff3e13c3c9070964b82e9c11de2537c6 Mon Sep 17 00:00:00 2001 From: linesight Date: Sat, 18 Apr 2026 11:26:55 -0700 Subject: [PATCH 001/125] Modernize build toolchain for CEF 123+ and Python 3.10+ - Add tools/download_cef.py to auto-download CEF from Spotify CDN with SHA1 verification and progress output - Detect vcvarsall.bat dynamically via vswhere.exe instead of hardcoding VS2022 Community path; fall back through known editions - Remove dead code for VS2008/VS2010/VS2013 and simplify prepare_build_command() - Make VERSION argument optional in build.py, defaulting to {CHROME_VERSION_MAJOR}.0 from the version header - Add venv support notes and document download_cef.py workflow in Build-instructions.md Co-Authored-By: Claude Sonnet 4.6 --- docs/Build-instructions.md | 49 +++--- tools/automate.py | 83 ++-------- tools/build.py | 112 ++----------- tools/build_cpp_projects.py | 2 - tools/common.py | 68 +++++--- tools/download_cef.py | 309 ++++++++++++++++++++++++++++++++++++ 6 files changed, 405 insertions(+), 218 deletions(-) create mode 100644 tools/download_cef.py diff --git a/docs/Build-instructions.md b/docs/Build-instructions.md index a8013041..de6aa748 100644 --- a/docs/Build-instructions.md +++ b/docs/Build-instructions.md @@ -94,9 +94,9 @@ pip install --upgrade -r ../tools/requirements.txt 8) Extract the archive in the "build/" directory. -9) Build cefpython and run examples (xx.x is version number): +9) Build cefpython and run examples: ``` -python ../tools/build.py xx.x +python ../tools/build.py ``` @@ -143,9 +143,9 @@ sudo pip install --upgrade -r ../tools/requirements.txt 7) Extract the archive in the "build/" directory. -8) Build cefpython and run examples (xx.x is version number): +8) Build cefpython and run examples: ``` -python ../tools/build.py xx.x +python ../tools/build.py ``` @@ -260,9 +260,9 @@ cd build/ 3) Extract the downloaded archive eg. "cef55_3.2883.1553.g80bd606_win32.zip" in the "build/" directory (using "extract here" option) -4) Run the build.py tool (xx.x is version number): +4) Run the build.py tool: ``` -python ../tools/build.py xx.x +python ../tools/build.py ``` @@ -281,27 +281,36 @@ mkdir build/ cd build/ ``` -2) Install python dependencies: +2) Download and extract CEF binaries automatically using the + download_cef.py tool. It reads the required CEF version from + "cefpython/src/version/", queries the Spotify CDN index, downloads + the standard distribution, verifies the SHA1 checksum, and extracts + it to the build/ directory: +``` +python ../tools/download_cef.py ``` -pip install --upgrade -r ../tools/requirements.txt -```` - -3) Download CEF binaries from [Spotify Automated Builds](https://cef-builds.spotifycdn.com/index.html). - The version of the binaries must match exactly the CEF version - from the "cefpython/src/version/" directory (look for CEF_VERSION - constant in .h file). -4) Extract the downloaded archive eg. - "cef_binary_3.2883.1553.g80bd606_windows32.tar.bz2" - in the build/ directory (using "extract here" option) + Alternatively, download manually from + [Spotify Automated Builds](https://cef-builds.spotifycdn.com/index.html). + The version must match exactly the CEF version from + "cefpython/src/version/" (look for CEF_VERSION constant in .h file). + Extract the archive eg. "cef_binary_3.2883.1553.g80bd606_windows32.tar.bz2" + in the build/ directory (using "extract here" option). -5) Run the automate.py tool. After it completes you should see a new - directory eg. "cef55_3.2883.1553.g80bd606_win32/". +3) Build libcef_dll_wrapper and prepare the CEF binaries directory using + the automate.py tool. This processes the downloaded "cef_binary_*" + directory and creates a new directory eg. "cef55_3.2883.1553.g80bd606_win32/" + that build.py requires. Note: this step requires cmake and ninja on PATH. ``` python ../tools/automate.py --prebuilt-cef ``` -5) Run the build.py tool (xx.x is version number): +4) Run the build.py tool. The version number is optional and defaults to + {CHROME_VERSION_MAJOR}.0 read from "cefpython/src/version/": +``` +python ../tools/build.py +``` + To override the patch version (eg. for a second release off the same CEF): ``` python ../tools/build.py xx.x ``` diff --git a/tools/automate.py b/tools/automate.py index 73645724..67aed1f0 100644 --- a/tools/automate.py +++ b/tools/automate.py @@ -368,8 +368,6 @@ def build_cef_projects(): if WINDOWS: fix_cmake_variables_permanently_windows() - fix_cef_include_files() - # Find cef_binary directory. # Might already be set if --prebuilt-cef flag was passed. if not Options.cef_binary: @@ -476,7 +474,7 @@ def build_wrapper_library_windows(runtime_library, msvs, vcvars): fix_cmake_variables_for_MD_library(try_undo=True) # Command to build libcef_dll_wrapper - cmake_wrapper = prepare_build_command(build_lib=True, vcvars=vcvars) + cmake_wrapper = prepare_build_command() cmake_wrapper.extend(["cmake", "-G", "Ninja", "-DCMAKE_BUILD_TYPE="+Options.build_type, ".."]) @@ -515,27 +513,14 @@ def build_wrapper_library_windows(runtime_library, msvs, vcvars): Options.gyp_msvs_version = msvs if runtime_library == RUNTIME_MD: fix_cmake_variables_for_MD_library() - env = getenv() - if msvs == "2010": - # When Using WinSDK 7.1 vcvarsall.bat doesn't work. Use - # setuptools.msvc.msvc9_query_vcvarsall to query env vars. - from setuptools.msvc import msvc9_query_vcvarsall - env.update(msvc9_query_vcvarsall(10.0, arch=VS_PLATFORM_ARG)) - # On Python 2.7 env values returned by both distutils - # and setuptools are unicode, but Python expects env - # dict values as strings. - for env_key in env: - env_value = env[env_key] - if type(env_value) != str: - env[env_key] = env_value.encode("utf-8") - run_command(cmake_wrapper, working_dir=build_wrapper_dir, env=env) + run_command(cmake_wrapper, working_dir=build_wrapper_dir) Options.gyp_msvs_version = old_gyp_msvs_version if runtime_library == RUNTIME_MD: fix_cmake_variables_for_MD_library(undo=True) print("[automate.py] cmake OK") # Run ninja - ninja_wrapper = prepare_build_command(build_lib=True, vcvars=vcvars) + ninja_wrapper = prepare_build_command() ninja_wrapper.extend(["ninja", "-j", Options.ninja_jobs, "libcef_dll_wrapper"]) run_command(ninja_wrapper, working_dir=build_wrapper_dir) @@ -581,7 +566,6 @@ def fix_cmake_variables_for_MD_library(undo=False, try_undo=False): # Warnings are treated as errors so this needs to be ignored: # >> warning C4275: non dll-interface class 'stdext::exception' # >> used as base for dll-interface class 'std::bad_cast' - # This warning occurs only in VS2008, in VS2013 not. # This replacements must be unique for the undo operation # to be reliable. @@ -632,7 +616,7 @@ def build_wrapper_library_mac(): # On Mac it is required to link libcef_dll_wrapper against # libc++ library, so must build this library separately # from cefclient. - cmake_wrapper = prepare_build_command(build_lib=True) + cmake_wrapper = prepare_build_command() cmake_wrapper.extend(["cmake", "-G", "Ninja", "-DPROJECT_ARCH=x86_64", "-DCMAKE_CXX_FLAGS=-stdlib=libc++", @@ -664,7 +648,7 @@ def build_wrapper_library_mac(): run_command(cmake_wrapper, build_wrapper_dir) print("[automate.py] cmake OK") # Ninja - ninja_wrapper = prepare_build_command(build_lib=True) + ninja_wrapper = prepare_build_command() ninja_wrapper.extend(["ninja", "-j", Options.ninja_jobs, "libcef_dll_wrapper"]) run_command(ninja_wrapper, build_wrapper_dir) @@ -672,42 +656,14 @@ def build_wrapper_library_mac(): assert os.path.exists(wrapper_lib) -def prepare_build_command(build_lib=False, vcvars=None): - """On Windows VS env variables must be set up by calling vcvarsall.bat""" - command = list() +def prepare_build_command(): + """On Windows VS env variables must be set up by calling vcvarsall.bat.""" + command = [] if platform.system() == "Windows": - if build_lib: - if vcvars: - command.append(vcvars) - else: - command.append(get_vcvars_for_python()) - command.append(VS_PLATFORM_ARG) - else: - if int(Options.cef_branch) >= 2704: - command.append(VS2015_VCVARS) - command.append(VS_PLATFORM_ARG) - command.append("&&") + command.extend([VCVARS, VS_PLATFORM_ARG, "&&"]) return command -def fix_cef_include_files(): - """Fixes to CEF include header files for eg. VS2008 on Windows.""" - # TODO: This was fixed in upstream CEF, remove this code during - # next CEF update on Windows. - if platform.system() == "Windows" and get_msvs_for_python() == "2008": - print("[automate.py] Fixing CEF include/ files") - # cef_types_wrappers.h - cef_types_wrappers = os.path.join(Options.cef_binary, "include", - "internal", "cef_types_wrappers.h") - with open(cef_types_wrappers, "rb") as fp: - contents = fp.read().decode("utf-8") - # error C2059: syntax error : '{' - contents = contents.replace("s->range = {0, 0};", - "s->range.from = 0; s->range.to = 0;") - with open(cef_types_wrappers, "wb") as fp: - fp.write(contents.encode("utf-8")) - - def create_prebuilt_binaries(): """After building copy binaries/libs to build/cef_xxxx/. Not all projects may have been built on all platforms.""" @@ -860,23 +816,10 @@ def copy_app(app): def get_available_python_compilers(): - all_python_compilers = OrderedDict([ - ("2015", VS2015_VCVARS), - ]) - ret_compilers = OrderedDict() - for msvs in all_python_compilers: - vcvars = all_python_compilers[msvs] - if os.path.exists(vcvars): - ret_compilers[msvs] = vcvars - else: - print("[automate.py] INFO: Visual Studio compiler not found:" - " {vcvars}".format(vcvars=vcvars)) - return ret_compilers - - -def get_vcvars_for_python(): - msvs = get_msvs_for_python() - return globals()["VS"+msvs+"_VCVARS"] + if not os.path.exists(VCVARS): + print("[automate.py] ERROR: vcvarsall.bat not found: {}".format(VCVARS)) + return OrderedDict() + return OrderedDict([("2015", VCVARS)]) def getenv(): diff --git a/tools/build.py b/tools/build.py index 24294667..77c17bc4 100644 --- a/tools/build.py +++ b/tools/build.py @@ -18,12 +18,13 @@ from sources or use ready binaries from Spotify Automated Builds. Usage: - build.py VERSION [--rebuild-cpp] [--unittests] [--fast] [--clean] [--kivy] - [--hello-world] [--enable-profiling] - [--enable-line-tracing] + build.py [VERSION] [--rebuild-cpp] [--unittests] [--fast] [--clean] [--kivy] + [--hello-world] [--enable-profiling] + [--enable-line-tracing] Options: - VERSION Version number eg. 50.0 + VERSION Version number eg. 50.0. Optional: defaults to + {CHROME_VERSION_MAJOR}.0 read from src/version/. --unittests Run only unit tests. Do not run examples while building cefpython modules. Examples require interaction such as closing window before proceeding. @@ -131,12 +132,14 @@ def command_line_args(): REBUILD_CPP, VERSION, UNITTESTS VERSION = get_version_from_command_line_args(__file__) - # Other scripts called by this script expect that version number - # is available in sys.argv, so don't remove it like it's done - # for all other args starting with "--". if not VERSION: - print(__doc__) - sys.exit(1) + cef_ver = get_cefpython_version() + VERSION = "{major}.0".format(major=cef_ver["CHROME_VERSION_MAJOR"]) + # Inject into sys.argv so child scripts that call + # get_version_from_command_line_args() can find it. + sys.argv.insert(1, VERSION) + print("[build.py] No version specified, defaulting to {v}" + .format(v=VERSION)) print("[build.py] Parse command line arguments") @@ -423,97 +426,6 @@ def compile_cpp_projects_with_setuptools(): shutil.copy(SUBPROCESS_EXE, CEFPYTHON_BINARY) -def compile_cpp_projects_windows_DEPRECATED(): - """DEPRECATED. Not used currently. - Build C++ projects using .vcproj files.""" - - # TODO: Remove code after setuptools compilation was tested for some time - - print("[build.py] Compile C++ projects") - - print("[build.py] ~~ Build CLIENT_HANDLER vcproj") - vcproj = ("client_handler_py{pyver}_{os}.vcproj" - .format(pyver=PYVERSION, os=OS_POSTFIX2)) - vcproj = os.path.join(SRC_DIR, "client_handler", vcproj) - build_vcproj_DEPRECATED(vcproj) - - print("[build.py] ~~ Build LIBCEFPYTHONAPP vcproj") - vcproj = ("libcefpythonapp_py{pyver}_{os}.vcproj" - .format(pyver=PYVERSION, os=OS_POSTFIX2)) - vcproj = os.path.join(SRC_DIR, "subprocess", vcproj) - build_vcproj_DEPRECATED(vcproj) - - print("[build.py] ~~ Build SUBPROCESS vcproj") - vcproj = ("subprocess_{os}.vcproj" - .format(os=OS_POSTFIX2)) - vcproj = os.path.join(SRC_DIR, "subprocess", vcproj) - ret = build_vcproj_DEPRECATED(vcproj) - - # Copy subprocess executable - subprocess_from = os.path.join( - SUBPROCESS_DIR, - "Release_{os}".format(os=OS_POSTFIX2), - "subprocess_{os}.exe".format(os=OS_POSTFIX2)) - subprocess_to = os.path.join(CEFPYTHON_BINARY, "subprocess.exe") - if os.path.exists(subprocess_to): - os.remove(subprocess_to) - if ret == 0: - print("[build.py] Copy subprocess executable") - # shutil.copy() will also copy Permission bits - shutil.copy(subprocess_from, subprocess_to) - - print("[build.py] ~~ Build CPP_UTILS vcproj") - vcproj = ("cpp_utils_{os}.vcproj" - .format(os=OS_POSTFIX2)) - vcproj = os.path.join(SRC_DIR, "cpp_utils", vcproj) - build_vcproj_DEPRECATED(vcproj) - - -def build_vcproj_DEPRECATED(vcproj): - """DEPRECATED. Not used currently.""" - - # TODO: Remove code after setuptools compilation was tested for some time - - # In VS2010 vcbuild.exe was replaced by msbuild.exe. - # Ufortunately WinSDK 7.1 does not come with msbuild.exe, - # so it would be required to install Visual Studio 2010, - # and to support both 32-bit ad 64-bit compilations it - # a non-express version would have to be installed, which - # is not free. So to make it free open-source it was - # required migrate to a new compilation system that uses - # distutils/setuptools packages. - - # msbuild.exe flags: - # /clp:disableconsolecolor - # msbuild /p:BuildProjectReferences=false project.proj - # MSBuild.exe MyProject.proj /t:build - - VS2008_BUILD = ("%LocalAppData%\\Programs\\Common\\" - "Microsoft\\Visual C++ for Python\\9.0\\" - "VC\\bin\\amd64\\vcbuild.exe") - VS2008_BUILD = VS2008_BUILD.replace("%LocalAppData%", - os.environ["LOCALAPPDATA"]) - - if PYVERSION == "27": - args = list() - args.append(VS2008_VCVARS) - args.append(VS_PLATFORM_ARG) - args.append("&&") - args.append(VS2008_BUILD) - args.append("/nocolor") - args.append("/nologo") - args.append("/nohtmllog") - if REBUILD_CPP: - args.append("/rebuild") - args.append(vcproj) - ret = subprocess.call(args, shell=True) - if ret != 0: - compile_ask_to_continue() - return ret - else: - raise Exception("Only Python 2.7 32-bit is currently supported") - - def compile_ask_to_continue(): # noinspection PyUnboundLocalVariable what = input("[build.py] make failed, 'y' to continue, Enter to stop: ") diff --git a/tools/build_cpp_projects.py b/tools/build_cpp_projects.py index b93deed8..2ea9569a 100644 --- a/tools/build_cpp_projects.py +++ b/tools/build_cpp_projects.py @@ -110,8 +110,6 @@ def print_compiler_options(): def get_compiler(static=False): - # NOTES: - # - VS2008 and VS2010 are both using distutils/msvc9compiler.py compiler = new_compiler() # Must initialize so that "compile_options" and others are available compiler.initialize() diff --git a/tools/common.py b/tools/common.py index 814f3aca..dd44c6f6 100644 --- a/tools/common.py +++ b/tools/common.py @@ -217,9 +217,42 @@ # with setuptools/distutils in the build_cpp_projects.py tool. # ----------------------------------------------------------------------------- +def _find_vcvars(): + """Locate vcvarsall.bat for VS2022+ using vswhere.exe, + falling back to known Community/Professional/Enterprise paths.""" + import subprocess as _sp + vswhere = (r"C:\Program Files (x86)\Microsoft Visual Studio" + r"\Installer\vswhere.exe") + if os.path.isfile(vswhere): + try: + out = _sp.check_output( + [vswhere, "-latest", + "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", "installationPath"], + stderr=_sp.DEVNULL).decode().strip() + if out: + candidate = os.path.join( + out, r"VC\Auxiliary\Build\vcvarsall.bat") + if os.path.isfile(candidate): + return candidate + except Exception: + pass + # Fallback: try known editions in preference order + for edition in ("Community", "Professional", "Enterprise", "BuildTools"): + for year in ("2022", "2019", "2017"): + candidate = (r"C:\Program Files\Microsoft Visual Studio" + r"\{year}\{ed}\VC\Auxiliary\Build\vcvarsall.bat" + .format(year=year, ed=edition)) + if os.path.isfile(candidate): + return candidate + # Last resort: a guessed path so the string is never empty + return (r"C:\Program Files\Microsoft Visual Studio\2022\Community" + r"\VC\Auxiliary\Build\vcvarsall.bat") + + VS_PLATFORM_ARG = "x86" if ARCH32 else "amd64" -VS2015_VCVARS = (r"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat") +VCVARS = _find_vcvars() # ----------------------------------------------------------------------------- @@ -413,6 +446,8 @@ def _detect_distrib_dir(): def get_version_from_command_line_args(caller_script, ignore_error=False): + """Parse version number from sys.argv. Returns None (or "" when + ignore_error=True) if not found; callers may supply a default.""" args = " ".join(sys.argv) match = re.search(r"\b(\d+)\.\d+\b", args) if match: @@ -448,32 +483,13 @@ def get_version_from_file(header_file): def get_msvs_for_python(vs_prefix=False): - """Get MSVS version (eg 2008) for current python running.""" - if sys.version_info[:2] == (2, 7): - return "VS2008" if vs_prefix else "2008" - elif sys.version_info[:2] == (3, 4): - return "VS2010" if vs_prefix else "2010" - elif sys.version_info[:2] == (3, 5): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 6): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 7): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 8): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 9): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 10): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 11): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 12): - return "VS2015" if vs_prefix else "2015" - elif sys.version_info[:2] == (3, 13): + """Return the VS lib subdirectory label used in CEF prebuilt binaries. + The label 'VS2015' is a historical artifact from the CEF binary layout; + it does not indicate the actual VS version used to compile.""" + if sys.version_info >= (3, 5): return "VS2015" if vs_prefix else "2015" - else: - print("ERROR: This version of Python is not supported") - sys.exit(1) + print("ERROR: Python 3.5 or later is required") + sys.exit(1) _detect_cef_binaries_libraries_dir() diff --git a/tools/download_cef.py b/tools/download_cef.py new file mode 100644 index 00000000..cdfa5764 --- /dev/null +++ b/tools/download_cef.py @@ -0,0 +1,309 @@ +# Copyright (c) 2017 CEF Python, see the Authors file. +# All rights reserved. Licensed under BSD 3-clause license. +# Project website: https://github.com/cztomczak/cefpython + +""" +Download CEF binaries from Spotify Automated Builds. + +Reads the required CEF version from src/version/cef_version_*.h, queries +the Spotify CDN index to find the matching standard distribution, downloads +it with progress output, verifies the SHA1 checksum, and extracts it to the +build/ directory. + +The extracted directory (eg. build/cef_binary_3.2883.1553.g80bd606_windows64/) +is exactly what automate.py --prebuilt-cef expects. + +Usage: + download_cef.py [--build-dir=] [--platform=] + [--no-extract] [--keep-archive] [--dry-run] + download_cef.py (-h | --help) + +Options: + -h --help Show this help message. + --build-dir= Build directory [default: cefpython/build/]. + --platform= CEF platform postfix to download, eg. windows64, + linux64, macosx64. Defaults to current platform. + --no-extract Download the archive but do not extract it. + --keep-archive Keep the archive file after extraction. + --dry-run Print what would be done without downloading. + +Typical workflow: + python tools/download_cef.py + python tools/automate.py --prebuilt-cef + python tools/build.py xx.x +""" + +import argparse +import hashlib +import json +import os +import sys +import tarfile +import zipfile + +# Allow running from any directory +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import common + +SPOTIFY_CDN_BASE = "https://cef-builds.spotifycdn.com" +SPOTIFY_INDEX_URL = SPOTIFY_CDN_BASE + "/index.json" + +SCRIPT = os.path.basename(__file__) + + +def log(msg): + print("[{}] {}".format(SCRIPT, msg)) + + +def main(): + args = parse_args() + + build_dir = os.path.abspath(args.build_dir) if args.build_dir else common.BUILD_DIR + cef_postfix2 = args.platform if args.platform else common.CEF_POSTFIX2 + + if cef_postfix2 == "unknown": + log("ERROR: Could not detect platform. Use --platform to specify it.") + log("Valid values: windows32, windows64, linux32, linux64, macosx64") + sys.exit(1) + + version = common.get_cefpython_version() + cef_version = version["CEF_VERSION"] + + log("CEF version : {}".format(cef_version)) + log("Platform : {}".format(cef_postfix2)) + log("Build dir : {}".format(build_dir)) + + # Skip if already extracted + extract_dir = os.path.join( + build_dir, "cef_binary_{}_{}".format(cef_version, cef_postfix2)) + if os.path.isdir(extract_dir): + log("Already extracted: {}".format(extract_dir)) + log("Delete that directory to force a fresh download.") + return + + # Query Spotify index + log("Fetching index: {}".format(SPOTIFY_INDEX_URL)) + file_info = find_in_index(cef_version, cef_postfix2) + + filename = file_info["name"] + expected_sha1 = file_info.get("sha1", "") + file_size = int(file_info.get("size", 0)) + download_url = "{}/{}".format(SPOTIFY_CDN_BASE, filename) + archive_path = os.path.join(build_dir, filename) + + log("File : {}".format(filename)) + if file_size: + log("Size : {:.1f} MB".format(file_size / (1024 * 1024))) + if expected_sha1: + log("SHA1 : {}".format(expected_sha1)) + + if args.dry_run: + log("Dry run — nothing downloaded.") + return + + os.makedirs(build_dir, exist_ok=True) + + # Download (skip if archive already present and valid) + if os.path.isfile(archive_path): + log("Archive already present, verifying checksum...") + if expected_sha1 and not verify_sha1(archive_path, expected_sha1): + log("Checksum mismatch — re-downloading.") + os.remove(archive_path) + download(download_url, archive_path, file_size) + check_sha1(archive_path, expected_sha1) + else: + log("Checksum OK — skipping download.") + else: + download(download_url, archive_path, file_size) + check_sha1(archive_path, expected_sha1) + + if args.no_extract: + log("--no-extract set — done.") + return + + log("Extracting to: {}".format(build_dir)) + extract(archive_path, build_dir) + + if not args.keep_archive: + log("Removing archive: {}".format(os.path.basename(archive_path))) + os.remove(archive_path) + + if os.path.isdir(extract_dir): + log("Done: {}".format(extract_dir)) + else: + log("WARNING: Expected directory not found after extraction:") + log(" {}".format(extract_dir)) + log("Check build/ for the extracted contents.") + + +def parse_args(): + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--build-dir", metavar="DIR", + help="Build directory (default: cefpython/build/)") + parser.add_argument("--platform", metavar="PLAT", + help="CEF platform postfix eg. windows64, linux64, " + "macosx64 (default: auto-detect)") + parser.add_argument("--no-extract", action="store_true", + help="Download archive but do not extract") + parser.add_argument("--keep-archive", action="store_true", + help="Keep archive after extraction") + parser.add_argument("--dry-run", action="store_true", + help="Print what would happen without downloading") + return parser.parse_args() + + +def find_in_index(cef_version, cef_postfix2): + """Fetch Spotify index and return the standard-distribution file entry.""" + try: + from urllib.request import urlopen + from urllib.error import URLError + except ImportError: + from urllib2 import urlopen, URLError + + try: + response = urlopen(SPOTIFY_INDEX_URL, timeout=30) + index = json.loads(response.read().decode("utf-8")) + except Exception as exc: + log("ERROR: Could not fetch index: {}".format(exc)) + sys.exit(1) + + if cef_postfix2 not in index: + log("ERROR: Platform '{}' not found in Spotify index.".format(cef_postfix2)) + log("Available platforms: {}".format(", ".join(sorted(index.keys())))) + sys.exit(1) + + versions = index[cef_postfix2].get("versions", []) + for ver_entry in versions: + if ver_entry.get("cef_version") != cef_version: + continue + for file_entry in ver_entry.get("files", []): + if file_entry.get("type") == "standard": + return file_entry + log("ERROR: No standard distribution found for version '{}' on '{}'." + .format(cef_version, cef_postfix2)) + log("Available file types: {}" + .format(", ".join(f.get("type", "?") + for f in ver_entry.get("files", [])))) + sys.exit(1) + + recent = [v.get("cef_version", "?") for v in versions[:8]] + log("ERROR: CEF version '{}' not found for platform '{}'." + .format(cef_version, cef_postfix2)) + log("Most recent available versions: {}".format(", ".join(recent))) + sys.exit(1) + + +def download(url, dest_path, expected_size=0): + """Download url to dest_path with a progress bar.""" + try: + from urllib.request import urlopen + except ImportError: + from urllib2 import urlopen + + log("Downloading: {}".format(url)) + try: + response = urlopen(url, timeout=120) + except Exception as exc: + log("ERROR: Download failed: {}".format(exc)) + sys.exit(1) + + total = int(response.headers.get("Content-Length") or expected_size or 0) + downloaded = 0 + chunk_size = 1024 * 1024 # 1 MB + + try: + with open(dest_path, "wb") as fp: + while True: + chunk = response.read(chunk_size) + if not chunk: + break + fp.write(chunk) + downloaded += len(chunk) + _print_progress(downloaded, total) + except Exception as exc: + if os.path.isfile(dest_path): + os.remove(dest_path) + log("\nERROR: Download failed: {}".format(exc)) + sys.exit(1) + + print() # end progress line + log("Saved: {}".format(os.path.basename(dest_path))) + + +def _print_progress(downloaded, total): + mb = downloaded / (1024 * 1024) + if total: + pct = min(downloaded * 100 // total, 100) + total_mb = total / (1024 * 1024) + line = "\r {:.1f} / {:.1f} MB ({:3d}%)".format(mb, total_mb, pct) + else: + line = "\r {:.1f} MB".format(mb) + sys.stdout.write(line) + sys.stdout.flush() + + +def verify_sha1(file_path, expected_sha1): + """Return True if the file's SHA1 matches expected_sha1.""" + sha1 = hashlib.sha1() + with open(file_path, "rb") as fp: + for chunk in iter(lambda: fp.read(65536), b""): + sha1.update(chunk) + return sha1.hexdigest().lower() == expected_sha1.lower() + + +def check_sha1(file_path, expected_sha1): + """Verify SHA1; remove file and exit on mismatch.""" + if not expected_sha1: + return + log("Verifying SHA1...") + if verify_sha1(file_path, expected_sha1): + log("SHA1 OK.") + else: + log("ERROR: SHA1 mismatch for {}.".format(os.path.basename(file_path))) + os.remove(file_path) + sys.exit(1) + + +def extract(archive_path, dest_dir): + """Extract a .zip or .tar.bz2/.tar.gz archive with progress.""" + if archive_path.endswith(".zip"): + _extract_zip(archive_path, dest_dir) + elif ".tar." in os.path.basename(archive_path): + _extract_tar(archive_path, dest_dir) + else: + log("ERROR: Unrecognised archive format: {}".format(archive_path)) + sys.exit(1) + print() # end progress line + + +def _extract_zip(archive_path, dest_dir): + with zipfile.ZipFile(archive_path, "r") as zf: + members = zf.namelist() + total = len(members) + for i, member in enumerate(members, 1): + zf.extract(member, dest_dir) + if i % 200 == 0 or i == total: + sys.stdout.write("\r {}/{} files".format(i, total)) + sys.stdout.flush() + + +def _extract_tar(archive_path, dest_dir): + mode = "r:*" # auto-detect compression + with tarfile.open(archive_path, mode) as tf: + members = tf.getmembers() + total = len(members) + # filter= kwarg added in Python 3.12 to suppress deprecation warning + extract_kwargs = {} + if sys.version_info >= (3, 12): + extract_kwargs["filter"] = "data" + for i, member in enumerate(members, 1): + tf.extract(member, dest_dir, **extract_kwargs) + if i % 200 == 0 or i == total: + sys.stdout.write("\r {}/{} files".format(i, total)) + sys.stdout.flush() + + +if __name__ == "__main__": + main() From 252b5da688ede5f4e55987a969b228eb1da6ab9f Mon Sep 17 00:00:00 2001 From: linesight Date: Sat, 18 Apr 2026 11:39:36 -0700 Subject: [PATCH 002/125] fix x86/x64 mismatch in MSVC compiler initialization on Windows Pass explicit plat_name to distutils compiler.initialize() in build_cpp_projects.py, and add --plat-name to the cython_setup.py build_ext invocation in build.py. Without these, distutils defaults to win32 even on 64-bit Python, causing C1905 (front/back end incompatible) when linking against x64 CEF libraries. Co-Authored-By: Claude Sonnet 4.6 --- tools/build.py | 6 +++++- tools/build_cpp_projects.py | 10 ++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/tools/build.py b/tools/build.py index 77c17bc4..c6bc71c8 100644 --- a/tools/build.py +++ b/tools/build.py @@ -698,9 +698,13 @@ def build_cefpython_module(): if ENABLE_LINE_TRACING: enable_line_tracing = "--enable-line-tracing" + plat_name = "" + if WINDOWS: + plat_name = "--plat-name win-amd64" if ARCH64 else "--plat-name win32" command = ("\"{python}\" {tools_dir}/cython_setup.py build_ext" - " {enable_profiling} {enable_line_tracing}" + " {plat_name} {enable_profiling} {enable_line_tracing}" .format(python=sys.executable, tools_dir=TOOLS_DIR, + plat_name=plat_name, enable_profiling=enable_profiling, enable_line_tracing=enable_line_tracing)) if FAST_FLAG: diff --git a/tools/build_cpp_projects.py b/tools/build_cpp_projects.py index 2ea9569a..b4588e2b 100644 --- a/tools/build_cpp_projects.py +++ b/tools/build_cpp_projects.py @@ -111,8 +111,14 @@ def print_compiler_options(): def get_compiler(static=False): compiler = new_compiler() - # Must initialize so that "compile_options" and others are available - compiler.initialize() + # Must initialize so that "compile_options" and others are available. + # Pass plat_name explicitly: without it distutils may default to win32 + # (32-bit) even on 64-bit Python, causing linker failures against x64 + # CEF libraries. + if WINDOWS: + compiler.initialize(plat_name="win-amd64" if ARCH64 else "win32") + else: + compiler.initialize() if static: compiler.compile_options.remove("/MD") # Overwrite function that adds /MANIFESTFILE, as for subprocess From e8135525b36ce24560d1882e0450a7d57deb997f Mon Sep 17 00:00:00 2001 From: linesight Date: Sat, 18 Apr 2026 21:21:24 -0700 Subject: [PATCH 003/125] CEF 146: fix windowed rendering with Alloy runtime and deferred browser creation Two root causes fixed to make windowed browsers work on CEF 123+: 1. Set CEF_RUNTIME_STYLE_ALLOY explicitly after SetAsChild/SetAsPopup in window_info.pyx. CEF 123+ defaults to Chrome runtime (no native Win32 title bar, blank content). Also declared cef_runtime_style_t enum and runtime_style field in cef_win.pxd. 2. Defer CreateBrowserSync() until OnContextInitialized fires. Calling before context is ready causes blink.mojom.WidgetHost rejection and a blank window. g_pending_browsers list + CefPostTask posts creation at the outer message-loop level after the callback returns. Also fix PyQt6 high-DPI sizing in qt.py: call WindowUtils.OnSize after CreateBrowserSync() so the browser fills the HWND client rect in device pixels rather than the smaller logical-pixel rect Qt reports. Co-Authored-By: Claude Sonnet 4.6 --- examples/qt.py | 5 ++ src/cefpython.pyx | 20 +++++- src/extern/cef/cef_win.pxd | 6 ++ src/handlers/browser_process_handler.pyx | 23 +++++++ src/include/internal/cef_types_runtime.h | 81 ++++++++++++++++++++++++ src/subprocess/cefpython_app.cpp | 11 ++++ src/window_info.pyx | 4 ++ 7 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/include/internal/cef_types_runtime.h diff --git a/examples/qt.py b/examples/qt.py index d359dcd8..4297d562 100644 --- a/examples/qt.py +++ b/examples/qt.py @@ -257,6 +257,11 @@ def embedBrowser(self): url="https://www.google.com/") self.browser.SetClientHandler(LoadHandler(self.parent.navigation_bar)) self.browser.SetClientHandler(FocusHandler(self)) + if WINDOWS: + # Sync browser size to actual HWND client rect using device pixels. + # PyQt6 high-DPI scaling means self.width()/height() may be smaller + # than the real client rect, leaving content in a smaller area. + WindowUtils.OnSize(self.getHandle(), 0, 0, 0) def getHandle(self): if self.hidden_window: diff --git a/src/cefpython.pyx b/src/cefpython.pyx index 27502f97..5c768f6f 100644 --- a/src/cefpython.pyx +++ b/src/cefpython.pyx @@ -323,6 +323,8 @@ cdef unique_ptr[MainMessageLoopExternalPump] g_external_message_pump cdef py_bool g_MessageLoop_called = False cdef py_bool g_MessageLoopWork_called = False cdef py_bool g_cef_initialized = False +cdef py_bool g_context_initialized = False +cdef list g_pending_browsers = [] cdef dict g_globalClientCallbacks = {} @@ -639,6 +641,7 @@ def Initialize(applicationSettings=None, commandLineSwitches=None, **kwargs): # Install by default. WindowUtils.InstallX11ErrorHandlers() + return ret def CreateBrowser(**kwargs): @@ -664,8 +667,21 @@ def CreateBrowserSync(windowInfo=None, raise Exception("Invalid argument: "+kwarg) Debug("CreateBrowserSync() called") - assert IsThread(TID_UI), ( - "cefpython.CreateBrowserSync() may only be called on the UI thread") + # CEF 146+: CefCurrentlyOn(TID_UI) returns false before MessageLoop starts, + # so skip the assert here and let CEF's own internal checks handle it. + + # Defer browser creation until OnContextInitialized fires inside MessageLoop. + # In CEF 123+, windowed browser creation before OnContextInitialized causes + # blink.mojom.WidgetHost rejection and renderer shows no content. + if not g_context_initialized: + Debug("CreateBrowserSync() deferred until OnContextInitialized") + g_pending_browsers.append({ + "windowInfo": windowInfo, + "browserSettings": browserSettings, + "navigateUrl": navigateUrl, + "window_title": window_title, + }) + return None """ # CEF views diff --git a/src/extern/cef/cef_win.pxd b/src/extern/cef/cef_win.pxd index e6844e58..3b1dd1a8 100644 --- a/src/extern/cef/cef_win.pxd +++ b/src/extern/cef/cef_win.pxd @@ -17,7 +17,13 @@ cdef extern from "include/internal/cef_win.h": # noinspection PyUnresolvedReferences ctypedef HCURSOR CefCursorHandle + ctypedef enum cef_runtime_style_t: + CEF_RUNTIME_STYLE_DEFAULT + CEF_RUNTIME_STYLE_CHROME + CEF_RUNTIME_STYLE_ALLOY + cdef cppclass CefWindowInfo: + cef_runtime_style_t runtime_style void SetAsChild(CefWindowHandle parent, const CefRect windowRect) void SetAsPopup(CefWindowHandle parent, diff --git a/src/handlers/browser_process_handler.pyx b/src/handlers/browser_process_handler.pyx index 09463b0e..ac007a2e 100644 --- a/src/handlers/browser_process_handler.pyx +++ b/src/handlers/browser_process_handler.pyx @@ -4,6 +4,29 @@ include "../cefpython.pyx" +cdef public void BrowserProcessHandler_OnContextInitialized() except * with gil: + try: + global g_context_initialized + Debug("BrowserProcessHandler_OnContextInitialized()") + g_context_initialized = True + # Browser creation is handled by BrowserProcessHandler_CreatePendingBrowsers, + # posted as a separate task in C++ so it runs at the outer message-loop level. + except: + (exc_type, exc_value, exc_trace) = sys.exc_info() + sys.excepthook(exc_type, exc_value, exc_trace) + +cdef public void BrowserProcessHandler_CreatePendingBrowsers() except * with gil: + try: + Debug("BrowserProcessHandler_CreatePendingBrowsers()") + if g_pending_browsers: + pending = list(g_pending_browsers) + del g_pending_browsers[:] + for params in pending: + CreateBrowserSync(**params) + except: + (exc_type, exc_value, exc_trace) = sys.exc_info() + sys.excepthook(exc_type, exc_value, exc_trace) + cdef public void BrowserProcessHandler_OnRenderProcessThreadCreated( CefRefPtr[CefListValue] extra_info ) except * with gil: diff --git a/src/include/internal/cef_types_runtime.h b/src/include/internal/cef_types_runtime.h new file mode 100644 index 00000000..b3cc14a8 --- /dev/null +++ b/src/include/internal/cef_types_runtime.h @@ -0,0 +1,81 @@ +// 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_INTERNAL_CEF_TYPES_RUNTIME_H_ +#define CEF_INCLUDE_INTERNAL_CEF_TYPES_RUNTIME_H_ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/// +/// CEF supports both a Chrome runtime style (based on the Chrome UI layer) and +/// an Alloy runtime style (based on the Chromium content layer). Chrome style +/// provides the full Chrome UI and browser functionality whereas Alloy style +/// provides less default browser functionality but adds additional client +/// callbacks and support for windowless (off-screen) rendering. The style type +/// is individually configured for each window/browser at creation time and +/// different styles can be mixed during runtime. For additional comparative +/// details on runtime styles see +/// https://chromiumembedded.github.io/cef/architecture#cef3 +/// +/// Windowless rendering will always use Alloy style. Windowed rendering with a +/// default window or client-provided parent window can configure the style via +/// CefWindowInfo.runtime_style. Windowed rendering with the Views framework can +/// configure the style via CefWindowDelegate::GetWindowRuntimeStyle and +/// CefBrowserViewDelegate::GetBrowserRuntimeStyle. Alloy style Windows with the +/// Views framework can host only Alloy style BrowserViews but Chrome style +/// Windows can host both style BrowserViews. Additionally, a Chrome style +/// Window can host at most one Chrome style BrowserView but potentially +/// multiple Alloy style BrowserViews. See CefWindowInfo.runtime_style +/// documentation for any additional platform-specific limitations. +/// +typedef enum { + /// + /// Use the default style. See above documentation for exceptions. + /// + CEF_RUNTIME_STYLE_DEFAULT, + + /// + /// Use Chrome style. + /// + CEF_RUNTIME_STYLE_CHROME, + + /// + /// Use Alloy style. + /// + CEF_RUNTIME_STYLE_ALLOY, +} cef_runtime_style_t; + +#ifdef __cplusplus +} +#endif + +#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_RUNTIME_H_ diff --git a/src/subprocess/cefpython_app.cpp b/src/subprocess/cefpython_app.cpp index 38bd30ac..ebf5c9bf 100644 --- a/src/subprocess/cefpython_app.cpp +++ b/src/subprocess/cefpython_app.cpp @@ -7,6 +7,10 @@ #ifdef BROWSER_PROCESS #include "common/cefpython_public_api.h" +// Forward declaration for the Cython public function (generated in cefpython_fixed.h +// after Cython runs; declared here so the C++ build does not depend on build order). +extern "C" void BrowserProcessHandler_OnContextInitialized(); +extern "C" void BrowserProcessHandler_CreatePendingBrowsers(); #endif #if defined(OS_WIN) @@ -168,6 +172,13 @@ CefRefPtr CefPythonApp::GetRenderProcessHandler() { void CefPythonApp::OnContextInitialized() { #ifdef BROWSER_PROCESS REQUIRE_UI_THREAD(); + BrowserProcessHandler_OnContextInitialized(); + // Post browser creation as a separate task so it runs at the outer + // message-loop level, after OnContextInitialized returns. This avoids + // the nested RunLoop that CreateBrowserSync() would otherwise create + // while still inside this callback. + CefPostTask(TID_UI, CefCreateClosureTask( + base::BindOnce(&BrowserProcessHandler_CreatePendingBrowsers))); #if defined(OS_LINUX) print_handler_ = new ClientPrintHandlerGtk(); #endif // OS_LINUX diff --git a/src/window_info.pyx b/src/window_info.pyx index 8d7e9858..8a5211ba 100644 --- a/src/window_info.pyx +++ b/src/window_info.pyx @@ -40,6 +40,8 @@ cdef void SetCefWindowInfo( cefWindowInfo.SetAsChild( windowInfo.parentWindowHandle, windowRect) + # CEF 123+: must request Alloy runtime for native windowed rendering. + cefWindowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY ELIF UNAME_SYSNAME == "Darwin": cefWindowInfo.SetAsChild( windowInfo.parentWindowHandle, @@ -64,6 +66,8 @@ cdef void SetCefWindowInfo( cefWindowInfo.SetAsPopup( windowInfo.parentWindowHandle, windowName) + # CEF 123+: must request Alloy runtime for native windowed rendering. + cefWindowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY if windowInfo.windowType == "offscreen": cefWindowInfo.SetAsWindowless( From 71afdf0d5b592c1f88896d5d8ae29d1c9f53fec8 Mon Sep 17 00:00:00 2001 From: linesight Date: Sat, 18 Apr 2026 21:23:50 -0700 Subject: [PATCH 004/125] CEF 146: update CEF headers, client handlers, and build tools Sync all CEF public headers, capi headers, and internal headers from CEF 146 binary distribution. Includes new headers for task manager, component updater, OSR types, color types, runtime style, and API versioning. Update client handlers (dialog, download, lifespan, request) for CEF 146 API changes. Update cef_types.pxd, network_error.pyx, settings.pyx, and version header for CEF 146. Update build tools (cython_setup.py, build_cpp_projects.py) for the new toolchain. Co-Authored-By: Claude Sonnet 4.6 --- src/client_handler/dialog_handler.cpp | 4 + src/client_handler/dialog_handler.h | 2 + src/client_handler/download_handler.cpp | 3 +- src/client_handler/download_handler.h | 2 +- src/client_handler/lifespan_handler.cpp | 1 + src/client_handler/lifespan_handler.h | 1 + src/client_handler/request_handler.cpp | 4 +- src/client_handler/request_handler.h | 4 +- src/extern/cef/cef_types.pxd | 8 +- src/include/base/cef_bind.h | 120 +- src/include/base/cef_build.h | 23 +- src/include/base/cef_callback.h | 324 +- src/include/base/cef_callback_forward.h | 8 +- src/include/base/cef_callback_helpers.h | 280 +- src/include/base/cef_compiler_specific.h | 625 +- src/include/base/cef_dump_without_crashing.h | 92 + src/include/base/cef_immediate_crash.h | 197 + src/include/base/cef_is_complete.h | 58 + src/include/base/cef_is_instantiation.h | 73 + src/include/base/cef_logging.h | 134 +- src/include/base/cef_platform_thread.h | 7 +- src/include/base/cef_ref_counted.h | 91 +- src/include/base/cef_scoped_refptr.h | 169 +- src/include/base/cef_thread_checker.h | 6 +- src/include/base/cef_to_address.h | 88 + src/include/base/cef_weak_ptr.h | 321 +- src/include/base/internal/README-TRANSFER.txt | 10 +- src/include/base/internal/cef_always_false.h | 59 + src/include/base/internal/cef_bind_internal.h | 1981 +- .../base/internal/cef_callback_internal.h | 245 +- src/include/base/internal/cef_callback_tags.h | 74 + .../base/internal/cef_color_id_macros.inc | 50 + src/include/base/internal/cef_lock_impl.h | 4 +- .../base/internal/cef_net_error_list.h | 252 +- .../base/internal/cef_thread_checker_impl.h | 10 +- .../capi/cef_accessibility_handler_capi.h | 87 + src/include/capi/cef_app_capi.h | 243 + src/include/capi/cef_audio_handler_capi.h | 127 + src/include/capi/cef_auth_callback_capi.h | 82 + src/include/capi/cef_base_capi.h | 99 + src/include/capi/cef_browser_capi.h | 1115 + .../capi/cef_browser_process_handler_capi.h | 182 + src/include/capi/cef_callback_capi.h | 96 + src/include/capi/cef_client_capi.h | 216 + src/include/capi/cef_command_handler_capi.h | 130 + src/include/capi/cef_command_line_capi.h | 230 + src/include/capi/cef_component_updater_capi.h | 200 + .../capi/cef_context_menu_handler_capi.h | 379 + src/include/capi/cef_cookie_capi.h | 211 + src/include/capi/cef_crash_util_capi.h | 158 + .../capi/cef_devtools_message_observer_capi.h | 154 + src/include/capi/cef_dialog_handler_capi.h | 128 + src/include/capi/cef_display_handler_capi.h | 225 + src/include/capi/cef_dom_capi.h | 355 + src/include/capi/cef_download_handler_capi.h | 161 + src/include/capi/cef_download_item_capi.h | 187 + src/include/capi/cef_drag_data_capi.h | 246 + src/include/capi/cef_drag_handler_capi.h | 98 + src/include/capi/cef_file_util_capi.h | 136 + src/include/capi/cef_find_handler_capi.h | 88 + src/include/capi/cef_focus_handler_capi.h | 99 + src/include/capi/cef_frame_capi.h | 268 + src/include/capi/cef_frame_handler_capi.h | 216 + src/include/capi/cef_i18n_util_capi.h | 62 + src/include/capi/cef_image_capi.h | 212 + src/include/capi/cef_jsdialog_handler_capi.h | 149 + src/include/capi/cef_keyboard_handler_capi.h | 96 + src/include/capi/cef_life_span_handler_capi.h | 316 + src/include/capi/cef_load_handler_capi.h | 132 + src/include/capi/cef_media_router_capi.h | 360 + src/include/capi/cef_menu_model_capi.h | 523 + .../capi/cef_menu_model_delegate_capi.h | 129 + src/include/capi/cef_navigation_entry_capi.h | 139 + src/include/capi/cef_origin_whitelist_capi.h | 116 + src/include/capi/cef_parser_capi.h | 188 + src/include/capi/cef_path_util_capi.h | 63 + .../capi/cef_permission_handler_capi.h | 174 + src/include/capi/cef_preference_capi.h | 227 + src/include/capi/cef_print_handler_capi.h | 170 + src/include/capi/cef_print_settings_capi.h | 208 + src/include/capi/cef_process_message_capi.h | 117 + src/include/capi/cef_process_util_capi.h | 69 + src/include/capi/cef_registration_capi.h | 69 + src/include/capi/cef_render_handler_capi.h | 277 + .../capi/cef_render_process_handler_capi.h | 174 + src/include/capi/cef_request_capi.h | 365 + src/include/capi/cef_request_context_capi.h | 399 + .../capi/cef_request_context_handler_capi.h | 114 + src/include/capi/cef_request_handler_capi.h | 297 + src/include/capi/cef_resource_bundle_capi.h | 115 + .../capi/cef_resource_bundle_handler_capi.h | 116 + src/include/capi/cef_resource_handler_capi.h | 220 + .../capi/cef_resource_request_handler_capi.h | 263 + src/include/capi/cef_response_capi.h | 183 + src/include/capi/cef_response_filter_capi.h | 116 + src/include/capi/cef_scheme_capi.h | 148 + src/include/capi/cef_server_capi.h | 336 + .../capi/cef_shared_memory_region_capi.h | 85 + .../cef_shared_process_message_builder_capi.h | 107 + src/include/capi/cef_ssl_info_capi.h | 88 + src/include/capi/cef_ssl_status_capi.h | 101 + src/include/capi/cef_stream_capi.h | 275 + src/include/capi/cef_string_visitor_capi.h | 75 + src/include/capi/cef_task_capi.h | 166 + src/include/capi/cef_task_manager_capi.h | 123 + src/include/capi/cef_thread_capi.h | 123 + src/include/capi/cef_trace_capi.h | 126 + .../cef_unresponsive_process_callback_capi.h | 80 + src/include/capi/cef_urlrequest_capi.h | 219 + src/include/capi/cef_v8_capi.h | 1142 + src/include/capi/cef_values_capi.h | 773 + src/include/capi/cef_waitable_event_capi.h | 123 + src/include/capi/cef_x509_certificate_capi.h | 207 + src/include/capi/cef_xml_reader_capi.h | 280 + src/include/capi/cef_zip_reader_capi.h | 154 + .../capi/test/cef_api_version_test_capi.h | 1251 + src/include/capi/test/cef_test_helpers_capi.h | 85 + src/include/capi/test/cef_test_server_capi.h | 206 + .../capi/test/cef_translator_test_capi.h | 788 + src/include/capi/views/cef_box_layout_capi.h | 94 + .../capi/views/cef_browser_view_capi.h | 136 + .../views/cef_browser_view_delegate_capi.h | 185 + src/include/capi/views/cef_button_capi.h | 110 + .../capi/views/cef_button_delegate_capi.h | 86 + src/include/capi/views/cef_display_capi.h | 186 + src/include/capi/views/cef_fill_layout_capi.h | 71 + .../capi/views/cef_label_button_capi.h | 169 + src/include/capi/views/cef_layout_capi.h | 91 + src/include/capi/views/cef_menu_button_capi.h | 105 + .../views/cef_menu_button_delegate_capi.h | 97 + .../capi/views/cef_overlay_controller_capi.h | 223 + src/include/capi/views/cef_panel_capi.h | 157 + .../capi/views/cef_panel_delegate_capi.h | 71 + src/include/capi/views/cef_scroll_view_capi.h | 118 + src/include/capi/views/cef_textfield_capi.h | 281 + .../capi/views/cef_textfield_delegate_capi.h | 89 + src/include/capi/views/cef_view_capi.h | 442 + .../capi/views/cef_view_delegate_capi.h | 177 + src/include/capi/views/cef_window_capi.h | 439 + .../capi/views/cef_window_delegate_capi.h | 304 + src/include/cef_api_hash.h | 127 +- src/include/cef_api_versions.h | 268 + src/include/cef_app.h | 73 +- src/include/cef_base.h | 13 +- src/include/cef_browser.h | 188 +- src/include/cef_browser_process_handler.h | 15 +- src/include/cef_color_ids.h | 1898 ++ src/include/cef_command_handler.h | 35 +- src/include/cef_command_ids.h | 96 +- src/include/cef_command_line.h | 10 + src/include/cef_component_updater.h | 166 + src/include/cef_config.h | 4 +- src/include/cef_cookie.h | 1 + src/include/cef_dialog_handler.h | 25 +- src/include/cef_display_handler.h | 55 +- src/include/cef_dom.h | 1 + src/include/cef_download_handler.h | 20 +- src/include/cef_download_item.h | 8 + src/include/cef_drag_data.h | 1 + src/include/cef_frame.h | 6 + src/include/cef_frame_handler.h | 88 +- src/include/cef_id_mappers.h | 89 + src/include/cef_life_span_handler.h | 147 +- src/include/cef_media_router.h | 1 + src/include/cef_pack_resources.h | 3412 +- src/include/cef_pack_strings.h | 25615 +++++++++------- src/include/cef_permission_handler.h | 10 +- src/include/cef_preference.h | 64 + src/include/cef_render_handler.h | 19 +- src/include/cef_request.h | 1 + src/include/cef_request_context.h | 164 +- src/include/cef_request_handler.h | 52 +- src/include/cef_resource_bundle.h | 17 +- src/include/cef_resource_bundle_handler.h | 17 +- src/include/cef_response.h | 1 + src/include/cef_sandbox_win.h | 55 +- src/include/cef_server.h | 1 + src/include/cef_ssl_info.h | 1 - src/include/cef_task_manager.h | 109 + .../cef_unresponsive_process_callback.h | 62 + src/include/cef_v8.h | 90 +- src/include/cef_values.h | 1 + src/include/cef_version.h | 49 +- src/include/cef_version_info.h | 154 + src/include/internal/cef_app_win.h | 4 + .../cef_dump_without_crashing_internal.h | 83 + src/include/internal/cef_export.h | 6 +- src/include/internal/cef_string_wrappers.h | 19 + src/include/internal/cef_thread_internal.h | 2 + src/include/internal/cef_time.h | 5 +- src/include/internal/cef_types.h | 913 +- src/include/internal/cef_types_color.h | 59 + src/include/internal/cef_types_component.h | 184 + .../internal/cef_types_content_settings.h | 204 +- src/include/internal/cef_types_osr.h | 121 + src/include/internal/cef_types_win.h | 59 +- src/include/internal/cef_types_wrappers.h | 211 +- src/include/internal/cef_win.h | 18 +- src/include/test/cef_api_version_test.h | 1172 + src/include/test/cef_test_helpers.h | 78 + src/include/test/cef_test_server.h | 185 + src/include/test/cef_translator_test.h | 808 + src/include/views/cef_browser_view.h | 11 +- src/include/views/cef_browser_view_delegate.h | 38 +- src/include/views/cef_display.h | 7 +- src/include/views/cef_view.h | 32 +- src/include/views/cef_view_delegate.h | 21 + src/include/views/cef_window.h | 54 + src/include/views/cef_window_delegate.h | 80 +- .../wrapper/cef_certificate_util_win.h | 151 + src/include/wrapper/cef_library_loader.h | 247 + src/include/wrapper/cef_util_win.h | 65 + src/network_error.pyx | 1 - src/settings.pyx | 9 +- src/version/cef_version_win.h | 77 +- tools/build_cpp_projects.py | 5 +- tools/cython_setup.py | 2 +- 217 files changed, 51213 insertions(+), 15043 deletions(-) create mode 100644 src/include/base/cef_dump_without_crashing.h create mode 100644 src/include/base/cef_immediate_crash.h create mode 100644 src/include/base/cef_is_complete.h create mode 100644 src/include/base/cef_is_instantiation.h create mode 100644 src/include/base/cef_to_address.h create mode 100644 src/include/base/internal/cef_always_false.h create mode 100644 src/include/base/internal/cef_callback_tags.h create mode 100644 src/include/base/internal/cef_color_id_macros.inc create mode 100644 src/include/capi/cef_accessibility_handler_capi.h create mode 100644 src/include/capi/cef_app_capi.h create mode 100644 src/include/capi/cef_audio_handler_capi.h create mode 100644 src/include/capi/cef_auth_callback_capi.h create mode 100644 src/include/capi/cef_base_capi.h create mode 100644 src/include/capi/cef_browser_capi.h create mode 100644 src/include/capi/cef_browser_process_handler_capi.h create mode 100644 src/include/capi/cef_callback_capi.h create mode 100644 src/include/capi/cef_client_capi.h create mode 100644 src/include/capi/cef_command_handler_capi.h create mode 100644 src/include/capi/cef_command_line_capi.h create mode 100644 src/include/capi/cef_component_updater_capi.h create mode 100644 src/include/capi/cef_context_menu_handler_capi.h create mode 100644 src/include/capi/cef_cookie_capi.h create mode 100644 src/include/capi/cef_crash_util_capi.h create mode 100644 src/include/capi/cef_devtools_message_observer_capi.h create mode 100644 src/include/capi/cef_dialog_handler_capi.h create mode 100644 src/include/capi/cef_display_handler_capi.h create mode 100644 src/include/capi/cef_dom_capi.h create mode 100644 src/include/capi/cef_download_handler_capi.h create mode 100644 src/include/capi/cef_download_item_capi.h create mode 100644 src/include/capi/cef_drag_data_capi.h create mode 100644 src/include/capi/cef_drag_handler_capi.h create mode 100644 src/include/capi/cef_file_util_capi.h create mode 100644 src/include/capi/cef_find_handler_capi.h create mode 100644 src/include/capi/cef_focus_handler_capi.h create mode 100644 src/include/capi/cef_frame_capi.h create mode 100644 src/include/capi/cef_frame_handler_capi.h create mode 100644 src/include/capi/cef_i18n_util_capi.h create mode 100644 src/include/capi/cef_image_capi.h create mode 100644 src/include/capi/cef_jsdialog_handler_capi.h create mode 100644 src/include/capi/cef_keyboard_handler_capi.h create mode 100644 src/include/capi/cef_life_span_handler_capi.h create mode 100644 src/include/capi/cef_load_handler_capi.h create mode 100644 src/include/capi/cef_media_router_capi.h create mode 100644 src/include/capi/cef_menu_model_capi.h create mode 100644 src/include/capi/cef_menu_model_delegate_capi.h create mode 100644 src/include/capi/cef_navigation_entry_capi.h create mode 100644 src/include/capi/cef_origin_whitelist_capi.h create mode 100644 src/include/capi/cef_parser_capi.h create mode 100644 src/include/capi/cef_path_util_capi.h create mode 100644 src/include/capi/cef_permission_handler_capi.h create mode 100644 src/include/capi/cef_preference_capi.h create mode 100644 src/include/capi/cef_print_handler_capi.h create mode 100644 src/include/capi/cef_print_settings_capi.h create mode 100644 src/include/capi/cef_process_message_capi.h create mode 100644 src/include/capi/cef_process_util_capi.h create mode 100644 src/include/capi/cef_registration_capi.h create mode 100644 src/include/capi/cef_render_handler_capi.h create mode 100644 src/include/capi/cef_render_process_handler_capi.h create mode 100644 src/include/capi/cef_request_capi.h create mode 100644 src/include/capi/cef_request_context_capi.h create mode 100644 src/include/capi/cef_request_context_handler_capi.h create mode 100644 src/include/capi/cef_request_handler_capi.h create mode 100644 src/include/capi/cef_resource_bundle_capi.h create mode 100644 src/include/capi/cef_resource_bundle_handler_capi.h create mode 100644 src/include/capi/cef_resource_handler_capi.h create mode 100644 src/include/capi/cef_resource_request_handler_capi.h create mode 100644 src/include/capi/cef_response_capi.h create mode 100644 src/include/capi/cef_response_filter_capi.h create mode 100644 src/include/capi/cef_scheme_capi.h create mode 100644 src/include/capi/cef_server_capi.h create mode 100644 src/include/capi/cef_shared_memory_region_capi.h create mode 100644 src/include/capi/cef_shared_process_message_builder_capi.h create mode 100644 src/include/capi/cef_ssl_info_capi.h create mode 100644 src/include/capi/cef_ssl_status_capi.h create mode 100644 src/include/capi/cef_stream_capi.h create mode 100644 src/include/capi/cef_string_visitor_capi.h create mode 100644 src/include/capi/cef_task_capi.h create mode 100644 src/include/capi/cef_task_manager_capi.h create mode 100644 src/include/capi/cef_thread_capi.h create mode 100644 src/include/capi/cef_trace_capi.h create mode 100644 src/include/capi/cef_unresponsive_process_callback_capi.h create mode 100644 src/include/capi/cef_urlrequest_capi.h create mode 100644 src/include/capi/cef_v8_capi.h create mode 100644 src/include/capi/cef_values_capi.h create mode 100644 src/include/capi/cef_waitable_event_capi.h create mode 100644 src/include/capi/cef_x509_certificate_capi.h create mode 100644 src/include/capi/cef_xml_reader_capi.h create mode 100644 src/include/capi/cef_zip_reader_capi.h create mode 100644 src/include/capi/test/cef_api_version_test_capi.h create mode 100644 src/include/capi/test/cef_test_helpers_capi.h create mode 100644 src/include/capi/test/cef_test_server_capi.h create mode 100644 src/include/capi/test/cef_translator_test_capi.h create mode 100644 src/include/capi/views/cef_box_layout_capi.h create mode 100644 src/include/capi/views/cef_browser_view_capi.h create mode 100644 src/include/capi/views/cef_browser_view_delegate_capi.h create mode 100644 src/include/capi/views/cef_button_capi.h create mode 100644 src/include/capi/views/cef_button_delegate_capi.h create mode 100644 src/include/capi/views/cef_display_capi.h create mode 100644 src/include/capi/views/cef_fill_layout_capi.h create mode 100644 src/include/capi/views/cef_label_button_capi.h create mode 100644 src/include/capi/views/cef_layout_capi.h create mode 100644 src/include/capi/views/cef_menu_button_capi.h create mode 100644 src/include/capi/views/cef_menu_button_delegate_capi.h create mode 100644 src/include/capi/views/cef_overlay_controller_capi.h create mode 100644 src/include/capi/views/cef_panel_capi.h create mode 100644 src/include/capi/views/cef_panel_delegate_capi.h create mode 100644 src/include/capi/views/cef_scroll_view_capi.h create mode 100644 src/include/capi/views/cef_textfield_capi.h create mode 100644 src/include/capi/views/cef_textfield_delegate_capi.h create mode 100644 src/include/capi/views/cef_view_capi.h create mode 100644 src/include/capi/views/cef_view_delegate_capi.h create mode 100644 src/include/capi/views/cef_window_capi.h create mode 100644 src/include/capi/views/cef_window_delegate_capi.h create mode 100644 src/include/cef_api_versions.h create mode 100644 src/include/cef_color_ids.h create mode 100644 src/include/cef_component_updater.h create mode 100644 src/include/cef_id_mappers.h create mode 100644 src/include/cef_task_manager.h create mode 100644 src/include/cef_unresponsive_process_callback.h create mode 100644 src/include/cef_version_info.h create mode 100644 src/include/internal/cef_dump_without_crashing_internal.h create mode 100644 src/include/internal/cef_types_color.h create mode 100644 src/include/internal/cef_types_component.h create mode 100644 src/include/internal/cef_types_osr.h create mode 100644 src/include/test/cef_api_version_test.h create mode 100644 src/include/test/cef_test_helpers.h create mode 100644 src/include/test/cef_test_server.h create mode 100644 src/include/test/cef_translator_test.h create mode 100644 src/include/wrapper/cef_certificate_util_win.h create mode 100644 src/include/wrapper/cef_library_loader.h create mode 100644 src/include/wrapper/cef_util_win.h diff --git a/src/client_handler/dialog_handler.cpp b/src/client_handler/dialog_handler.cpp index 6946e4f6..4f711759 100644 --- a/src/client_handler/dialog_handler.cpp +++ b/src/client_handler/dialog_handler.cpp @@ -19,6 +19,8 @@ bool DialogHandler::OnFileDialog(CefRefPtr browser, const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, + const std::vector& accept_extensions, + const std::vector& accept_descriptions, CefRefPtr callback) { #if defined(OS_LINUX) @@ -27,6 +29,8 @@ bool DialogHandler::OnFileDialog(CefRefPtr browser, title, default_file_path, accept_filters, + accept_extensions, + accept_descriptions, callback); #else return false; diff --git a/src/client_handler/dialog_handler.h b/src/client_handler/dialog_handler.h index 2cea565f..1698c47b 100644 --- a/src/client_handler/dialog_handler.h +++ b/src/client_handler/dialog_handler.h @@ -23,6 +23,8 @@ class DialogHandler : public CefDialogHandler const CefString& title, const CefString& default_file_path, const std::vector& accept_filters, + const std::vector& accept_extensions, + const std::vector& accept_descriptions, CefRefPtr callback) override; diff --git a/src/client_handler/download_handler.cpp b/src/client_handler/download_handler.cpp index 9e887e46..ac63a4ee 100644 --- a/src/client_handler/download_handler.cpp +++ b/src/client_handler/download_handler.cpp @@ -6,7 +6,7 @@ #include "include/base/cef_logging.h" -void DownloadHandler::OnBeforeDownload( +bool DownloadHandler::OnBeforeDownload( CefRefPtr browser, CefRefPtr download_item, const CefString& suggested_name, @@ -23,6 +23,7 @@ void DownloadHandler::OnBeforeDownload( LOG(INFO) << "[Browser process] Tried to download file," " but downloads are disabled"; } + return false; } diff --git a/src/client_handler/download_handler.h b/src/client_handler/download_handler.h index e4fc5faf..a64ba17f 100644 --- a/src/client_handler/download_handler.h +++ b/src/client_handler/download_handler.h @@ -12,7 +12,7 @@ class DownloadHandler : public CefDownloadHandler DownloadHandler(){} virtual ~DownloadHandler(){} - void OnBeforeDownload(CefRefPtr browser, + bool OnBeforeDownload(CefRefPtr browser, CefRefPtr download_item, const CefString& suggested_name, CefRefPtr callback diff --git a/src/client_handler/lifespan_handler.cpp b/src/client_handler/lifespan_handler.cpp index d9d6010d..1298a411 100644 --- a/src/client_handler/lifespan_handler.cpp +++ b/src/client_handler/lifespan_handler.cpp @@ -11,6 +11,7 @@ bool LifespanHandler::OnBeforePopup(CefRefPtr browser, CefRefPtr frame, + int popup_id, const CefString& target_url, const CefString& target_frame_name, WindowOpenDisposition target_disposition, diff --git a/src/client_handler/lifespan_handler.h b/src/client_handler/lifespan_handler.h index 6b38d7dd..ddef2bc9 100644 --- a/src/client_handler/lifespan_handler.h +++ b/src/client_handler/lifespan_handler.h @@ -16,6 +16,7 @@ class LifespanHandler : public CefLifeSpanHandler bool OnBeforePopup(CefRefPtr browser, CefRefPtr frame, + int popup_id, const CefString& target_url, const CefString& target_frame_name, WindowOpenDisposition target_disposition, diff --git a/src/client_handler/request_handler.cpp b/src/client_handler/request_handler.cpp index a070a9b7..ef3cfc61 100644 --- a/src/client_handler/request_handler.cpp +++ b/src/client_handler/request_handler.cpp @@ -104,7 +104,9 @@ bool RequestHandler::OnCertificateError( void RequestHandler::OnRenderProcessTerminated(CefRefPtr browser, - cef_termination_status_t status) + cef_termination_status_t status, + int error_code, + const CefString& error_string) { REQUIRE_UI_THREAD(); LOG(ERROR) << "[Browser process] OnRenderProcessTerminated()"; diff --git a/src/client_handler/request_handler.h b/src/client_handler/request_handler.h index 6ce8cde6..0c7abe4a 100644 --- a/src/client_handler/request_handler.h +++ b/src/client_handler/request_handler.h @@ -65,7 +65,9 @@ class RequestHandler : public CefRequestHandler, CefRefPtr callback) override; void OnRenderProcessTerminated(CefRefPtr browser, - cef_termination_status_t status) override; + cef_termination_status_t status, + int error_code, + const CefString& error_string) override; private: IMPLEMENT_REFCOUNTING(RequestHandler); diff --git a/src/extern/cef/cef_types.pxd b/src/extern/cef/cef_types.pxd index e25f601d..9bd0105b 100644 --- a/src/extern/cef/cef_types.pxd +++ b/src/extern/cef/cef_types.pxd @@ -67,17 +67,12 @@ cdef extern from "include/internal/cef_types.h": cef_state_t javascript_close_windows cef_state_t javascript_access_clipboard cef_state_t javascript_dom_paste - cef_state_t plugins - cef_state_t universal_access_from_file_urls - cef_state_t file_access_from_file_urls - cef_state_t web_security cef_state_t image_loading cef_state_t image_shrink_standalone_to_fit cef_state_t text_area_resize cef_state_t tab_to_links cef_state_t local_storage - cef_state_t databases - cef_state_t application_cache + cef_state_t databases_deprecated cef_state_t webgl int windowless_frame_rate @@ -231,7 +226,6 @@ cdef extern from "include/internal/cef_types.h": ERR_ADDRESS_UNREACHABLE = -109, ERR_SSL_CLIENT_AUTH_CERT_NEEDED = -110, ERR_TUNNEL_CONNECTION_FAILED = -111, - ERR_NO_SSL_VERSIONS_ENABLED = -112, ERR_SSL_VERSION_OR_CIPHER_MISMATCH = -113, ERR_SSL_RENEGOTIATION_REQUESTED = -114, ERR_CERT_COMMON_NAME_INVALID = -200, diff --git a/src/include/base/cef_bind.h b/src/include/base/cef_bind.h index e879b569..0d92904d 100644 --- a/src/include/base/cef_bind.h +++ b/src/include/base/cef_bind.h @@ -59,12 +59,6 @@ /// for the full documentation. /// -// Implementation notes -// -// If you're reading the implementation, before proceeding further, you should -// read the top comment of base/internal/cef_bind_internal.h for a definition -// of common terms and concepts. - #ifndef CEF_INCLUDE_BASE_CEF_BIND_H_ #define CEF_INCLUDE_BASE_CEF_BIND_H_ #pragma once @@ -86,9 +80,10 @@ #include "include/base/cef_compiler_specific.h" #include "include/base/internal/cef_bind_internal.h" -#if defined(OS_APPLE) && !HAS_FEATURE(objc_arc) -#include "include/base/internal/cef_scoped_block_mac.h" -#endif +// Implementation notes: +// If you're reading the implementation, before proceeding further, you should +// read the top comment of include/base/internal/cef_bind_internal.h for a +// definition of common terms and concepts. namespace base { @@ -96,65 +91,50 @@ namespace base { /// Bind as OnceCallback. /// template -inline OnceCallback> -BindOnce(Functor&& functor, Args&&... args) { - static_assert(!cef_internal::IsOnceCallback>() || - (std::is_rvalue_reference() && - !std::is_const>()), - "BindOnce requires non-const rvalue for OnceCallback binding." - " I.e.: base::BindOnce(std::move(callback))."); - static_assert( - std::conjunction>...>::value, - "Use std::move() instead of base::Passed() with base::BindOnce()"); - - return cef_internal::BindImpl(std::forward(functor), - std::forward(args)...); +inline auto BindOnce(Functor&& functor, Args&&... args) { + return cef_internal::BindHelper::Bind( + std::forward(functor), std::forward(args)...); } /// /// Bind as RepeatingCallback. /// template -inline RepeatingCallback> -BindRepeating(Functor&& functor, Args&&... args) { - static_assert( - !cef_internal::IsOnceCallback>(), - "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move()."); - - return cef_internal::BindImpl( +inline auto BindRepeating(Functor&& functor, Args&&... args) { + return cef_internal::BindHelper::Bind( std::forward(functor), std::forward(args)...); } -/// -/// Special cases for binding to a base::Callback without extra bound arguments. -/// We CHECK() the validity of callback to guard against null pointers -/// accidentally ending up in posted tasks, causing hard-to-debug crashes. -/// -template -OnceCallback BindOnce(OnceCallback callback) { - CHECK(callback); - return callback; -} - -template -OnceCallback BindOnce(RepeatingCallback callback) { - CHECK(callback); - return callback; -} - -template -RepeatingCallback BindRepeating( - RepeatingCallback callback) { - CHECK(callback); - return callback; -} +// Overloads to allow nicer compile errors when attempting to pass the address +// an overloaded function to `BindOnce()` or `BindRepeating()`. Otherwise, clang +// provides only the error message "no matching function [...] candidate +// template ignored: couldn't infer template argument 'Functor'", with no +// reference to the fact that `&` is being used on an overloaded function. +// +// These overloads to provide better error messages will never be selected +// unless template type deduction fails because of how overload resolution +// works; per [over.ics.rank/2.2]: +// +// When comparing the basic forms of implicit conversion sequences (as defined +// in [over.best.ics]) +// - a standard conversion sequence is a better conversion sequence than a +// user-defined conversion sequence or an ellipsis conversion sequence, and +// - a user-defined conversion sequence is a better conversion sequence than +// an ellipsis conversion sequence. +// +// So these overloads will only be selected as a last resort iff template type +// deduction fails. +BindFailedCheckPreviousErrors BindOnce(...); +BindFailedCheckPreviousErrors BindRepeating(...); /// /// Unretained() allows binding a non-refcounted class, and to disable -/// refcounting on arguments that are refcounted objects. +/// refcounting on arguments that are refcounted. /// -/// EXAMPLE OF Unretained(): +/// CEF simplified: no dangling pointer detection (UnsafeDangling, +/// UnsafeDanglingUntriaged removed). +/// +/// Example of Unretained() usage: /// ///
 ///   class Foo {
@@ -325,8 +305,10 @@ cef_internal::OwnedRefWrapper> OwnedRef(T&& t) {
 /// first via use of enable_if, and the second takes a T* which will not bind to
 /// T&.
 ///
-template ::value>* = nullptr>
+/// DEPRECATED - Do not use in new code. See https://crbug.com/1326449
+///
+template 
+  requires(!std::is_lvalue_reference_v)
 inline cef_internal::PassedWrapper Passed(T&& scoper) {
   return cef_internal::PassedWrapper(std::move(scoper));
 }
@@ -359,30 +341,6 @@ inline cef_internal::IgnoreResultHelper IgnoreResult(T data) {
   return cef_internal::IgnoreResultHelper(std::move(data));
 }
 
-#if defined(OS_APPLE) && !HAS_FEATURE(objc_arc)
-
-///
-/// RetainBlock() is used to adapt an Objective-C block when Automated Reference
-/// Counting (ARC) is disabled. This is unnecessary when ARC is enabled, as the
-/// BindOnce and BindRepeating already support blocks then.
-///
-/// EXAMPLE OF RetainBlock():
-///
-/// 
-///   // Wrap the block and bind it to a callback.
-///   OnceCallback cb =
-///       BindOnce(RetainBlock(^(int n) { NSLog(@"%d", n); }));
-///   std::move(cb).Run(1);  // Logs "1".
-/// 
-/// -template -base::mac::ScopedBlock RetainBlock(R (^block)(Args...)) { - return base::mac::ScopedBlock(block, - base::scoped_policy::RETAIN); -} - -#endif // defined(OS_APPLE) && !HAS_FEATURE(objc_arc) - } // namespace base #endif // !USING_CHROMIUM_INCLUDES diff --git a/src/include/base/cef_build.h b/src/include/base/cef_build.h index 717f05df..7f156f3c 100644 --- a/src/include/base/cef_build.h +++ b/src/include/base/cef_build.h @@ -1,4 +1,5 @@ -// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved. +// Copyright (c) 2011 Marshall A. Greenblatt. Portions copyright (c) 2012 +// Google Inc. All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -69,7 +70,27 @@ #if defined(USING_CHROMIUM_INCLUDES) // When building CEF include the Chromium header directly. #include "build/build_config.h" +#include "cef/libcef/features/features.h" + +// The following #defines are used in cef/include/ headers and CEF client-side +// code. CEF library-side code should use BUILDFLAG checks directly instead of +// these #defines. CEF client-side code will get these #defines from +// cef_config.h so any changes must also be reflected in +// tools/make_config_header.py. + +#if BUILDFLAG(IS_LINUX) +#include "ui/base/ozone_buildflags.h" +#if BUILDFLAG(SUPPORTS_OZONE_X11) +#define CEF_X11 1 +#endif +#endif + #else // !USING_CHROMIUM_INCLUDES + +#if !defined(GENERATING_CEF_API_HASH) +#include "include/cef_config.h" +#endif + // The following is substantially similar to the Chromium implementation. // If the Chromium implementation diverges the below implementation should be // updated to match. diff --git a/src/include/base/cef_callback.h b/src/include/base/cef_callback.h index bcfe4992..3c13ced7 100644 --- a/src/include/base/cef_callback.h +++ b/src/include/base/cef_callback.h @@ -28,6 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/// /// \file /// A callback is similar in concept to a function pointer: it wraps a runnable /// object such as a function, method, lambda, or even another callback, @@ -60,6 +61,7 @@ /// /// See https://chromium.googlesource.com/chromium/src/+/lkgr/docs/callback.md /// for the full documentation. +/// #ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_H_ #define CEF_INCLUDE_BASE_CEF_CALLBACK_H_ @@ -75,41 +77,90 @@ #include +#include +#include + #include "include/base/cef_bind.h" #include "include/base/cef_callback_forward.h" +#include "include/base/cef_compiler_specific.h" #include "include/base/cef_logging.h" #include "include/base/internal/cef_callback_internal.h" +#include "include/base/internal/cef_callback_tags.h" namespace base { +namespace cef_internal { + +template +auto ToDoNothingCallback( + DoNothingCallbackTag::WithBoundArguments t); + +} // namespace cef_internal + template -class OnceCallback : public cef_internal::CallbackBase { +class TRIVIAL_ABI OnceCallback { public: using ResultType = R; using RunType = R(Args...); using PolymorphicInvoke = R (*)(cef_internal::BindStateBase*, cef_internal::PassingType...); + // Constructs a null `OnceCallback`. A null callback has no associated functor + // and cannot be run. constexpr OnceCallback() = default; + // Disallowed to prevent ambiguity. OnceCallback(std::nullptr_t) = delete; - explicit OnceCallback(cef_internal::BindStateBase* bind_state) - : cef_internal::CallbackBase(bind_state) {} - + // `OnceCallback` is not copyable since its bound functor may only run at most + // once. OnceCallback(const OnceCallback&) = delete; OnceCallback& operator=(const OnceCallback&) = delete; + // Subtle: since `this` is marked as TRIVIAL_ABI, the move operations + // must leave the moved-from callback in a trivially destructible state. OnceCallback(OnceCallback&&) noexcept = default; OnceCallback& operator=(OnceCallback&&) noexcept = default; - OnceCallback(RepeatingCallback other) - : cef_internal::CallbackBase(std::move(other)) {} + ~OnceCallback() = default; + // A `OnceCallback` is a strict subset of `RepeatingCallback`'s functionality, + // so allow seamless conversion. + // NOLINTNEXTLINE(google-explicit-constructor) + OnceCallback(RepeatingCallback other) + : holder_(std::move(other.holder_)) {} OnceCallback& operator=(RepeatingCallback other) { - static_cast(*this) = std::move(other); + holder_ = std::move(other.holder_); return *this; } + // Returns true if `this` is non-null and can be `Run()`. + explicit operator bool() const { return !!holder_; } + // Returns true if `this` is null and cannot be `Run()`. + bool is_null() const { return holder_.is_null(); } + + // Returns true if calling `Run()` is a no-op because of cancellation. + // + // - Not thread-safe, i.e. must be called on the same sequence that will + // ultimately `Run()` the callback + // - May not be called on a null callback. + bool IsCancelled() const { return holder_.IsCancelled(); } + + // Subtle version of `IsCancelled()` that allows cancellation state to be + // queried from any sequence. May return true even if the callback has + // actually been cancelled. + // + // Do not use. This is intended for internal //base usage. + // TODO(dcheng): Restrict this since it, in fact, being used outside of its + // originally intended use. + bool MaybeValid() const { return holder_.MaybeValid(); } + + // Resets this to a null state. + REINITIALIZES_AFTER_MOVE void Reset() { holder_.Reset(); } + + // Non-consuming `Run()` is disallowed for `OnceCallback`. R Run(Args... args) const& { static_assert(!sizeof(*this), "OnceCallback::Run() may only be invoked on a non-const " @@ -117,15 +168,21 @@ class OnceCallback : public cef_internal::CallbackBase { NOTREACHED(); } + // Calls the bound functor with any already-bound arguments + `args`. Consumes + // `this`, i.e. `this` becomes null. + // + // May not be called on a null callback. R Run(Args... args) && { + CHECK(!is_null()); + // Move the callback instance into a local variable before the invocation, // that ensures the internal state is cleared after the invocation. // It's not safe to touch |this| after the invocation, since running the // bound function may destroy |this|. - OnceCallback cb = std::move(*this); + cef_internal::BindStateHolder holder = std::move(holder_); PolymorphicInvoke f = - reinterpret_cast(cb.polymorphic_invoke()); - return f(cb.bind_state_.get(), std::forward(args)...); + reinterpret_cast(holder.polymorphic_invoke()); + return f(holder.bind_state().get(), std::forward(args)...); } // Then() returns a new OnceCallback that receives the same arguments as @@ -141,7 +198,7 @@ class OnceCallback : public cef_internal::CallbackBase { template OnceCallback Then(OnceCallback then) && { CHECK(then); - return BindOnce( + return base::BindOnce( cef_internal::ThenHelper< OnceCallback, OnceCallback>::CreateTrampoline(), std::move(*this), std::move(then)); @@ -154,58 +211,166 @@ class OnceCallback : public cef_internal::CallbackBase { OnceCallback Then( RepeatingCallback then) && { CHECK(then); - return BindOnce( + return base::BindOnce( cef_internal::ThenHelper< OnceCallback, RepeatingCallback>::CreateTrampoline(), std::move(*this), std::move(then)); } + + // Internal constructors for various callback helper tag types, e.g. + // `base::DoNothing()`. + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr OnceCallback(cef_internal::NullCallbackTag) : OnceCallback() {} + constexpr OnceCallback& operator=(cef_internal::NullCallbackTag) { + *this = OnceCallback(); + return *this; + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr OnceCallback(cef_internal::NullCallbackTag::WithSignature) + : OnceCallback(cef_internal::NullCallbackTag()) {} + constexpr OnceCallback& operator=( + cef_internal::NullCallbackTag::WithSignature) { + *this = cef_internal::NullCallbackTag(); + return *this; + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr OnceCallback(cef_internal::DoNothingCallbackTag) + requires(std::is_void_v) + : OnceCallback(BindOnce([](Args... args) {})) {} + constexpr OnceCallback& operator=(cef_internal::DoNothingCallbackTag) + requires(std::is_void_v) + { + *this = BindOnce([](Args... args) {}); + return *this; + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr OnceCallback( + cef_internal::DoNothingCallbackTag::WithSignature) + requires(std::is_void_v) + : OnceCallback(cef_internal::DoNothingCallbackTag()) {} + constexpr OnceCallback& operator=( + cef_internal::DoNothingCallbackTag::WithSignature) + requires(std::is_void_v) + { + *this = cef_internal::DoNothingCallbackTag(); + return *this; + } + + template + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr OnceCallback( + cef_internal::DoNothingCallbackTag::WithBoundArguments tag) + requires(std::is_void_v) + : OnceCallback(cef_internal::ToDoNothingCallback( + std::move(tag))) {} + template + constexpr OnceCallback& operator=( + cef_internal::DoNothingCallbackTag::WithBoundArguments tag) + requires(std::is_void_v) + { + *this = cef_internal::ToDoNothingCallback(std::move(tag)); + return *this; + } + + // Internal constructor for `base::BindOnce()`. + explicit OnceCallback(cef_internal::BindStateBase* bind_state) + : holder_(bind_state) {} + + private: + cef_internal::BindStateHolder holder_; }; template -class RepeatingCallback - : public cef_internal::CallbackBaseCopyable { +class TRIVIAL_ABI RepeatingCallback { public: using ResultType = R; using RunType = R(Args...); using PolymorphicInvoke = R (*)(cef_internal::BindStateBase*, cef_internal::PassingType...); + // Constructs a null `RepeatingCallback`. A null callback has no associated + // functor and cannot be run. constexpr RepeatingCallback() = default; + // Disallowed to prevent ambiguity. RepeatingCallback(std::nullptr_t) = delete; - explicit RepeatingCallback(cef_internal::BindStateBase* bind_state) - : cef_internal::CallbackBaseCopyable(bind_state) {} - - // Copyable and movable. + // Unlike a `OnceCallback`, a `RepeatingCallback` may be copied since its + // bound functor may be run more than once. RepeatingCallback(const RepeatingCallback&) = default; RepeatingCallback& operator=(const RepeatingCallback&) = default; + + // Subtle: since `this` is marked as TRIVIAL_ABI, the move operations + // must leave the moved-from callback in a trivially destructible state. RepeatingCallback(RepeatingCallback&&) noexcept = default; RepeatingCallback& operator=(RepeatingCallback&&) noexcept = default; - bool operator==(const RepeatingCallback& other) const { - return EqualsInternal(other); - } + ~RepeatingCallback() = default; - bool operator!=(const RepeatingCallback& other) const { - return !operator==(other); - } + // Returns true if `this` is non-null and can be `Run()`. + explicit operator bool() const { return !!holder_; } + // Returns true if `this` is null and cannot be `Run()`. + bool is_null() const { return holder_.is_null(); } + + // Returns true if calling `Run()` is a no-op because of cancellation. + // + // - Not thread-safe, i.e. must be called on the same sequence that will + // ultimately `Run()` the callback + // - May not be called on a null callback. + bool IsCancelled() const { return holder_.IsCancelled(); } + + // Subtle version of `IsCancelled()` that allows cancellation state to be + // queried from any sequence. May return true even if the callback has + // actually been cancelled. + // + // Do not use. This is intended for internal //base usage. + // TODO(dcheng): Restrict this since it, in fact, being used outside of its + // originally intended use. + bool MaybeValid() const { return holder_.MaybeValid(); } + + // Equality operators: two `RepeatingCallback`'s are equal + friend bool operator==(const RepeatingCallback&, + const RepeatingCallback&) = default; + + // Resets this to null. + REINITIALIZES_AFTER_MOVE void Reset() { holder_.Reset(); } + // Calls the bound functor with any already-bound arguments + `args`. Does not + // consume `this`, i.e. this remains non-null. + // + // May not be called on a null callback. R Run(Args... args) const& { + CHECK(!is_null()); + + // Keep `bind_state` alive at least until after the invocation to ensure all + // bound `Unretained` arguments remain valid. + scoped_refptr bind_state = + holder_.bind_state(); + PolymorphicInvoke f = - reinterpret_cast(this->polymorphic_invoke()); - return f(this->bind_state_.get(), std::forward(args)...); + reinterpret_cast(holder_.polymorphic_invoke()); + return f(bind_state.get(), std::forward(args)...); } + // Calls the bound functor with any already-bound arguments + `args`. Consumes + // `this`, i.e. `this` becomes null. + // + // May not be called on a null callback. R Run(Args... args) && { + CHECK(!holder_.is_null()); + // Move the callback instance into a local variable before the invocation, // that ensures the internal state is cleared after the invocation. // It's not safe to touch |this| after the invocation, since running the // bound function may destroy |this|. - RepeatingCallback cb = std::move(*this); + cef_internal::BindStateHolder holder = std::move(holder_); PolymorphicInvoke f = - reinterpret_cast(cb.polymorphic_invoke()); - return f(std::move(cb).bind_state_.get(), std::forward(args)...); + reinterpret_cast(holder.polymorphic_invoke()); + return f(holder.bind_state().get(), std::forward(args)...); } // Then() returns a new RepeatingCallback that receives the same arguments as @@ -241,8 +406,109 @@ class RepeatingCallback RepeatingCallback>::CreateTrampoline(), std::move(*this), std::move(then)); } + + // Internal constructors for various callback helper tag types, e.g. + // `base::DoNothing()`. + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr RepeatingCallback(cef_internal::NullCallbackTag) + : RepeatingCallback() {} + constexpr RepeatingCallback& operator=(cef_internal::NullCallbackTag) { + *this = RepeatingCallback(); + return *this; + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr RepeatingCallback( + cef_internal::NullCallbackTag::WithSignature) + : RepeatingCallback(cef_internal::NullCallbackTag()) {} + constexpr RepeatingCallback& operator=( + cef_internal::NullCallbackTag::WithSignature) { + *this = cef_internal::NullCallbackTag(); + return *this; + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr RepeatingCallback(cef_internal::DoNothingCallbackTag) + requires(std::is_void_v) + : RepeatingCallback(BindRepeating([](Args... args) {})) {} + constexpr RepeatingCallback& operator=(cef_internal::DoNothingCallbackTag) + requires(std::is_void_v) + { + *this = BindRepeating([](Args... args) {}); + return *this; + } + + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr RepeatingCallback( + cef_internal::DoNothingCallbackTag::WithSignature) + requires(std::is_void_v) + : RepeatingCallback(cef_internal::DoNothingCallbackTag()) {} + constexpr RepeatingCallback& operator=( + cef_internal::DoNothingCallbackTag::WithSignature) + requires(std::is_void_v) + { + *this = cef_internal::DoNothingCallbackTag(); + return *this; + } + + template + // NOLINTNEXTLINE(google-explicit-constructor) + constexpr RepeatingCallback( + cef_internal::DoNothingCallbackTag::WithBoundArguments tag) + requires(std::is_void_v) + : RepeatingCallback(cef_internal::ToDoNothingCallback( + std::move(tag))) {} + template + constexpr RepeatingCallback& operator=( + cef_internal::DoNothingCallbackTag::WithBoundArguments tag) + requires(std::is_void_v) + { + *this = + cef_internal::ToDoNothingCallback(std::move(tag)); + return this; + } + + // Internal constructor for `base::BindRepeating()`. + explicit RepeatingCallback(cef_internal::BindStateBase* bind_state) + : holder_(bind_state) {} + + private: + friend class OnceCallback; + + cef_internal::BindStateHolder holder_; }; +namespace cef_internal { + +// Helper for the `DoNothingWithBoundArgs()` implementation. +// Unlike the other helpers, this cannot be easily moved to callback_internal.h, +// since it depends on `BindOnce()` and `BindRepeating()`. +template +auto ToDoNothingCallback( + DoNothingCallbackTag::WithBoundArguments t) { + return std::apply( + [](auto&&... args) { + if constexpr (is_once) { + return base::BindOnce( + [](TransformToUnwrappedType..., + UnboundArgs...) {}, + std::move(args)...); + } else { + return base::BindRepeating( + [](TransformToUnwrappedType..., + UnboundArgs...) {}, + std::move(args)...); + } + }, + std::move(t.bound_args)); +} + +} // namespace cef_internal + } // namespace base #endif // !USING_CHROMIUM_INCLUDES diff --git a/src/include/base/cef_callback_forward.h b/src/include/base/cef_callback_forward.h index 2d227743..eb49e932 100644 --- a/src/include/base/cef_callback_forward.h +++ b/src/include/base/cef_callback_forward.h @@ -28,8 +28,8 @@ // (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 INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_ -#define INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_ +#ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_ +#define CEF_INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_ #pragma once #if defined(USING_CHROMIUM_INCLUDES) @@ -58,6 +58,6 @@ using RepeatingClosure = RepeatingCallback; } // namespace base -#endif // !!USING_CHROMIUM_INCLUDES +#endif // !USING_CHROMIUM_INCLUDES -#endif // INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_ +#endif // CEF_INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_ diff --git a/src/include/base/cef_callback_helpers.h b/src/include/base/cef_callback_helpers.h index 5e386440..51b10e98 100644 --- a/src/include/base/cef_callback_helpers.h +++ b/src/include/base/cef_callback_helpers.h @@ -47,16 +47,19 @@ #include #include +#include #include #include +#include #include "include/base/cef_bind.h" #include "include/base/cef_callback.h" #include "include/base/cef_logging.h" +#include "include/base/internal/cef_callback_tags.h" namespace base { -namespace internal { +namespace cef_internal { template struct IsBaseCallbackImpl : std::false_type {}; @@ -67,45 +70,17 @@ struct IsBaseCallbackImpl> : std::true_type {}; template struct IsBaseCallbackImpl> : std::true_type {}; -template -struct IsOnceCallbackImpl : std::false_type {}; - -template -struct IsOnceCallbackImpl> : std::true_type {}; - -} // namespace internal +} // namespace cef_internal /// -/// IsBaseCallback::value is true when T is any of the Closure or Callback -/// family of types. +/// IsBaseCallback is satisfied if and only if T is an instantiation of +/// base::OnceCallback or base::RepeatingCallback. /// template -using IsBaseCallback = internal::IsBaseCallbackImpl>; - -/// -/// IsOnceCallback::value is true when T is a OnceClosure or OnceCallback -/// type. -/// -template -using IsOnceCallback = internal::IsOnceCallbackImpl>; - -/// -/// SFINAE friendly enabler allowing to overload methods for both Repeating and -/// OnceCallbacks. -/// -/// Usage: -///
-///   template