From 04fef45ec6de264514ddeb2e8edf8370599a8595 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Thu, 29 Jan 2026 14:47:42 -0500 Subject: [PATCH] Add docs/ converted from Bitbucket Wiki (see #4085) Converts Bitbucket wiki files to cef/docs/ with: - Typewriter_case filenames - Generated TOC - Bitbucket -> GitHub link conversion - Code block language identifiers - Jekyll/GitHub Pages config --- docs/README.md | 34 + docs/_config.yml | 3 + docs/api_versioning.md | 169 ++ docs/architecture.md | 181 ++ docs/automated_build_setup.md | 240 +++ docs/branches_and_building.md | 296 +++ docs/chromium_update.md | 334 +++ docs/contributing_with_git.md | 260 +++ docs/crash_reporting.md | 314 +++ docs/general_usage.md | 1287 ++++++++++++ docs/hands_on_tutorial.md | 2045 +++++++++++++++++++ docs/index.md | 3 + docs/javascript_integration.md | 433 ++++ docs/linking_different_runtime_libraries.md | 47 + docs/master_build_quick_start.md | 389 ++++ docs/sandbox_setup.md | 139 ++ docs/tutorial.md | 264 +++ docs/using_address_sanitizer.md | 196 ++ docs/using_chrome_driver.md | 104 + docs/using_the_capi.md | 1742 ++++++++++++++++ 20 files changed, 8480 insertions(+) create mode 100644 docs/README.md create mode 100644 docs/_config.yml create mode 100644 docs/api_versioning.md create mode 100644 docs/architecture.md create mode 100644 docs/automated_build_setup.md create mode 100644 docs/branches_and_building.md create mode 100644 docs/chromium_update.md create mode 100644 docs/contributing_with_git.md create mode 100644 docs/crash_reporting.md create mode 100644 docs/general_usage.md create mode 100644 docs/hands_on_tutorial.md create mode 100644 docs/index.md create mode 100644 docs/javascript_integration.md create mode 100644 docs/linking_different_runtime_libraries.md create mode 100644 docs/master_build_quick_start.md create mode 100644 docs/sandbox_setup.md create mode 100644 docs/tutorial.md create mode 100644 docs/using_address_sanitizer.md create mode 100644 docs/using_chrome_driver.md create mode 100644 docs/using_the_capi.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..c1ee023cc --- /dev/null +++ b/docs/README.md @@ -0,0 +1,34 @@ +The Chromium Embedded Framework (CEF) is a simple framework for embedding Chromium-based browsers in other applications. Visit the [Project Overview page](https://github.com/chromiumembedded/cef) for more information. + + +*** + +# Wiki Pages + +* [Tutorial](tutorial.md) - Tutorial explaining how to create a simple application using CEF3. +* [Hands On Tutorial](hands_on_tutorial.md) - Step-by-step hands-on tutorial that teaches CEF by progressively modifying the cefsimple example. +* [Master Build Quick Start](master_build_quick_start.md) - Quick-start guide for building the CEF/Chromium master (development) branch. +* [Branches And Building](branches_and_building.md) - Information about CEF branches and instructions for downloading, building and packaging source code. +* [Contributing With Git](contributing_with_git.md) - How to contribute code changes to CEF using Git. +* [General Usage](general_usage.md) - Overview and general usage of CEF3. +* [Java Script Integration](javascript_integration.md) - How to use V8 JavaScript integration in client applications. +* [Architecture](architecture.md) - Overview of the CEF architecture. +* [Api Versioning](api_versioning.md) - Overview and usage of CEF API versioning. +* [Using Chrome Driver](using_chrome_driver.md) - How to use ChromeDriver and Selenium to automate CEF-based applications. +* [Using Address Sanitizer](using_address_sanitizer.md) - How to use AddressSanitizer with CEF-based applications. +* [Using The CAPI](using_the_capi.md) - How to use the C API in your client application. +* [Linking Different Run Time Libraries](linking_different_runtime_libraries.md) - How to link CEF against a different run-time library. +* [BuildingOnDebian7](buildingondebian7.md) - How to build CEF on Debian 7 systems (these instructions are deprecated). +* [Chromium Update](chromium_update.md) - How to update CEF to use the newest Chromium revision. +* [Automated Build Setup](automated_build_setup.md) - How to set up an automated build system for CEF. +* [Crash Reporting](crash_reporting.md) - How to handle crash reporting from CEF-based applications. +* [Sandbox Setup](sandbox_setup.md) - Sandbox usage and requirements for CEF. + +The complete list of CEF Wiki pages is available [here](.). + +# External Links + +* Support Forum - http://www.magpcss.org/ceforum/ +* C++ API Docs - [Stable release docs](https://cef-builds.spotifycdn.com/docs/stable.html) / [Beta release docs](https://cef-builds.spotifycdn.com/docs/beta.html) +* Downloads - https://cef-builds.spotifycdn.com/index.html +* Donations - http://www.magpcss.org/ceforum/donate.php \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..a4ef0b7e2 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,3 @@ +title: CEF Documentation +description: Chromium Embedded Framework documentation +theme: jekyll-theme-minimal diff --git a/docs/api_versioning.md b/docs/api_versioning.md new file mode 100644 index 000000000..383b86af9 --- /dev/null +++ b/docs/api_versioning.md @@ -0,0 +1,169 @@ +This page explains CEF API versioning. + +**Contents** + +- [Overview](#overview) +- [Usage in Pull Requests](#usage-in-pull-requests) +- [Implementation](#implementation) + - [Number Format](#number-format) + - [Macros](#macros) + - [ABI Guidelines](#abi-guidelines) + - [Test Coverage](#test-coverage) + - [Supported Versions](#supported-versions) + +--- + +# Overview + +The CEF library/framework exports an application binary interface (ABI) that is consumed by client applications. Historically this ABI has been unversioned meaning that any change in [CEF major/minor version](branches_and_building.md#version-number-format) would require a recompilation of the client application. Given the long release cycles for many client applications this could mean users being stuck at an old/insecure Chromium version for an extended period of time. + +To address this and related issues we have introduced the concept of CEF API versioning. API versioning allows applications built for one Stable API version to run with all past and future CEF binaries that also support that version (see "Supported Versions" below). + +CEF API versioning has three levels: + +* Legacy API. API that existed prior to 2025 is grandfathered in as Stable API without an explicitly assigned version number. +* Versioned API. Stable API introduced in 2025 and later that is explicitly assigned a version number. +* Experimental API. API introduced in 2025 and later that is explicitly marked as "experimental" (see "Macros" below). + +Stable API is guaranteed to provide back/forward ABI compatibility and a fixed C/C++ API within a specific (supported) range of binary builds. Developers that wish to update CEF/Chromium separately from the client application should select this option by defining `CEF_API_VERSION=XXXYY` in their project configuration (see "Number Format" and "Test Coverage" below). + +Experimental API provides access to additional/experimental functionality on top of the most recent Stable API version but comes with some limitations: + +* It's tied to a specific CEF major/minor version build. +* It doesn't support back/forward ABI compatibility. +* It's excluded (compiled out) when a Stable API version is selected. + +By default, client applications are built with Experimental API enabled (no explicit `CEF_API_VERSION` define). The `CEF_API_VERSION` definition, in combination with certain macros (see "Macros" below), is used to customize the available C/C++ API as seen by the C/C++ compiler. Client applications and libcef_dll_wrapper must be recompiled if the `CEF_API_VERSION` definition changes. + +API versioning does not does not guarantee behavioral compatibility, particularly when moving between major Chromium versions. App developers are advised to perform their own testing before rolling out any particular combination of binaries. + +# Usage in Pull Requests + +Project contributors use [pull requests](contributing_with_git.md#working-with-pull-requests) to propose CEF code changes. Any API changes in pull requests should follow the Implementation guidelines laid out below and use the `CEF_EXPERIMENTAL` placeholder value in C/C++ header files. + +API changes may become Stable (be assigned a version) if explicitly approved by the CEF admin. API approved for Stable can use the `CEF_NEXT` placeholder value instead of `CEF_EXPERIMENTAL` in pull requests. This value will be converted to a specific/new CEF API version by the CEF admin prior to upstream merge (see example [here](https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2587791506)). + +# Implementation + +The CEF library/framework exports a [C API](using_the_capi.md) that isolates the user from the CEF runtime and code base. The libcef_dll_wrapper project, which is distributed in source code form as part of the binary release, wraps this exported C API in a C++ API that is then linked into the client application. The code for this C/C++ API translation layer is automatically generated by the [translator tool](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt). + +At runtime the client application reports the configured `CEF_API_VERSION` to the CEF library/framework via the first call to [cef_api_hash](https://github.com/chromiumembedded/cef/blob/master/include/cef_api_hash.h#L128) (performed internally by libcef_dll_wrapper). This is a global value that modifies the library/framework runtime behavior and cannot be changed after initial configuration. All API surface (enums, structs, etc.) must match the configured API version or otherwise the application will crash with a fatal runtime error. + +Each API version has an associated set of API hashes. The [version_manager.py tool](https://github.com/chromiumembedded/cef/blob/master/tools/version_manager.py#L383) verifies API hashes at build time by reading and parsing all header files that contribute to the exported C API at that particular version. An API hash mismatch may occur during the `cef_create_projects` build step if the exported C API for an existing version has changed in an unexpected/unsupported way. This is considered a fatal build error and should be resolved before proceeding (see example [here](https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2587767028)). + +## Number Format + +The CEF API version number format is `XXXZZ` where: + +* `XXX` is the CEF (and Chromium) major version (e.g. `133`) +* `ZZ` is an incremental number (e.g. `01`, `02`, etc) that gets reset to `00` when the CEF major version changes. This [becomes](branches_and_building.md#version-number-format) the CEF minor version. + +This format is incremental to work with logical operators and based on the [CEF version](branches_and_building.md#version-number-format) at which it was first introduced. New version numbers are generated by the [version_manager.py tool](https://github.com/chromiumembedded/cef/blob/master/tools/version_manager.py#L383) (see "Usage in Pull Requests" above). + +By default, client applications are built with Experimental API enabled (no explicit `CEF_API_VERSION` define). Client applications can select a Stable API version by defining `CEF_API_VERSION=XXXYY` in their project configuration (see "Test Coverage" below). + +## Macros + +Stable and Experimental API is explicitly tagged in C/C++ header files using CEF versioning macros provided by [cef_api_hash.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_api_hash.h#L108). API without explicit tags is considered Legacy API (see "Overview" above). In C++ header files, versioning information is additionally included in CEF metadata (the `/*--cef(...)--*/` comment). Stable API uses a specific version number and Experimental API uses the `CEF_EXPERIMENTAL` placeholder (see "Number Format" above). + +CEF macros (for C/C++ headers) are as follows: + +* `#if CEF_API_ADDED(XXXYY)` surrounds code added in version `XXXYY`. +* `#if CEF_API_REMOVED(XXXYY)` surrounds code removed in version `XXXYY`. +* `#if CEF_API_RANGE(XXXYY, XXXYZ)` surrounds code added in version `XXXYY` and removed in version `XXXYZ`. + +CEF metadata (for classes/methods in C++ headers) is as follows: + +* `added=XXXYY` marks classes/methods added in version `XXXYY`. +* `removed=XXXYY` marks classes/methods removed in version `XXXYY`. +* `added=XXXYY,removed=XXXYZ` marks classes/methods added in version `XXXYY` and removed in version `XXXYZ`. + +For example, a C++ header might contain: + +```cpp +#include "include/cef_api_hash.h" + +/// +/// Client handler. +/// +/*--cef(source=client)--*/ +class CefClientHandler : public virtual CefBaseRefCounted { + public: + // Other method declarations here... + +#if CEF_API_ADDED(13305) + /// + /// Callback when something happens. Added in version 13305. + /// + /*--cef(added=13305)--*/ + virtual void OnSomething() = 0; +#endif +}; +``` + +The new `OnSomething` callback will be available with Experimental API versions and Stable API versions >= `13305`. It will be unavailable (compiled out) client-side with Stable API versions < `13305`. See [cef_api_hash.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_api_hash.h#L108) for additional client-side macros. + +The associated CEF library/framework (libcef) implementation might contain: + +```cpp +#include "cef/libcef/common/api_version_util.h" + +void CefClientImpl::OnSomething() { + if (CEF_API_IS_ADDED(13305)) { + handler->OnSomething(); + } else { + // Default handling + } +} +``` + +All API versions are supported on the library/framework side so it's necessary to check the runtime-configured value. The `CEF_API_IS_ADDED` macro shown above returns true if the configured value is >= `13305`. See [api_version_util.h](https://github.com/chromiumembedded/cef/blob/master/libcef/common/api_version_util.h) for additional libcef-side macros. + +See "Test Coverage" below for additional usage examples. + +## ABI Guidelines + +ABI versioning requires strict guidelines for how API surface is defined and mutated across versions. + +Enums: + +* All enums that might change get a `_NUM_VALUES` value at the end. +* New values are added immediately before `_NUM_VALUES` (except in cases where the value is explicitly set). +* Old/deprecated values are renamed to `_DEPRECATED` (or `_REMOVED`) but not removed. + +Structs: + +* All structs get a `size_t size` member at the beginning. +* New members are added at the end. +* Old/deprecated members are renamed to `_deprecated` (or `_removed`) but not removed. +* Existing members never change type (old may be renamed and new added with the same name). + +Member methods: + +* Return value and parameters never change for existing methods. +* New methods are added at the end of the class. +* Old/deprecated members in the C API struct are given an opaque placeholder pointer type (`uintptr_t`) to preserve binary compatibility (memory layout) with older versions. +* The existing method may be deprecated and a new method added if return value or parameters need to change. C++ naming may use polymorphism (e.g. multiple `OnEvent` with different params) but C API should use numbering (e.g. `on_event` as the original, `on_event[2...N]` or `on_event_[VERSION]` as the replacement). + +Static methods & functions: + +* Return value and parameters never change for existing methods/functions. +* Ordering doesn't matter as these symbols are exported directly from the library/framework. +* The existing method/function may be deprecated and a new method/function added if return value or parameters need to change. C++ naming may use polymorphism (e.g. multiple `CefDoWork` with different params) but C API should use numbering (e.g. `cef_do_work` as the original, `cef_do_work[2...N]` or `cef_do_work_[VERSION]` as the replacement). + +See [cef_types.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_types.h) and "Test Coverage" below for examples. + +## Test Coverage + +Test coverage has been added for API version compatibility. CEF sample apps (cefclient, cefsimple, ceftests) can be built with different Stable API versions as follows (see "Number Format" above): + +* Add `cef_api_version=XXXYY` to `GN_DEFINES` when building CEF/Chromium from source code. +* Add `-D api_version=XXXYY` to the `cmake` command-line when building with a CEF binary distribution. + +API version-related unit tests can be run with `ceftests --gtest_filter=ApiVersionTest.*`. + +Examples of API versioning are available at [include/test/cef_api_version_test.h](https://github.com/chromiumembedded/cef/blob/master/include/test/cef_api_version_test.h) (C++ header), [libcef/common/test/api_version_test_impl.cc](https://github.com/chromiumembedded/cef/blob/master/libcef/common/test/api_version_test_impl.cc) (libcef implementation) and [tests/ceftests/api_version_unittest.cc](https://github.com/chromiumembedded/cef/blob/master/tests/ceftests/api_version_unittest.cc) (client implementation). An explanation of the associated C API headers and C++ wrapper code generated by the [translator tool](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) can be found [here](https://bitbucket.org/chromiumembedded/cef/pull-requests/852#comment-580301235). + +## Supported Versions + +API versioning support was added in M133 (January 2025). Newer CEF versions may occasionally drop support for older API versions (see example [here](https://github.com/chromiumembedded/cef/issues/3836#issuecomment-2483837347)). This may occur on a schedule (e.g. annually), or as a result of incompatible Chromium changes breaking existing APIs in irresolvable ways. When this occurs it will be clearly communicated and likely supported by shared installers. \ No newline at end of file diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 000000000..2e9c6dc56 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,181 @@ +This page provides an overview of the CEF architecture. + +**Contents** + +- [Overview](#overview) +- [Dependencies](#dependencies) +- [Versions](#versions) +- [History](#history) +- [Modern Architecture](#modern-architecture) +- [Common API Usage](#common-api-usage) +- [C Wrapper API](#c-wrapper-api) +- [CEF1 (Discontinued)](#cef1-discontinued) + - [API Usage](#api-usage) + - [Threading Considerations](#threading-considerations) + - [Implementation Details](#implementation-details) +- [CEF2 (Discontinued)](#cef2-discontinued) +- [CEF3](#cef3) + - [API Usage](#api-usage) + - [Process Considerations](#process-considerations) + - [Threading Considerations](#threading-considerations) + - [Implementation Details](#implementation-details) + - [Alloy Runtime Classes](#alloy-runtime-classes) + - [Chrome Runtime Classes](#chrome-runtime-classes) + +--- + +# Overview + +The Chromium Embedded Framework (CEF) is an open source project founded by Marshall Greenblatt in 2008 to develop a Web browser control based on the [Google Chromium](http://www.chromium.org/Home) project. CEF currently supports a range of programming languages and operating systems and can be easily integrated into both new and existing applications. It was designed from the ground up with both performance and ease of use in mind. The base framework includes C and C++ programming interfaces exposed via native libraries that insulate the host application from Chromium and Blink implementation details. It provides close integration between the browser control and the host application, which can optionally control resource loading, navigation, context menus, printing, JavaScript bindings and more, while taking advantage of the same performance and HTML5 technologies available in the Google Chrome Web browser. + +See the project [README.md](https://github.com/chromiumembedded/cef/blob/master/README.md) for additional introductory material. + +# Dependencies + +The CEF project depends on a number of other projects maintained by third parties. The major projects that CEF depends on are: + + * [Chromium](http://www.chromium.org/Home) - Provides general functionality like network stack, threading, message loop, logging and process control needed to create a fully functional Web browser. Implements "platform" code that allows Blink to communicate with V8 and Skia. Many Chromium design documents can be found at http://dev.chromium.org/developers. + * [Blink](https://www.chromium.org/blink) (formerly WebKit) - The rendering implementation used by Chromium. Provides DOM parsing, layout, event handling, rendering and HTML5 JavaScript APIs. Some HTML5 implementations are split between the Blink and Chromium code bases. + * [V8](https://developers.google.com/v8/) - JavaScript engine. + * [Skia](https://skia.org/) - 2D graphics library used for rendering non-accelerated content. More information on how Chromium integrates Skia is available [here](http://www.chromium.org/developers/design-documents/graphics-and-skia). + * [Angle](https://chromium.googlesource.com/angle/angle/+/master/README.md) - 3D graphics translation layer for Windows that converts GLES calls to DirectX. More information about accelerated compositing is available [here](http://dev.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome). + +# Versions + +There have been three versions of CEF to date. + + * CEF1 - Single process implementation using the Chromium WebKit API (now discontinued). + * CEF2 - Multi process implementation built on the Chromium browser (now discontinued). + * CEF3 - Multi process implementation using either the [Chromium Content API](http://www.chromium.org/developers/content-module/content-api) (called the "Alloy runtime") or the complete Chrome UI (called the "Chrome runtime"). + +Only the CEF3 version is currently developed and supported. See the "History" and "Modern Architecture" sections below for background and the [Branches And Building](branches_and_building.md) page for current development information. + +# History + +In 2008, when the CEF project started, Chromium was a monolithic application built on top of Apple's [WebKit](https://webkit.org/) rendering engine. Google maintained an in-tree variant of WebKit (called the [Chromium WebKit API](https://www.youtube.com/watch?v=JFzC_Gx76E8)) that added additional functionality specific to Chromium. The first version of CEF (called CEF1) was implemented on top of this Chromium WebKit API and used the default single-process application model supported by WebKit1 at that time (for more details on CEF1 architecture see the "CEF1" section below). + +Use of the Chromium WebKit API came with some known limitations. For example, that API layer did not support the multi-process model that was the basis for most of Google Chrome's [stability and security advantages](https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/design-documents/multi-process-architecture/index.md). It also lacked many of the UI features that were becoming necessary to support new web platform features (like device selection dialogs, permissions management, etc). We therefore began a new effort, in 2010, to reimplement CEF (called CEF2) on top of the fully-featured but monolithic Chromium browser UI. The lack of internal API boundaries in the Chromium code at that time made it necessary for us to take an "all or nothing" approach. If we could create a CEF browser window based on the complete Chrome UI we would effectively gain access to all of Chrome's capabilities "for free" (for more details on CEF2 architecture see the "CEF2" section below). + +Google began acknowledging the validity of the embedded use case for Chromium in 2010 and started work on new internal API boundaries to make embedding easier. The [Chromium Content API](http://www.chromium.org/developers/content-module/content-api), which encapsulated the multi-process application model and provided stub implementations for most web platform features, reached a development stage in late 2011 where it was a viable option for Chromium embedders like CEF. It still didn't provide all of the features that we might like, but it was a "supported" API layer. We therefore abandoned the CEF2 effort in early 2012 and focused our efforts instead on the Content API as the more viable embedding option. The existing CEF1 API, which was strongly dependent on WebKit1 and the single-process model, could not be directly ported to the Content API. A new CEF API (called CEF3), with substantial breaking API changes and multi-process support, was released in early 2013 (for more details on CEF3 architecture see the "Modern Architecture" and "CEF3" sections below). + +Also in 2013, Google decided to [fork the WebKit project](https://blog.chromium.org/2013/04/blink-rendering-engine-for-chromium.html). After renaming it to Blink they removed many of the API boundaries that had previously existed between Chromium and WebKit and effectively deleted the Chromium WebKit API. The multi-process architecture, which was optional in WebKit1, was now a requirement with Chromium/Blink. CEF1, which depended on the Chromium WebKit API, no longer had a viable future and CEF3 became the only path forward. + +Fast forward another 7 years, to 2020, and the Chromium architecture has again changed substantially. A lot of effort has been spent to define clear architectural layers (sometimes called [components](https://www.chromium.org/developers/design-documents/cookbook/)) in the Chromium/Blink source code. New platforms and new embedders have entered the Chromium ecosystem. And yet, many features desired by CEF users remain stubbornly out of reach in the Chrome UI layer. With this new, more modern, version of Chromium, we decided it was time to revisit our goals from CEF2 and create a new CEF version based on the Chrome UI layer (now called the "Chrome runtime" in CEF3). Continue to the "Modern Architecture" section for details. + +# Modern Architecture + +The modern Chromium code base is composed of architectural layers, with the primary application layers being "content" (for the [Content API](http://www.chromium.org/developers/content-module/content-api)) and "chrome" (for the Chrome UI layer). The "content" layer includes [WebContents](https://source.chromium.org/chromium/chromium/src/+/master:content/public/browser/web_contents.h) as the primary browser object and provides implementations for most of the generic web platform and application/process management functionality. The "chrome" layer includes [Browser](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser.h) as the primary browser object and provides implementations for many advanced features (including datalist/autofill, extensions, gamepad, webhid, webmidi, etc.), along with standard Chrome UI toolbars and dialogs for device selection, user permissions, settings, etc. + +For historical reasons (outlined above), CEF browser windows have been based on the "content" layer WebContents object since the introduction of CEF3 in 2013. Adding support for additional "chrome" layer features in that architecture was a serious effort because it involved careful understanding and cherry-picking of the related functionality from "chrome" code into the CEF code base. Over time we have added dependencies on the "chrome" layer targets to support some features in CEF (such and extensions, PDF viewer and print preview) and to avoid code duplication. As a result, CEF3 binaries in modern times already contained most/all of the code that would be required to launch a stand-alone “chrome” Browser window, but simply lacked the mechanism to do so. + +In 2020 we launched a [new effort](https://github.com/chromiumembedded/cef/issues/2969) to implement the CEF3 API on top of a fully-featured "chrome" Browser window. To be usable in existing CEF3 client applications the "chrome" window needed to support a large subset of CEF3's existing callbacks/intercepts (e.g. loading progress, network requests, etc.), and be inserted into the existing [Views framework](https://www.chromium.org/developers/design-documents/chromeviews/) structure. At the same time, it was necessary to substantially refactor the internal CEF (libcef) code to extract functionality that was common to both the old WebContents-based approach and the new Browser-based approach. As part of this refactoring we renamed the existing "content" layer implementation to the "Alloy runtime" (where Alloy = Chrome + other stuff) and named the new "chrome" layer implementation as the "Chrome runtime". Proceed to the "CEF3" section below for additional feature and implementation details. + +# Common API Usage + +All versions of CEF expose a simple, easy-to-use API designed to insulate users from the underlying Chromium and Blink code complexity. Common usage is as follows: + +1. Initialize CEF by calling CefInitialize(). + +2. Perform work on the UI message loop by calling CefRunMessageLoop() or CefDoMessageLoopWork(). + +3. Create a browser window by calling CreateBrowser() or CreateBrowserSync() and passing in a CefClient instance. + +4. Shut down CEF by calling CefShutdown() before the application exits. + +# C Wrapper API + +The libcef shared library exports a C API that isolates the user from the CEF runtime and code base. The libcef\_dll\_wrapper project, which is distributed in source code form as part of the binary release, wraps this exported C API in a C++ API that is then linked into the client application. The code for this C/C++ API translation layer is automatically generated by the [translator](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) tool. Direct usage of the C API is described on the [Using The CAPI](using_the_capi.md) page. + +# CEF1 (Discontinued) + +CEF1 was the initial version of CEF first released in 2008. It was discontinued in 2013 when Google forked the WebKit project and subsequently deleted the Chromium WebKit API. See the "History" section above for additional details. + +The single process architecture used by CEF1 integrates Chromium and WebKit directly into the client application. Advantages to the single process architecture included reduced memory usage and closer integration with the client application. For example, having the renderer running in the same process allowed JavaScript bindings to synchronously communicate between client code and renderer code. Disadvantages included [reduced performance](https://github.com/chromiumembedded/cef/issues/304) with certain types of accelerated content, [crashes](https://github.com/chromiumembedded/cef/issues/242) due to plugins like Flash running in the same process, and lack of support for application [security and stability features](https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/design-documents/multi-process-architecture/index.md) that required a multi-process architecture. + +## API Usage + +Below is an overview of the main CEF1 interfaces and their uses. Since CEF1 is discontinued we no longer provide detailed usage information. + + * [CefApp](http://magpcss.org/ceforum/apidocs/projects/(default)/CefApp.html) - This interface is passed to CefInitialize() and allows the application to customize global functionality like resource loading and proxy handling. + * [CefClient](http://magpcss.org/ceforum/apidocs/projects/(default)/CefClient.html) - This interface is passed to CefCreateBrowser() or CefCreateBrowserSync() and acts as the connection between an individual CEF browser instance and the client application. Additional interfaces for request handling, display handling, etc. are exposed via this interface. + * [CefBrowser](http://magpcss.org/ceforum/apidocs/projects/(default)/CefBrowser.html) - Exposes capabilities provided by the browser. This includes back/forward navigation, source retrieval, request loading, etc. A single CefBrowser may have one or more child [CefFrame](http://magpcss.org/ceforum/apidocs/projects/(default)/CefFrame.html) objects. + +## Threading Considerations + +CEF1 includes UI, IO and FILE threads. The UI thread creates browser windows and is used for all interaction with WebKit and V8. The IO thread is used for handling schema and network requests. The FILE thread is used for the application cache and other miscellaneous activities. + +When using CEF1 you should keep the following threading considerations in mind: + + * Do not perform blocking operations on the UI thread. This can lead to serious performance issues. + * The UI thread will be the same as the main application thread if CefInitialize() is called with a CefSettings.multi\_threaded\_message\_loop value of false. + * All WebKit and V8 interation must take place on the UI thread. Consequently, some CEF API functions can only be called on the UI thread. Functions that have this limitation will be documented accordingly in the associated CEF header file. + * The [CefPostTask](http://magpcss.org/ceforum/apidocs/projects/(default)/(_globals).html#CefPostTask(CefThreadId,CefRefPtr)) method can be used to post tasks asnychronously between the various threads. + +## Implementation Details + +CEF1 has the following major implementation classes: + + * CefContext - Represents the global CEF context. A single CefContext object is created by CefInitialize() and destroyed by CefShutdown(). + * CefProcess - Used by CefContext to create and manage the CEF threads. + * BrowserWebKitInit - Manages the global WebKit environment as exposed by the Chromium WebKit API. + * WebViewHost - Provides the native window "wrapper" implementation for a WebView. This class extends WebWidgetHost which provides functionality shared in common with popup widgets (like select menus) on some platforms. + * CefBrowserImpl - Implements the CefBrowser interface, creates the WebViewHost and provides the glue code for a single browser instance. + * BrowserWebViewDelegate - Implements the WebKit interfaces that provide communication between CefBrowserImpl and the underlying WebView. + +# CEF2 (Discontinued) + +CEF2 was an effort to reimplement the CEF1 API on top of the Chrome browser UI as it existed in 2010. CEF2 was discontinued when Chromium announced support for the Content API. Information about CEF2 can be found in the "History" section above and [here](http://magpcss.org/ceforum/viewtopic.php?f=10&t=122) on the CEF Forum. + +# CEF3 + +CEF3 has been the recommended and supported version of CEF since January 2013. It uses the same multi process architecture as the Chromium Web browser via either the [Chromium Content API](http://www.chromium.org/developers/content-module/content-api) (called the "Alloy runtime") or the complete Chrome UI (called the "Chrome runtime"). This architecture provides a number of advantages over the single process architecture used by CEF1: + + * Support for multi-process run mode (with related [stability and security advantages](https://chromium.googlesource.com/playground/chromium-org-site/+/refs/heads/main/developers/design-documents/multi-process-architecture/index.md)). + * More code sharing with the Chromium browser. + * Improved performance and less breakage due to use of the "supported" code path. + * Faster access to new features. + +In most cases CEF3 will have the same performance and stability characteristics as the Chromium Web browser. Both the Alloy runtime and the Chrome runtime support modern web platform features and provide the safety/security expected from an up-to-date Chromium-based browser. The Chrome runtime, which was introduced in 2020, adds implementations for many advanced features (including datalist/autofill, extensions, gamepad, webhid, webmidi, etc.), along with standard Chrome UI toolbars and dialogs for device selection, user permissions, settings, etc. At the time of writing, the Chrome runtime requires use of the [Views framework](https://www.chromium.org/developers/design-documents/chromeviews/) in CEF client applications and does not support off-screen rendering. A current list of open issues specific to the Chrome runtime can be found [here](https://github.com/chromiumembedded/cef/issues?q=is%3Aissue+is%3Aopen+label%3Achrome). + +Starting with the M125 release (mid-2024) the Alloy runtime has been [split](https://github.com/chromiumembedded/cef/issues/3681) into separate style and bootstrap components. Both Chrome style and Alloy style browsers/windows can now be created while using the Chrome bootstrap. The Alloy bootstrap has been [removed](https://github.com/chromiumembedded/cef/issues/3685) starting with the M128 release. + +## API Usage + +See the [General Usage](general_usage.md) page for detailed API usage instructions. + +## Process Considerations + +See the [Processes](general_usage.md#processes) section of the [General Usage](general_usage.md) page for details. + +## Threading Considerations + +See the [Threads](general_usage.md#threads) section of the [General Usage](general_usage.md) page for details. + +## Implementation Details + +For an implementation overview see the "Modern Architecture" section above. + +Shared CEF library/runtime classes use the Cef prefix. Classes that implement the Alloy or Chrome runtime use the Alloy or Chrome prefixes respectively. Classes that extend an existing Chrome-prefixed class add the Cef or Alloy suffix, thereby following the existing naming pattern of Chrome-derived classes. + +### Alloy Runtime Classes + +Alloy runtime bootstrap was [removed](https://github.com/chromiumembedded/cef/issues/3685) in M128 (mid-2024) and Alloy runtime style is now supported using the Chrome runtime bootstrap. Alloy runtime style is based on the "content" layer and has the following major implementation classes: + + * [AlloyBrowserHostImpl](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/alloy/alloy_browser_host_impl.h) - Implements the CefBrowser and CefBrowserHost interfaces in the browser process. Provides the glue code and implements interfaces for communicating with the RenderViewHost. + +### Chrome Runtime Classes + +Chrome runtime bootstrap and style is based on the "chrome" layer and has the following major implementation classes: + + * [ChromeMainDelegateCef](https://github.com/chromiumembedded/cef/blob/master/libcef/common/chrome/chrome_main_delegate_cef.h) - Implements the common process bootstrap logic. + * [ChromeContentClientCef](https://github.com/chromiumembedded/cef/blob/master/libcef/common/chrome/chrome_content_client_cef.h) - Implements the Content API callbacks that are common to all processes. + * [CefContext](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/context.h) - Represents the global CEF context in the browser process. A single CefContext object is created by CefInitialize() and destroyed by CefShutdown(). + * [ChromeBrowserMainExtraPartsCef](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h) - Implements the browser process bootstrap logic. + * [ChromeContentBrowserClientCef](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_content_browser_client_cef.h) - Implements the Content API callbacks for the browser process. + * [ChromeBrowserHostImpl](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_browser_host_impl.h) - Implements the CefBrowser and CefBrowserHost interfaces in the browser process. Provides the glue code and implements interfaces for communicating with the RenderViewHost. + * [ChromeContentRendererClientCef](https://github.com/chromiumembedded/cef/blob/master/libcef/renderer/chrome/chrome_content_renderer_client_cef.h) - Implements the Content API callbacks for the render process. + * [CefBrowserImpl](https://github.com/chromiumembedded/cef/blob/master/libcef/renderer/browser_impl.h) - Implements the CefBrowser interface in the render process. Provides the glue code and implements interfaces for communicating with the RenderView. + * [ChromeBrowserDelegate](https://github.com/chromiumembedded/cef/blob/master/libcef/browser/chrome/chrome_browser_delegate.h) - Interface injected into Chrome's [Browser](https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/ui/browser.h) object (via [patch files](https://github.com/chromiumembedded/cef/blob/master/patch/README.txt)) to support callbacks into CEF code. + * [ChromeBrowserFrame](https://github.com/chromiumembedded/cef/blob/ecdfd467f84da9bb6ef57eb4fcb2778fdef5e07a/libcef/browser/chrome/views/chrome_browser_frame.h) - Widget for a Views-hosted Chrome browser. + +An overview of the Chrome Browser object model is also available [here](https://github.com/chromiumembedded/cef/blob/ecdfd467f84da9bb6ef57eb4fcb2778fdef5e07a/libcef/browser/chrome/views/chrome_browser_frame.h). \ No newline at end of file diff --git a/docs/automated_build_setup.md b/docs/automated_build_setup.md new file mode 100644 index 000000000..95c9f009f --- /dev/null +++ b/docs/automated_build_setup.md @@ -0,0 +1,240 @@ +This page describes the setup of an automated build system for CEF. + +**Contents** + +- [Overview](#overview) +- [Services](#services) +- [Execution Steps](#execution-steps) + - [1\. Change Trigger](#1-change-trigger) + - [2\. Platform Builder](#2-platform-builder) + - [3\. Artifact Publisher](#3-artifact-publisher) +- [Platform Build Configurations](#platform-build-configurations) + - [Linux Configuration](#linux-configuration) + - [MacOS Configuration](#macos-configuration) + - [Windows Configuration](#windows-configuration) + +--- + +# Overview + +CEF provides tools for automatically downloading, building and packaging Chromium and CEF source code. These tools are the recommended way of building CEF locally and can also be integrated with an automated build system. Examples of automated build systems for CEF include https://cef-builds.spotifycdn.com/index.html hosted by Spotify. This document outlines how to build a system similar to Spotify's. For general CEF build instructions see the [Branches And Building](branches_and_building.md) page. + +# Services + +An automated build system tracks changes to a CEF branch, automatically builds a new version of CEF when changes are detected, and uploads the resulting artifacts (CEF binary files) to an Internet or Intranet Website. + +The following high-level services are necessary for an automated build system: + +1. Build execution service. Used to perform the CEF automated builds using agents running on different OS platforms. For example, a build system like [TeamCity](http://www.jetbrains.com/teamcity/) or [Jenkins](http://jenkins-ci.org/). +2. Artifact storage service. Used to store artifacts referenced and generated by the build agents. For example, a shared file system or a storage system like [Artifactory](https://www.jfrog.com/artifactory/). +3. Artifact publishing service. Used to publish artifacts for download on the Intranet or Internet. Generally provides some form of distributed caching. For example, a cloud provider like [Amazon S3 + Cloudfront](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/MigrateS3ToCloudFront.html) or [Google Cloud Storage](https://cloud.google.com/storage/). + +Setup of these specific services is outside the scope of this document. However, we will refer to the capabilities of these services in generic terms. + +# Execution Steps + +The reference build system works by executing the following steps in order: + +## 1\. Change Trigger + +Runs automatically at some interval (for example, once daily) to check if a new change has been committed to the CEF repository. The [Bitbucket REST API](https://confluence.atlassian.com/bitbucket/commits-or-commit-resource-389775478.html) exposes an endpoint that can be queried to identify the most recent commit in a branch. For example, this will return the most recent commit for 2785 branch: + +https://api.bitbucket.org/2.0/repositories/chromiumembedded/cef/commit/2785 + +The resulting "hash" value can then be compared to the last successful CEF build version to identify if a new build is required (e.g. a hash value of "1e15b7626244fa6c6455b7a24552664e4cc14fd3" from branch 2785 will match a build artifact file named "cef_binary_3.2785.\*.g1e15b76_\*.tar.bz2"). + +If artifacts are stored on a shared file system then languages like Python can access the file list directly. If artifacts are stored in Artifactory then see the [Artifactory REST API](https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API) documentation for instructions on how to retrieve a directory listing. + +## 2\. Platform Builder + +Initiated by the change trigger when a new commit is detected. A separate platform builder is configured for each supported build platform (linux32, linux64, macosx64, windows32, windows64). It executes a build on that platform and then uploads the resulting build artifact files to the storage service (shared file system, Artifactory, etc.). + +See the "Platform Build Configurations" section below for recommended platform build configurations. + +## 3\. Artifact Publisher + +Initiated by the platform builder upon a successful build. It retrieves the list of build artifact files from the storage service and uses the [cefbuilds](https://github.com/chromiumembedded/cef/blob/master/tools/cefbuilds/) tools to compare against the index.json file generated by the previous run. When changes are detected it uploads the new changes to the publishing service (Amazon S3, GCS, etc.). The new index.json file is then stored for future reference. + +In addition to generating [index.json](https://cef-builds.spotifycdn.com/index.json) files the [cefbuilds](https://github.com/chromiumembedded/cef/blob/master/tools/cefbuilds/) tools can also generate the [index.html](https://cef-builds.spotifycdn.com/index.html) file used by the Spotify builder (provide your own custom branding to cef_html_builder.py via the "branding" parameter). See the cef_json_builder_example.py and cef_html_builder.py files from the cefbuilds directory for sample usage. + +# Platform Build Configurations + +The following configurations are executed by the platform builder step. These are the recommended configurations for externally published artifacts but are not recommended for local builds. See the the [Branches And Building](branches_and_building.md) page for general build instructions. + +These instructions are intended for use with the [currently supported release branches](branches_and_building.md#current-release-branches-supported). This page will be updated as build requirements change. + +Lower-case values between %% (%download_dir%, %cef_branch%, etc.) must be provided by you. + +## Linux Configuration + +**What's Required** + +- Linux Build Requirements as listed on the [Branches And Building](branches_and_building.md#current-release-branches-supported) page. +- At least 16GB of RAM and 200GB of free disk space. + +We recommend building on Linux using a [Docker container](https://www.docker.com/resources/what-container). All architectures can be built using the same Linux container image with a configuration [as shown here](https://magpcss.org/ceforum/viewtopic.php?f=7&t=17776&p=46448#p54107) that utilizes Chromium's [install-build-deps.py](https://source.chromium.org/chromium/chromium/src/+/master:build/install-build-deps.py) script. + +**64-bit Build Commands** + +To build 64-bit CEF with a 64-bit Linux Docker image: + +```sh +export GN_DEFINES="is_official_build=true use_sysroot=true symbol_level=1 is_cfi=false" +export CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --x64-build --with-pgo-profiles +``` + +**ARM Build Commands** + +To build ARM CEF with a 64-bit Linux Docker image: + +```sh +export CEF_INSTALL_SYSROOT=arm +export GN_DEFINES="is_official_build=true use_sysroot=true symbol_level=1 is_cfi=false use_thin_lto=false chrome_pgo_phase=0 use_vaapi=false" +export CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --arm-build +``` + +**ARM64 Build Commands** + +To build ARM64 CEF with a 64-bit Linux Docker image: + +```sh +export CEF_INSTALL_SYSROOT=arm64 +export GN_DEFINES="is_official_build=true use_sysroot=true symbol_level=1 is_cfi=false use_thin_lto=false chrome_pgo_phase=0" +export CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --arm64-build +``` + +## MacOS Configuration + +**What's Required** + +- MacOS Build Requirements as listed on the [Branches And Building](branches_and_building.md#current-release-branches-supported) page. +- At least 16GB of RAM and 200GB of free disk space. + +If Xcode is not installed to the default location then: + +1\. Set the correct location using the `xcodeselect` tool. + +2\. Set the `SDKROOT` environment variable: + +```sh +export SDKROOT=$(xcrun -show-sdk-path -sdk macosx) +``` + +**64-bit Build Commands** + +To build Intel 64-bit CEF on a Intel 64-bit MacOS host system: + +```sh +export GN_DEFINES=is_official_build=true +export CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --x64-build --with-pgo-profiles +``` + +To build Intel 64-bit CEF on a ARM64 MacOS host system: + +```sh +export GN_DEFINES=is_official_build=true +export CEF_ARCHIVE_FORMAT=tar.bz2 +export CEF_ENABLE_AMD64=1 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --x64-build --with-pgo-profiles +``` + +**ARM64 Build Commands** + +ARM64 builds require Xcode 12.2 and CEF branch 4280 or newer. + +To build ARM64 CEF on an ARM64 MacOS host system: + +```sh +export GN_DEFINES=is_official_build=true +export CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --arm64-build --with-pgo-profiles +``` + +To build ARM64 CEF on a Intel 64-bit MacOS host system: + +```sh +export GN_DEFINES=is_official_build=true +export CEF_ARCHIVE_FORMAT=tar.bz2 +export CEF_ENABLE_ARM64=1 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --arm64-build --with-pgo-profiles +``` + +## Windows Configuration + +**What's Required** + +- Visual Studio and Windows SDK versions as listed on the [Branches And Building](branches_and_building.md#current-release-branches-supported) page. +- At least 16GB of RAM and 200GB of free disk space. + +Install the required Visual Studio sub-components by passing the following arguments to the Visual Studio installer: + +```sh +$ PATH_TO_INSTALLER.EXE ^ +--add Microsoft.VisualStudio.Workload.NativeDesktop ^ +--add Microsoft.VisualStudio.Component.VC.ATLMFC ^ +--includeRecommended +``` + +If building for ARM64 install the following additional sub-components: + +```sh +$ PATH_TO_INSTALLER.EXE ^ +--add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^ +--add Microsoft.VisualStudio.Component.VC.MFC.ARM64 ^ +--includeRecommended +``` + +If Visual Studio or Windows SDK is not installed to the default location then set environment variables like the following before executing automate-git.py: + +```sh +set WIN_CUSTOM_TOOLCHAIN=1 +set CEF_VCVARS=none +set GYP_MSVS_OVERRIDE_PATH=%vs_root% +set VS_CRT_ROOT=%vs_crt_root% +set SDK_ROOT=%sdk_root% +set PATH=%sdk_root%\bin\%sdk_version%\x64;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\bin\HostX64\x64;%vs_root%\VC\Redist\MSVC\%vc_redist_version%\x64\%vc_redist_crt%;%vs_root%\SystemCRT;%PATH% +set LIB=%sdk_root%\Lib\%sdk_version\um\%arch%;%sdk_root%\Lib\%sdk_version\ucrt\%arch%;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\lib\%arch%;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\atlmfc\lib\%arch%;%LIB% +set INCLUDE=%sdk_root%\Include\%sdk_version%\um;%sdk_root%\Include\%sdk_version%\ucrt;%sdk_root%\Include\%sdk_version%\shared;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\include;%vs_root%\VC\Tools\MSVC\%vc_tools_version%\atlmfc\include;%INCLUDE% +``` + +The correct `PATH`, `LIB` and `INCLUDE` values for your installation can be determined by running the `vcvarsall.bat` script and passing in the desired architecture and SDK version. + +See comments in [gclient_hook.py](https://github.com/chromiumembedded/cef/blob/2785/tools/gclient_hook.py#L54) for Windows custom toolchain requirements. VS + SDK can be packaged for distribution to build agents using a script like Chromium's [package_from_installed.py](https://source.chromium.org/chromium/chromium/tools/depot_tools/+/main:win_toolchain/package_from_installed.py). + +**32-bit Build Commands** + +To build 32-bit CEF on a 64-bit Windows host system: + +```sh +set GN_DEFINES=is_official_build=true +set GYP_MSVS_VERSION=2022 +set CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --with-pgo-profiles +``` + +**64-bit Build Commands** + +To build 64-bit CEF on a 64-bit Windows host system: + +```sh +set GN_DEFINES=is_official_build=true +set GYP_MSVS_VERSION=2022 +set CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --x64-build --with-pgo-profiles +``` + +**ARM64 Build Commands** + +To build ARM64 CEF on a 64-bit Windows host system: + +```sh +set CEF_ENABLE_ARM64=1 +set GN_DEFINES=is_official_build=true use_thin_lto=false chrome_pgo_phase=0 +set GYP_MSVS_VERSION=2022 +set CEF_ARCHIVE_FORMAT=tar.bz2 +python3 automate-git.py --download-dir=%download_dir% --branch=%cef_branch% --minimal-distrib --client-distrib --force-clean --no-chromium-history --build-target=cefsimple --arm64-build +``` \ No newline at end of file diff --git a/docs/branches_and_building.md b/docs/branches_and_building.md new file mode 100644 index 000000000..02a515ae3 --- /dev/null +++ b/docs/branches_and_building.md @@ -0,0 +1,296 @@ +This page provides information about CEF branches and instructions for downloading, building and packaging source code. + +**Contents** + +- [Background](#background) +- [Development](#development) +- [Release Branches](#release-branches) + - [Version Number Format](#version-number-format) + - [Current Release Branches (Supported)](#current-release-branches-supported) + - [Legacy Release Branches (Unsupported)](#legacy-release-branches-unsupported) +- [Building from Source](#building-from-source) + - [Automated Method](#automated-method) + - [Manual Downloading](#manual-downloading) + - [Manual Building](#manual-building) + - [Manual Packaging](#manual-packaging) + - [Build Notes](#build-notes) + +--- + +# Background + +The CEF project is an extension of the Chromium project hosted at [chromium.org](https://www.chromium.org). CEF maintains development and release branches that track Chromium branches. CEF source code can be built manually or with automated tools. + +# Development + +Ongoing development of CEF occurs in the [CEF master branch](https://github.com/chromiumembedded/cef/tree/master). This location tracks the current [Chromium master branch](https://chromium.googlesource.com/chromium/src.git) and is not recommended for production use. + +Current CEF master branch build requirements are as follows. See the [Master Build Quick Start](master_build_quick_start.md) page for a development build quick-start guide. + +Windows Build Requirements | macOS Build Requirements | Linux Build Requirements | +|:---------------------------|:----------------------------|:-------------------------| +Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | + +The following URLs should be used for downloading development versions of CEF. + + * CEF3 - https://github.com/chromiumembedded/cef/tree/master + +CEF1 is no longer actively developed or supported. See the [CEF1 Retirement Plan](http://magpcss.org/ceforum/viewtopic.php?f=10&t=10647) for details. + +# Release Branches + +CEF branches are created to track each Chromium release milesone (MXX) branch. Users developing applications for production environments are encouraged to use release branches for the following reasons: + + * Binary CEF builds are tied to specific Chromium releases. + * Release versions of CEF/Chromium are better tested and more appropriate for release applications. + * Within a release branch the CEF API is "frozen" and generally only security/bug fixes are applied. + * CEF release branches can include patches to Chromium/Blink source if necessary. + * CEF master development won't interfere with consumer release schedules. + +CEF release branches and associated platform build requirements are described below. + +## Version Number Format + +The CEF version number format was changed in 2019 to include more relevant information and to provide compatibility with the [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html) standard. + +Newer CEF release version numbers have the format "X.Y.Z+gHHHHHHH+chromium-A.B.C.D" where: + +* "X" is the CEF (and Chromium) major version (e.g. 73). +* "Y" is the CEF minor version. It's an incremental number that starts at 0 when a release branch is created and changes only when the CEF C/C++ API changes (see [Api Versioning](api_versioning.md) for details). +* "Z" is the CEF bugfix version. It's 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. +* "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This facilitates lookup of the relevant commit history in Git. +* "A.B.C.D" is the Chromium version (e.g. 73.0.3683.75). + +Older CEF release version numbers have the format X.YYYY.A.gHHHHHHH where: + + * "X" is the CEF major version (e.g. 3). + * "YYYY" is the Chromium branch. + * "A" is an incremental number representing the number of commits in the current branch. This is roughly equivalent to the SVN revision number but on a per-branch basis and assists people in quickly determining the order of builds in the same branch (for bug reports, etc). + * "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This facilitates lookup of the relevant commit history in Git. + +Detailed Chromium and CEF version information is available in the include/cef\_version.h header file which is created during the build process or by loading the “about:version” URL in a CEF-derived application. + +## Current Release Branches (Supported) + +Support for newer branches begins when they enter the Chromium beta channel. Support for older branches ends when they exit the Chromium stable channel. Every sixth branch (starting with M138) proceeds through the long-term support candidate (LTC) and long-term support (LTS) channels after exiting stable. The LTC/LTS channels continue to receive platform-agnostic security fixes for ~8 additional months (details [here](https://github.com/chromiumembedded/cef/issues/3947)). + +The [Spotify automated builder](https://cef-builds.spotifycdn.com/index.html) provides CEF builds for supported branches. Updating CEF branches is currently a manual process so there will likely be a delay between [Chromium release announcements](http://googlechromereleases.blogspot.com/) and the availability of associated CEF builds. See the [Chromium release calendar](https://chromiumdash.appspot.com/schedule) for estimated Chromium release dates and versions. + +| Channel |Release Branch | Version | Branch Date | Last Refresh | Windows Build Requirements | macOS Build Requirements | Linux Build Requirements | +|:--------|:--------------|:--------|:------------|:--------------|:---------------------------|:----------------------------|:-------------------------| +| Beta | [7632](https://github.com/chromiumembedded/cef/tree/7632) | 145 | Jan 2026 | Mar 9, 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| Stable | [7559](https://github.com/chromiumembedded/cef/tree/7559) | 144 | Dec 2025 | Oct 6, 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| LTC | [7204](https://github.com/chromiumembedded/cef/tree/7204) | 138 | Jun 2025 | Apr 21, 2026 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 11.0+ deployment, 15.2+ build system w/ 15.4 base SDK (Xcode 16.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | + +## Legacy Release Branches (Unsupported) + +Legacy CEF builds are available from the [Spotify automated builder](https://cef-builds.spotifycdn.com/index.html) back to 2704 branch. Building legacy branches is not supported. If you choose to build a legacy branch you will need to solve any build errors on your own. + + * Newer legacy branches (within the past year) can often be built using the same tooling as current branches. You will need to (a) manually download depot_tools, (b) sync depot_tools to a revision that existed at the time of the branch, and (c) set the `DEPOT_TOOLS_UPDATE=0` environment variable to keep it from updating automatically. + * Older legacy branches can potentially be built by downloading a CEF source archive at the desired branch from [here](https://github.com/chromiumembedded/cef/tags) and a Chromium source archive at the associated/required version from [here](https://gsdview.appspot.com/chromium-browser-official/), and then combining them to create the required directory structure. + * See the Build Notes section at the end of this page for historical build details. + +| Release Branch | Version | Branch Date | Windows Build Requirements | macOS Build Requirements | Linux Build Requirements | +|:---------------|:--------|:------------|:---------------------------|:----------------------------|:-------------------------| +| [7499](https://github.com/chromiumembedded/cef/tree/7499) | 143 | Nov 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7444](https://github.com/chromiumembedded/cef/tree/7444) | 142 | Oct 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.6+ build system w/ 26.0 base SDK (Xcode 26.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7390](https://github.com/chromiumembedded/cef/tree/7390) | 141 | Sep 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.4654 SDK, Ninja | macOS 12.0+ deployment, 15.3+ build system w/ 15.5 base SDK (Xcode 16.4), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7339](https://github.com/chromiumembedded/cef/tree/7339) | 140 | Aug 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 12.0+ deployment, 15.3+ build system w/ 15.5 base SDK (Xcode 16.4), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7258](https://github.com/chromiumembedded/cef/tree/7258) | 139 | Jul 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 12.0+ deployment, 15.2+ build system w/ 15.4 base SDK (Xcode 16.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7151](https://github.com/chromiumembedded/cef/tree/7151) | 137 | May 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7103](https://github.com/chromiumembedded/cef/tree/7103) | 136 | Apr 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.13.4, Win 10.0.26100.3323 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [7049](https://github.com/chromiumembedded/cef/tree/7049) | 135 | Mar 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6998](https://github.com/chromiumembedded/cef/tree/6998) | 134 | Feb 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6943](https://github.com/chromiumembedded/cef/tree/6943) | 133 | Jan 2025 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6834](https://github.com/chromiumembedded/cef/tree/6834) | 132 | Nov 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6778](https://github.com/chromiumembedded/cef/tree/6778) | 131 | Oct 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 14.5+ build system w/ 15.0 base SDK (Xcode 16.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6723](https://github.com/chromiumembedded/cef/tree/6723) | 130 | Sep 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6668](https://github.com/chromiumembedded/cef/tree/6668) | 129 | Aug 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621.2428 SDK, Ninja | macOS 11.0+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6613](https://github.com/chromiumembedded/cef/tree/6613) | 128 | Jul 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6533](https://github.com/chromiumembedded/cef/tree/6533) | 127 | Jun 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6478](https://github.com/chromiumembedded/cef/tree/6478) | 126 | May 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.9.2, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6422](https://github.com/chromiumembedded/cef/tree/6422) | 125 | Apr 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6367](https://github.com/chromiumembedded/cef/tree/6367) | 124 | Mar 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6312](https://github.com/chromiumembedded/cef/tree/6312) | 123 | Feb 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6261](https://github.com/chromiumembedded/cef/tree/6261) | 122 | Jan 2024 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6167](https://github.com/chromiumembedded/cef/tree/6167) | 121 | Dec 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6099](https://github.com/chromiumembedded/cef/tree/6099) | 120 | Nov 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [6045](https://github.com/chromiumembedded/cef/tree/6045) | 119 | Oct 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.5+ build system w/ 14.0 base SDK (Xcode 15.0), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [5993](https://github.com/chromiumembedded/cef/tree/5993) | 118 | Sep 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [5938](https://github.com/chromiumembedded/cef/tree/5938) | 117 | Aug 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.15+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 20.04+, Debian 10+, Ninja | +| [5845](https://github.com/chromiumembedded/cef/tree/5845) | 116 | Jun 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5790](https://github.com/chromiumembedded/cef/tree/5790) | 115 | May 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 13.0+ build system w/ 13.3 base SDK (Xcode 14.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5735](https://github.com/chromiumembedded/cef/tree/5735) | 114 | Apr 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0-14.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5672](https://github.com/chromiumembedded/cef/tree/5672) | 113 | Mar 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5615](https://github.com/chromiumembedded/cef/tree/5615) | 112 | Feb 2023 | Win 10+ deployment, Win 10+ build system w/ VS2022 17.5+, Win 10.0.22621 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5563](https://github.com/chromiumembedded/cef/tree/5563) | 111 | Jan 2023 | Win 10+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5481](https://github.com/chromiumembedded/cef/tree/5481) | 110 | Dec 2022 | Win 10+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5414](https://github.com/chromiumembedded/cef/tree/5414) | 109 | Nov 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12.5+ build system w/ 13.0 base SDK (Xcode 14.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5359](https://github.com/chromiumembedded/cef/tree/5359) | 108 | Oct 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5304](https://github.com/chromiumembedded/cef/tree/5304) | 107 | Sep 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5249](https://github.com/chromiumembedded/cef/tree/5249) | 106 | Aug 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5195](https://github.com/chromiumembedded/cef/tree/5195) | 105 | Jul 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5112](https://github.com/chromiumembedded/cef/tree/5112) | 104 | Jun 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.13+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5060](https://github.com/chromiumembedded/cef/tree/5060) | 103 | May 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.11+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [5005](https://github.com/chromiumembedded/cef/tree/5005) | 102 | Apr 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.11.13+, Win 10.0.20348 SDK, Ninja | macOS 10.11+ deployment, 12+ build system w/ 12.3 base SDK (Xcode 13.3), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4951](https://github.com/chromiumembedded/cef/tree/4951) | 101 | Mar 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 11.3+ build system w/ 12.1 base SDK (Xcode 13.2.1), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4896](https://github.com/chromiumembedded/cef/tree/4896) | 100 | Feb 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 11.3+ build system w/ 12.1 base SDK (Xcode 13.2.1), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4844](https://github.com/chromiumembedded/cef/tree/4844) | 99 | Jan 2022 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4758](https://github.com/chromiumembedded/cef/tree/4758) | 98 | Dec 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4692](https://github.com/chromiumembedded/cef/tree/4692) | 97 | Nov 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4664](https://github.com/chromiumembedded/cef/tree/4664) | 96 | Oct 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-13.0), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4638](https://github.com/chromiumembedded/cef/tree/4638) | 95 | Sep 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4606](https://github.com/chromiumembedded/cef/tree/4606) | 94 | Aug 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4577](https://github.com/chromiumembedded/cef/tree/4577) | 93 | Jul 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 18.04+, Debian 10+, Ninja | +| [4515](https://github.com/chromiumembedded/cef/tree/4515) | 92 | Jun 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4472](https://github.com/chromiumembedded/cef/tree/4472) | 91 | Apr 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2-12.5), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4430](https://github.com/chromiumembedded/cef/tree/4430) | 90 | Mar 2021 | Win 7+ deployment, Win 10+ build system w/ VS2019 16.8.4+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4389](https://github.com/chromiumembedded/cef/tree/4389) | 89 | Feb 2021 | Win 7+ deployment, Win 10+ build system w/ VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4324](https://github.com/chromiumembedded/cef/tree/4324) | 88 | Dec 2020 | Win 7+ deployment, Win 10+ build system w/ VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.11+ deployment, 10.15.4+ build system w/ 11.0 base SDK (Xcode 12.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4280](https://github.com/chromiumembedded/cef/tree/4280) | 87 | Oct 2020 | Win 7+ deployment, Win 10+ build system w/ VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.10+ deployment, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4240](https://github.com/chromiumembedded/cef/tree/4240) | 86 | Sep 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 16.04+, Debian Sid+, Ninja | +| [4183](https://github.com/chromiumembedded/cef/tree/4183) | 85 | Jul 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.19041 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [4147](https://github.com/chromiumembedded/cef/tree/4147) | 84 | Jun 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [4103](https://github.com/chromiumembedded/cef/tree/4103) | 83 | Apr 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.15, 10.10+ deployment target, 10.14.4+ build system w/ 10.15.1 base SDK (Xcode 11.2), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [4044](https://github.com/chromiumembedded/cef/tree/4044) | 81 | Mar 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3987](https://github.com/chromiumembedded/cef/tree/3987) | 80 | Feb 2020 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3945](https://github.com/chromiumembedded/cef/tree/3945) | 79 | Nov 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3904](https://github.com/chromiumembedded/cef/tree/3904) | 78 | Oct 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3865](https://github.com/chromiumembedded/cef/tree/3865) | 77 | Sep 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.18362 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3809](https://github.com/chromiumembedded/cef/tree/3809) | 76 | Jul 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3770](https://github.com/chromiumembedded/cef/tree/3770) | 75 | Jun 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3729](https://github.com/chromiumembedded/cef/tree/3729) | 74 (CEF 74, 3) | Mar 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.13.2+ build system w/ 10.13+ base SDK (Xcode 9.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3683](https://github.com/chromiumembedded/cef/tree/3683) | 73 (CEF 73, 3) | Feb 2019 | Win 7+, VS2017 15.7.1+, Win 10.0.17134.0 or 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3626](https://github.com/chromiumembedded/cef/tree/3626) | 72 (CEF 3) | Dec 2018 | Win 7+, VS2017 15.7.1+, Win 10.0.17134.0 or 10.0.17763 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3578](https://github.com/chromiumembedded/cef/tree/3578) | 71 (CEF 3) | Oct 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.14, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3538](https://github.com/chromiumembedded/cef/tree/3538) | 70 (CEF 3) | Sep 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3497](https://github.com/chromiumembedded/cef/tree/3497) | 69 (CEF 3) | Jul 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3440](https://github.com/chromiumembedded/cef/tree/3440) | 68 (CEF 3) | Jun 2018 | Win 7+, VS2017 15.7.1+, Win10.0.17134.0 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3396](https://github.com/chromiumembedded/cef/tree/3396) | 67 (CEF 3) | Apr 2018 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3359](https://github.com/chromiumembedded/cef/tree/3359) | 66 (CEF 3) | Mar 2018 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3325](https://github.com/chromiumembedded/cef/tree/3325) | 65 (CEF 3) | Jan 2018 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3282](https://github.com/chromiumembedded/cef/tree/3282) | 64 (CEF 3) | Dec 2017 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3239](https://github.com/chromiumembedded/cef/tree/3239) | 63 (CEF 3) | Oct 2017 | Win 7+, VS2017 15.3.2+, Win10.0.15063.468 SDK, Ninja | macOS 10.10-10.13, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3202](https://github.com/chromiumembedded/cef/tree/3202) | 62 (CEF 3) | Sep 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.10-10.12, 10.10+ deployment target, 10.12+ build system w/ 10.12+ base SDK (Xcode 8.3.2+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3163](https://github.com/chromiumembedded/cef/tree/3163) | 61 (CEF 3) | Jul 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3112](https://github.com/chromiumembedded/cef/tree/3112) | 60 (CEF 3) | Jun 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3071](https://github.com/chromiumembedded/cef/tree/3071) | 59 (CEF 3) | Apr 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Jessie+, Ninja | +| [3029](https://github.com/chromiumembedded/cef/tree/3029) | 58 (CEF 3) | Mar 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 8.3+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2987](https://github.com/chromiumembedded/cef/tree/2987) | 57 (CEF 3) | Jan 2017 | Win 7+, VS2015u3, Win10.0.14393 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2924](https://github.com/chromiumembedded/cef/tree/2924) | 56 (CEF 3) | Nov 2016 | Win 7+, VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.12, 10.9+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2883](https://github.com/chromiumembedded/cef/tree/2883) | 55 (CEF 3) | Oct 2016 | Win 7+, VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.12, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2840](https://github.com/chromiumembedded/cef/tree/2840) | 54 (CEF 3) | Aug 2016 | Win 7+, VS2015u2 or VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.12, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2785](https://github.com/chromiumembedded/cef/tree/2785) | 53 (CEF 3) | Jul 2016 | Win 7+, VS2015u2 or VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.11, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.3.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2743](https://github.com/chromiumembedded/cef/tree/2743) | 52 (CEF 3) | May 2016 | Win 7+, VS2015u2 or VS2015u3, Win10.0.10586 SDK, Ninja | macOS 10.9-10.11, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.1.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2704](https://github.com/chromiumembedded/cef/tree/2704) | 51 (CEF 3) | Apr 2016 | Win 7+, VS2015u2, Win10.0.10586 SDK, Ninja | macOS 10.9-10.11, 10.7+ deployment target, 10.9+ build system w/ 10.10+ base SDK (Xcode 7.1.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2623](https://github.com/chromiumembedded/cef/tree/2623) | 49 (CEF 3) | Jan 2016 | WinXP+, VS2013u4 or VS2015u1 (experimental), Win10 SDK, Ninja | macOS 10.6-10.11, 10.6+ deployment target, 10.7+ build system w/ 10.10+ base SDK (Xcode 7.1.1+), Ninja, 64-bit only | Ubuntu 14.04+, Debian Wheezy+, Ninja | +| [2526](https://github.com/chromiumembedded/cef/tree/2526) | 47 (CEF 3) | Oct 2015 | WinXP+, VS2013u4 or VS2015u1 (experimental), Win8.1 SDK, Ninja | macOS 10.6-10.11, 10.6+ deployment target, 10.10 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [2454](https://github.com/chromiumembedded/cef/tree/2454) | 45 (CEF 3) | Jul 2015 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.10, 10.6+ deployment target, 10.9 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [2357](https://github.com/chromiumembedded/cef/tree/2357) | 43 (CEF 3) | Apr 2015 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.10, 10.6+ deployment target, 10.9 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [2272](https://github.com/chromiumembedded/cef/tree/2272) | 41 (CEF 3) | Jan 2015 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.10, 10.6+ deployment target, 10.9 base SDK, Xcode 6.1, Ninja, 64-bit only | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [2171](https://github.com/chromiumembedded/cef/tree/2171) | 39 (CEF 3) | Oct 2014 | WinXP+, VS2013u4, Win8.1 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [2062](https://github.com/chromiumembedded/cef/tree/2062) | 37 (CEF 3) | Aug 2014 | WinXP+, VS2013, Win8 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [1916](https://github.com/chromiumembedded/cef/tree/1916) | 35 (CEF 3) | Apr 2014 | WinXP+, VS2013, Win8 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [1750](https://github.com/chromiumembedded/cef/tree/1750) | 33 (CEF 3) | Jan 2014 | WinXP+, VS2010-2013, Win8 SDK, Ninja | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [1650](https://github.com/chromiumembedded/cef/tree/1650) | 31 (CEF 3) | Oct 2013 | WinXP+, VS2010-2012, Win8 SDK, Ninja (optional) | macOS 10.6-10.9, 10.6+ SDK, Xcode 5.1.1, Ninja | Ubuntu 12.04+, Debian Wheezy+, Ninja | +| [1547](https://github.com/chromiumembedded/cef/tree/1547) | 29 (CEF 3) | Jul 2013 | WinXP+, VS2010-2012, Win8 SDK, Ninja (optional) | macOS 10.6-10.8, 10.6+ SDK, Xcode 3.2.6-4.x, Ninja (optional) | Ubuntu 12.04+, Debian Squeeze+, Ninja | +| [1453](https://github.com/chromiumembedded/cef/tree/1453) | 27 (CEF 1, 3) | Apr 2013 | WinXP+, VS2010, Win8 SDK, Ninja (optional) | macOS 10.6-10.8, 10.6+ SDK, Xcode 3.2.6-4.x, Ninja (optional) | Ubuntu 12.04+, Debian Squeeze+, Ninja (optional) | +| [1364](https://github.com/chromiumembedded/cef/tree/1364) | 25 (CEF 1, 3) | Jan 2013 | WinXP+, VS2010, Win8 SDK, Ninja (optional) | macOS 10.6-10.8, Xcode 3.2.6-4.x, Ninja (optional) | Ubuntu 12.04+, Debian Squeeze+, Ninja (optional) | +| [1271](https://github.com/chromiumembedded/cef/tree/1271) | 23 (CEF 1, 3) | Oct 2012 | WinXP+, VS2010, Win7 SDK | macOS 10.6-10.8, 10.6+ SDK, Xcode 3.2.6-4.x | Ubuntu 12.04+, Debian Squeeze+ | +| [1180](https://github.com/chromiumembedded/cef/tree/1180) | 21 (CEF 1, 3) | Aug 2012 | WinXP+, VS2010, Win7 SDK | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6-4.x | Ubuntu 12.04+, Debian Squeeze+ | +| [1084](https://github.com/chromiumembedded/cef/tree/1084) | 19 (CEF 1) | Apr 2012 | WinXP+, VS2008, Win7 SDK | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6-4.x | Ubuntu 10.04+, Debian Squeeze+ | +| [1025](https://github.com/chromiumembedded/cef/tree/1025) | 18 (CEF 1) | Feb 2012 | WinXP+, VS2008, Win7 SDK | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6-4.x | Ubuntu 10.04+, Debian Squeeze+ | +| [963](https://github.com/chromiumembedded/cef/tree/963) | 17 (CEF 1) | Dec 2011 | WinXP+, VS2008, Win7 SDK | macOS 10.6-10.7, 10.5+ SDK, Xcode 3.2.6 | Ubuntu 10.04+, Debian Squeeze+ | + +The following URL should be used for downloading release versions of CEF where YYYY is the release branch number. + + * https://github.com/chromiumembedded/cef/tree/YYYY + +Note that 1025 and older branches contain only CEF1 source code and that 1547 and newer branches contain only CEF3 source code. + +# Building from Source + +Building from source code is currently supported on Windows, macOS and Linux platforms. Use of the Automated Method described below is recommended. Building the current CEF/Chromium master branch for local development is described on the [Master Build Quick Start](master_build_quick_start.md) page. Building the current CEF/Chromium stable branch automatically for production use is described on the [Automated Build Setup](automated_build_setup.md#linux-configuration) page. For other branches see the build requirements listed in the “Release Branches” section above and the “Build Notes” section below. + +## Automated Method + +CEF provides tools for automatically downloading, building and packaging Chromium and CEF source code. These tools are the recommended way of building CEF locally and can also be integrated with automated build systems as described on the [Automated Build Setup](automated_build_setup.md) page. See the [Master Build Quick Start](master_build_quick_start.md) page for an example of the recommended workflow for local development builds. + +These steps apply to the Git workflow only. The Git workflow is recommended for all users and supports CEF3 master and newer CEF3 release branches (1750+). + +1\. Download the [automate-git.py script](https://github.com/chromiumembedded/cef/blob/master/tools/automate/automate-git.py). Use the most recent master version of this script even when building release branches. + +2\. On Linux: Chromium requires that certain packages be installed. You can install them by running the [install-build-deps.sh script](master_build_quick_start.md#linux-setup) or by [explicitly running](automated_build_setup.md#linux-configuration) the necessary installation commands. + +3\. Run the automate-git.py script at whatever interval is appropriate (for each CEF commit, once per day, once per week, etc). + +To build master: + +```sh +python /path/to/automate/automate-git.py --download-dir=/path/to/download +``` + +To build a release branch: + +```sh +python /path/to/automate/automate-git.py --download-dir=/path/to/download --branch=2785 +``` + +By default the script will download depot\_tools, Chromium and CEF source code, run Debug and Release builds of CEF, and create a binary distribution package containing the build artifacts in the “/path/to/download/chromium/src/cef/binary\_distrib” directory. Future runs of the script will perform the minimum work necessary (unless otherwise configured using command-line flags). For example, if there are no pending CEF or Chromium updates the script will do nothing. + +If you run the script and CEF or Chromium updates are pending the “/path/to/download/chromium/src/cef” directory will be removed and replaced with a clean copy from “/path/to/download/cef\_(branch)” (specify the `--no-update` command-line flag to disable updates). Make sure to back up any changes that you made in the “/path/to/download/chromium/src/cef” directory before re-running the script. + +The same download directory can be used for building multiple CEF branches (just specify a different `--branch` command-line value). The existing “/path/to/download/chromium/src/out” directory will be moved to “/path/to/download/out\_(previousbranch)” so that the build output from the previous branch is not lost. When you switch back to a previous branch the out directory will be restored to its original location. + +The script will create a 32-bit build on Windows by default. To create a 64-bit build on Windows, macOS or Linux specify the `--x64-build` command-line flag. 32-bit builds on macOS are [no longer supported](https://groups.google.com/a/chromium.org/d/msg/chromium-dev/sdsDCkq_zwo/yep65H8Eg3sJ) starting with 2272 branch so this flag is now required when building 2272+ on that platform. + +If you receive Git errors when moving an existing checkout from one branch to another you can force a clean Chromium Git checkout (specify the `--force-clean` command-line flag) and optionally a clean download of Chromium dependencies (specify the `--force-clean-deps` command-line flag). Any build output that currently exists in the “src/out” directory will be deleted. Re-downloading the Chromium dependencies can take approximately 30 minutes with a reasonably fast internet connection. + +Add the `--help` command-line switch to output a complete list of supported command-line options. + +## Manual Downloading + +See the [Master Build Quick Start](master_build_quick_start.md) page for an example of the recommended developer workflow. + +## Manual Building + +See the [Master Build Quick Start](master_build_quick_start.md) page for an example of the recommended developer workflow. + +## Manual Packaging + +After building both Debug and Release configurations you can use the make\_distrib tool (.bat on Windows, .sh on macOS and Linux) to create a binary distribution. + +```sh +cd /path/to/chromium/src/cef/tools +./make_distrib.sh --ninja-build +``` + +If the process succeeds a binary distribution package will be created in the /path/to/chromium/src/cef/binary\_distrib directory. + +See the [make\_distrib.py](https://github.com/chromiumembedded/cef/blob/master/tools/make_distrib.py) script for additional usage options. + +The resulting binary distribution can then be built using CMake and platform toolchains. See the README.txt file included with the binary distribution for more information. + +## Build Notes + +This section summarizes build-related requirements and options. + + * Building on most platforms will require at least 8GB of system memory. + * [Ninja](https://ninja-build.org/) must be used when building newer CEF/Chromium branches. + * [Clang](https://clang.llvm.org/) is used by default for compiling/linking Chromium/CEF on macOS in all branches, Linux starting in 2063 branch, and Windows starting in 3282 branch. + * [GYP](https://gyp.gsrc.io/docs/UserDocumentation.md) is supported by 2785 branch and older. [GN](http://www.chromium.org/developers/gn-build-configuration) is supported by 2785 branch and newer, and required starting with 2840 branch. Set `CEF_USE_GN=1` to build 2785 branch with GN instead of GYP. + * To perform a 64-bit build on Windows (any branch) or macOS (branch 2171 or older) set `GYP_DEFINES=target_arch=x64` (GYP only) or build the `out/[Debug|Release]_GN_x64` target (GN only). To perform a 32-bit Linux build on a 64-bit Linux system see instructions on the [Automated Build Setup](automated_build_setup.md#linux-configuration) page. + * To perform an “official” build set `GYP_DEFINES=buildtype=Official` (GYP only) or `GN_DEFINES=is_official_build=true` (GN only). This will disable debugging code and enable additional link-time optimizations in Release builds. See instructions on the [Automated Build Setup](automated_build_setup.md) page for additional official build recommendations. + * Windows - + * If multiple versions of Visual Studio are installed on your system you can set the GYP\_MSVS\_VERSION environment variable to create project files for that version. For example, set the value to "2015" for VS2015 or "2017" for VS2017. Check the Chromium documentation for the correct value when using other Visual Studio versions. + * If you wish to use Visual Studio for debugging and compiling in combination with a Ninja build you can set `GYP_GENERATORS=ninja,msvs-ninja` (GYP only) or `GN_ARGUMENTS=--ide=vs2017 --sln=cef --filters=//cef/*` (GN only) to generate both Ninja and VS project files. Visual Studio is supported only for debugging and compiling individual source files -- it will not build whole targets successfully. You must use Ninja when building CEF/Chromium targets. + * For best local developer (non-official debug) build-time performance: + * When using VS2015 set `GN_DEFINES=is_win_fastlink=true` for improved compile and link time (branches <= 3202). + * When using VS2017 or VS2019 set `GN_DEFINES=use_jumbo_build=true` for improved compile and link time (branches <= 4044). + * Component builds are supported by 3202 branch and newer and significantly reduce link time. Add `is_component_build=true` to GN_DEFINES in combination with the above VS-version-specific values. Component builds cannot be used to create a CEF binary distribution. See [issue #1617](https://github.com/chromiumembedded/cef/issues/1617#issuecomment-1464996498) for details. + * macOS - + * The combination of deployment target and base SDK version will determine the platforms supported by the resulting binaries. For proper functioning you must use the versions specified under build requirements for each branch. + * 32-bit builds are no longer supported with 2272 branch and newer. See [here](https://groups.google.com/a/chromium.org/d/msg/chromium-dev/sdsDCkq_zwo/yep65H8Eg3sJ) for the Chromium announcement. + * Linux - + * CEF is developed and tested on the Ubuntu version specified in the "Release Branches" section. It should be possible to build and run CEF on other compatible Linux distributions but this is untested. + * The libgtkglext1-dev package is required in branch 1547 and newer to support the off-screen rendering example in cefclient. This is only a requirement for cefclient and not a requirement for other applications using CEF. \ No newline at end of file diff --git a/docs/chromium_update.md b/docs/chromium_update.md new file mode 100644 index 000000000..dab1f664c --- /dev/null +++ b/docs/chromium_update.md @@ -0,0 +1,334 @@ +This page describes how to update CEF to use the newest Chromium revision. + +**Contents** + +- [Overview](#overview) +- [Recommended workflow](#recommended-workflow) + - [1\. Setup a local developer checkout](#1-setup-a-local-developer-checkout) + - [2\. Check for changes in Chromium's build requirements](#2-check-for-changes-in-chromiums-build-requirements) + - [3\. Start the update](#3-start-the-update) + - [A\. Identify the target Chromium version](#a-identify-the-target-chromium-version) + - [B\. Run CEF's `patch_updater.py` script](#b-run-cefs-patch_updaterpy-script) + - [C\. Identify potentially relevant Chromium changes](#c-identify-potentially-relevant-chromium-changes) + - [D\. Identify problematic patterns in the Chromium source code](#d-identify-problematic-patterns-in-the-chromium-source-code) + - [4\. Build CEF and fix whatever else is broken](#4-build-cef-and-fix-whatever-else-is-broken) + - [5\. Run CEF tests](#5-run-cef-tests) + - [6\. Update the compatible Chromium version](#6-update-the-compatible-chromium-version) + - [7\. Create and submit a PR](#7-create-and-submit-a-pr) + - [8\. Test your changes on other supported platforms](#8-test-your-changes-on-other-supported-platforms) +- [Resolving automate_git.py update failures](#resolving-automate_gitpy-update-failures) +- [Resolving Chromium breakage](#resolving-chromium-breakage) + +--- + +# Overview + +The Chromium developers work very hard to introduce new features and capabilities as quickly as possible. Consequently, projects like CEF that depend on Chromium must also be updated regularly. The update process can be complicated and must be done carefully to avoid introducing new bugs and breakage. Below are the steps to follow when updating CEF to work with a new Chromium revision. + +# Recommended workflow + +## 1\. Setup a local developer checkout + +Setup a local developer checkout of the CEF/Chromium master branch as described on the [Master Build Quick Start](master_build_quick_start.md) page. The standard `automate-git.py` parameters discussed on that page are represented by the `[...]` placeholder in the below examples. + +## 2\. Check for changes in Chromium's build requirements + +Chromium's build requirements change over time. You may need to update your build environment before proceeding. + +* **Windows**: Visual Studio and Windows SDK requirements are listed [here](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/windows_build_instructions.md#Setting-up-Windows) and [here](https://source.chromium.org/chromium/chromium/src/+/main:build/vs_toolchain.py;l=20;bpv=0). Visual Studio bootstrap installers for specific versions can be found [here](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history#fixed-version-bootstrappers). +* **MacOS**: SDK and Xcode version requirements are listed [here](https://source.chromium.org/chromium/chromium/src/+/main:build/config/mac/mac_sdk.gni;l=43?q=mac_sdk_official_version&ss=chromium) and [here](https://source.chromium.org/chromium/chromium/src/+/main:build/mac_toolchain.py;l=44?q=MAC_BINARIES_LABEL&ss=chromium%2Fchromium%2Fsrc). SDK versions can also be mapped to Xcode versions using [this table](https://en.wikipedia.org/wiki/Xcode#Xcode_11.x_-_13.x_(since_SwiftUI_framework)). +* **Linux**: Version and distro requirements are listed [here](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md#System-requirements). Most dependency version issues can be avoided by building with a [sysroot image](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/sysroot.md) by setting `GN_DEFINES=use_sysroot=true`. + +If the build requirements have changed the [MasterBuildQuickStart page](branches_and_building.md#development) will also need to be updated. + +## 3\. Start the update + +### A\. Identify the target Chromium version + +The Chromium [release cycle](https://chromium.googlesource.com/chromium/src/+/master/docs/process/release_cycle.md) utilizes milestone versions (M98, M99, etc.) and [release channels](https://www.chromium.org/getting-involved/dev-channel/) (canary, beta, stable). New milestone versions branch approximately every 4 weeks and begin life in the canary channel. Over the next 4 weeks they progress through the beta and stable channels to reach Chrome's ~3 billion users globally. + +The CEF project has a `master` branch for ongoing development and creates a [release branch](branches_and_building.md#release-branches) that tracks each milestone version. Automated builds are provided for [currently supported](branches_and_building.md#current-release-branches-supported) versions. + +* **CEF master updates** target new milestone versions as they are announced to the chromium-dev mailing list. For example, [this email](https://groups.google.com/a/chromium.org/g/chromium-dev/c/uuVm_MltNY4/m/6GO-cpseAQAJ) was sent for the M100 branch. These versions should have 0 as the last component (e.g. "100.0.4896.0"). Updates are performed manually and usually take around 1 week to complete. The "Branch" date for upcoming milestones can be found on the [Chromium schedule](https://chromiumdash.appspot.com/schedule). +* **CEF beta and stable channel updates** use the version information published [here](https://chromiumdash.appspot.com/releases?platform=Windows). These versions should not have 0 as the last component (e.g. "99.0.4844.45"). Updates are performed automatically in most cases and a PR will be submitted to the public repository if the build succeeds. + +To manually specify the Chromium version and update the checkout of master: + +```sh +python automate-git.py [...] --no-build --fast-update --log-chromium-changes --chromium-checkout=refs/tags/100.0.4896.0 +``` + +To manually specify the Chromium version and update the checkout of an existing release branch: + +```sh +python automate-git.py [...] --no-build --fast-update --force-cef-update --branch=4844 --chromium-checkout=refs/tags/99.0.4844.45 +``` + +### B\. Run CEF's `patch_updater.py` script + +This will update the Chromium patch files in the `patch/patches` directory. If patch files cannot be updated automatically the `automate-git.py` script will fail. + +Claude Code can assist with updating patches. See [tools/claude/README.md](https://github.com/chromiumembedded/cef/blob/master/tools/claude/). + +**If one or more patch files have unresolved conflicts you will get a failure like the following:** + +``` +-------------------------------------------------------------------------------- +!!!! FAILED PATCHES, fix manually and run with --resave +content_2015: + Hunk #4 FAILED at 4220. + 1 out of 5 hunks FAILED -- saving rejects to file content/browser/frame_host/render_frame_host_impl.cc.rej +storage_partition_1973: + Hunk #1 FAILED at 167. + 1 out of 1 hunk FAILED -- saving rejects to file content/browser/shared_worker/shared_worker_service_impl.cc.rej +-------------------------------------------------------------------------------- +``` + +Use a text editor to manually fix the specified files, and then re-run the `patch_updater.py` script: + +```sh +$ cd /path/to/chromium_git/chromium/src/cef/tools +$ python patch_updater.py +``` + +**If a patched file is missing (moved or deleted) you will get a failure like the following:** + +```cpp +--> Reading patch file /path/to/chromium_git/chromium/src/cef/patch/patches/content_mojo_3123.patch +--> Skipping non-existing file /path/to/chromium_git/chromium/src/content/public/browser/document_service_base.h +--> Applying patch to /path/to/chromium_git/chromium/src +(Stripping trailing CRs from patch; use --binary to disable.) +can't find file to patch at input line 5 +... +Skip this patch? [y] +Skipping patch. +2 out of 2 hunks ignored +--> Saving changes to /path/to/chromium_git/chromium/src/cef/patch/patches/content_mojo_3123.patch +Traceback (most recent call last): + File "/path/to/chromium_git/chromium/src/cef/tools/patch_updater.py", line 294, in + raise Exception('Failed to add paths: %s' % result['err']) +Exception: Failed to add paths: fatal: pathspec '/path/to/chromium_git/chromium/src/content/public/browser/document_service_base.h' did not match any files + +``` + +You can use this Git command to discover what happened to the missing Chromium file: + +```sh +$ cd /path/to/chromium_git/chromium/src +$ git log --full-history -1 -- content/public/browser/document_service_base.h +``` + +Once you know the offending Git commit hash you can use the `git show ` command or load `https://crrev.com/` in a web browser to see the contents of the change. Edit the patch file manually in a text editor to fix the paths and then re-run the `patch_updater.py` script as shown above. + +**To create a new patch file use this command:** + +```sh +$ cd /path/to/chromium_git/chromium/src +$ git diff --no-prefix --relative [path1] [path2] > [name].patch +``` + +Copy the resulting `[name].patch` file to the `src/cef/patch/patches` directory and add an appropriate entry to the `src/cef/patch/patch.cfg` file. + +**To add additional files to an existing patch file use this command:** + +```sh +$ cd /path/to/chromium_git/chromium/src/cef/tools +$ python patch_updater.py --resave --patch [name] --add [path1] --add [path2] +``` + +All paths are relative to the `src` directory by default. + +**After all patch files have been fixed you can re-run `automate-git.py` with the additional `--resave` command-line flag to resave the patch files and continue the update process:** + +```sh +python automate-git.py [...] --resave +``` + +### C\. Identify potentially relevant Chromium changes + +This step creates a `chromium_update_changes.diff` file in your download directory that will act as your guide when updating the CEF source code. CEF began life as a customized version of content\_shell and there's still a one-to-one relationship between many of the files. The list of relevant paths is taken from CEF's [CHROMIUM_UPDATE.txt](https://github.com/chromiumembedded/cef/blob/master/CHROMIUM_UPDATE.txt) file. + +### D\. Identify problematic patterns in the Chromium source code + +This step looks for patterns in Chromium src files that may cause issues for CEF. If these patterns are found then the `automate-git.py` script will create a `chromium_update_patterns.txt` file in your download directory and fail with output like the following: + +``` +Evaluating pattern: static_cast( +ERROR Matches found. See chromium_update_changes.diff for output. +``` + +In that case the contents of `chromium_update_patterns.txt` might look like this: + +```text +!!!! WARNING: FOUND PATTERN: static_cast( +New instances in non-test files should be converted to call StoragePartition methods. +See storage_partition_1973.patch. + +content/browser/loader/navigation_url_loader_impl.cc:1295: auto* partition = static_cast(storage_partition); +content/browser/renderer_interface_binders.cc:189: static_cast(host->GetStoragePartition()) +``` + +Use the process described in part B to fix these failures. + +## 4\. Build CEF and fix whatever else is broken + +The diff file created in step C above will assist you in this process. Refer to the [Master Build Quick Start](master_build_quick_start.md) page for build instructions. If Chromium changes are required refer to the "Resolving Chromium breakage" section below. + +Claude Code can assist with fixing compile/build errors. See [tools/claude/README.md](https://github.com/chromiumembedded/cef/blob/master/tools/claude/). + +## 5\. Run CEF tests + +After updating Chromium you should run some tests to verify that everything is working as expected. The tests should eventually be run on all supported platforms. + +A\. The `cefclient` sample application supports various runtime modes that should be tested for startup/shutdown crashes or strange runtime behaviors (on MacOS use `open cefclient.app --args `): + +```sh +# Chrome bootstrap: +$ cefclient + +# Chrome bootstrap + Alloy style: +$ cefclient --use-alloy-style +$ cefclient --use-alloy-style --use-native +$ cefclient --off-screen-rendering-enabled + +# Multi-threaded message loop (Windows/Linux only): +$ cefclient --multi-threaded-message-loop +$ cefclient --use-alloy-style --multi-threaded-message-loop + +# Chrome style + native parent (Windows/Linux only): +$ cefclient --use-native +``` + +B\. Run the various manual tests available via the Tests menu in `cefclient` to verify that everything still works. If any particular subsystem had significant changes (like printing, for example) then make sure to give that subsystem additional testing. + +C\. Unit tests included in the `ceftests` application are expected to pass on all development platforms. + +To run unit tests: +```sh +# Test Chrome style (default) +$ ceftests --use-views + +# Test Alloy style +$ ceftests --use-views --use-alloy-style +``` + +On macOS use `./ceftests.app/Contents/MacOS/ceftests` as the test executable. + +Some tests require synthetic events (mouse/key input, focus/activation, fullscreen, etc), device access, or timing considerations that are known to be flaky on headless/CI systems. To disable these tests during automated test runs add the `--gtest_filter=-[test:...]` command-line argument shown below. + +On Windows: + +``` +:: Disabled tests: +:: - AudioOutputTest.*: Flaky +:: - DisplayTest.AutoResize: Flaky +:: - DisplayTest.Title: Flaky +:: - DraggableRegionsTest.*: Flaky +:: - NavigationTest.History: Flaky +:: - NavigationTest.Load*CtrlLeftClick*: Flaky +:: - NavigationTest.Load*MiddleClick*: Flaky +:: - PdfViewerTest.*: Flaky +:: - ScopedTempDir.TempDir: Flaky +:: - ViewsButtonTest.*Click*: Flaky +:: - ViewsButtonTest.MenuButtonCustomPopup*: Flaky +:: - ViewsTextfieldTest.TextfieldKeyEvent: Flaky +:: - ViewsWindowTest.WindowCreateWithOrigin: Flaky +ceftests --use-views [--use-alloy-style] ^ + --gtest_filter=-AudioOutputTest.*:DisplayTest.AutoResize:DisplayTest.Title:DraggableRegionsTest.*:NavigationTest.History:NavigationTest.Load*CtrlLeftClick*:NavigationTest.Load*MiddleClick*:PdfViewerTest.*:ScopedTempDir.TempDir:ViewsButtonTest.*Click*:ViewsButtonTest.MenuButtonCustomPopup*:ViewsTextfieldTest.TextfieldKeyEvent:ViewsWindowTest.WindowCreateWithOrigin +``` + +On macOS: + +```sh +# Disabled tests: +# - DisplayTest.AutoResize: Flaky +# - ViewsButtonTest.MenuButtonCustomPopupActivate: Flaky +# - ViewsWindowTest.Window*Fullscreen*: Fails/crashes on headless agents +./ceftests.app/Contents/MacOS/ceftests --use-views [--use-alloy-style] \ + --gtest_filter=-DisplayTest.AutoResize:ViewsButtonTest.MenuButtonCustomPopupActivate:ViewsWindowTest.Window\*Fullscreen\* +``` + +On Linux: + +```sh +# Headless agents often run using `xvfb-run`. +xvfb-run -a ceftests --use-views [--use-alloy-style] \ + +# Docker containers may not support the Chromium sandbox. + --no-sandbox \ + +# Docker containers often default to 64MB for /dev/shm, which is far too small for Chromium. +# Run docker with `--shm-size=2g` or add `--disable-dev-shm-usage` to increase available space. + --disable-dev-shm-usage \ + +# Disabled tests: +# - OSRTest.*: Flaky +# - ViewsWindowTest.WindowMaximize*: Flaky +# - ViewsWindowTest.WindowMinimize*: Flaky + --gtest_filter=-OSRTest.*:ViewsWindowTest.WindowMaximize*:ViewsWindowTest.WindowMinimize* +``` + +If automated test runs are slow (tests timing out) you can additionally add `--test-timeout-multiplier=3` for e.g. 3x longer test timeouts. + +## 6\. Update the compatible Chromium version + +Update the compatible Chromium version listed in CEF's [CHROMIUM_BUILD_COMPATIBILITY.txt](https://github.com/chromiumembedded/cef/blob/master/CHROMIUM_BUILD_COMPATIBILITY.txt) file. + +## 7\. Create and submit a PR + +Create a commit with your changes and submit a PR as described on the [Contributing With Git](contributing_with_git.md) page. See the [CEF commit history](https://github.com/chromiumembedded/cef/commits/master) for examples of the expected commit message format. + +## 8\. Test your changes on other supported platforms + +You can update, build and run tests automatically on those platforms with the following command: + +```sh +python automate-git.py [...] --run-tests --build-failure-limit=1000 --fast-update --force-cef-update +``` + +If running in headless mode on Linux install the `xvfb` package and add the `--test-prefix=xvfb-run --test-args="--no-sandbox"` command-line flags. + +Access to automated builders as described on the [Automated Build Setup](automated_build_setup.md) page is recommended for this step. + +# Resolving automate_git.py update failures + +The automate_git.py script can sometimes fail to update an existing Chromium checkout due to errors while running Chromium tooling (git, gclient, etc). When that occurs you can perform the update steps manually. + +The following example assumes the usual [file structure](master_build_quick_start.md#file-structure) with `path/to/chromium_git` as your existing automate_git.py download directory. + +```sh +# Check out the required Chromium version. +$ cd path/to/chromium_git/chromium/src +$ git checkout refs/tags/100.0.4896.0 + +# Copy the `cef` directory to `chromium/src/cef` if it doesn't already exist. +$ cd path/to/chromium_git +$ cp -R cef chromium/src/ + +# Windows only. Apply the patch for `runhooks`. +$ cd path/to/chromium_git/chromium/src/cef/tools +$ python patch_updater.py --reapply --patch runhooks + +# Windows only. Don't expect VS to be installed via depot_tools. +$ set DEPOT_TOOLS_WIN_TOOLCHAIN=0 + +# Update Chromium third_party dependencies and execute runhooks. +$ cd path/to/chromium_git/chromium/src +$ gclient sync --with_branch_heads +``` + +You can then run `cef_create_projects.[bat|sh]` and `ninja` to build CEF in the usual way. + +# Resolving Chromium breakage + +In most cases (say, 90% of the time) any code breakage will be due to naming changes, minor code reorganization and/or project name/location changes. The remaining 10% can require pretty significant changes to CEF, usually due to the ongoing refactoring in Chromium code. If you identify a change to Chromium that has broken a required feature for CEF, and you can't work around the breakage by making reasonable changes to CEF, then you should work with the Chromium team to resolve the problem. + +1\. Identify the specific Chromium revision that broke the feature and make sure you understand why the change was made. + +2\. Post a message to the chromium-dev mailing list explaining why the change broke CEF and either seeking additional information or suggesting a fix that works for both CEF and Chromium. + +3\. After feedback from the Chromium developers create an issue in the [Chromium issue tracker](https://crbug.com) and a [code review](http://www.chromium.org/developers/contributing-code) with the fix and publish it with the appropriate (responsible) developer(s) as reviewers. + +4\. Follow through with the Chromium developer(s) to get the code review committed. + +The CEF build currently contains a patch capability that should be used only as a last resort or as a stop-gap measure if you expect the code review to take a while. The best course of action is always to get your Chromium changes accepted into the Chromium trunk if possible. \ No newline at end of file diff --git a/docs/contributing_with_git.md b/docs/contributing_with_git.md new file mode 100644 index 000000000..6dd58e9cc --- /dev/null +++ b/docs/contributing_with_git.md @@ -0,0 +1,260 @@ +This page provides information about using Git to contribute code changes to CEF. + +**Contents** + +- [Overview](#overview) +- [Initial Setup](#initial-setup) +- [Working With Private Changes](#working-with-private-changes) + - [Creating a Branch](#creating-a-branch) + - [Creating a Commit](#creating-a-commit) + - [Modifying a Commit](#modifying-a-commit) + - [Rebasing on Upstream Changes](#rebasing-on-upstream-changes) + - [Deleting a Branch](#deleting-a-branch) + - [Cleaning a Checkout](#cleaning-a-checkout) +- [Working With Pull Requests](#working-with-pull-requests) + - [Coding Style](#coding-style) + - [Creating a Pull Request](#creating-a-pull-request) + - [Reviewing a Pull Request](#reviewing-a-pull-request) +- [Contributing to the Wiki](#contributing-to-the-wiki) + +--- + +# Overview + +The CEF project uses the Git source code management system hosted via GitHub. The easiest way to contribute changes to CEF is by creating your own personal fork of the CEF Git repository and submitting pull requests with your proposed modifications. This document is intended as a quick-start guide for developers who already have some familiarity with Git. If you are completely new to Git you might want to review the series of [Git tutorials](https://docs.github.com/en/get-started/getting-started-with-git) provided by GitHub. + +# Initial Setup + +Git can maintain your changes both locally and on a remote server. To work with Git efficiently the remote server locations must be configured properly. + +1\. Log into GitHub and create a public forked version of the cef.git repository using the Fork button at https://github.com/chromiumembedded/cef. This public linked fork will be used to create and submit pull requests. + +2\. Optionally, create a private unlinked fork using git commands directly. This private fork can be used for day-to-day development without exposing your work publicly. + +3\. Check out CEF/Chromium source code as described on the [Master Build Quick Start](master_build_quick_start.md) or [Branches And Building](branches_and_building.md) page. Note that if you use the automate-git.py tool you will want to back up your customized CEF checkout before changing branches or performing a clean build. + +4\. Change the remote origin of the CEF checkout so that it points to your private forked repository. This is the remote server location that the `git push` and `git pull` commands will operate on by default. + +```sh +cd /path/to/chromium/src/cef + +# Replace with your GitHub user name. +# If you don't have a private fork, point origin to your public fork instead. +git remote set-url origin https://@github.com//cef_private.git +``` + +5\. Add the remote public location pointing to your public forked repository. This is used to push branches for pull request submission. + +```sh +# Replace with your GitHub user name. +git remote add public https://@github.com//cef.git +``` + +6\. Set the remote upstream of the CEF checkout so that you can merge changes from the main CEF repository. + +```sh +git remote add upstream https://github.com/chromiumembedded/cef.git +``` + +7\. Verify that the remotes are configured correctly. + +```sh +git remote -v +``` + +You should see output like the following: + +```cpp +origin https://@github.com//cef_private.git (fetch) +origin https://@github.com//cef_private.git (push) +public https://@github.com//cef.git (fetch) +public https://@github.com//cef.git (push) +upstream https://github.com/chromiumembedded/cef.git (fetch) +upstream https://github.com/chromiumembedded/cef.git (push) +``` + +8\. Configure your name and email address. + +```sh +git config user.name "User Name" +git config user.email user@example.com +``` + +9\. Configure the correct handling of line endings in the repository. + +```sh +# Use this value on all platforms. Files will be unchanged in the working +# directory and converted to LF line endings in the object database. +git config core.autocrlf input + +# Cause Git to abort actions on files with mixed line endings if the change is +# not reversible (e.g. changes to binary files that are accidentally classified +# as text). +git config core.safecrlf true +``` + +# Working With Private Changes + +You can now commit changes to your personal repository and merge upstream changes from the main CEF repository. To facilitate creation of a pull request or the sharing of your code changes with other developers you should make your changes in a branch. Use `git push origin` to push changes to your private fork for day-to-day development, and `git push public` when you're ready to submit a pull request. + +## Creating a Branch + +Create a new personal branch for your changes. + +```sh +# Start with the branch that your changes will be based upon. +git checkout master + +# Create a new personal branch for your changes. +# Replace with your new branch name. +git checkout -b +``` + +## Creating a Commit + +After making local modifications you can commit them to your personal branch. + +```sh +# For example, add a specified file by path. +git add path/to/file.txt + +# For example, add all existing files that have been modified or deleted. +git add -u + +# Commit the modifications locally. +git commit -m "A good description of the fix (issue #1234)" + +# Push the modifications to your personal remote repository. +git push origin +``` + +## Modifying a Commit + +You can also modify an existing commit if you need to make additional changes. + +```sh +# For example, add all existing files that have been modified or deleted. +git add -u + +# Update the current HEAD commit with the changes. +git commit --amend + +# Push the modifications to your personal remote repository. +# Using the `--force` argument is not recommended if multiple people are sharing the +# same branch. +git push origin --force +``` + +## Rebasing on Upstream Changes + +The main CEF repository will receive additional commits over time. You will want to include these changes in your personal repository. To keep Git history correct (showing upstream CEF commits on the CEF branch instead of on your personal branch) you will need to rebase the local CEF branch before rebasing your local personal branch. + +```sh +# Fetch changes from the main CEF repository. This does not apply them to any +# particular branch. +git fetch upstream + +# Check out the local CEF branch that tracks the upstream CEF branch. +# Replace "master" with a different branch name as appropriate (e.g. "2171", "2272", etc). +git checkout master + +# Rebase your local CEF branch on top of the upstream CEF branch. +# After this command your local CEF branch should be identical to the upstream CEF branch. +git rebase upstream/master + +# Check out the personal branch that you want to update with changes from the CEF branch. +# Replace with the name of your branch. +git checkout + +# Rebase your personal branch on top of the local CEF branch. +# After this command your local commits will come after all CEF commits on the same branch. +git rebase master + +# Push the modifications to your personal remote repository. +git push origin +``` + +You may get merge conflicts if your personal changes conflict with changes made to the main CEF respository. For instructions on resolving merge conflicts see [this articicle](https://help.github.com/articles/resolving-merge-conflicts-after-a-git-rebase/). + +For more information on using the rebase command go [here](https://www.atlassian.com/git/tutorials/merging-vs-rebasing). + +## Deleting a Branch + +Once you no longer need a branch you can delete it both locally and remotely. Do not delete branches that are associated with open pull requests. + +```sh +# Delete the branch locally. +git branch -D + +# Delete the branch remotely. +git push origin --delete +``` + +## Cleaning a Checkout + +You can remove all local changes from your checkout using the below commands. + +```sh +# Check the current state of the repository before deleting anything. +git status + +# Remove all non-committed files and directories from the local checkout. +# If you run this command with JCEF it will also remove all third_party directories and you will +# need to re-run the `gclient runhooks` command. +git clean -dffx + +# Remove all local commits from the current branch and reset branch state to match +# origin/master. Replace "origin/master" with a different remote branch name as appropriate. +git reset --hard origin/master +``` + +# Working With Pull Requests + +Once your personal changes are complete you can request that they be merged into the main CEF (or JCEF) repository. This is done using a pull request. Before submitting a pull request you should: + +* Rebase your changes on the upstream CEF (or JCEF) branch (see "Rebasing on Upstream Changes"). +* Fix any coding style issues (see "Coding Style"). +* Make sure your changes follow [API versioning guidelines](api_versioning.md#usage-in-pull-requests). +* Find or create an appropriate issue in the [CEF issue tracker](https://github.com/chromiumembedded/cef/issues) (or [JCEF issue tracker](https://github.com/chromiumembedded/java-cef/issues) if the change targets that project). Make sure the issue number is referenced in your commit description. +* Include new or modified unit tests as appropriate to the functionality. +* Remove unnecessary or unrelated changes. + +## Coding Style + +CEF uses the [Chromium coding style](https://chromium.googlesource.com/chromium/src/+/master/styleguide/styleguide.md). All C/C++, ObjC, Java and Python code must be formatted using the fix_style tool. For example, to fix the style of the unstaged files in your CEF Git checkout: + +```sh +cd /path/to/chromium/src/cef +./tools/fix_style.sh unstaged +``` + +The fix_style tool supports file paths and git hashes as input. Run `tools/fix_style.[bat|sh]` without arguments for complete usage information. + +Changes to other types of files should match the existing style in that file. + +## Creating a Pull Request + +Pull requests can only be created from a public repository that was [forked](https://docs.github.com/articles/fork-a-repo) using the GitHub interface. Push your branch to your public fork and then create the pull request as described [here](https://docs.github.com/articles/creating-a-pull-request-from-a-fork). Pull requests will only be accepted if they meet the requirements described above. + +```sh +# Push your branch to your public fork for PR submission. +git push public +``` + +## Reviewing a Pull Request + +Your pull request will be reviewed by one or more CEF developers. Please address any comments and update your pull request. The easiest way to update a pull request is by pushing new commits to the same branch -- those new commits will be automatically reflected in the pull request. Once your changes are deemed acceptable they will be squashed and merged into the main CEF repository. + +The contents of a pull request can also be downloaded as a patch file and applied to your local Git checkout: + +```sh +# Download the patch file (replace {pull_no} with the PR number). +curl -L https://github.com/chromiumembedded/cef/pull/{pull_no}.diff -o name.patch + +# Apply the patch file to your local Git checkout. +git apply name.patch +``` + +# Contributing to the Wiki + +To contribute to the wiki, clone it, apply your changes and upload it in a public location before submitting it for review in the forum or issue tacker. \ No newline at end of file diff --git a/docs/crash_reporting.md b/docs/crash_reporting.md new file mode 100644 index 000000000..f46764273 --- /dev/null +++ b/docs/crash_reporting.md @@ -0,0 +1,314 @@ +This page explains how to handle crashes in CEF-based applications. + +**Contents** + +- [Overview](#overview) +- [Configuration](#configuration) + - [[Config] section](#config-section) + - [[CrashKeys] section](#crashkeys-section) +- [Testing](#testing) +- [Decoding Minidumps](#decoding-minidumps) + +--- + +# Overview + +As a developer or vendor that cares about software quality you would like to know when and how your application is crashing in the wild. A crash reporting system is an important part of that feedback loop. Applications using CEF version 3.2883.1543 or newer have the option to save crash reports locally or upload them to a web server for later analysis. CEF generates minidump files that include exception state, callstacks, stack memory, and loaded modules. The crash report upload, if enabled, includes the minidump file and configurable crash metadata information such as product state, command-line flags and crash keys. Minidump files can be analyzed using existing systems such as [Socorro](https://wiki.mozilla.org/Socorro) or command-line tools (see the "Decoding Minidumps" section). + +CEF provides a simple HTTP server script written in Python that can be used for testing crash report upload (see the Testing section below). See the Socorro documentation for details on how to build a robust crash reporting server for use with production applications. + +The crash reporting capability in CEF/Chromium is implemented using [Crashpad](https://chromium.googlesource.com/crashpad/crashpad/+/master/README.md) on Windows and macOS, and [Breakpad](https://chromium.googlesource.com/breakpad/breakpad) on Linux. + +# Configuration + +Crash reporting is configured using an INI-style config file named "crash_reporter.cfg". On Windows and Linux this file must be placed next to the main application executable. On macOS this file must be placed in the top-level app bundle Resources directory (e.g. ".app/Contents/Resources"). See comments in [include/cef_crash_util.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_crash_util.h) for the most up-to-date version of this documentation. + +The "crash_reporter.cfg" file contents are defined as follows: + +```sh +# Comments start with a hash character and must be on their own line. + +[Config] +ProductName= +ProductVersion= +AppName= +ExternalHandler= +BrowserCrashForwardingEnabled= +ServerURL= +RateLimitEnabled= +MaxUploadsPerDay= +MaxDatabaseSizeInMb= +MaxDatabaseAgeInDays= + +[CrashKeys] +my_key1= +my_key2= +``` + +## [Config] section + +Values in the "[Config]" section work as follows: + +* If "ProductName" and/or "ProductVersion" are set then the specified values will be included in the crash dump metadata. On macOS if these values are set to empty then they will be retrieved from the Info.plist file using the "CFBundleName" and "CFBundleShortVersionString" keys respectively. +* If "AppName" is set on Windows then crash report information (metrics, database and dumps) will be stored locally on disk under the "C:\Users\\[CurrentUser]\AppData\Local\\[AppName]\User Data" folder. On other platforms the CefSettings.user_data_path value will be used. +* If "ExternalHandler" is set on Windows then the specified exe will be launched as the crashpad-handler instead of re-launching the main process exe. The value can be an absolute path or a path relative to the main exe directory. On Linux the CefSettings.browser_subprocess_path value will be used. On macOS the existing subprocess app bundle will be used. +* If "BrowserCrashForwardingEnabled" is set to true on macOS then browser process crashes will be forwarded to the system crash reporter. This results in the crash UI dialog being displayed to the user and crash reports being logged under "~/Library/Logs/DiagnosticReports". Forwarding of crash reports from non-browser processes and Debug builds is always disabled. +* If "ServerURL" is set then crashes will be uploaded as a multi-part POST request to the specified URL. Otherwise, reports will only be stored locally on disk. +* If "RateLimitEnabled" is set to true then crash report uploads will be rate limited as follows: + * If "MaxUploadsPerDay" is set to a positive value then at most the specified number of crashes will be uploaded in each 24 hour period. + * If crash upload fails due to a network or server error then an incremental backoff delay up to a maximum of 24 hours will be applied for retries. + * If a backoff delay is applied and "MaxUploadsPerDay" is > 1 then the "MaxUploadsPerDay" value will be reduced to 1 until the client is restarted. This helps to avoid an upload flood when the network or server error is resolved. + * Rate limiting is not supported on Linux. +* If "MaxDatabaseSizeInMb" is set to a positive value then crash report storage on disk will be limited to that size in megabytes. For example, on Windows each dump is about 600KB so a "MaxDatabaseSizeInMb" value of 20 equates to about 34 crash reports stored on disk. Not supported on Linux. +* If "MaxDatabaseAgeInDays" is set to a positive value then crash reports older than the specified age in days will be deleted. Not supported on Linux. + +## [CrashKeys] section + +A maximum of 26 crash keys of each size can be specified for use by the application. Crash key values will be truncated based on the specified size (small = 64 bytes, medium = 256 bytes, large = 1024 bytes). The value of crash keys can be set from any thread or process using the CefSetCrashKeyValue function. These key/value pairs will be sent to the crash server along with the crash dump file. + +# Testing + +CEF provides a [tools/crash_server.py](https://github.com/chromiumembedded/cef/blob/master/tools/crash_server.py) script that implements a simple HTTP server for receiving crash report uploads from a Breakpad/Crashpad client (any application using CEF version 3.2883.1543 or newer). This script is intended for testing purposes only. An HTTPS server and a system such as [Socorro](https://wiki.mozilla.org/Socorro) should be used when uploading crash reports from production applications. See comments in the crash_server.py script for the most up-to-date version of this documentation. + +Usage of the crash_server.py script is as follows: + +1\. Run the script from the command-line. The first argument is the server port number and the second argument is the directory where uploaded report information will be saved: + +```sh +python crash_server.py 8080 /path/to/dumps +``` + +2\. Create a "crash_reporter.cfg" file at the required platform-specific location. On Windows and Linux this file must be placed next to the main application executable. On macOS this file must be placed in the top-level app bundle Resources directory (e.g. ".app/Contents/Resources"). At a minimum it must contain a "ServerURL=http://localhost:8080" line under the "[Config]" section (make sure the port number matches the value specified in step 1). See the Configuration section above for a complete specification of this file's contents. + +Example file contents: + +``` +[Config] +# Product information. +ProductName=cefclient +ProductVersion=1.0.0 + +# Required to enable crash dump upload. +ServerURL=http://localhost:8080 + +# Disable rate limiting so that all crashes are uploaded. +RateLimitEnabled=false +MaxUploadsPerDay=0 + +[CrashKeys] +# The cefclient sample application sets these values (see step 5 below). +testkey_small1=small +testkey_small2=small +testkey_medium1=medium +testkey_medium2=medium +testkey_large1=large +testkey_large2=large +``` + +3\. Load one of the following URLs in the CEF-based application to cause a crash: + +* Main (browser) process crash: chrome://inducebrowsercrashforrealz +* Renderer process crash: chrome://crash +* GPU process crash: chrome://gpucrash + +4\. When the script successfully receives a crash report upload you will see console output like the following: + +``` +01/10/2017 12:31:23: Dump +``` + +The "" value is a 16 digit hexadecimal string that uniquely identifies the dump. Crash minidump contents and metadata (product state, command-line flags and crash keys) will be written to the ".dmp" and ".json" files respectively underneath the directory specified in step 1. + +On Linux, Breakpad uses the `wget` utility to upload crash dumps, so make sure that utility is installed. If the crash is handled correctly then you should see console output like the following when the client uploads a crash dump: + +```text +--2017-01-10 12:31:22-- http://localhost:8080/ +Resolving localhost (localhost)... 127.0.0.1 +Connecting to localhost (localhost)|127.0.0.1|:8080... connected. +HTTP request sent, awaiting response... 200 OK +Length: unspecified [text/html] +Saving to: '/dev/fd/3' +Crash dump id: +``` + +On macOS, when uploading a crash report to the script over HTTP you may receive an error like the following: + +``` +Transport security has blocked a cleartext HTTP (http://) resource load +since it is insecure. Temporary exceptions can be configured via your app's +Info.plist file. +``` + +You can work around this error by adding the "NSAppTransportSecurity" key to the Info.plist file in your application's Helper.app bundle (e.g. "tests/cefclient/resources/mac/helper-Info.plist" before building cefclient, or ".app/Contents/Frameworks/ Helper. app/Contents/Info.plist" in the resulting app bundle): + +```html + + + + + + NSAppTransportSecurity + + + NSAllowsArbitraryLoads + + + + +``` + +5\. The cefclient sample application sets test crash key values in the browser and renderer processes. To work properly these values must also be defined in the "[CrashKeys]" section of "crash_reporter.cfg" as shown above. + +In [tests/cefclient/browser/client_browser.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/browser/client_browser.cc) (browser process): + +``` +CefSetCrashKeyValue("testkey_small1", "value1_small_browser"); +CefSetCrashKeyValue("testkey_small2", "value2_small_browser"); +CefSetCrashKeyValue("testkey_medium1", "value1_medium_browser"); +CefSetCrashKeyValue("testkey_medium2", "value2_medium_browser"); +CefSetCrashKeyValue("testkey_large1", "value1_large_browser"); +CefSetCrashKeyValue("testkey_large2", "value2_large_browser"); +``` + +In [tests/cefclient/renderer/client_renderer.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/renderer/client_renderer.cc) (renderer process): + +``` +CefSetCrashKeyValue("testkey_small1", "value1_small_renderer"); +CefSetCrashKeyValue("testkey_small2", "value2_small_renderer"); +CefSetCrashKeyValue("testkey_medium1", "value1_medium_renderer"); +CefSetCrashKeyValue("testkey_medium2", "value2_medium_renderer"); +CefSetCrashKeyValue("testkey_large1", "value1_large_renderer"); +CefSetCrashKeyValue("testkey_large2", "value2_large_renderer"); +``` + +When crashing the browser or renderer processes with cefclient you should verify that the test crash key values are included in the metadata (".json") file. Some values may be chunked as described in the Configuration section above. + +Example metadata for a browser process crash: + +```json +{ + "LOG_FATAL": "debug_urls.cc:208: Check failed: false. \n0 Chromium Embedded Framework 0x00000001161a1a0e _ZN4base5debug10StackTraceC2Ev + 30\n1 Chromium Embedded Framework 0x00000001161a1a75 _ZN4base5debug10StackTraceC1Ev + 21\n2 Chromium Embedded Fr", + "guid": "6ada20da-7306-477e-a715-ada36448a23f", + "num-switches": "3", + "pid": "2073", + "platform": "macos", + "product": "cefclient", + "ptype": "browser", + "switch-1": "--url=chrome:\/\/inducebrowsercrashforrealz", + "switch-2": "--lang=en-US", + "testkey_large1": "value1_large_browser", + "testkey_large2": "value2_large_browser", + "testkey_medium1": "value1_medium_browser", + "testkey_medium2": "value2_medium_browser", + "testkey_small1": "value1_small_browser", + "testkey_small2": "value2_small_browser", + "version": "1.0.0", +} +``` + +Example metadata for a renderer process crash: + +```json +{ + "discardable-memory-allocated": "4194304", + "discardable-memory-free": "3198976", + "guid": "6ada20da-7306-477e-a715-ada36448a23f", + "num-switches": "15", + "origin_mismatch_origin": "https:\/\/www.google.com", + "origin_mismatch_redirects": "2", + "origin_mismatch_same_page": "0" + "origin_mismatch_transition": "1", + "origin_mismatch_url-1": "https:\/\/www.google.com\/?gws_rd=ssl", + "pid": "2706", + "platform": "macos", + "product": "cefclient", + "ptype": "renderer", + "rvinit_main_frame_id": "2", + "rvinit_proxy_id": "-2", + "rvinit_view_id": "1", + "switch-1": "--disable-databases", + "switch-2": "--lang=en-US", + "switch-3": "--lang=en-US", + "switch-4": "--enable-pinch", + "switch-5": "--num-raster-threads=4", + "switch-6": "--enable-gpu-rasterization", + "switch-7": "--enable-zero-copy", + "switch-8": "--enable-gpu-memory-buffer-compositor-resources", + "switch-9": "--enable-main-frame-before-activation", + "switch-10": "--renderer-client-id=3", + "testkey_large1": "value1_large_renderer", + "testkey_large2": "value2_large_renderer", + "testkey_medium1": "value1_medium_renderer", + "testkey_medium2": "value2_medium_renderer", + "testkey_small1": "value1_small_renderer", + "testkey_small2": "value2_small_renderer", + "v8-ignition": "N", + "version": "1.0.0", +} +``` + +Example metadata for a GPU process crash: + +```json +{ + "guid": "6ada20da-7306-477e-a715-ada36448a23f", + "num-switches": "17", + "pid": "1664", + "platform": "macos", + "product": "cefclient", + "ptype": "gpu-process", + "switch-1": "--lang=en-US", + "switch-2": "--supports-dual-gpus=true", + "switch-3": "--gpu-driver-bug-workarounds=0,1,10,23,25,35,38,45,51,59,61,62,63,64,66,70,71,73,81,82,83,86,88,89", + "switch-4": "--gpu-vendor-id=0x1002", + "switch-5": "--gpu-device-id=0x6821", + "switch-6": "--gpu-driver-vendor", + "switch-7": "--gpu-driver-version", + "switch-8": "--gpu-driver-date", + "switch-9": "--gpu-secondary-vendor-ids=0x8086", + "switch-10": "--gpu-secondary-device-ids=0x0d26" + "switch-11": "--gpu-active-vendor-id=0x8086", + "switch-12": "--gpu-active-device-id=0x0d26", + "switch-13": "--lang=en-US", + "version": "1.0.0", +} +``` + +# Decoding Minidumps + +The crash report upload, if enabled, includes the minidump file with exception state, callstacks, stack memory, and loaded modules. The minidump file can be decoded using the `dump_syms` and `minidump_stackwalk` tools from Breakpad as described [here](https://www.chromium.org/developers/decoding-crash-dumps). + +The Breakpad tools can be built from a local Chromium checkout on Windows, MacOS and Linux as follows: + +1\. Download the Chromium code (for example, by using [CEF tooling](master_build_quick_start.md)). + +2\. Write the following contents to the `out/Release/args.gn` file: + +``` +is_component_build=false +is_debug=false +target_cpu="x64" +is_official_build=true +``` + +3\. Generate the config and build: + +```sh +gn gen out/Release +ninja -C out/Release dump_syms minidump_stackwalk +``` + +4\. Windows requires the `msdia140.dll` COM DLL. It must be placed next to `dump_syms.exe` or registered with the system: + +``` +regsvr32 /s msdia140.dll +``` + +Visual Studio 2022 includes a 64-bit version of this DLL at "C:\Program Files\Microsoft Visual Studio\2022\Professional\DIA SDK\bin\amd64". The 64-bit version 14.29.30133.0 or newer is recommended to avoid failures when loading large (> 4GB) PDB files ([details](https://developercommunity.visualstudio.com/t/pdb-limit-of-4-gib-is-likely-to-be-a-problem-in-a/904784)). \ No newline at end of file diff --git a/docs/general_usage.md b/docs/general_usage.md new file mode 100644 index 000000000..9151e265e --- /dev/null +++ b/docs/general_usage.md @@ -0,0 +1,1287 @@ +This page provides an overview of CEF3 and general usage information. + +**Contents** + +- [Introduction](#introduction) +- [Getting Started](#getting-started) + - [Using a Binary Distribution](#using-a-binary-distribution) + - [Building from Source Code](#building-from-source-code) +- [Sample Application](#sample-application) +- [Important Concepts](#important-concepts) + - [C++ Wrapper](#c-wrapper) + - [Processes](#processes) + - [Threads](#threads) + - [Reference Counting](#reference-counting) + - [Strings](#strings) + - [Command Line Arguments](#command-line-arguments) + - [Coordinate Systems](#coordinate-systems) +- [Application Layout](#application-layout) + - [Windows](#windows) + - [Linux](#linux) + - [MacOS](#macos) +- [Application Structure](#application-structure) + - [Entry-Point Function](#entry-point-function) + - [Single Executable](#single-executable) + - [Separate Sub-Process Executable](#separate-sub-process-executable) + - [Message Loop Integration](#message-loop-integration) + - [CefSettings](#cefsettings) + - [CefBrowser and CefFrame](#cefbrowser-and-cefframe) + - [CefApp](#cefapp) + - [CefClient](#cefclient) + - [Browser Life Span](#browser-life-span) + - [Off-Screen Rendering](#off-screen-rendering) +- [Posting Tasks](#posting-tasks) +- [Inter-Process Communication (IPC)](#inter-process-communication-ipc) + - [Process Startup Messages](#process-startup-messages) + - [Process Runtime Messages](#process-runtime-messages) + - [Asynchronous JavaScript Bindings](#asynchronous-javascript-bindings) + - [Generic Message Router](#generic-message-router) + - [Custom Implementation](#custom-implementation) + - [Synchronous Requests](#synchronous-requests) +- [Network Layer](#network-layer) + - [Custom Requests](#custom-requests) + - [Browser-Independent Requests](#browser-independent-requests) + - [Request Handling](#request-handling) + - [Generic Resource Manager](#generic-resource-manager) + - [Scheme Handler](#scheme-handler) + - [Request Interception](#request-interception) + - [Response Filtering](#response-filtering) + - [Other Callbacks](#other-callbacks) + - [Proxy Resolution](#proxy-resolution) + +--- + +# Introduction + +The Chromium Embedded Framework (CEF) is an open source project based on the [Google Chromium](http://www.chromium.org/Home) project. Unlike the Chromium project itself, which focuses mainly on Google Chrome application development, CEF focuses on facilitating embedded browser use cases in third-party applications. CEF insulates the user from the underlying Chromium and Blink code complexity by offering production-quality stable APIs, release branches tracking specific Chromium releases, and binary distributions. Most features in CEF have default implementations that provide rich functionality while requiring little or no integration work from the user. As of this article’s publication there are over 100 million installed instances of CEF around the world embedded in products from a wide range of companies and industries. A partial list of companies and products using CEF is available on the [CEF Wikipedia page](http://en.wikipedia.org/wiki/Chromium_Embedded_Framework#Applications_using_CEF). Some use cases for CEF include: + + * Embedding an HTML5-compliant Web browser control in an existing native application. + * Creating a light-weight native “shell” application that hosts a user interface developed primarily using Web technologies. + * Rendering Web content “off-screen” in applications that have their own custom drawing frameworks. + * Acting as a host for automated testing of existing Web properties and applications. + +CEF3 is the next generation of CEF based on the multi-process [Chromium Content API](http://www.chromium.org/developers/content-module/content-api). Advantages to CEF3’s multi-process architecture include: + + * Improved performance and stability (JavaScript and plugins run in a separate process). + * Support for Retina displays. + * GPU acceleration for WebGL and 3D CSS. + * Cool new features like WebRTC (webcam support) and speech input. + * Better automated UI testing via the DevTools remote debugging protocol and [ChromeDriver2](https://code.google.com/p/chromedriver/wiki/ChromeDriver2). + * Faster access to current and future Web features and standards. + +This document introduces the general concepts involved when developing an application using CEF3. + +# Getting Started + +## Using a Binary Distribution + +Binary distributions of CEF3 are available from the [project Downloads page](https://cef-builds.spotifycdn.com/index.html). They contain all files necessary to build a particular version of CEF3 on a particular platform (Windows, MacOS or Linux). See the [Tutorial](tutorial.md) page for detailed instructions on how to create a simple application using the CEF3 binary distribution. + +No matter the platform all binary distributions share the same general structure: + + * **CMakeLists.txt** provides the [CMake configuration](https://cmake.org/overview/) for building the test applications included with the binary distribution. Platform-specific build instructions are provided as comments at the top of this file. + * **Debug** contains a debug build the CEF shared library (libcef) and any other libraries required to run on the platform. + * **include** contains all required CEF header files. + * **libcef\_dll** contains the source code for the libcef\_dll\_wrapper static library that all applications using the CEF C++ API must link against. See the “C++ Wrapper” section for more information. + * **Release** contains a release build the CEF shared library (libcef) and any other libraries required to run on the platform. + * **Resources** contains resources required by applications using CEF (Windows and Linux only). This includes .pak files (binary files with globbed resources) and potentially other files such depending on the platform. + * **tests/cefclient** contains the cefclient sample application configured to build using the files in the binary distribution. This application demonstrates a wide range of CEF functionalities. + * **tests/cefsimple** contains the cefsimple sample application configured to build using the files in the binary distribution. This application demonstrates the minimal functionality required to create a browser window. + * **tests/ceftests** contains the ceftests sample application configured to build using the files in the binary distribution. This application provides unit test coverage for CEF APIs and functionality. + +Each binary distribution also contains a README.txt file that describes the platform-specific distribution in greater detail and a LICENSE.txt file that contains CEF’s BSD license. When distributing an application based on CEF you should include the license text somewhere in your application’s distribution. For example, you can list it on an “About” or “Credits” page in your application’s UI, or in the documentation bundled with your application. License and credit information is also available inside of a CEF3 browser window by loading “about:license” and “about:credits” respectively. + +Applications based on CEF binary distributions can be built using standard platform build tools. This includes Visual Studio on Windows, Xcode on MacOS and gcc/make on Linux. The project Downloads page contains information about the OS and build tool versions required for specific binary releases. When building on Linux also pay careful attention to the listed package dependencies. + +## Building from Source Code + +CEF can be built from source code either locally or using automated build systems like [TeamCity](http://www.jetbrains.com/teamcity/). This requires the download of Chromium and CEF source code via Git. The Chromium code base is quite large and building Chromium from source code is only recommended on moderately powerful machines with more than 8GB of RAM. Detailed instructions for building Chromium and CEF from source code are available on the [Branches And Building](branches_and_building.md) page. + +# Sample Application + +The cefclient sample application is a complete working example of CEF integration and is included in source code form with each binary distribution. The easiest way to create a new application using CEF is to start with the cefclient application and remove the parts that you don’t need. Many of the examples in this document originate from the cefclient application. + +# Important Concepts + +There are some important underlying concepts to developing CEF3-based applications that should be understood before proceeding. + +## C++ Wrapper + +The libcef shared library exports a C API that isolates the user from the CEF runtime and code base. The libcef\_dll\_wrapper project, which is distributed in source code form as part of the binary release, wraps this exported C API in a C++ API that is then linked into the client application. The code for this C/C++ API translation layer is automatically generated by the [translator](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) tool. Direct usage of the C API is described on the [Using The CAPI](using_the_capi.md) page. + +## Processes + +CEF3 runs using multiple processes. The main process which handles window creation, UI and network access is called the “browser” process. This is generally the same process as the host application and the majority of the application logic will run in the browser process. Blink rendering and JavaScript execution occur in a separate “render” process. Some application logic, such as JavaScript bindings and DOM access, will also run in the render process. The default [process model](http://www.chromium.org/developers/design-documents/process-models) will spawn a new render process for each unique origin (scheme + domain). Other processes will be spawned as needed, such as the “gpu” process to handle [accelerated compositing](http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome). + +By default the main application executable will be spawned multiple times to represent separate processes. This is handled via command-line flags that are passed into the CefExecuteProcess function. If the main application executable is large, takes a long time to load, or is otherwise unsuitable for non-browser processes the host can use a separate executable for those other processes. This can be configured via the CefSettings.browser\_subprocess\_path variable. See the “Application Structure” section for more information. + +The separate processes spawned by CEF3 communicate using Inter-Process Communication (IPC). Application logic implemented in the browser and render processes can communicate by sending asynchronous messages back and forth. [Java Script Integration](javascript_integration.md) in the render process can expose asynchronous APIs that are handled in the browser process. See the “Inter-Process Communication” section for more information. + +Platform-specific debugging tips are also available for [Windows](https://www.chromium.org/developers/how-tos/debugging-on-windows), [MacOS](https://chromium.googlesource.com/chromium/src/+/main/docs/mac/debugging.md) and [Linux](https://chromium.googlesource.com/chromium/src/+/master/docs/linux/debugging.md). + +## Threads + +Each process in CEF3 runs multiple threads. For a complete list of threads see the [cef\_thread\_id\_t](https://github.com/chromiumembedded/cef/blob/81e7748fb5008295c2a1f2d75b0f0c907c1fdfe8/include/internal/cef_types.h#L1366) enumeration. These are some of the commonly-referenced threads: + + * **TID\_UI** thread is the main thread in the browser process. This thread will be the same as the main application thread if CefInitialize() is called with a CefSettings.multi\_threaded\_message\_loop value of false. + * **TID\_IO** thread is used in the browser process to handle IPC and network messages. + * **TID\_FILE\_\*** threads are used in the browser process to interact with the file system. Blocking operations should only be performed on this thread or a [CefThread](https://cef-builds.spotifycdn.com/docs/stable.html?classCefThread.html) created by the client application. + * **TID\_RENDERER** thread is the main thread in the renderer process. All Blink and V8 interation must take place on this thread. + +Due to the multi-threaded nature of CEF it’s important to use message passing or locking to protect data members from access on multiple threads. The CefPostTask family of functions support easy asynchronous message passing between threads. See the “Posting Tasks” section for more information. + +The current thread can be verified using the CefCurrentlyOn() function. The CEF sample applications use the following defines to verify that methods are executed on the expected thread. These defines are included in the [include/wrapper/cef\_helpers.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_helpers.h) header file. + +```cpp +#define CEF_REQUIRE_UI_THREAD() DCHECK(CefCurrentlyOn(TID_UI)); +#define CEF_REQUIRE_IO_THREAD() DCHECK(CefCurrentlyOn(TID_IO)); +#define CEF_REQUIRE_FILE_BACKGROUND_THREAD() \ + DCHECK(CefCurrentlyOn(TID_FILE_BACKGROUND)); +#define CEF_REQUIRE_FILE_USER_VISIBLE_THREAD() \ + DCHECK(CefCurrentlyOn(TID_FILE_USER_VISIBLE)); +#define CEF_REQUIRE_FILE_USER_BLOCKING_THREAD() \ + DCHECK(CefCurrentlyOn(TID_FILE_USER_BLOCKING)); +#define CEF_REQUIRE_RENDERER_THREAD() DCHECK(CefCurrentlyOn(TID_RENDERER)); +``` + +To support synchronized access to blocks of code CEF provides base::Lock and base::AutoLock types via the [include/base/cef\_lock.h](https://github.com/chromiumembedded/cef/blob/master/include/base/cef_lock.h) header file. For example: + +```cpp +// Include the necessary header. +#include "include/base/cef_lock.h" + +// Class declaration. +class MyClass : public CefBaseRefCounted { + public: + MyClass() : value_(0) {} + // Method that may be called on multiple threads. + void IncrementValue(); + private: + // Value that may be accessed on multiple theads. + int value_; + // Lock used to protect access to |value_|. + base::Lock lock_; + IMPLEMENT_REFCOUNTING(MyClass); +}; + +// Class implementation. +void MyClass::IncrementValue() { + // Acquire the lock for the scope of this method. + base::AutoLock lock_scope(lock_); + // |value_| can now be modified safely. + value_++; +} +``` + +## Reference Counting + +All framework classes implement the CefBase[RefCounted|Scoped] interface and all instance pointers are handled using the CefRefPtr smart pointer implementation that automatically handles reference counting via calls to AddRef() and Release(). The easiest way to implement these classes is as follows: + +```cpp +class MyClass : public CefBaseRefCounted { + public: + // Various class methods here... + + private: + // Various class members here... + + IMPLEMENT_REFCOUNTING(MyClass); // Provides atomic refcounting implementation. +}; + +// References a MyClass instance +CefRefPtr my_class = new MyClass(); +``` + +## Strings + +CEF defines its own data structure for representing strings. This is for a few different reasons: + + * The libcef library and the host application may use different runtimes for managing heap memory. All objects, including strings, need to be freed using the same runtime that allocated the memory. + * The libcef library can be compiled to support different underlying string types (UTF8, UTF16 or wide). The default is UTF16 but it can be changed by modifying the defines in [cef\_string.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_string.h) and recompiling CEF. When choosing the wide string type keep in mind that the size will vary depending on the platform. + +For UTF16 the string structure looks like this: + +```cpp +typedef struct _cef_string_utf16_t { + char16_t* str; // Pointer to the string + size_t length; // String length + void (*dtor)(char16_t* str); // Destructor for freeing the string on the correct heap +} cef_string_utf16_t; +``` + +The selected string type is then typedef'd to the generic type: + +```cpp +typedef char16_t cef_char_t; +typedef cef_string_utf16_t cef_string_t; +``` + +CEF provides a number of C API functions for operating on the CEF string types (mapped via #defines to the type-specific functions). For example: + + * **cef\_string\_set** will assign a string value to the structure with or without copying the value. + * **cef\_string\_clear** will clear the string value. + * **cef\_string\_cmp** will compare two string values. + +CEF also provides functions for converting between all supported string types (ASCII, UTF8, UTF16 and wide). See the [cef\_string.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_string.h) and [cef\_string\_types.h](https://github.com/chromiumembedded/cef/blob/master/include/internal/cef_string_types.h) headers for the complete list of functions. + +Usage of CEF strings in C++ is simplified by the CefString class. CefString provides automatic conversion to and from std::string (UTF8) and std::wstring (wide) types. It can also be used to wrap an existing cef\_string\_t structure for assignment purposes. + +Assignment to and from std::string: + +```cpp +std::string str = “Some UTF8 string”; + +// Equivalent ways of assigning |str| to |cef_str|. Conversion from UTF8 will occur if necessary. +CefString cef_str(str); +cef_str = str; +cef_str.FromString(str); + +// Equivalent ways of assigning |cef_str| to |str|. Conversion to UTF8 will occur if necessary. +str = cef_str; +str = cef_str.ToString(); +``` + +Assignment to and from std::wstring: + +```cpp +std::wstring str = “Some wide string”; + +// Equivalent ways of assigning |str| to |cef_str|. Conversion from wide will occur if necessary. +CefString cef_str(str); +cef_str = str; +cef_str.FromWString(str); + +// Equivalent ways of assigning |cef_str| to |str|. Conversion to wide will occur if necessary. +str = cef_str; +str = cef_str.ToWString(); +``` + +Use the FromASCII() method if you know that the format is ASCII: + +```cpp +const char* cstr = “Some ASCII string”; +CefString cef_str; +cef_str.FromASCII(cstr); +``` + +Some structures like CefSettings have cef\_string\_t members. CefString can be used to simplify the assignment to those members: + +```cpp +CefSettings settings; +const char* path = “/path/to/log.txt”; + +// Equivalent assignments. +CefString(&settings.log_file).FromASCII(path); +cef_string_from_ascii(path, strlen(path), &settings.log_file); +``` + +## Command Line Arguments + +Many features in CEF3 and Chromium can be configured using command line arguments. These arguments take the form "--some-argument[=optional-param]" and are passed into CEF via CefExecuteProcess() and the CefMainArgs structure (see the “Application Structure” section below). + + * To disable processing of arguments from the command line set CefSettings.command\_line\_args\_disabled to true before passing the CefSettings structure into CefInitialize(). + * To specify CEF/Chromium command line arguments inside the host application implement the CefApp::OnBeforeCommandLineProcessing() method. + * To pass application-specific (non-CEF/Chromium) command line arguments to sub-processes implement the CefBrowserProcessHandler::OnBeforeChildProcessLaunch() method. + +See comments in [shared/common/client\_switches.cc](https://github.com/chromiumembedded/cef/blob/master/tests/shared/common/client_switches.cc) for more information on how to discover supported CEF/Chromium command line switches. + +## Coordinate Systems + +Browser applications use different coordinate systems depending on the context. Screen/window coordinates are generally represented as density independent pixel (DIP) coordinates with upper-left origin. These DIP coordinates will be passed to [Views APIs](https://github.com/chromiumembedded/cef/tree/master/include/views) and browser callbacks such as OnAutoResize and OnContentsBoundsChange. JavaScript and CSS mostly use CSS pixels which are similar to DIP coordinates but also reflect browser zoom settings [(details)](https://developer.mozilla.org/en-US/docs/Web/CSS/CSSOM_view/Viewport_concepts). Applications using other platform APIs/toolkits may also need to convert to/from specific device coordinate systems. + +Important details related to coordinate system usage in CEF: + +* DIP coordinate and CSS pixel factors will be the same when browser zoom is set to 100%. +* Views-hosted browsers are aware of the containing [CefWindow](https://cef-builds.spotifycdn.com/docs/stable.html?classCefWindow.html) and browser callbacks such as OnContentsBoundsChange will report frame bounds for that window. Same for browsers with a native parent NSWindow on macOS. +* Windowless (off-screen) browsers can be made aware of containing screen/window bounds by implementing the appropriate [CefRenderHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRenderHandler.html) methods (GetScreenInfo, GetRootScreenRect, GetViewRect). +* Other browsers (native hosted or windowless) will report bounds for the browser content only. + * The client application is responsible for converting bounds and enlarging to include native controls and/or window frame (see below). +* DIP conversion requirements differ by platform API/toolkit. + * DIP coordinates convert to device coordinates based on the device scale factor. + * By default the device scale factor will match the associated display (e.g. user/system-level display settings). + * The device scale factor can be changed to a non-default value globally by using the `--force-device-scale-factor=[float]` command-line flag. + * On macOS a non-default device scale factor impacts rendering quality but does not impact the DIP conversion itself. + * Windowed browsers should convert DIP coordinates using [CefDisplay](https://cef-builds.spotifycdn.com/docs/stable.html?classCefDisplay.html) methods. + * Windowless browsers should convert DIP coordinates using the [device_scale_factor](https://cef-builds.spotifycdn.com/docs/stable.html?structcef__screen__info__t.html#a82e584007cd1cc85fa837ae699866305) that was last configured via [GetScreenInfo](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRenderHandler.html#a68a34e2102f3cca48e054f0c27c365da). + * Views API methods use DIP coordinates directly. + * Windows API methods ([SetWindowPos](ttps://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos), [AdjustWindowRectEx](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-adjustwindowrectex), etc.) expect [device (pixel) coordinates](https://learn.microsoft.com/en-us/windows/win32/gdi/window-coordinate-system). + * Use the static CefDisplay conversion methods on Windows for best (multi-dpi-aware) results. + * The DIP conversion factor may be different from the [DPI awareness settings](https://learn.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows) used with native controls. WinAPI functions like [GetDpiForWindow](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow) should be used to convert native control coordinates. + * Linux platform toolkits (GTK, etc) usually expect root window (pixel) coordinates. + * MacOS (Cocoa) API methods use DIP coordinates as device coordinates but with a [different](https://developer.apple.com/library/archive/documentation/General/Devpedia-CocoaApp-MOSX/CoordinateSystem.html) (lower-left) origin. +* JavaScript can convert CSS pixels to device coordinates using [window.devicePixelRatio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio). + + +Coordinate system behavior can be explored further in the cefclient sample app by running with the `--url=https://tests/window` command-line flag. + +# Application Layout + +Application layout can differ significantly depending on the platform. For example, on MacOS your application layout must follow a specific app bundle structure. Windows and Linux are more flexible, allowing you to customize the location where CEF libraries and resources are stored. For a complete working example of the required layout you can download a “Sample Application” from the [project Downloads page](https://cef-builds.spotifycdn.com/index.html). Some distributed files are required and some are optional. Requirements and additional information for each file can be found in the binary distribution README.txt file. + +## Windows + +On Windows the default layout places the libcef library and related resources next to the application executable. The directory structure looks like this for 4692 branch: + +```text +Application/ + cefclient.exe <= cefclient application executable + libcef.dll <= main CEF library + icudtl.dat <= unicode support data + libEGL.dll, libGLESv2.dll, ... <= accelerated compositing support libraries + chrome_100_percent.pak, chrome_200_percent.pak, resources.pak <= non-localized resources and strings + snapshot_blob.bin, v8_context_snapshot.bin <= V8 initial snapshot + locales/ + en-US.pak, ... <= locale-specific resources and strings +``` + +The location of the CEF libraries and resource files can be customized using the CefSettings structure (see the README.txt file or “CefSettings” section for details). The cefclient application on Windows compiles in resources via the BINARY resource type in [cefclient/resources/win/cefclient.rc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/resources/win/cefclient.rc) but an application could just as easily load resources from the local file system. + +## Linux + +On Linux the default layout places the libcef library and related resources next to the application executable. Note however that there’s a discrepancy between where libcef.so is located in the client distribution and where it’s located in the binary distribution that you build yourself. The location depends on how the linker rpath value is set when building the application executable. For example, a value of “-Wl,-rpath,.” (“.” meaning the current directory) will allow you to place libcef.so next to the application executable. The path to libcef.so can also be specified using the LD\_LIBRARY\_PATH environment variable. The directory structure looks like this for 4692 branch: + +```text +Application/ + cefclient <= cefclient application executable + chrome-sandbox <= sandbox support binary + libcef.so <= main CEF library + icudtl.dat <= unicode support data + chrome_100_percent.pak, chrome_200_percent.pak, resources.pak <= non-localized resources and strings + snapshot_blob.bin, v8_context_snapshot.bin <= V8 initial snapshot + locales/ + en-US.pak, ... <= locale-specific resources and strings + files/ + binding.html, ... <= cefclient application resources +``` + +The location of the CEF libraries and resource files can be customized using the CefSettings structure (see the README.txt file of “CefSettings” section for details). + +## MacOS + +The application (app bundle) layout on MacOS is mandated by the Chromium implementation and consequently is not very flexible. The directory structure looks like this for 4692 branch: + +```text +cefclient.app/ + Contents/ + Frameworks/ + Chromium Embedded Framework.framework/ + Chromium Embedded Framework <= main application library + Resources/ + chrome_100_percent.pak, chrome_200_percent.pak, resources.pak, ... <= non-localized resources and strings + icudtl.dat <= unicode support data + snapshot_blob.bin, v8_context_snapshot.bin <= V8 initial snapshot + en.lproj/, ... <= locale-specific resources and strings + cefclient Helper.app/ + Contents/ + Info.plist + MacOS/ + cefclient Helper <= helper executable + Pkginfo + Info.plist + MacOS/ + cefclient <= cefclient application executable + Pkginfo + Resources/ + binding.html, ... <= cefclient application resources +``` + +The "Chromium Embedded Framework.framework" is an [unversioned framework](http://src.chromium.org/viewvc/chrome/trunk/src/build/mac/copy_framework_unversioned.sh?view=markup) that contains all CEF binaries and resources. Executables (cefclient, cefclient Helper, etc) dynamically load the CEF Framework as described [here](https://groups.google.com/d/msg/cef-announce/Fith0A3kWtw/6ds_mJVMCQAJ). + +The "cefclient Helper" app is used for executing separate processes (renderer, plugin, etc) with different characteristics. It needs to have a separate app bundle and Info.plist file so that, among other things, it doesn’t show dock icons. + +# Application Structure + +Every CEF3 application has the same general structure. + + * Provide an entry-point function that initializes CEF and runs either sub-process executable logic or the CEF message loop. + * Provide an implementation of [CefApp](https://cef-builds.spotifycdn.com/docs/stable.html?classCefApp.html) to handle process-specific callbacks. + * Provide an implementation of [CefClient](https://cef-builds.spotifycdn.com/docs/stable.html?classCefClient.html) to handle browser-instance-specific callbacks. + * Call CefBrowserHost::CreateBrowser() to create a browser instance and manage the browser life span using [CefLifeSpanHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefLifeSpanHandler.html). + +## Entry-Point Function + +As described in the “Processes” section a CEF3 application will run multiple processes. The processes can all use the same executable or a separate executable can be specified for the sub-processes. Execution of the process begins in the entry-point function. Complete platform-specific examples for Windows, Linux and MacOS are available in [cefclient/cefclient\_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/cefclient_win.cc), [cefclient/cefclient\_gtk.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/cefclient_gtk.cc) and [cefclient/cefclient\_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/cefclient_mac.mm) respectively. + +When launching sub-processes CEF will specify configuration information using the command-line that must be passed into the CefExecuteProcess function via the CefMainArgs structure. The definition of CefMainArgs is platform-specific. On Linux and MacOS it accepts the argc and argv values which are passed into the [main() function](https://en.wikipedia.org/wiki/Main_function). + +``` +CefMainArgs main_args(argc, argv); +``` + +On Windows it accepts the instance handle (HINSTANCE) which is passed into the [wWinMain() function](http://msdn.microsoft.com/en-us/library/windows/desktop/ff381406(v=vs.85).aspx). The instance handle is also retrievable via GetModuleHandle(nullptr). + +``` +CefMainArgs main_args(hInstance); +``` + +### Single Executable + +When running as a single executable the entry-point function is required to differentiate between the different process types. The single executable structure is supported on Windows and Linux but not on MacOS. + +```cpp +// Program entry-point function. +int main(int argc, char* argv[]) { + // Structure for passing command-line arguments. + // The definition of this structure is platform-specific. + CefMainArgs main_args(argc, argv); + + // Implementation of the CefApp interface. + CefRefPtr app(new MyApp); + + // Execute the sub-process logic, if any. This will either return immediately for the browser + // process or block until the sub-process should exit. + int exit_code = CefExecuteProcess(main_args, app.get()); + if (exit_code >= 0) { + // The sub-process terminated, exit now. + return exit_code; + } + + // Populate this structure to customize CEF behavior. + CefSettings settings; + + // Initialize CEF in the main process. + CefInitialize(main_args, settings, app.get()); + + // Run the CEF message loop. This will block until CefQuitMessageLoop() is called. + CefRunMessageLoop(); + + // Shut down CEF. + CefShutdown(); + + return 0; +} +``` + +### Separate Sub-Process Executable + +When using a separate sub-process executable you need two separate executable projects and two separate entry-point functions. + +Main application entry-point function: + +```cpp +// Program entry-point function. +int main(int argc, char* argv[]) { + // Load the CEF framework library at runtime instead of linking directly + // as required by the macOS sandbox implementation. + CefScopedLibraryLoader library_loader; + if (!library_loader.LoadInMain()) + return 1; + + // Structure for passing command-line arguments. + // The definition of this structure is platform-specific. + CefMainArgs main_args(argc, argv); + + // Implementation of the CefApp interface. + CefRefPtr app(new MyApp); + + // Populate this structure to customize CEF behavior. + CefSettings settings; + + // Specify the path for the sub-process executable. + CefString(&settings.browser_subprocess_path).FromASCII(“/path/to/subprocess”); + + // Initialize CEF in the main process. + CefInitialize(main_args, settings, app.get()); + + // Run the CEF message loop. This will block until CefQuitMessageLoop() is called. + CefRunMessageLoop(); + + // Shut down CEF. + CefShutdown(); + + return 0; +} +``` + +Sub-process application entry-point function: + +```cpp +// Program entry-point function. +int main(int argc, char* argv[]) { + // Initialize the macOS sandbox for this helper process. + CefScopedSandboxContext sandbox_context; + if (!sandbox_context.Initialize(argc, argv)) + return 1; + + // Load the CEF framework library at runtime instead of linking directly + // as required by the macOS sandbox implementation. + CefScopedLibraryLoader library_loader; + if (!library_loader.LoadInHelper()) + return 1; + + // Structure for passing command-line arguments. + // The definition of this structure is platform-specific. + CefMainArgs main_args(argc, argv); + + // Implementation of the CefApp interface. + CefRefPtr app(new MyApp); + + // Execute the sub-process logic. This will block until the sub-process should exit. + return CefExecuteProcess(main_args, app.get()); +} +``` + +## Message Loop Integration + +CEF can also integrate with an existing application message loop instead of running its own message loop. There are two ways to do this. + + 1. Call CefDoMessageLoopWork() on a regular basis instead of calling CefRunMessageLoop(). Each call to CefDoMessageLoopWork() will perform a single iteration of the CEF message loop. Caution should be used with this approach. Calling the method too infrequently will starve the CEF message loop and negatively impact browser performance. Calling the method too frequently will negatively impact CPU usage. See [CefBrowserProcessHandler::OnScheduleMessagePumpWork](https://cef-builds.spotifycdn.com/docs/stable.html?classCefBrowserProcessHandler.html#a7ff7d1618399ede096ba16486a71d76e) for advanced usage details. You can test this mode in cefclient by running with the “--external-message-pump” command-line flag. + 1. Set CefSettings.multi\_threaded\_message\_loop = true (Windows and Linux only). This will cause CEF to run the browser UI thread on a separate thread from the main application thread. With this approach neither CefDoMessageLoopWork() nor CefRunMessageLoop() need to be called. CefInitialize() and CefShutdown() should still be called on the main application thread. You will need to provide your own mechanism for communicating with the main application thread (see for example the message window usage in cefclient\_win.cpp). You can test this mode in cefclient on Windows or Linux by running with the “--multi-threaded-message-loop” command-line flag. + +## CefSettings + +The CefSettings structure allows configuration of application-wide CEF settings. Some commonly configured members include: + + * **browser\_subprocess\_path** The path to a separate executable that will be launched for sub-processes. See the “Separate Sub-Process Executable” section for more information. + * **multi\_threaded\_message\_loop** Set to true to have the browser process message loop run in a separate thread. See the “Message Loop Integration” section for more information. + * **command\_line\_args\_disabled** Set to true to disable configuration of browser process features using standard CEF and Chromium command-line arguments. See the “Command Line Arguments” section for more information. + * **cache\_path** The location where cache data will be stored on disk. If empty an in-memory cache will be used for some features and a temporary disk cache will be used for others. HTML5 databases such as localStorage will only persist across sessions if a cache path is specified. + * **locale** The locale string that will be passed to Blink. If empty the default locale of "en-US" will be used. This value is ignored on Linux where locale is determined using environment variable parsing with the precedence order: LANGUAGE, LC\_ALL, LC\_MESSAGES and LANG. Also configurable using the "lang" command-line switch. + * **log\_file** The directory and file name to use for the debug log. If empty, the default name of "debug.log" will be used and the file will be written to the application directory. Also configurable using the "log-file" command-line switch. + * **log\_severity** The log severity. Only messages of this severity level or higher will be logged. Also configurable using the "log-severity" command-line switch with a value of "verbose", "info", "warning", "error", "error-report" or "disable". + * **resources\_dir\_path** The fully qualified path for the resources directory. If this value is empty the cef.pak and/or devtools\_resources.pak files must be located in the module directory on Windows/Linux or the app bundle Resources directory on MacOS. Also configurable using the "resources-dir-path" command-line switch. + * **locales\_dir\_path** The fully qualified path for the locales directory. If this value is empty the locales directory must be located in the module directory. This value is ignored on MacOS where pack files are always loaded from the app bundle Resources directory. Also configurable using the "locales-dir-path" command-line switch. + * **remote\_debugging\_port** Set to a value between 1024 and 65535 to enable remote debugging on the specified port. For example, if 8080 is specified the remote debugging URL will be http://localhost:8080. CEF can be remotely debugged from any CEF or Chrome browser window. Also configurable using the "remote-debugging-port" command-line switch. + +## CefBrowser and CefFrame + +The [CefBrowser](https://cef-builds.spotifycdn.com/docs/stable.html?classCefBrowser.html) and [CefFrame](https://cef-builds.spotifycdn.com/docs/stable.html?classCefFrame.html) objects are used for sending commands to the browser and for retrieving state information in callback methods. Each CefBrowser object will have a single main CefFrame object representing the top-level frame and zero or more CefFrame objects representing sub-frames. For example, a browser that loads two iframes will have three CefFrame objects (the top-level frame and the two iframes). + +To load a URL in the browser main frame: + +``` +browser->GetMainFrame()->LoadURL(some_url); +``` + +To navigate the browser backwards: + +``` +browser->GoBack(); +``` +To retrieve the main frame HTML contents: + +```cpp +// Implementation of the CefStringVisitor interface. +class Visitor : public CefStringVisitor { + public: + Visitor() {} + + // Called asynchronously when the HTML contents are available. + virtual void Visit(const CefString& string) override { + // Do something with |string|... + } + + IMPLEMENT_REFCOUNTING(Visitor); +}; + +browser->GetMainFrame()->GetSource(new Visitor()); +``` + +CefBrowser and CefFrame objects exist in both the browser process and the render process. Host behavior can be controlled in the browser process via the CefBrowser::GetHost() method. For example, the native handle for a windowed browser can be retrieved as follows: + +```cpp +// CefWindowHandle is defined as HWND on Windows, NSView* on MacOS +// and (usually) X11 Window on Linux. +CefWindowHandle window_handle = browser->GetHost()->GetWindowHandle(); +``` + +Other methods are available for history navigation, loading of strings and requests, sending edit commands, retrieving text/html contents, and more. See the class documentation for the complete list of supported methods. + +## CefApp + +The [CefApp](https://cef-builds.spotifycdn.com/docs/stable.html?classCefApp.html) interface provides access to process-specific callbacks. Important callbacks include: + + * **OnBeforeCommandLineProcessing** which provides the opportunity to programmatically set command-line arguments. See the “Command Line Arguments” section for more information. + * **OnRegisterCustomSchemes** which provides an opportunity to register custom schemes. See the “”Request Handling” section for more information. + * **GetBrowserProcessHandler** which returns the handler for functionality specific to the browser process including the OnContextInitialized() method. + * **GetRenderProcessHandler** which returns the handler for functionality specific to the render process. This includes JavaScript-related callbacks and process messages. See the [Java Script Integration](javascript_integration.md) page and the “Inter-Process Communication” section for more information. + +An example CefApp implementation can be seen in [cefsimple/simple\_app.h](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.h) and [cefsimple/simple\_app.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.cc). + +## CefClient + +The [CefClient](https://cef-builds.spotifycdn.com/docs/stable.html?classCefClient.html) interface provides access to browser-instance-specific callbacks. A single CefClient instance can be shared among any number of browsers. Important callbacks include: + + * Handlers for things like browser life span, context menus, dialogs, display notifications, drag events, focus events, keyboard events and more. The majority of handlers are optional. See the class documentation for the side effects, if any, of not implementing a specific handler. + * **OnProcessMessageReceived** which is called when an IPC message is received from the render process. See the “Inter-Process Communication” section for more information. + +An example CefClient implementation can be seen in [cefsimple/simple\_handler.h](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler.h) and [cefsimple/simple\_handler.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler.cc). + +## Browser Life Span + +Browser life span begins with a call to CefBrowserHost::CreateBrowser() or CefBrowserHost::CreateBrowserSync(). Convenient places to execute this logic include the CefBrowserProcessHandler::OnContextInitialized() callback or platform-specific message handlers like WM\_CREATE on Windows. + +```cpp +// Information about the window that will be created including parenting, size, etc. +// The definition of this structure is platform-specific. +CefWindowInfo info; +// On Windows for example... +info.SetAsChild(parent_hwnd, client_rect); + +// Customize this structure to control browser behavior. +CefBrowserSettings settings; + +// CefClient implementation. +CefRefPtr client(new MyClient); + +// Create the browser asynchronously. Initially loads the Google URL. +CefBrowserHost::CreateBrowser(info, client.get(), “http://www.google.com”, settings, nullptr, nullptr); +``` + +The [CefLifeSpanHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefLifeSpanHandler.html) class provides the callbacks necessary for managing browser life span. Below is an extract of the relevant methods and members. + +```cpp +class MyClient : public CefClient, + public CefLifeSpanHandler, + ... { + // CefClient methods. + virtual CefRefPtr GetLifeSpanHandler() override { + return this; + } + + // CefLifeSpanHandler methods. + void OnAfterCreated(CefRefPtr browser) override; + bool DoClose(CefRefPtr browser) override; + void OnBeforeClose(CefRefPtr browser) override; + + // Member accessors. + CefRefPtr GetBrower() const { return browser_; } + bool IsClosing() const { return is_closing_; } + + private: + CefRefPtr browser_; + int browser_id_ = -1; // invalid value + int browser_count_ = 0; + bool is_closing_ = false; + + IMPLEMENT_REFCOUNTING(MyClient); +}; +``` + +The OnAfterCreated() method will be called immediately after the browser object is created. The host application can use this method to keep a reference to the main browser object. + +```cpp +void MyClient::OnAfterCreated(CefRefPtr browser) { + // Must be executed on the UI thread. + REQUIRE_UI_THREAD(); + + if (!browser_) { + // Keep a reference to the main browser. + browser_ = browser; + browser_id_ = browser->GetIdentifier(); + } + + // Keep track of how many browsers currently exist. + browser_count_++; +} +``` + +To destroy the browser call CefBrowserHost::CloseBrowser(). + +```cpp +// Notify the browser window that we would like to close it. This will result in a call to +// MyHandler::DoClose() if the JavaScript 'onbeforeunload' event handler allows it. +browser->GetHost()->CloseBrowser(false); +``` + +If the browser is parented to another window then the close event may originate in the OS function for that parent window (for example, by clicking the X on the parent window). The parent window then needs to call CloseBrowser(false) and wait for a second OS close event to indicate that the browser has allowed the close. The second OS close event will not be sent if the close is canceled by a JavaScript ‘onbeforeunload’ event handler or by the DoClose() callback. Notice the IsClosing() check in the below examples -- it will return false for the first OS close event and true for the second (after DoClose is called). + +Handling in the parent window WndProc on Windows: + +```cpp +case WM_CLOSE: + if (g_handler && !g_handler->IsClosing()) { + CefRefPtr browser = g_handler->GetBrowser(); + if (browser) { + // Notify the browser window that we would like to close it. This will result in a call to + // MyHandler::DoClose() if the JavaScript 'onbeforeunload' event handler allows it. + browser->GetHost()->CloseBrowser(false); + + // Cancel the close. + return 0; + } + } + + // Allow the close. + break; + +case WM_DESTROY: + // Quitting CEF is handled in MyHandler::OnBeforeClose(). + return 0; +} +``` + +Handling the “delete\_event” signal on Linux: + +```cpp +gboolean delete_event(GtkWidget* widget, GdkEvent* event, + GtkWindow* window) { + if (g_handler && !g_handler->IsClosing()) { + CefRefPtr browser = g_handler->GetBrowser(); + if (browser) { + // Notify the browser window that we would like to close it. This will result in a call to + // MyHandler::DoClose() if the JavaScript 'onbeforeunload' event handler allows it. + browser->GetHost()->CloseBrowser(false); + + // Cancel the close. + return TRUE; + } + } + + // Allow the close. + return FALSE; +} +``` + +Shutdown on OS X is more complicated. See comments in [cefsimple/cefsimple\_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_mac.mm) for a complete understanding of how shutdown works on that platform. + +The DoClose() method sets the is\_closing\_ flag and returns false to send the second OS close event. + +```cpp +bool MyClient::DoClose(CefRefPtr browser) { + // Must be executed on the UI thread. + REQUIRE_UI_THREAD(); + + // Closing the main window requires special handling. See the DoClose() + // documentation in the CEF header for a detailed description of this + // process. + if (browser_id_ == browser->GetIdentifier()) { + // Set a flag to indicate that the window close should be allowed. + is_closing_ = true; + } + + // Allow the close. For windowed browsers this will result in the OS close + // event being sent. + return false; +} +``` + +When the OS function receives the second OS close event it allows the parent window to actually close. This then results in a call to OnBeforeClose(). Make sure to release any references to the browser object in the OnBeforeClose() callback. + +```cpp +void MyHandler::OnBeforeClose(CefRefPtr browser) { + // Must be executed on the UI thread. + REQUIRE_UI_THREAD(); + + if (browser_id_ == browser->GetIdentifier()) { + // Free the browser pointer so that the browser can be destroyed. + browser_ = nullptr; + } + + if (--browser_count_ == 0) { + // All browser windows have closed. Quit the application message loop. + CefQuitMessageLoop(); + } +} +``` + +See the cefclient application for complete working examples on each platform. + +## Off-Screen Rendering + +With off-screen rendering CEF does not create a native browser window. Instead, CEF provides the host application with invalidated regions and a pixel buffer and the host application notifies CEF of input events such as mouse, keyboard and focus. Off-screen rendering does not currently support accelerated compositing so performance may suffer as compared to a windowed browser. Off-screen browsers will receive the same notifications as windowed browsers including the life span notifications described in the previous section. To use off-screen rendering: + + 1. Implement the [CefRenderHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRenderHandler.html) interface. All methods are required unless otherwise indicated. + 1. Call CefWindowInfo::SetAsWindowless() before passing the CefWindowInfo structure to CefBrowserHost::CreateBrowser(). If no parent window is passed to SetAsWindowless some functionality like context menus may not be available. + 1. The CefRenderHandler::GetViewRect() method will be called to retrieve the desired view rectangle. + 1. The CefRenderHandler::OnPaint() method will be called to provide invalid regions and the updated pixel buffer. The cefclient application draws the buffer using OpenGL but your application can use whatever technique you prefer. + 1. To resize the browser call CefBrowserHost::WasResized(). This will result in a call to GetViewRect() to retrieve the new size followed by a call to OnPaint(). + 1. Call the CefBrowserHost::SendXXX() methods to notify the browser of mouse, keyboard and focus events. + 1. Call CefBrowserHost::CloseBrowser() to destroy browser. + +Run cefclient with the “--off-screen-rendering-enabled” command-line flag for a working example. + +# Posting Tasks + +Tasks can be posted between the various threads in a single process using the CefPostTask family of methods (see the [include/cef\_task.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_task.h) header file for the complete list). The task will execute asynchronously on the message loop of the target thread. + +CEF provides base::Bind[Once|Repeating] and base::[Once|Repeating]Callback templated callback classes for passing bound methods, objects and arguments to CefPostTask. For complete base::Bind and base::Callback usage information see the [Chromium documentation](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/callback.md). The [include/wrapper/cef\_closure\_task.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_closure_task.h) header provides helpers for converting a base::[Once|Repeating]Closure to a CefTask. For example: + +```cpp +// Include the necessary headers. +#include “include/base/cef_callback.h” +#include “include/wrapper/cef_closure_task.h” + +// To execute a bound function: + +// Define a function. +void MyFunc(int arg) { /* do something with |arg| on the UI thread */ } + +// Post a task that will execute MyFunc on the UI thread and pass an |arg| +// value of 5. +CefPostTask(TID_UI, base::BindOnce(&MyFunc, 5)); + +// To execute a bound method: + +// Define a class. +class MyClass : public CefBaseRefCounted { + public: + MyClass() {} + void MyMethod(int arg) { /* do something with |arg| on the UI thread */ } + private: + IMPLEMENT_REFCOUNTING(MyClass); +}; + +// Create an instance of MyClass. +CefRefPtr instance = new MyClass(); + +// Post a task that will execute MyClass::MyMethod on the UI thread and pass +// an |arg| value of 5. |instance| will be kept alive until after the task +// completes. +CefPostTask(TID_UI, base::BindOnce(&MyClass::MyMethod, instance, 5)); +``` + +If the host application needs to keep a reference to a run loop it can use the CefTaskRunner class. For example, to get the task runner for the UI thread: + +```cpp +CefRefPtr task_runner = CefTaskRunner::GetForThread(TID_UI); +``` + +# Inter-Process Communication (IPC) + +Since CEF3 runs in multiple processes it is necessary to provide mechanisms for communicating between those processes. CefBrowser and CefFrame objects exist in both the browser and render processes which helps to facilitate this process. Each CefBrowser and CefFrame object also has a unique ID value associated with it that will match on both sides of the process boundary. + +## Process Startup Messages + +Startup data can be associated with a specific CefBrowser instance at creation time via the `CefRefPtr extra_info` parameter to CefBrowserHost::CreateBrowser. That extra_info data will be delivered to every renderer process associated with that CefBrowser via the CefRenderProcessHandler::OnBrowserCreated callback. See the “Processes” section for more information about when and how a new renderer process will be spawned. + +## Process Runtime Messages + +Messages can be passed between processes at runtime using the [CefProcessMessage](https://cef-builds.spotifycdn.com/docs/stable.html?classCefProcessMessage.html) class. These messages are associated with a specific CefBrowser and CefFrame instance and sent using the CefFrame::SendProcessMessage() method. The process message should contain whatever state information is required via CefProcessMessage::GetArgumentList(). + +```cpp +// Create the message object. +CefRefPtr msg= CefProcessMessage::Create(“my_message”); + +// Retrieve the argument list object. +CefRefPtr args = msg>GetArgumentList(); + +// Populate the argument values. +args->SetString(0, “my string”); +args->SetInt(0, 10); + +// Send the process message to the main frame in the render process. +// Use PID_BROWSER instead when sending a message to the browser process. +browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, msg); +``` + +A message sent from the browser process to the render process will arrive in CefRenderProcessHandler::OnProcessMessageReceived(). A message sent from the render process to the browser process will arrive in CefClient::OnProcessMessageReceived(). + +```cpp +bool MyHandler::OnProcessMessageReceived( + CefRefPtr browser, + CefRefPtr frame, + CefProcessId source_process, + CefRefPtr message) { + // Check the message name. + const std::string& message_name = message->GetName(); + if (message_name == “my_message”) { + // Handle the message here... + return true; + } + return false; +} +``` + +## Asynchronous JavaScript Bindings + +[Java Script Integration](javascript_integration.md) is implemented in the render process but frequently need to communicate with the browser process. The JavaScript APIs themselves should be designed to work asynchronously using [closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures) and [promises](http://www.html5rocks.com/en/tutorials/es6/promises/). + +### Generic Message Router + +CEF provides a generic implementation for routing asynchronous messages between JavaScript running in the renderer process and C++ running in the browser process. An application interacts with the router by passing it data from standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageRecieved, OnContextCreated, etc). The renderer-side router supports generic JavaScript callback registration and execution while the browser-side router supports application-specific logic via one or more application-provided Handler instances. See the [message_router example](https://github.com/chromiumembedded/cef-project/blob/master/examples/message_router/) for a stand-alone example application that demonstates CefMessageRouter usage. See [include/wrapper/cef\_message\_router.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_message_router.h) for complete usage documentation. + +### Custom Implementation + +A CEF-based application can also provide its own custom implementation of asynchronous JavaScript bindings. A simplistic implementation could work as follows: + +1\. The JavaScript binding in the render process is passed a callback function. + +```cpp +// In JavaScript register the callback function. +app.setMessageCallback('binding_test', function(name, args) { + document.getElementById('result').value = "Response: "+args[0]; +}); +``` + +2\. The render process keeps a reference to the callback function. + +```cpp +// Map of message callbacks. +typedef std::map, + std::pair, CefRefPtr > > + CallbackMap; +CallbackMap callback_map_; + +// In the CefV8Handler::Execute implementation for “setMessageCallback”. +if (arguments.size() == 2 && arguments[0]->IsString() && + arguments[1]->IsFunction()) { + std::string message_name = arguments[0]->GetStringValue(); + CefRefPtr context = CefV8Context::GetCurrentContext(); + int browser_id = context->GetBrowser()->GetIdentifier(); + callback_map_.insert( + std::make_pair(std::make_pair(message_name, browser_id), + std::make_pair(context, arguments[1]))); +} +``` + +3\. The render process sends an asynchronous IPC message to the browser process requesting that work be performed. + +4\. The browser process receives the IPC message and performs the work. + +5\. Upon completion of the work the browser process sends an asynchronous IPC message back to the render process with the result. + +6\. The render process receives the IPC message and executes the callback function with the result. + +```cpp +// Execute the registered JavaScript callback if any. +if (!callback_map_.empty()) { + const CefString& message_name = message->GetName(); + CallbackMap::const_iterator it = callback_map_.find( + std::make_pair(message_name.ToString(), + browser->GetIdentifier())); + if (it != callback_map_.end()) { + // Keep a local reference to the objects. The callback may remove itself + // from the callback map. + CefRefPtr context = it->second.first; + CefRefPtr callback = it->second.second; + + // Enter the context. + context->Enter(); + + CefV8ValueList arguments; + + // First argument is the message name. + arguments.push_back(CefV8Value::CreateString(message_name)); + + // Second argument is the list of message arguments. + CefRefPtr list = message->GetArgumentList(); + CefRefPtr args = CefV8Value::CreateArray(list->GetSize()); + SetList(list, args); // Helper function to convert CefListValue to CefV8Value. + arguments.push_back(args); + + // Execute the callback. + CefRefPtr retval = callback->ExecuteFunction(nullptr, arguments); + if (retval.get()) { + if (retval->IsBool()) + handled = retval->GetBoolValue(); + } + + // Exit the context. + context->Exit(); + } +} +``` + +7\. Release any V8 references associated with the context in CefRenderProcessHandler::OnContextReleased(). + +```cpp +void MyHandler::OnContextReleased(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) { + // Remove any JavaScript callbacks registered for the context that has been released. + if (!callback_map_.empty()) { + CallbackMap::iterator it = callback_map_.begin(); + for (; it != callback_map_.end();) { + if (it->second.first->IsSame(context)) + callback_map_.erase(it++); + else + ++it; + } + } +} +``` + +## Synchronous Requests + +In rare cases it may be necessary to implement synchronous communication between the browser and render processes. This should be avoided whenever possible because it will negatively impact performance in the render process. However, if you must have synchronous communication consider using [synchronous XMLHttpRequests](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests) which will block the render process while awaiting handling in the browser process network layer. The browser process can handle the requests using a custom scheme handler or network interception. See the “Network Layer” section for more information. + +# Network Layer + +By default network requests in CEF3 will be handled in a manner transparent to the host application. For applications wishing for a closer relationship with the network layer CEF3 exposes a range of network-related functionalities. + +Network-related callbacks can occur on different threads so make sure to pay attention to the documentation and properly protect your data members (see the “Threads” section for background). + +## Custom Requests + +The simplest way to load a URL in a browser frame is via the CefFrame::LoadURL() method. + +``` +browser->GetMainFrame()->LoadURL(some_url); +``` + +Applications wishing to send more complex requests containing custom request headers or upload data can use the CefFrame::LoadRequest() method. This method accepts a [CefRequest](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRequest.html) object as the single argument. + +**WARNING: The LoadRequest method will fail with "bad IPC message" reason INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the request origin (scheme + domain) using some other mechanism (LoadURL, link click, etc).** + +```cpp +// Create a CefRequest object. +CefRefPtr request = CefRequest::Create(); + +// Set the request URL. +request->SetURL(some_url); + +// Set the request method. Supported methods include GET, POST, HEAD, DELETE and PUT. +request->SetMethod(“POST”); + +// Optionally specify custom headers. +CefRequest::HeaderMap headerMap; +headerMap.insert( + std::make_pair("X-My-Header", "My Header Value")); +request->SetHeaderMap(headerMap); + +// Optionally specify upload content. +// The default “Content-Type” header value is "application/x-www-form-urlencoded". +// Set “Content-Type” via the HeaderMap if a different value is desired. +const std::string& upload_data = “arg1=val1&arg2=val2”; +CefRefPtr postData = CefPostData::Create(); +CefRefPtr element = CefPostDataElement::Create(); +element->SetToBytes(upload_data.size(), upload_data.c_str()); +postData->AddElement(element); +request->SetPostData(postData); +``` + +### Browser-Independent Requests + +Applications can send network requests via the [CefURLRequest](https://cef-builds.spotifycdn.com/docs/stable.html?classCefURLRequest.html) class. Implement the [CefURLRequestClient](https://cef-builds.spotifycdn.com/docs/stable.html?classCefURLRequestClient.html) interface to handle the resulting response. + + * Requests not associated with a particular CefBrowser/CefFrame can be sent via the CefURLRequest::Create method. These types of requests can only be used in the browser process. + * Requests associated with a particular CefBrowser/CefFrame can be sent via the CefFrame::CreateURLRequest method. These types of requests can be used in both the browser and the renderer process. + +See documentation on the above methods for additional usage restrictions. + +Here is an example of CefURLRequest usage: + +```cpp +class MyRequestClient : public CefURLRequestClient { + public: + MyRequestClient() + : upload_total_(0), + download_total_(0) {} + + void OnRequestComplete(CefRefPtr request) override { + CefURLRequest::Status status = request->GetRequestStatus(); + CefURLRequest::ErrorCode error_code = request->GetRequestError(); + CefRefPtr response = request->GetResponse(); + + // Do something with the response... + } + + void OnUploadProgress(CefRefPtr request, + int64 current, + int64 total) override { + upload_total_ = total; + } + + void OnDownloadProgress(CefRefPtr request, + int64 current, + int64 total) override { + download_total_ = total; + } + + void OnDownloadData(CefRefPtr request, + const void* data, + size_t data_length) override { + download_data_ += std::string(static_cast(data), data_length); + } + + bool GetAuthCredentials(bool isProxy, + const CefString& host, + int port, + const CefString& realm, + const CefString& scheme, + CefRefPtr callback) override { + return false; // Not handled. + } + + private: + int64 upload_total_; + int64 download_total_; + std::string download_data_; + + private: + IMPLEMENT_REFCOUNTING(MyRequestClient); +}; +``` + +To send the request: + +```cpp +// Set up the CefRequest object. +CefRefPtr request = CefRequest::Create(); +// Populate |request| as shown above... + +// Create the client instance. +CefRefPtr client = new MyRequestClient(); + +// Start the request. MyRequestClient callbacks will be executed asynchronously. +CefRefPtr url_request = CefURLRequest::Create(request, client.get(), nullptr); +// To cancel the request: url_request->Cancel(); +``` + +Requests made with CefURLRequest can also specify custom behaviors via the CefRequest::SetFlags() method. Supported bit flags include: + + * **UR\_FLAG\_SKIP\_CACHE** If set the cache will be skipped when handling the request. + * **UR\_FLAG\_ALLOW\_STORED\_CREDENTIALS** If set cookies may be sent with the request and saved from the response. + * **UR\_FLAG\_REPORT\_UPLOAD\_PROGRESS** If set upload progress events will be generated when a request has a body. + * **UR\_FLAG\_NO\_DOWNLOAD\_DATA** If set the CefURLRequestClient::OnDownloadData method will not be called. + * **UR\_FLAG\_NO\_RETRY\_ON\_5XX** If set 5XX redirect errors will be propagated to the observer instead of automatically re-tried. This currently only applies for requests originated in the browser process. + +See [cef\_urlrequest\_flags\_t](https://github.com/chromiumembedded/cef/blob/81e7748fb5008295c2a1f2d75b0f0c907c1fdfe8/include/internal/cef_types.h#L1243) for the complete list of supported flags. + +For example, to skip the cache and not report download data: + +``` +request->SetFlags(UR_FLAG_SKIP_CACHE | UR_FLAG_NO_DOWNLOAD_DATA); +``` + +## Request Handling + +CEF3 supports two approaches for handling network requests inside of an application. The scheme handler approach allows registration of a handler for requests targeting a particular origin (scheme + domain). The request interception approach allows handling of arbitrary requests at the application’s discretion. + +**WARNING: Use the HTTP scheme instead of a custom scheme to avoid a range of potential issues.** + +If you choose to use a custom scheme (anything other than “HTTP”, “HTTPS”, etc) you must register it with CEF so that it will behave as expected. If you would like your custom scheme to behave similar to HTTP (support POST requests and enforce [HTTP access control (CORS)](https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS) restrictions) then it should be registered as a “standard” scheme. If you are planning to perform cross-origin requests to other schemes or send POST requests via XMLHttpRequest to your scheme handler then you should use the HTTP scheme instead of a custom scheme to avoid [potential issues](https://github.com/chromiumembedded/cef/issues/950). If you wish to use custom schemes the attributes are registered via the CefApp::OnRegisterCustomSchemes() callback which must be implemented in all processes. + +```cpp +void MyApp::OnRegisterCustomSchemes(CefRefPtr registrar) { + // Register "client" as a standard scheme. + int options = CEF_SCHEME_OPTION_STANDARD; + registrar->AddCustomScheme("client", options); +} +``` + +See [cef\_scheme\_options\_t](https://github.com/chromiumembedded/cef/blob/81e7748fb5008295c2a1f2d75b0f0c907c1fdfe8/include/internal/cef_types.h#L2795) for the complete list of supported flags. + +### Generic Resource Manager + +CEF provides a generic implementation for managing resource requests from one or more data sources. This user registers handlers for different data sources, such as directories on disk, zip archives or custom implementations, and the manager handles the requests. An application interacts with the router by passing it data from standard CEF C++ callbacks (OnBeforeResourceLoad, GetResourceHandler). See the [resource_manager example](https://github.com/chromiumembedded/cef-project/blob/master/examples/resource_manager/) for a stand-alone example application that demonstates CefResourceManager usage. See [include/wrapper/cef\_resource\_manager.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_resource_manager.h) for complete usage documentation. + +### Scheme Handler + +A scheme handler is registered via the CefRegisterSchemeHandlerFactory() function. A good place to call this function is from CefBrowserProcessHandler::OnContextInitialized(). For example, you can register a handler for “client://myapp/” requests: + +``` +CefRegisterSchemeHandlerFactory("client", “myapp”, new MySchemeHandlerFactory()); +``` + +Handlers can be used with both built-in schemes (HTTP, HTTPS, etc) and custom schemes. When using a built-in scheme choose a domain name unique to your application (like “myapp” or “internal”). Implement the [CefSchemeHandlerFactory](https://cef-builds.spotifycdn.com/docs/stable.html?classCefSchemeHandlerFactory.html) and [CefResourceHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefResourceHandler.html) classes to handle the request and provide response data. If using custom schemes don't forget to implement the CefApp::OnRegisterCustomSchemes method as described above. See the [scheme_handler example](https://github.com/chromiumembedded/cef-project/blob/master/examples/scheme_handler/) for a stand-alone example application that demonstates CefSchemeHandlerFactory usage. See [include/cef\_scheme.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_scheme.h) for complete usage documentation. + +If the response data is known at request time the [CefStreamResourceHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefStreamResourceHandler.html) class provides a convenient default implementation of CefResourceHandler. + +```cpp +// CefStreamResourceHandler is part of the libcef_dll_wrapper project. +#include “include/wrapper/cef_stream_resource_handler.h” + +const std::string& html_content = “Hello!”; + +// Create a stream reader for |html_content|. +CefRefPtr stream = + CefStreamReader::CreateForData( + static_cast(const_cast(html_content.c_str())), + html_content.size()); + +// Constructor for HTTP status code 200 and no custom response headers. +// There’s also a version of the constructor for custom status code and response headers. +return new CefStreamResourceHandler("text/html", stream); +``` + +### Request Interception + +The CefRequestHandler::GetResourceHandler() method supports the interception of arbitrary requests. It uses the same CefResourceHandler class as the scheme handler approach. If using custom schemes don't forget to implement the CefApp::OnRegisterCustomSchemes method as described above. + +```cpp +CefRefPtr MyHandler::GetResourceHandler( + CefRefPtr browser, + CefRefPtr frame, + CefRefPtr request) { + // Evaluate |request| to determine proper handling... + if (...) + return new MyResourceHandler(); + + // Return nullptr for default handling of the request. + return nullptr; +} +``` + +### Response Filtering + +The CefRequestHandler::GetResourceResponseFilter() method supports filtering of request response data. See [cefclient/browser/response\_filter\_test.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/browser/response_filter_test.cc) (accessible via the Tests menu > Other Tests > Response Filtering from inside the cefclient sample application) for a working example. + +## Other Callbacks + +The [CefRequestHandler](https://cef-builds.spotifycdn.com/docs/stable.html?classCefRequestHandler.html) interface provides callbacks for various network-related events incuding authentication, cookie handling, external protocol handling, certificate errors and so on. + +## Proxy Resolution + +Proxy settings are configured in CEF3 using the same command-line flags as Google Chrome. + +``` +--proxy-server=host:port + Specify the HTTP/SOCKS4/SOCKS5 proxy server to use for requests. An individual proxy + server is specified using the format: + + [://][:] + + Where is the protocol of the proxy server, and is one of: + + "http", "socks", "socks4", "socks5". + + If the is omitted, it defaults to "http". Also note that "socks" is equivalent to + "socks5". + + Examples: + + --proxy-server="foopy:99" + Use the HTTP proxy "foopy:99" to load all URLs. + + --proxy-server="socks://foobar:1080" + Use the SOCKS v5 proxy "foobar:1080" to load all URLs. + + --proxy-server="sock4://foobar:1080" + Use the SOCKS v4 proxy "foobar:1080" to load all URLs. + + --proxy-server="socks5://foobar:66" + Use the SOCKS v5 proxy "foobar:66" to load all URLs. + + It is also possible to specify a separate proxy server for different URL types, by prefixing + the proxy server specifier with a URL specifier: + + Example: + + --proxy-server="https=proxy1:80;http=socks4://baz:1080" + Load https://* URLs using the HTTP proxy "proxy1:80". And load http://* + URLs using the SOCKS v4 proxy "baz:1080". + +--no-proxy-server + Disables the proxy server. + +--proxy-auto-detect + Autodetect proxy configuration. + +--proxy-pac-url=URL + Specify proxy autoconfiguration URL. +``` + +If the proxy requires authentication the CefRequestHandler::GetAuthCredentials() callback will be executed with an |isProxy| value of true to retrieve the username and password. + +```cpp +bool MyHandler::GetAuthCredentials( + CefRefPtr browser, + CefRefPtr frame, + bool isProxy, + const CefString& host, + int port, + const CefString& realm, + const CefString& scheme, + CefRefPtr callback) { + if (isProxy) { + // Provide credentials for the proxy server connection. + callback->Continue("myuser", "mypass"); + return true; + } + return false; +} +``` + +Web content loading during application startup can be delayed due to network proxy resolution (for example, if "Automatically detect proxy settings" is checked on Windows). For best user experience consider designing your application to first show a static splash page and then redirect to the actual website using [meta refresh](http://en.wikipedia.org/wiki/Meta_refresh) -- the redirect will be blocked until proxy resolution completes. For testing purposes proxy resolution can be disabled using the "--no-proxy-server" command-line flag. Proxy resolution delays can also be duplicated in Google Chrome by running "chrome --url=..." from the command line. \ No newline at end of file diff --git a/docs/hands_on_tutorial.md b/docs/hands_on_tutorial.md new file mode 100644 index 000000000..ba5b866b6 --- /dev/null +++ b/docs/hands_on_tutorial.md @@ -0,0 +1,2045 @@ +This page provides a hands-on tutorial for building a CEF application by progressively modifying the cefsimple example. + +**Contents** + +- [Introduction](#introduction) + - [CEF Quick Concepts](#cef-quick-concepts) +- [Step 0: Setup and Verify](#step-0-setup-and-verify) + - [Download and Build cefsimple](#download-and-build-cefsimple) + - [Understanding cefsimple Structure](#understanding-cefsimple-structure) +- [Step 1: Simplify to Absolute Minimum](#step-1-simplify-to-absolute-minimum) + - [What We're Removing](#what-were-removing) + - [Architecture Overview](#architecture-overview) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh) + - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc) + - [tests/cefsimple/simple_app.h](#testscefsimplesimple_apph) + - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc) + - [Delete Platform-Specific Handler Files](#delete-platform-specific-handler-files) + - [Update CMakeLists.txt](#update-cmakeliststxt) + - [Keep Unchanged](#keep-unchanged) + - [Limitations of This Simplified Version](#limitations-of-this-simplified-version) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) + - [Common Issues](#common-issues) +- [Step 2: Custom URL from Code](#step-2-custom-url-from-code) + - [What We're Adding](#what-were-adding) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Step 3: Command-Line URL Support](#step-3-command-line-url-support) + - [What We're Adding](#what-were-adding) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Step 4: Window Title Updates](#step-4-window-title-updates) + - [What We're Adding](#what-were-adding) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh) + - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Step 5: JavaScript Execution](#step-5-javascript-execution) + - [What We're Adding](#what-were-adding) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh) + - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Step 6: JavaScript-to-C++ Communication](#step-6-javascript-to-c-communication) + - [What We're Adding](#what-were-adding) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_app.h](#testscefsimplesimple_apph) + - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc) + - [Platform Entry Points](#platform-entry-points) + - [tests/cefsimple/cefsimple_linux.cc](#testscefsimplecefsimple_linuxcc) + - [tests/cefsimple/cefsimple_win.cc](#testscefsimplecefsimple_wincc) + - [tests/cefsimple/process_helper_mac.cc](#testscefsimpleprocess_helper_maccc) + - [tests/cefsimple/CMakeLists.txt (macOS only)](#testscefsimplecmakeliststxt-macos-only) + - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh) + - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Step 7: Multiple Browser Support](#step-7-multiple-browser-support) + - [What We're Adding](#what-were-adding) + - [Why This Matters](#why-this-matters) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_handler.h](#testscefsimplesimple_handlerh) + - [tests/cefsimple/simple_handler.cc](#testscefsimplesimple_handlercc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Step 8: Views Styling of Popup Browsers](#step-8-views-styling-of-popup-browsers) + - [What We're Adding](#what-were-adding) + - [Why This Matters](#why-this-matters) + - [Modified Files](#modified-files) + - [tests/cefsimple/simple_app.cc](#testscefsimplesimple_appcc) + - [Build and Run](#build-and-run) + - [What's Happening](#whats-happening) +- [Next Steps](#next-steps) + - [Explore More Features](#explore-more-features) + - [Learn Advanced Topics](#learn-advanced-topics) + - [Using the C API](#using-the-c-api) + - [Using Claude Code for Implementation](#using-claude-code-for-implementation) + +--- + +# Introduction + +This tutorial teaches CEF development by **modifying the cefsimple example** step-by-step. You'll start with a working application and progressively add features, learning CEF concepts along the way. + +**Who is this for?** + +- Developers new to CEF who want hands-on learning +- C++ developers with basic knowledge (classes, pointers, inheritance) +- Those who prefer learning by doing rather than reading reference documentation +- Anyone who wants to understand CEF architecture through practice + +**Why start from cefsimple?** + +- ✅ CMake already configured correctly +- ✅ Resources (`.pak` files, frameworks) already in the right place +- ✅ macOS app bundle structure already set up +- ✅ Platform-specific entry points already working +- ✅ You can verify your build environment works before making changes + +**Prerequisites:** + +- CEF binary distribution for your platform ([download here](https://cef-builds.spotifycdn.com/index.html)) +- C++ compiler: + - Windows: Visual Studio 2022 + - macOS: Xcode with command-line tools + - Linux: GCC/Clang, build-essential, and libgtk-3-dev packages +- CMake 3.19+ + +**What you'll build:** + +Starting from cefsimple, you'll progressively add features to create a custom browser with JavaScript integration and popup window customization. + +**Using the C API?** This tutorial uses the C++ API. For pure C implementation, see [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/) and [Using The CAPI](using_the_capi.md). + +## CEF Quick Concepts + +Before diving into code, here are the key CEF concepts you'll encounter: + +**Multi-process architecture:** CEF runs multiple processes for security and stability: + +- **Browser process** - Main process, manages UI and coordinates other processes +- **Render processes** - Isolated processes for web content (one per site) +- **GPU process** - Hardware-accelerated graphics +- **Other processes** - Network service, audio service, etc. + +**Reference counting:** CEF objects use reference counting for memory management: + +- `CefRefPtr` - Smart pointer that automatically manages reference counts +- `IMPLEMENT_REFCOUNTING` macro - Adds thread-safe reference counting to your classes +- Objects are deleted when their reference count reaches zero + +**Threading:** CEF callbacks run on specific threads: + +- **UI thread** - Browser process main thread (most callbacks run here) +- **IO thread** - Network operations +- **Renderer thread** - JavaScript execution (in render process) +- Use `CEF_REQUIRE_UI_THREAD()`, `CEF_REQUIRE_RENDERER_THREAD()`, etc. to assert correct thread usage + +**Browser styles:** + +- **Chrome style** - Full Chrome UI with tabs, address bar, etc. (default in unmodified cefsimple) +- **Alloy style** - Lightweight mode, you control all UI (we switch to this in Step 1) +- Unmodified cefsimple supports both styles: use `--use-alloy-style` command-line flag for Alloy +- Set via `GetBrowserRuntimeStyle()` and `GetWindowRuntimeStyle()` + +**Views framework:** Cross-platform UI system: + +- `CefWindow` - Top-level window +- `CefBrowserView` - Embeds the browser in a view +- Delegates (`CefWindowDelegate`, `CefBrowserViewDelegate`) - Control window/browser behavior +- Alternative: Platform-native UI or off-screen rendering (OSR) + +**For deeper coverage** of CEF architecture and concepts, see [Tutorial.md](tutorial.md). + +# Step 0: Setup and Verify + +## Download and Build cefsimple + +1. **Download CEF binary distribution:** + + Visit [https://cef-builds.spotifycdn.com/index.html](https://cef-builds.spotifycdn.com/index.html) and download the appropriate binary distribution for your platform (e.g., `cef_binary__windows64.tar.bz2`). + +2. **Extract and enter the directory:** + + ```bash + tar -xjf cef_binary__.tar.bz2 + cd cef_binary__ +``` + +3. **Build cefsimple as-is:** + + **Windows:** + ```bash + # Build with sandbox disabled for simplicity + cmake -B build -G "Visual Studio 17 2022" -A x64 -DUSE_SANDBOX=OFF + cmake --build build --config Release --target cefsimple + build\tests\cefsimple\Release\cefsimple.exe +``` + + **Note:** This tutorial builds with sandbox disabled (`-DUSE_SANDBOX=OFF`) for simplicity. For production applications, you should enable the sandbox using the [bootstrap.exe approach](sandbox_setup.md#windows). The sandbox provides important security isolation for renderer processes. + + **Linux:** + ```bash + cmake -B build + cmake --build build --target cefsimple + build/tests/cefsimple/cefsimple +``` + + **macOS:** + ```bash + cmake -B build -G Xcode + cmake --build build --config Release --target cefsimple + open build/tests/cefsimple/Release/cefsimple.app +``` + + **Using an IDE (optional):** + + Instead of building from the command line, you can open the generated project in your IDE: + + - **Windows**: Open `build/cef.sln` in Visual Studio 2022 + - **macOS**: Open `build/cef.xcodeproj` in Xcode + - **Linux**: Open the `build` directory in CLion or another CMake-supporting IDE + +4. **Verify it works:** + + - You should see a window displaying google.com + - Window title should update with the page title + - Closing the window should exit the app cleanly + +**If this works, your environment is set up correctly!** Now we can start learning CEF by modifying the code. + +## Understanding cefsimple Structure + +```text +tests/cefsimple/ +├── simple_app.h # Application handler (process-level) +├── simple_app.cc # Browser creation logic +├── simple_handler.h # Browser handler interface +├── simple_handler.cc # Browser-level event handling +├── simple_handler_win.cc # Windows-specific (window title) +├── simple_handler_linux.cc # Linux-specific (window title) +├── simple_handler_mac.mm # macOS-specific (window title) +├── cefsimple_win.cc # Windows entry point +├── cefsimple_linux.cc # Linux entry point +├── cefsimple_mac.mm # macOS browser process entry point +└── process_helper_mac.cc # macOS helper process entry point +``` + +**Cross-platform code:** `simple_app.*`, `simple_handler.h/cc` work identically on all platforms. + +**Platform-specific code:** Entry points and window title updates for platform-specific implementations. + +# Step 1: Simplify to Absolute Minimum + +**Goal:** Strip cefsimple down to the bare minimum (~150 lines total) to understand the essential parts. + +## What We're Removing + +cefsimple has features we don't need yet: + +- ❌ Command-line URL argument handling +- ❌ Window title updates +- ❌ Error page handling +- ❌ Multiple browser tracking + +Let's remove these to see the core clearly. + +## Architecture Overview + +Before we dive into the code, here's what each piece does: + +**SimpleApp** - Application-level handler + +- Creates the browser and window when CEF is initialized +- Uses the Views framework (cross-platform UI) + +**SimpleHandler** - Browser-level event handler + +- Handles browser lifecycle events (created, closed) +- Implements singleton pattern (global instance accessed by platform entry points) +- Quits the app when the browser closes + +**Views Framework Delegates** (in simple_app.cc) + +- `SimpleWindowDelegate` - Controls window size, close behavior, runtime style +- `SimpleBrowserViewDelegate` - Specifies Alloy browser style + +**Platform Entry Point Methods** + +- `GetInstance()` - Returns the singleton instance (fully functional) +- `CloseAllBrowsers()`, `IsClosing()` - Empty stubs for now (implemented in Step 7 for multi-browser support) +- `ShowMainWindow()` - Called on macOS when user clicks dock icon. Empty stub in this tutorial (a proper implementation would show/activate the main window) + +Now let's see the actual code: + +## Modified Files + +### tests/cefsimple/simple_handler.h + +This is the browser-level event handler. Note the singleton pattern (`GetInstance()`) and stub methods for platform entry points. + +**Replace the entire file with:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ + +#include "include/cef_client.h" + +// Simple browser event handler +// Inherits from CefClient (main handler interface) and CefLifeSpanHandler +// (lifecycle events). This allows one class to handle multiple callback types. +class SimpleHandler : public CefClient, public CefLifeSpanHandler { + public: + SimpleHandler(); + ~SimpleHandler() override; + + // Provide access to the single global instance of this object. + // Used by platform entry points (cefsimple_mac.mm, etc.) + static SimpleHandler* GetInstance(); + + // CefClient methods: + CefRefPtr GetLifeSpanHandler() override { return this; } + + // CefLifeSpanHandler methods: + void OnBeforeClose(CefRefPtr browser) override; + + // Request that all existing browser windows close. + // Used by platform entry points (cefsimple_mac.mm, etc.) + void CloseAllBrowsers(bool force_close); + + // Always returns false - stub for platform entry points + bool IsClosing() const { return false; } + + void ShowMainWindow(); + + private: + // Provides thread-safe reference counting (CefRefPtr). + IMPLEMENT_REFCOUNTING(SimpleHandler); + // Prevents copying (CEF objects shouldn't be copied). + DISALLOW_COPY_AND_ASSIGN(SimpleHandler); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +``` + +### tests/cefsimple/simple_handler.cc + +Implementation of SimpleHandler. The key method is `OnBeforeClose()` which quits the app when the browser closes. + +**Replace the entire file with:** + +```cpp +#include "tests/cefsimple/simple_handler.h" + +#include "include/cef_app.h" +#include "include/wrapper/cef_helpers.h" + +namespace { +// Anonymous namespace - variables here are only visible in this file +SimpleHandler* g_instance = nullptr; + +} // namespace + +SimpleHandler::SimpleHandler() { + DCHECK(!g_instance); // Debug assertion - crashes if instance already exists + g_instance = this; +} + +SimpleHandler::~SimpleHandler() { + g_instance = nullptr; +} + +// static +SimpleHandler* SimpleHandler::GetInstance() { + return g_instance; +} + +void SimpleHandler::OnBeforeClose(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + + // Browser closed - quit the application + // This simplified version only supports a single browser + CefQuitMessageLoop(); +} + +void SimpleHandler::CloseAllBrowsers(bool force_close) { + // Empty stub - required by platform entry points but not used + // in this simplified Views-based version +} + +void SimpleHandler::ShowMainWindow() { + // Empty stub. A proper implementation would show/activate the main window. + // Called on macOS when user clicks the dock icon while app is running. +} +``` + +### tests/cefsimple/simple_app.h + +Application-level handler that receives callbacks when CEF is initialized. Declares `OnContextInitialized()` where we create the browser. + +**Replace the entire file with:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ + +#include "include/cef_app.h" + +// Implement application-level callbacks for the browser process. +class SimpleApp : public CefApp, public CefBrowserProcessHandler { + public: + SimpleApp(); + + // CefApp methods: + CefRefPtr GetBrowserProcessHandler() override { + return this; + } + + // CefBrowserProcessHandler methods: + void OnContextInitialized() override; + + private: + IMPLEMENT_REFCOUNTING(SimpleApp); + DISALLOW_COPY_AND_ASSIGN(SimpleApp); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ +``` + +### tests/cefsimple/simple_app.cc + +Implementation of SimpleApp. Creates the browser and window using Views framework. Contains inline delegate classes that control window and browser behavior. + +**Replace the entire file with:** + +```cpp +#include "tests/cefsimple/simple_app.h" + +#include "tests/cefsimple/simple_handler.h" + +#include "include/cef_browser.h" +#include "include/views/cef_browser_view.h" +#include "include/views/cef_window.h" +#include "include/wrapper/cef_helpers.h" + +namespace { + +// Window delegate - controls window behavior +class SimpleWindowDelegate : public CefWindowDelegate { + public: + explicit SimpleWindowDelegate(CefRefPtr browser_view) + : browser_view_(browser_view) {} + + void OnWindowCreated(CefRefPtr window) override { + // Add the browser view and show the window + window->AddChildView(browser_view_); + window->Show(); + } + + bool CanClose(CefRefPtr window) override { + // Allow the window to close if the browser says it's OK + CefRefPtr browser = browser_view_->GetBrowser(); + if (browser) { + return browser->GetHost()->TryCloseBrowser(); + } + return true; + } + + CefSize GetPreferredSize(CefRefPtr view) override { + return CefSize(800, 600); + } + + cef_runtime_style_t GetWindowRuntimeStyle() override { + return CEF_RUNTIME_STYLE_ALLOY; + } + + private: + CefRefPtr browser_view_; + + IMPLEMENT_REFCOUNTING(SimpleWindowDelegate); + DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate); +}; + +// Browser view delegate +class SimpleBrowserViewDelegate : public CefBrowserViewDelegate { + public: + SimpleBrowserViewDelegate() = default; + + cef_runtime_style_t GetBrowserRuntimeStyle() override { + return CEF_RUNTIME_STYLE_ALLOY; + } + + private: + IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate); + DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate); +}; + +} // namespace + +SimpleApp::SimpleApp() = default; + +void SimpleApp::OnContextInitialized() { + CEF_REQUIRE_UI_THREAD(); + + CefRefPtr handler(new SimpleHandler()); + CefBrowserSettings browser_settings; + + // Create the browser view (Views framework - cross-platform) + CefRefPtr browser_view = CefBrowserView::CreateBrowserView( + handler, "https://www.google.com", browser_settings, nullptr, nullptr, + new SimpleBrowserViewDelegate()); + + // Create the window (Views framework - cross-platform) + CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view)); +} +``` + +### Delete Platform-Specific Handler Files + +Since we removed window title updates, delete these files: + +- `tests/cefsimple/simple_handler_win.cc` +- `tests/cefsimple/simple_handler_linux.cc` +- `tests/cefsimple/simple_handler_mac.mm` + +### Update CMakeLists.txt + +`CMakeLists.txt` tells CMake which source files to compile. Since we deleted the platform-specific handler files, we need to remove them from the build configuration. + +Update `tests/cefsimple/CMakeLists.txt` to remove references to the deleted files: + +**Find these lines:** + +```cmake +set(CEFSIMPLE_SRCS_LINUX + cefsimple_linux.cc + simple_handler_linux.cc + ) +set(CEFSIMPLE_SRCS_MAC + cefsimple_mac.mm + simple_handler_mac.mm + ) +set(CEFSIMPLE_SRCS_WINDOWS + cefsimple_win.cc + resource.h + simple_handler_win.cc + ) +``` + +**Replace with:** + +```cmake +set(CEFSIMPLE_SRCS_LINUX + cefsimple_linux.cc + ) +set(CEFSIMPLE_SRCS_MAC + cefsimple_mac.mm + ) +set(CEFSIMPLE_SRCS_WINDOWS + cefsimple_win.cc + resource.h + ) +``` + +This removes the references to `simple_handler_linux.cc`, `simple_handler_mac.mm`, and `simple_handler_win.cc` that we deleted. + +### Keep Unchanged + +**Don't modify these files** - they contain platform-specific entry point code that's already correct: + +- [cefsimple_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_win.cc) - Windows entry point (modified in Step 6) +- [cefsimple_linux.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_linux.cc) - Linux entry point (modified in Step 6) +- [cefsimple_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_mac.mm) - macOS browser process entry point +- [process_helper_mac.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/process_helper_mac.cc) - macOS helper process entry point (modified in Step 6) + +## Limitations of This Simplified Version + +This simplified code has the following limitations: + +- **Alloy style only**: Hardcoded to `CEF_RUNTIME_STYLE_ALLOY` in both `SimpleWindowDelegate` and `SimpleBrowserViewDelegate`. The original cefsimple supports both Chrome and Alloy styles via command-line flag. +- **Single browser only**: The app exits immediately when the browser window closes. Multi-browser support requires tracking browser instances (added in Step 7). +- **No window title updates**: We removed the handlers that update window titles based on page titles (added back in Step 4). +- **No command-line URL support**: The URL is hardcoded to "https://www.google.com" (added in Step 3). +- **Quit menu doesn't work**: On macOS, the Quit option in the application menu doesn't work (the stub `CloseAllBrowsers()` implementation does nothing). You must close the window to quit the app. (Fixed in Step 7) +- **Dock icon doesn't restore window**: On macOS, clicking the dock icon when the app is running doesn't restore the window (the stub `ShowMainWindow()` implementation does nothing). This remains a stub throughout the tutorial. +- **Empty stub methods**: `CloseAllBrowsers()` and `IsClosing()` are empty stubs (implemented in Step 7 for multi-browser support). `ShowMainWindow()` remains a stub throughout (a proper implementation would show/activate the main window on macOS). + +These limitations are intentional to keep the code minimal for learning. We'll add features back in subsequent steps. + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +You should see a window open with google.com. **Note:** The window title won't update with the page title anymore (we removed that feature to simplify), but otherwise the app works the same as the original. Now you understand every line of code! + +## What's Happening + +**Three key pieces:** + +1. **SimpleApp** (application-level handler) + - Inherits from `CefApp` and `CefBrowserProcessHandler` + - `OnContextInitialized()` - Called when CEF is ready to create browsers + - Creates the browser and window using Views framework + +2. **SimpleHandler** (browser-level event handler) + - Inherits from `CefClient` and `CefLifeSpanHandler` + - `GetLifeSpanHandler()` - Returns this handler for lifecycle events + - `OnBeforeClose()` - Called when browser is closing, quits the app + +3. **Views Framework Delegates** + - `SimpleWindowDelegate` - Controls window size, close behavior, runtime style + - `SimpleBrowserViewDelegate` - Specifies Alloy browser style + - Both are **cross-platform** - same code works on Windows, Linux, macOS + +**Why Alloy style?** Simpler than Chrome style - you control the UI completely. We explicitly set `CEF_RUNTIME_STYLE_ALLOY` in both delegates. + +**Entry points:** Platform-specific files (`cefsimple_*.cc/mm`) handle: + +- CEF initialization (`CefInitialize`) +- Message loop (`CefRunMessageLoop`) +- Shutdown (`CefShutdown`) +- macOS-specific: Framework loading, NSApplication setup + +**Program Flow:** Here's the complete execution sequence: + +1. **main()** (in entry point file) - Program starts +2. **CefInitialize()** - Initializes CEF with SimpleApp instance +3. **SimpleApp::OnContextInitialized()** - CEF ready, creates browser: + - Creates SimpleHandler instance + - Creates CefBrowserView with URL + - Creates CefWindow with SimpleWindowDelegate +4. **CefRunMessageLoop()** - Enters message loop, processes events +5. **User closes window** → SimpleWindowDelegate::CanClose() → TryCloseBrowser() +6. **SimpleHandler::OnBeforeClose()** - Called when browser is closing + - Calls CefQuitMessageLoop() to exit the message loop +7. **CefShutdown()** - Cleanup and shutdown CEF +8. **main() exits** - Program terminates + +## Common Issues + +- **Build errors about missing files** - Make sure you: + 1. Deleted the three platform handler files (`simple_handler_*.cc/mm`) + 2. Updated `CMakeLists.txt` to remove references to those files (see instructions above) + +# Step 2: Custom URL from Code + +**Goal:** Load different URLs by modifying the code (not command-line yet). + +## What We're Adding + +Just change one line to demonstrate how browser creation works. + +## Modified Files + +### tests/cefsimple/simple_app.cc + +**In `OnContextInitialized()`, replace the URL:** + +From: `"https://www.google.com"` +To: `"https://www.wikipedia.org"` + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +Now it loads Wikipedia instead! This shows that the URL is set when creating the `CefBrowserView`. + +**Try these:** + +- `file:///path/to/local.html` - Local files (use absolute path) +- `data:text/html,

Hello CEF!

` - Inline HTML +- Any HTTPS URL + +## What's Happening + +The second parameter to `CefBrowserView::CreateBrowserView` is the initial URL. The browser navigates to this URL immediately after creation. + +# Step 3: Command-Line URL Support + +**Goal:** Pass custom URLs via command-line: `cefsimple --url=https://example.com` + +## What We're Adding + +Read the command-line and use it to set the URL. + +## Modified Files + +### tests/cefsimple/simple_app.cc + +**Add at the top:** + +```cpp +#include "include/cef_command_line.h" +``` + +**Replace `OnContextInitialized` with:** + +```cpp +void SimpleApp::OnContextInitialized() { + CEF_REQUIRE_UI_THREAD(); + + // Get command-line arguments + CefRefPtr command_line = + CefCommandLine::GetGlobalCommandLine(); + + // Check for --url= parameter + std::string url = command_line->GetSwitchValue("url"); + if (url.empty()) { + url = "https://www.google.com"; // Default URL + } + + CefRefPtr handler(new SimpleHandler()); + CefBrowserSettings browser_settings; + + CefRefPtr browser_view = CefBrowserView::CreateBrowserView( + handler, url, browser_settings, nullptr, nullptr, + new SimpleBrowserViewDelegate()); + + CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view)); +} +``` + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run with custom URL:** + +```bash +# Windows +build\tests\cefsimple\Release\cefsimple.exe --url=https://github.com + +# Linux +build/tests/cefsimple/cefsimple --url=https://github.com + +# macOS +open build/tests/cefsimple/Release/cefsimple.app --args --url=https://github.com +``` + +## What's Happening + +**New concepts:** + +- `CefCommandLine::GetGlobalCommandLine()` - Access command-line arguments parsed by CEF +- `GetSwitchValue("url")` - Read the value of `--url=` parameter +- CEF automatically parses command-line in the entry point before calling `OnContextInitialized` + +**Try it:** + +```bash +# Load local file +cefsimple --url=file:///home/user/test.html + +# Load data URL (note the quotes to escape shell characters) +cefsimple --url="data:text/html,

Hello!

" +``` + +# Step 4: Window Title Updates + +**Goal:** Update window title to match the page title as it loads. + +## What We're Adding + +- Display handler to receive title change events +- Get window from browser to update its title + +## Modified Files + +### tests/cefsimple/simple_handler.h + +**Update to add display handler:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ + +#include "include/cef_client.h" + +class SimpleHandler : public CefClient, + // NEW: Add display handler for title change events + public CefDisplayHandler, + public CefLifeSpanHandler { + public: + SimpleHandler(); + ~SimpleHandler() override; + + static SimpleHandler* GetInstance(); + + // CefClient methods: + // NEW: Return display handler + CefRefPtr GetDisplayHandler() override { return this; } + CefRefPtr GetLifeSpanHandler() override { return this; } + + // CefDisplayHandler methods: + // NEW: Handle page title changes + void OnTitleChange(CefRefPtr browser, + const CefString& title) override; + + // CefLifeSpanHandler methods: + void OnBeforeClose(CefRefPtr browser) override; + + void CloseAllBrowsers(bool force_close); + bool IsClosing() const { return false; } + void ShowMainWindow(); + + private: + IMPLEMENT_REFCOUNTING(SimpleHandler); + DISALLOW_COPY_AND_ASSIGN(SimpleHandler); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +``` + +### tests/cefsimple/simple_handler.cc + +**Add new includes at the top:** + +```cpp +#include "include/views/cef_browser_view.h" +#include "include/views/cef_window.h" +``` + +**Add the OnTitleChange implementation** (after the existing methods, before `OnBeforeClose()`): + +```cpp +void SimpleHandler::OnTitleChange(CefRefPtr browser, + const CefString& title) { + CEF_REQUIRE_UI_THREAD(); + + // Get the browser view from the browser + CefRefPtr browser_view = + CefBrowserView::GetForBrowser(browser); + if (browser_view) { + // Get the window and update its title + CefRefPtr window = browser_view->GetWindow(); + if (window) { + window->SetTitle(title); + } + } +} +``` + +**Note:** `OnBeforeClose()` and other methods from Step 1 remain unchanged. + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +Now the window title updates to match the page title as you navigate! + +## What's Happening + +**New concepts:** + +- `CefDisplayHandler::OnTitleChange()` - Called when the page title changes +- `CefBrowserView::GetForBrowser()` - Get the browser view from a browser instance +- `CefBrowserView::GetWindow()` - Get the window containing the browser view +- `CefWindow::SetTitle()` - Update the window title + +**Flow:** + +1. Page loads or navigates → `OnTitleChange()` called with new title +2. We get the browser view from the browser parameter +3. We get the window from the browser view and update its title + +# Step 5: JavaScript Execution + +**Goal:** Execute JavaScript code in the page from C++. + +## What We're Adding + +- Load handler to know when page is ready +- Execute JavaScript after page loads + +## Modified Files + +### tests/cefsimple/simple_handler.h + +**Add load handler:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ + +#include "include/cef_client.h" + +class SimpleHandler : public CefClient, + public CefDisplayHandler, + public CefLifeSpanHandler, + // NEW: Add load handler for page load events + public CefLoadHandler { + public: + SimpleHandler(); + ~SimpleHandler() override; + + static SimpleHandler* GetInstance(); + + // CefClient methods: + CefRefPtr GetDisplayHandler() override { return this; } + CefRefPtr GetLifeSpanHandler() override { return this; } + // NEW: Return load handler + CefRefPtr GetLoadHandler() override { return this; } + + // CefDisplayHandler methods: + void OnTitleChange(CefRefPtr browser, + const CefString& title) override; + + // CefLifeSpanHandler methods: + void OnBeforeClose(CefRefPtr browser) override; + + // CefLoadHandler methods: + // NEW: Handle page load completion + void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) override; + + void CloseAllBrowsers(bool force_close); + bool IsClosing() const { return false; } + void ShowMainWindow(); + + private: + IMPLEMENT_REFCOUNTING(SimpleHandler); + DISALLOW_COPY_AND_ASSIGN(SimpleHandler); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +``` + +### tests/cefsimple/simple_handler.cc + +**Add the OnLoadEnd implementation** (after `OnTitleChange()`, before `OnBeforeClose()`): + +```cpp +void SimpleHandler::OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) { + CEF_REQUIRE_UI_THREAD(); + + // Only execute on the main frame + if (!frame->IsMain()) { + return; + } + + // Execute JavaScript to change the page background color + frame->ExecuteJavaScript( + "document.body.style.backgroundColor = 'lightblue';", + frame->GetURL(), 0); +} +``` + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +Now when pages load, the background turns light blue! + +## What's Happening + +**New concepts:** + +- `CefLoadHandler::OnLoadEnd()` - Called when a frame finishes loading +- `CefFrame::IsMain()` - Check if this is the main frame (not an iframe) +- `CefFrame::ExecuteJavaScript()` - Execute arbitrary JavaScript code +- Parameters: JavaScript code, source URL (for debugging), start line number + +**Try modifying the JavaScript:** + +```cpp +// Alert box +frame->ExecuteJavaScript("alert('Hello from C++!');", frame->GetURL(), 0); + +// DOM manipulation +frame->ExecuteJavaScript( + "var h1 = document.createElement('h1');" + "h1.textContent = 'Added by CEF!';" + "document.body.insertBefore(h1, document.body.firstChild);", + frame->GetURL(), 0); + +// Console log +frame->ExecuteJavaScript("console.log('CEF executed this');", + frame->GetURL(), 0); +``` + +**Important notes:** + +- JavaScript executes asynchronously +- `ExecuteJavaScript()` doesn't return the result directly +- To get results, use `EvaluateJavaScript()` (not shown) or process messages (next step) + +# Step 6: JavaScript-to-C++ Communication + +**Goal:** Call C++ functions from JavaScript code in the page. + +## What We're Adding + +- Process message handler to receive messages from the renderer process +- V8 context handler to register JavaScript functions +- Bidirectional communication between C++ and JavaScript + +This requires implementing both browser process and renderer process handlers. + +## Modified Files + +### tests/cefsimple/simple_app.h + +**Update to add renderer process handler:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ + +#include "include/cef_app.h" + +class SimpleApp : public CefApp, + public CefBrowserProcessHandler, + // NEW: Add renderer process handler for JavaScript integration + public CefRenderProcessHandler { + public: + SimpleApp(); + + // CefApp methods: + CefRefPtr GetBrowserProcessHandler() override { + return this; + } + // NEW: Return renderer process handler + CefRefPtr GetRenderProcessHandler() override { + return this; + } + + // CefBrowserProcessHandler methods: + void OnContextInitialized() override; + + // NEW: CefRenderProcessHandler methods for JavaScript integration + // NEW: Called when the JavaScript context is created in the renderer process + void OnContextCreated(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) override; + + private: + IMPLEMENT_REFCOUNTING(SimpleApp); + DISALLOW_COPY_AND_ASSIGN(SimpleApp); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_ +``` + +### tests/cefsimple/simple_app.cc + +**Add new includes at the top** (after the existing includes): + +```cpp +#include "include/cef_v8.h" +``` + +**Add V8 handler class in the anonymous namespace** (add after the includes, before the existing SimpleWindowDelegate and SimpleBrowserViewDelegate classes which remain unchanged): + +```cpp +// V8 handler to handle JavaScript function calls in the renderer process +class MyV8Handler : public CefV8Handler { + public: + MyV8Handler() = default; + + bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) override { + if (name == "sayHello") { + // Get the argument + if (arguments.size() == 1 && arguments[0]->IsString()) { + CefString message = arguments[0]->GetStringValue(); + + // Send message to browser process + CefRefPtr msg = + CefProcessMessage::Create("greeting"); + msg->GetArgumentList()->SetString(0, message); + + CefRefPtr context = CefV8Context::GetCurrentContext(); + CefRefPtr frame = context->GetFrame(); + + // Results in an asynchronous call to + // SimpleHandler::OnProcessMessageReceived in the browser process + frame->SendProcessMessage(PID_BROWSER, msg); + + // Return value to JavaScript + retval = CefV8Value::CreateString("Message sent to C++!"); + return true; + } + } + + return false; + } + + private: + IMPLEMENT_REFCOUNTING(MyV8Handler); + DISALLOW_COPY_AND_ASSIGN(MyV8Handler); +}; +``` + +**Add the OnContextCreated implementation** (after OnContextInitialized, before the end of the file): + +```cpp +// Called when the JavaScript context is created in the renderer process +void SimpleApp::OnContextCreated(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) { + // Debug assertion - crashes if called on wrong thread + // V8 APIs must only be called from the renderer thread + CEF_REQUIRE_RENDERER_THREAD(); + + // Register JavaScript function 'sayHello' on the global object (window.sayHello) + CefRefPtr object = context->GetGlobal(); + CefRefPtr handler = new MyV8Handler(); + + CefRefPtr func = + CefV8Value::CreateFunction("sayHello", handler); + object->SetValue("sayHello", func, V8_PROPERTY_ATTRIBUTE_NONE); +} +``` + +**Note:** The SimpleWindowDelegate, SimpleBrowserViewDelegate, and OnContextInitialized implementations remain unchanged from previous steps. + +### Platform Entry Points + +**Important:** For JavaScript-to-C++ communication to work, the renderer process needs access to `SimpleApp::OnContextCreated` to register the JavaScript function. + +- **macOS:** Uses separate helper executables for sub-processes (renderer, GPU, etc.) - update `process_helper_mac.cc` +- **Windows and Linux:** Reuse the main executable for sub-processes - update `cefsimple_win.cc` and `cefsimple_linux.cc` + +#### tests/cefsimple/cefsimple_linux.cc + +**Update the main function to create SimpleApp before CefExecuteProcess:** + +Find: +```cpp + // CEF applications have multiple sub-processes (render, GPU, etc) that share + // the same executable. This function checks the command-line and, if this is + // a sub-process, executes the appropriate logic. + int exit_code = CefExecuteProcess(main_args, nullptr, nullptr); + if (exit_code >= 0) { + // The sub-process has completed so return here. + return exit_code; + } +``` + +Replace with: +```cpp + // SimpleApp implements application-level callbacks. It will create the first + // browser instance in OnContextInitialized() after CEF has initialized. + CefRefPtr app(new SimpleApp); + + // CEF applications have multiple sub-processes (render, GPU, etc) that share + // the same executable. This function checks the command-line and, if this is + // a sub-process, executes the appropriate logic. + int exit_code = CefExecuteProcess(main_args, app, nullptr); + if (exit_code >= 0) { + // The sub-process has completed so return here. + return exit_code; + } +``` + +**Then find the later SimpleApp creation:** + +```cpp + // SimpleApp implements application-level callbacks for the browser process. + // It will create the first browser instance in OnContextInitialized() after + // CEF has initialized. + CefRefPtr app(new SimpleApp); +``` + +**Delete these lines** (since we now create app earlier). + +#### tests/cefsimple/cefsimple_win.cc + +**Update the RunMain function to create SimpleApp before CefExecuteProcess:** + +Find: +```cpp + // CEF applications have multiple sub-processes (render, GPU, etc) that share + // the same executable. This function checks the command-line and, if this is + // a sub-process, executes the appropriate logic. + exit_code = CefExecuteProcess(main_args, nullptr, sandbox_info); + if (exit_code >= 0) { + // The sub-process has completed so return here. + return exit_code; + } +``` + +Replace with: +```cpp + // SimpleApp implements application-level callbacks. It will create the first + // browser instance in OnContextInitialized() after CEF has initialized. + CefRefPtr app(new SimpleApp); + + // CEF applications have multiple sub-processes (render, GPU, etc) that share + // the same executable. This function checks the command-line and, if this is + // a sub-process, executes the appropriate logic. + exit_code = CefExecuteProcess(main_args, app, sandbox_info); + if (exit_code >= 0) { + // The sub-process has completed so return here. + return exit_code; + } +``` + +**Then find the later SimpleApp creation:** + +```cpp + // SimpleApp implements application-level callbacks for the browser process. + // It will create the first browser instance in OnContextInitialized() after + // CEF has initialized. + CefRefPtr app(new SimpleApp); +``` + +**Delete these lines** (since we now create app earlier). + +#### tests/cefsimple/process_helper_mac.cc + +**Add include at the top:** + +```cpp +#include "tests/cefsimple/simple_app.h" +``` + +**Update the main function to create SimpleApp before CefExecuteProcess:** + +Find: +```cpp +return CefExecuteProcess(main_args, nullptr, nullptr); +``` + +Replace with: +```cpp +// SimpleApp implements application-level callbacks for the sub-process. +// This allows SimpleApp::OnContextCreated to be called in the renderer process. +CefRefPtr app(new SimpleApp); + +// Execute the sub-process. +return CefExecuteProcess(main_args, app, nullptr); +``` + +**Note:** Unlike the main executable, the macOS helper doesn't have a separate browser process initialization section, so there's no duplicate SimpleApp creation to remove. + +#### tests/cefsimple/CMakeLists.txt (macOS only) + +**Update the helper sources to include simple_app:** + +Find: +```cmake +# cefsimple helper sources. +set(CEFSIMPLE_HELPER_SRCS_MAC + process_helper_mac.cc + ) +``` + +Replace with: +```cmake +# cefsimple helper sources. +set(CEFSIMPLE_HELPER_SRCS_MAC + process_helper_mac.cc + simple_app.cc + simple_app.h + simple_handler.cc + simple_handler.h + ) +``` + +This ensures the helper process can compile and link the SimpleApp code. + +**Note:** We're including simple_handler.cc/h in the helper sources even though SimpleHandler is never used in renderer processes (only SimpleApp::OnContextCreated is called). For a production application, you could create a separate CefApp-derived class for the renderer process (e.g., `SimpleRendererApp`) to avoid linking browser-process-only dependencies like SimpleHandler into the helper executables. + +**Reconfigure CMake (macOS only)** to pick up the CMakeLists.txt changes: + +```bash +cmake -B build -G Xcode +``` + +### tests/cefsimple/simple_handler.h + +**Add process message handler:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ + +#include "include/cef_client.h" + +class SimpleHandler : public CefClient, + public CefDisplayHandler, + public CefLifeSpanHandler, + public CefLoadHandler { + public: + SimpleHandler(); + ~SimpleHandler() override; + + static SimpleHandler* GetInstance(); + + // CefClient methods: + CefRefPtr GetDisplayHandler() override { return this; } + CefRefPtr GetLifeSpanHandler() override { return this; } + CefRefPtr GetLoadHandler() override { return this; } + // NEW: Handle messages from renderer process + bool OnProcessMessageReceived(CefRefPtr browser, + CefRefPtr frame, + CefProcessId source_process, + CefRefPtr message) override; + + // CefDisplayHandler methods: + void OnTitleChange(CefRefPtr browser, + const CefString& title) override; + + // CefLifeSpanHandler methods: + void OnBeforeClose(CefRefPtr browser) override; + + // CefLoadHandler methods: + void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) override; + + void CloseAllBrowsers(bool force_close); + bool IsClosing() const { return false; } + void ShowMainWindow(); + + private: + IMPLEMENT_REFCOUNTING(SimpleHandler); + DISALLOW_COPY_AND_ASSIGN(SimpleHandler); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +``` + +### tests/cefsimple/simple_handler.cc + +**Add at the top** (after the existing includes): + +```cpp +#include +``` + +**Update OnLoadEnd** to inject a test button (replace the background color change with button injection): + +```cpp +// Frame load finished in the browser process +void SimpleHandler::OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) { + CEF_REQUIRE_UI_THREAD(); + + if (!frame->IsMain()) { + return; + } + + // Inject a test button to call our C++ function + std::stringstream ss; + ss << "var button = document.createElement('button');" + << "button.textContent = 'Call C++ Function';" + << "button.style.position = 'fixed';" + << "button.style.top = '10px';" + << "button.style.left = '10px';" + << "button.style.zIndex = '10000';" + << "button.style.backgroundColor = '#4CAF50';" + << "button.style.color = 'white';" + << "button.style.padding = '10px 15px';" + << "button.style.border = 'none';" + << "button.style.borderRadius = '4px';" + << "button.style.cursor = 'pointer';" + << "button.onclick = function() {" + << " var result = sayHello('Hello from JavaScript!');" + << " alert(result);" + << "};" + << "document.body.appendChild(button);"; + + frame->ExecuteJavaScript(ss.str(), frame->GetURL(), 0); +} +``` + +**Add OnProcessMessageReceived** (after OnLoadEnd, before OnBeforeClose): + +```cpp +// Process message received in the browser process +bool SimpleHandler::OnProcessMessageReceived( + CefRefPtr browser, + CefRefPtr frame, + CefProcessId source_process, + CefRefPtr message) { + CEF_REQUIRE_UI_THREAD(); + + // Handle message from MyHandler::Execute() in the renderer process + if (message->GetName() == "greeting") { + CefString msg = message->GetArgumentList()->GetString(0); + + // Show the message in a JavaScript alert + std::stringstream ss; + ss << "alert('C++ received: " << msg.ToString() << "');"; + frame->ExecuteJavaScript(ss.str(), frame->GetURL(), 0); + + return true; + } + + return false; +} +``` + +**Note:** OnTitleChange and OnBeforeClose remain unchanged from previous steps. + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +Now you'll see a button in the top-left corner of every page. Click it to: + +1. Call JavaScript `sayHello()` function +2. JavaScript sends message to C++ via process message +3. C++ receives message in browser process +4. C++ sends alert back to JavaScript + +## What's Happening + +**New concepts:** + +1. **Multi-process architecture:** + - Browser process (UI, main logic) + - Renderer process (usually one per origin, runs web content) + - Processes communicate via messages + +2. **Renderer process (SimpleApp):** + - `OnContextCreated()` - Called when JavaScript context is created + - `CefV8Value::CreateFunction()` - Register a JavaScript function + - `CefV8Handler::Execute()` - Handle JavaScript function calls + +3. **Process messages:** + - `CefProcessMessage::Create()` - Create a message + - `CefFrame::SendProcessMessage()` - Send from renderer to browser + - `CefClient::OnProcessMessageReceived()` - Receive in browser process + +**Flow:** + +1. Renderer process creates → `OnContextCreated()` registers `sayHello()` function +2. User clicks button → JavaScript calls `sayHello('Hello from JavaScript!')` +3. `MyV8Handler::Execute()` receives call, creates process message +4. Message sent to browser process +5. `SimpleHandler::OnProcessMessageReceived()` handles message in browser process +6. C++ executes JavaScript to show alert + +**Important notes:** + +- JavaScript function runs in renderer process (sandboxed) +- C++ handler runs in browser process (has full access) +- Messages are the bridge between processes +- Messages can contain simple data types (strings, ints, lists, dictionaries), binary data, and shared memory regions + +**Learn more:** + +- **[JavaScriptIntegration.md](javascript_integration.md)** - Complete guide to V8 JavaScript integration: + - Window binding and extensions + - V8 value creation and type conversion + - Working with V8 contexts + - JavaScript objects and arrays + - Function handlers (CefV8Handler) + +- **[GeneralUsage.md](general_usage.md#inter-process-communication-ipc)** - Inter-Process Communication section: + - Process startup messages + - Process runtime messages (CefProcessMessage) + - Asynchronous JavaScript bindings + - Generic message router for request/response patterns + - Custom IPC implementations + +# Step 7: Multiple Browser Support + +**Goal:** Track multiple browser instances and only quit the application when all browsers are closed. + +## What We're Adding + +In Steps 1-6, the application only supported a single browser. When that browser closed, the app quit immediately. Now we'll add: + +- Browser instance tracking (map using browser ID as key) +- Proper lifecycle management (add on create, remove on close) +- Only quit when the last browser closes +- Working `CloseAllBrowsers()` implementation +- A second button to create popup windows + +## Why This Matters + +The single-browser approach from earlier steps has limitations: + +- **Quits too early**: If user creates a popup, closing the main window quits immediately (popup also closes) +- **No browser tracking**: Can't iterate over browsers to close them all +- **CloseAllBrowsers() is a stub**: Doesn't actually do anything + +Multi-browser tracking is essential for real applications that support popups, new windows, or multiple browser instances. + +## Modified Files + +### tests/cefsimple/simple_handler.h + +**Add browser tracking and lifecycle methods:** + +```cpp +#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ + +#include + +#include "include/cef_client.h" + +class SimpleHandler : public CefClient, + public CefDisplayHandler, + public CefLifeSpanHandler, + public CefLoadHandler { + public: + SimpleHandler(); + ~SimpleHandler() override; + + static SimpleHandler* GetInstance(); + + // CefClient methods: + CefRefPtr GetDisplayHandler() override { return this; } + CefRefPtr GetLifeSpanHandler() override { return this; } + CefRefPtr GetLoadHandler() override { return this; } + bool OnProcessMessageReceived(CefRefPtr browser, + CefRefPtr frame, + CefProcessId source_process, + CefRefPtr message) override; + + // CefDisplayHandler methods: + void OnTitleChange(CefRefPtr browser, + const CefString& title) override; + + // CefLifeSpanHandler methods: + // NEW: Track browser creation + void OnAfterCreated(CefRefPtr browser) override; + void OnBeforeClose(CefRefPtr browser) override; + + // CefLoadHandler methods: + void OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) override; + + void CloseAllBrowsers(bool force_close); + bool IsClosing() const { return is_closing_; } + void ShowMainWindow(); + + private: + // NEW: Track all browser instances (keyed by browser ID) + // These members are only accessed on the UI thread (OnAfterCreated, + // OnBeforeClose, and CloseAllBrowsers all run on TID_UI), so no + // additional synchronization is needed. + using BrowserMap = std::map>; + BrowserMap browser_map_; + + // NEW: Track whether we're closing + bool is_closing_ = false; + + IMPLEMENT_REFCOUNTING(SimpleHandler); + DISALLOW_COPY_AND_ASSIGN(SimpleHandler); +}; + +#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_ +``` + +**Changes:** + +- Added `#include ` for browser tracking container +- Added `OnAfterCreated()` to track browser creation +- Added `browser_map_` member to store all browser instances (keyed by browser ID) +- Added `is_closing_` flag to prevent new browsers during shutdown +- Changed `IsClosing()` to return the actual flag instead of hardcoded `false` + +### tests/cefsimple/simple_handler.cc + +**Add includes for callbacks and closure tasks** (after the existing includes): + +```cpp +#include "include/base/cef_callback.h" +#include "include/wrapper/cef_closure_task.h" +``` + +**Add OnAfterCreated** (new method, add after OnTitleChange): + +```cpp +void SimpleHandler::OnAfterCreated(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + + // Add browser to our tracking map + browser_map_[browser->GetIdentifier()] = browser; +} +``` + +**Update OnLoadEnd** to add second button (replace the existing OnLoadEnd): + +```cpp +void SimpleHandler::OnLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) { + CEF_REQUIRE_UI_THREAD(); + + if (!frame->IsMain()) { + return; + } + + // Inject test buttons + std::stringstream ss; + // "Call C++ Function" button + ss << "var button1 = document.createElement('button');" + << "button1.textContent = 'Call C++ Function';" + << "button1.style.position = 'fixed';" + << "button1.style.top = '10px';" + << "button1.style.left = '10px';" + << "button1.style.zIndex = '10000';" + << "button1.style.backgroundColor = '#4CAF50';" + << "button1.style.color = 'white';" + << "button1.style.padding = '10px 15px';" + << "button1.style.border = 'none';" + << "button1.style.borderRadius = '4px';" + << "button1.style.cursor = 'pointer';" + << "button1.onclick = function() {" + << " var result = sayHello('Hello from JavaScript!');" + << " alert(result);" + << "};" + << "document.body.appendChild(button1);" + // "Create Popup Window" button + << "var button2 = document.createElement('button');" + << "button2.textContent = 'Create Popup Window';" + << "button2.style.position = 'fixed';" + << "button2.style.top = '50px';" + << "button2.style.left = '10px';" + << "button2.style.zIndex = '10000';" + << "button2.style.backgroundColor = '#2196F3';" + << "button2.style.color = 'white';" + << "button2.style.padding = '10px 15px';" + << "button2.style.border = 'none';" + << "button2.style.borderRadius = '4px';" + << "button2.style.cursor = 'pointer';" + << "button2.onclick = function() {" + << " window.open('https://www.wikipedia.org', '_blank', 'width=800,height=600');" + << "};" + << "document.body.appendChild(button2);"; + + frame->ExecuteJavaScript(ss.str(), frame->GetURL(), 0); +} +``` + +**Update OnBeforeClose** (replace the existing OnBeforeClose): + +```cpp +void SimpleHandler::OnBeforeClose(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + + // Remove browser from our tracking map + browser_map_.erase(browser->GetIdentifier()); + + // Only quit when all browsers are closed + if (browser_map_.empty()) { + CefQuitMessageLoop(); + } +} +``` + +**Update CloseAllBrowsers** (replace the existing stub implementation): + +```cpp +void SimpleHandler::CloseAllBrowsers(bool force_close) { + // CloseAllBrowsers can be called from anywhere (e.g., macOS menu's Quit command), + // but CEF browser operations must run on the UI thread. Check if we're already + // on the UI thread; if not, post a task to run this method on the UI thread. + if (!CefCurrentlyOn(TID_UI)) { + CefPostTask(TID_UI, base::BindOnce(&SimpleHandler::CloseAllBrowsers, this, + force_close)); + return; + } + + is_closing_ = true; + + if (browser_map_.empty()) { + return; + } + + // Iterate over browsers and request close + // Use a copy because browser_map_ will be modified during iteration (OnBeforeClose) + BrowserMap browser_map_copy = browser_map_; + for (auto& pair : browser_map_copy) { + pair.second->GetHost()->CloseBrowser(force_close); + } +} +``` + +**Note:** Constructor, OnTitleChange, OnProcessMessageReceived, and ShowMainWindow remain unchanged from previous steps. + +**Changes:** + +- Added `OnAfterCreated()`: Adds browser to `browser_map_` when created (keyed by browser ID) +- Updated `OnLoadEnd()`: Added second button "Create Popup Window" (blue, positioned below first button) +- Updated `OnBeforeClose()`: Removes browser from map by ID, only quits when map is empty +- Implemented `CloseAllBrowsers()`: Sets `is_closing_` flag, iterates over browser_map_ copy, closes each browser +- Uses `CefPostTask()` to ensure execution on UI thread + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +## What's Happening + +**New concepts:** + +1. **Browser lifecycle tracking with map:** + - Use `std::map>` keyed by browser ID + - Browser ID obtained via `browser->GetIdentifier()` - unique integer for each browser + - `OnAfterCreated()` - Called when browser is created, add to map + - `OnBeforeClose()` - Called when browser is closing, remove from map by ID + - Only quit when map is empty + - Why map instead of set? `CefRefPtr` comparison doesn't work as expected for `erase()`, so we key by integer ID + +2. **Thread-safe closing:** + - `CloseAllBrowsers()` uses `CefPostTask()` to execute on UI thread + - CEF requires most operations on the UI thread + - `base::BindOnce()` creates a callback that captures `this` and arguments + - Requires two includes: + - `include/base/cef_callback.h` - provides `base::BindOnce` + - `include/wrapper/cef_closure_task.h` - converts callbacks to `CefTask` objects for `CefPostTask` + +3. **Container iteration safety:** + - Create a copy of `browser_map_` before iterating + - `OnBeforeClose()` modifies the map during iteration (would cause crashes) + - Copy ensures safe iteration even as browsers close + - Iterate over `pair.second` to get browser from map entry + +**Testing:** + +1. Launch the app - main window appears +2. Click "Create Popup Window" - popup opens +3. Close main window - app stays running (popup still open) +4. Close popup - now app quits (all browsers closed) +5. Try creating multiple popups and closing them in different orders + +**macOS note:** The Quit menu now works! `CloseAllBrowsers()` is properly implemented, so the macOS application menu's Quit option (which calls `CloseAllBrowsers()`) will close all browsers and quit the app. + +**Learn more:** + +- **[GeneralUsage.md](general_usage.md#posting-tasks)** - Posting Tasks section: + - Complete guide to CefPostTask family of functions + - base::BindOnce and base::Callback usage + - Thread-safe task posting patterns + - CefTaskRunner for accessing specific thread message loops + - Bound methods vs bound functions + +# Step 8: Views Styling of Popup Browsers + +**Goal:** Customize the appearance and behavior of popup browser windows using the Views framework. + +## What We're Adding + +In Step 7, clicking "Create Popup Window" opened a new browser, but it used default styling (same size as main window). Now we'll add custom styling for popup windows: + +- `OnPopupBrowserViewCreated()` callback in SimpleBrowserViewDelegate +- Custom window creation for popups (smaller size, different from main window) +- Understanding of when to use `OnBeforePopup` vs `OnPopupBrowserViewCreated` + +## Why This Matters + +CEF provides two callbacks for popup customization with different purposes: + +**OnBeforePopup (CefLifeSpanHandler)** - Low-level popup control: + +- Called **before** the popup browser is created +- Runs in the browser process +- Can cancel popup creation (return true to cancel) +- Can change the popup's `CefWindowInfo`, `CefClient` and `CefBrowserSettings` +- Use for: Blocking popups, popup policy enforcement, native window parenting + +**OnPopupBrowserViewCreated (CefBrowserViewDelegate)** - Views-specific window creation: + +- Called **after** the popup browser view is created +- Only called when using the Views framework +- Gives you control over window creation and styling +- Create custom CefWindow with different size, position, title bar, etc. +- Use for: Custom popup window appearance and behavior in Views-based apps + +In this step, we use `OnPopupBrowserViewCreated` to create smaller popup windows (600x400) compared to the main window (800x600). + +## Modified Files + +### tests/cefsimple/simple_app.cc + +**Update SimpleBrowserViewDelegate** to add OnPopupBrowserViewCreated (add after GetBrowserRuntimeStyle, before the private section): + +```cpp +// Browser view delegate +class SimpleBrowserViewDelegate : public CefBrowserViewDelegate { + public: + SimpleBrowserViewDelegate() = default; + + // NEW: Called when a popup browser view is created + bool OnPopupBrowserViewCreated( + CefRefPtr browser_view, + CefRefPtr popup_browser_view, + bool is_devtools) override { + // Create a smaller window for popups (600x400 instead of 800x600) + // We use a custom SimpleWindowDelegate that returns a different size + CefWindow::CreateTopLevelWindow( + new SimpleWindowDelegate(popup_browser_view)); + + // Returning true indicates we created the window + return true; + } + + cef_runtime_style_t GetBrowserRuntimeStyle() override { + return CEF_RUNTIME_STYLE_ALLOY; + } + + private: + IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate); + DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate); +}; +``` + +**Update SimpleWindowDelegate** to support custom popup sizes (replace the GetPreferredSize method): + +```cpp + CefSize GetPreferredSize(CefRefPtr view) override { + // Check if this is a popup by seeing if we have a browser yet + CefRefPtr browser = browser_view_->GetBrowser(); + if (browser && browser->IsPopup()) { + // Popup windows are smaller + return CefSize(600, 400); + } + // Main window is larger + return CefSize(800, 600); + } +``` + +**Note:** The SimpleWindowDelegate, MyV8Handler, and OnContextInitialized/OnContextCreated implementations remain unchanged from Step 7. + +## Build and Run + +```bash +# Rebuild using the same commands as Step 0 + +# Windows +cmake --build build --config Release --target cefsimple + +# Linux +cmake --build build --target cefsimple + +# macOS +cmake --build build --config Release --target cefsimple +``` + +**Run:** See Step 0 for platform-specific run instructions. + +## What's Happening + +**New concepts:** + +1. **OnPopupBrowserViewCreated callback:** + - Called by CEF after a popup browser view is created + - Only invoked when using Views framework (not for native windows) + - Parameters: + - `browser_view` - The parent browser view that initiated the popup + - `popup_browser_view` - The newly created popup browser view + - `is_devtools` - True if this is a DevTools popup + - Return value: + - `true` - You created the window (CEF won't create a default window) + - `false` - CEF will create a default window + +2. **Custom popup window creation:** + - We create a new `CefWindow` for the popup using `CefWindow::CreateTopLevelWindow()` + - Pass the `popup_browser_view` to `SimpleWindowDelegate` (same pattern as main window) + - The delegate's `GetPreferredSize()` returns different sizes for popups vs main windows + - `browser->IsPopup()` identifies popup browsers + +3. **Popup detection:** + - `CefBrowser::IsPopup()` returns true for browsers created via `window.open()` or similar + - Main browser (created in `OnContextInitialized`) returns false + - We use this to return different window sizes + +4. **Alternative approach - GetDelegateForPopupBrowserView:** + - Instead of using the same delegate for all browser views, you can override `CefBrowserViewDelegate::GetDelegateForPopupBrowserView()` to return a different delegate for popups + - This allows you to completely separate popup behavior from main window behavior + - Example: Create a `PopupBrowserViewDelegate` class with different implementations of `OnPopupBrowserViewCreated()`, etc. + - The approach in this tutorial (same delegate, detect popups with `IsPopup()`) is simpler and works well for most cases + - Use `GetDelegateForPopupBrowserView` when you need significantly different delegate behavior for popups + +**Testing:** + +1. Launch the app - main window is 800x600 +2. Click "Create Popup Window" - popup opens at 600x400 (smaller) +3. Click "Create Popup Window" from the popup - another 600x400 popup opens +4. All popups use the custom smaller size +5. Close popups - app continues running until all browsers closed + +**When to use each callback:** + +| Scenario | Use OnBeforePopup | Use OnPopupBrowserViewCreated | +|----------|------------------|-------------------------------| +| Block all popups | ✅ Return true to cancel | ❌ Too late (browser already created) | +| Custom popup window size (Views) | ❌ Limited control | ✅ Full window control | +| Custom popup window styling (Views) | ❌ Limited control | ✅ Full window control | +| Popup policy enforcement | ✅ Can examine URL, features | ❌ Too late | +| Native window popups (non-Views) | ✅ Can modify CefWindowInfo | ❌ Not called for native windows | + +**Important notes:** + +- `OnPopupBrowserViewCreated` is **only called for Views-based browsers** (our tutorial uses Views) +- If using native platform windows (non-Views), use `OnBeforePopup` and `CefWindowInfo` instead +- Both callbacks can be used together (OnBeforePopup for policy, OnPopupBrowserViewCreated for styling) +- DevTools windows also trigger these callbacks (check `is_devtools` parameter) + +# Next Steps + +Congratulations! You've built a CEF application from scratch and learned: + +- ✅ CEF initialization and lifecycle +- ✅ Views framework for cross-platform UI +- ✅ Browser and window delegates +- ✅ Command-line argument handling +- ✅ Display and load handlers +- ✅ JavaScript execution from C++ +- ✅ JavaScript-to-C++ communication via process messages +- ✅ Multiple browser tracking and lifecycle management +- ✅ Custom popup window styling with OnPopupBrowserViewCreated + +## Explore More Features + +**[cefclient](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/)** - A comprehensive sample application demonstrating: + +- Chrome style browsers (full Chrome UI) +- Platform-specific implementations (WinAPI, GTK, Cocoa) +- Off-screen rendering (OSR) +- Custom scheme handlers (`client://` URLs) +- Request interception and modification +- Cookie management +- Dialog handlers +- Context menus +- Drag and drop +- And much more... + +**[cef-project](https://github.com/chromiumembedded/cef-project)** - Focused example applications demonstrating specific features: + +- **[message_router](https://github.com/chromiumembedded/cef-project/blob/master/examples/message_router)** - JavaScript bindings using CefMessageRouter for request/response patterns +- **[resource_manager](https://github.com/chromiumembedded/cef-project/blob/master/examples/resource_manager)** - Resource request handling using CefResourceManager +- **[scheme_handler](https://github.com/chromiumembedded/cef-project/blob/master/examples/scheme_handler)** - Custom protocol handlers using CefSchemeHandlerFactory + +## Learn Advanced Topics + +**[General Usage](general_usage.md)** - Complete CEF documentation covering: + +- Multi-process architecture in depth +- Threading model and task posting +- Request handling and network interception +- JavaScript integration patterns +- Custom protocol handlers +- Performance optimization +- Security considerations + +## Using the C API + +**[Using The CAPI](using_the_capi.md)** - Complete guide to the CEF C API: + +- Manual reference counting patterns +- Structure allocation and ownership +- String handling +- Thread safety and atomic operations +- Complete working examples in [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/) + +## Using Claude Code for Implementation + +Want help implementing additional features in your CEF application? The CEF project includes instructions for using Claude Code to assist with tasks like adding custom URL schemes, JavaScript-to-C++ communication, request interception, and more. + +See the [CEF Client Development Guide](https://github.com/chromiumembedded/cef/blob/master/tools/claude/CLIENT_DEVELOPMENT.md) for step-by-step instructions. \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..206df88bb --- /dev/null +++ b/docs/index.md @@ -0,0 +1,3 @@ +--- +redirect_to: README +--- diff --git a/docs/javascript_integration.md b/docs/javascript_integration.md new file mode 100644 index 000000000..087a66505 --- /dev/null +++ b/docs/javascript_integration.md @@ -0,0 +1,433 @@ +This page explains how to use V8 JavaScript integration in client applications. + +**Contents** + +- [Introduction](#introduction) +- [ExecuteJavaScript](#executejavascript) +- [Window Binding](#window-binding) +- [Extensions](#extensions) +- [Basic JS Types](#basic-js-types) +- [JS Arrays](#js-arrays) +- [JS Objects](#js-objects) + - [Objects with Accessors](#objects-with-accessors) +- [JS Functions](#js-functions) + - [Functions and Window Binding](#functions-and-window-binding) + - [Functions and Extensions](#functions-and-extensions) +- [Working with Contexts](#working-with-contexts) +- [Executing Functions](#executing-functions) + - [Using JS Callbacks](#using-js-callbacks) + - [Rethrowing Exceptions](#rethrowing-exceptions) + +--- + +# Introduction + +Chromium and CEF use the [V8 JavaScript Engine](http://code.google.com/p/v8/) for their internal JavaScript (JS) implementation. Each frame in a browser has its own JS context that provides scope and security for JS code executing in that frame (see the "Working with Contexts" section for more information). CEF exposes a large number of JS features for integration in client applications. + +With CEF3 Blink (WebKit) and JS execution run in a separate renderer process. The main thread in a renderer process is identified as TID\_RENDERER and all V8 execution must take place on this thread. Callbacks related to JS execution are exposed via the CefRenderProcessHandler interface. This interface is retrieved via CefApp::GetRenderProcessHandler() when a new renderer process is initialized. + +JS APIs that communicate between the browser and renderer processes should be designed using asynchronous callbacks. See the "Asynchronous JavaScript Bindings" section of the [General Usage](general_usage.md) wiki page for more information. + +# ExecuteJavaScript + +The simplest way to execute JS from a client application is using the CefFrame::ExecuteJavaScript() function. This function is available in both the browser process and the renderer process and can safely be used from outside of a JS context. + +```cpp +CefRefPtr browser = ...; +CefRefPtr frame = browser->GetMainFrame(); +frame->ExecuteJavaScript("alert('ExecuteJavaScript works!');", + frame->GetURL(), 0); +``` + +The above example will cause `alert('ExecuteJavaScript works!');` to be executed in the browser's main frame. + +The ExecuteJavaScript() function can be used to interact with functions and variables in the frame's JS context. In order to return values from JS to the client application consider using Window Binding or Extensions. + + +# Window Binding + +Window binding allows the client application to attach values to a frame's `window` object. Window bindings are implemented using the CefRenderProcessHandler::OnContextCreated() method. + +```cpp +void MyRenderProcessHandler::OnContextCreated( + CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) { + // Retrieve the context's window object. + CefRefPtr object = context->GetGlobal(); + + // Create a new V8 string value. See the "Basic JS Types" section below. + CefRefPtr str = CefV8Value::CreateString("My Value!"); + + // Add the string to the window object as "window.myval". See the "JS Objects" section below. + object->SetValue("myval", str, V8_PROPERTY_ATTRIBUTE_NONE); +} +``` + +JavaScript in the frame can then interact with the window bindings. + +```html + +``` + +Window bindings are reloaded each time a frame is reloaded giving the client application an opportunity to change the bindings if necessary. For example, different frames may be given access to different features in the client application by modifying the values that are bound to the window object for that frame. + + +# Extensions + +Extensions are like window bindings except they are loaded into the context for every frame and cannot be modified once loaded. The DOM does not exist when an extension is loaded and attempts to access the DOM during extension loading will result in a crash. Extensions are registered using the CefRegisterExtension() function which should be called from the CefRenderProcessHandler::OnWebKitInitialized() method. + +```cpp +void MyRenderProcessHandler::OnWebKitInitialized() { + // Define the extension contents. + std::string extensionCode = + "var test;" + "if (!test)" + " test = {};" + "(function() {" + " test.myval = 'My Value!';" + "})();"; + + // Register the extension. + CefRegisterExtension("v8/test", extensionCode, NULL); +} +``` + +The string represented by `extensionCode` can be any valid JS code. JS in the frame can then interact with the extension code. + +```html + +``` + +# Basic JS Types + +CEF supports the creation of basic JS data types including undefined, null, bool, int, double, date and string. These types are created using the CefV8Value::Create\*() static methods. For example, to create a new JS string value use the CreateString() method. + +```cpp +CefRefPtr str = CefV8Value::CreateString("My Value!"); +``` + +Basic value types can be created at any time and are not initially associated with a particular context (see the "Working with Contexts" section for more information). + +To test the value type use the Is\*() methods. + +```cpp +CefRefPtr val = ...; +if (val.IsString()) { + // The value is a string. +} +``` + +To retrieve the value use the Get\*Value() methods. + +``` +CefString strVal = val.GetStringValue(); +``` + +# JS Arrays + +Arrays are created using the CefV8Value::CreateArray() static method which accepts a length argument. Arrays can only be created and used from within a context (see the "Working with Contexts" section for more information). + +```cpp +// Create an array that can contain two values. +CefRefPtr arr = CefV8Value::CreateArray(2); +``` + +Values are assigned to an array using the SetValue() method variant that takes an index as the first argument. + +```cpp +// Add two values to the array. +arr->SetValue(0, CefV8Value::CreateString("My First String!")); +arr->SetValue(1, CefV8Value::CreateString("My Second String!")); +``` + +To test if a CefV8Value is an array use the IsArray() method. To get the length of an array use the GetArrayLength() method. To get a value from an array use the GetValue() variant that takes an index as the first argument. + +# JS Objects + +Objects are created using the CefV8Value::CreateObject() static method that takes an optional CefV8Accessor argument. Objects can only be created and used from within a context (see the "Working with Contexts" section for more information). + +```cpp +CefRefPtr obj = CefV8Value::CreateObject(NULL); +``` + +Values are assigned to an object using the SetValue() method variant that takes a key string as the first argument. + +```cpp +obj->SetValue("myval", CefV8Value::CreateString("My String!")); +``` + +## Objects with Accessors + +Objects can optionally have an associated CefV8Accessor that provides a native implementation for getting and setting values. + +```cpp +CefRefPtr accessor = …; +CefRefPtr obj = CefV8Value::CreateObject(accessor); +``` + +An implementation of the CefV8Accessor interface that must be provided by the client application. + +```cpp +class MyV8Accessor : public CefV8Accessor { +public: + MyV8Accessor() {} + + virtual bool Get(const CefString& name, + const CefRefPtr object, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + if (name == "myval") { + // Return the value. + retval = CefV8Value::CreateString(myval_); + return true; + } + + // Value does not exist. + return false; + } + + virtual bool Set(const CefString& name, + const CefRefPtr object, + const CefRefPtr value, + CefString& exception) OVERRIDE { + if (name == "myval") { + if (value->IsString()) { + // Store the value. + myval_ = value->GetStringValue(); + } else { + // Throw an exception. + exception = "Invalid value type"; + } + return true; + } + + // Value does not exist. + return false; + } + + // Variable used for storing the value. + CefString myval_; + + // Provide the reference counting implementation for this class. + IMPLEMENT_REFCOUNTING(MyV8Accessor); +}; +``` + +In order for a value to be passed to the accessor it must be set using the SetValue() method variant that accepts AccessControl and PropertyAttribute arguments. + +``` +obj->SetValue("myval", V8_ACCESS_CONTROL_DEFAULT, + V8_PROPERTY_ATTRIBUTE_NONE); +``` + +# JS Functions + +CEF supports the creation of JS functions with native implementations. Functions are created using the CefV8Value::CreateFunction() static method that accepts name and CefV8Handler arguments. Functions can only be created and used from within a context (see the "Working with Contexts" section for more information). + +```cpp +CefRefPtr handler = …; +CefRefPtr func = CefV8Value::CreateFunction("myfunc", handler); +``` + +An implementation of the CefV8Handler interface that must be provided by the client application. + +```cpp +class MyV8Handler : public CefV8Handler { +public: + MyV8Handler() {} + + virtual bool Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) OVERRIDE { + if (name == "myfunc") { + // Return my string value. + retval = CefV8Value::CreateString("My Value!"); + return true; + } + + // Function does not exist. + return false; + } + + // Provide the reference counting implementation for this class. + IMPLEMENT_REFCOUNTING(MyV8Handler); +}; +``` + +## Functions and Window Binding + +Functions can be used to create complex window bindings. + +```cpp +void MyRenderProcessHandler::OnContextCreated( + CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) { + // Retrieve the context's window object. + CefRefPtr object = context->GetGlobal(); + + // Create an instance of my CefV8Handler object. + CefRefPtr handler = new MyV8Handler(); + + // Create the "myfunc" function. + CefRefPtr func = CefV8Value::CreateFunction("myfunc", handler); + + // Add the "myfunc" function to the "window" object. + object->SetValue("myfunc", func, V8_PROPERTY_ATTRIBUTE_NONE); +} +``` + +```html + +``` + +## Functions and Extensions + +Functions can be used to create complex extensions. Note the use of the "native function" forward declaration which is required when using extensions. + +```cpp +void MyRenderProcessHandler::OnWebKitInitialized() { + // Define the extension contents. + std::string extensionCode = + "var test;" + "if (!test)" + " test = {};" + "(function() {" + " test.myfunc = function() {" + " native function myfunc();" + " return myfunc();" + " };" + "})();"; + + // Create an instance of my CefV8Handler object. + CefRefPtr handler = new MyV8Handler(); + + // Register the extension. + CefRegisterExtension("v8/test", extensionCode, handler); +} +``` + +```html + +``` + + +# Working with Contexts + +Each frame in a browser window has its own V8 context. The context defines the scope for all variables, objects and functions defined in that frame. V8 will be inside a context if the current code location has a CefV8Handler, CefV8Accessor or OnContextCreated()/OnContextReleased() callback higher in the call stack. + +The OnContextCreated() and OnContextReleased() methods define the complete life span for the V8 context associated with a frame. You should be careful to follow the below rules when using these methods: + +1. Do not hold onto or use a V8 context reference past the call to OnContextReleased() for that context. + +2. The lifespan of all V8 objects is unspecified (up to the GC). Be careful when maintaining references directly from V8 objects to your own internal implementation objects. In many cases it may be better to use a proxy object that your application associates with the V8 context and which can be "disconnected" (allowing your internal implementation object to be freed) when OnContextReleased() is called for the context. + +If V8 is not currently inside a context, or if you need to retrieve and store a reference to a context, you can use one of two available CefV8Context static methods. GetCurrentContext() returns the context for the frame that is currently executing JS. GetEnteredContext() returns the context for the frame where JS execution began. For example, if a function in frame1 calls a function in frame2 then the current context will be frame2 and the entered context will be frame1. + +Arrays, objects and functions may only be created, modified and, in the case of functions, executed, if V8 is inside a context. If V8 is not inside a context then the application needs to enter a context by calling Enter() and exit the context by calling Exit(). The Enter() and Exit() methods should only be used: + +1. When creating a V8 object, function or array outside of an existing context. For example, when creating a JS object in response to a native menu callback. + +2. When creating a V8 object, function or array in a context other than the current context. For example, if a call originating from frame1 needs to modify the context of frame2. + +# Executing Functions + +Native code can execute JS functions by using the ExecuteFunction() and ExecuteFunctionWithContext() methods. The ExecuteFunction() method should only be used if V8 is already inside a context as described in the "Working with Contexts" section. The ExecuteFunctionWithContext() method allows the application to specify the context that will be entered for execution. + +## Using JS Callbacks + +When registering a JS function callback with native code the application should store a reference to both the current context and the JS function in the native code. This could be implemented as follows. + +1\. Create a "register" function in OnJSBinding(). + +```cpp +void MyRenderProcessHandler::OnContextCreated( + CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) { + // Retrieve the context's window object. + CefRefPtr object = context->GetGlobal(); + + CefRefPtr handler = new MyV8Handler(this); + object->SetValue("register", + CefV8Value::CreateFunction("register", handler), + V8_PROPERTY_ATTRIBUTE_NONE); +} +``` + +2\. In the MyV8Handler::Execute() implementation for the "register" function keep a reference to both the context and the function. + +```cpp +bool MyV8Handler::Execute(const CefString& name, + CefRefPtr object, + const CefV8ValueList& arguments, + CefRefPtr& retval, + CefString& exception) { + if (name == "register") { + if (arguments.size() == 1 && arguments[0]->IsFunction()) { + callback_func_ = arguments[0]; + callback_context_ = CefV8Context::GetCurrentContext(); + return true; + } + } + + return false; +} +``` + +3\. Register the JS callback via JavaScript. + +```html + +``` + +4\. Execute the JS callback at some later time. + +```cpp +CefV8ValueList args; +CefRefPtr retval; +CefRefPtr exception; +if (callback_func_->ExecuteFunctionWithContext(callback_context_, NULL, args, retval, exception, false)) { + if (exception.get()) { + // Execution threw an exception. + } else { + // Execution succeeded. + } +} +``` + +See the [Asynchronous JavaScript Bindings](general_usage.md#asynchronous-javascript-bindings) section of the GeneralUsage wiki page for more information on using callbacks. + +## Rethrowing Exceptions + +If CefV8Value::SetRethrowExceptions(true) is called before CefV8Value::ExecuteFunction\*() then any exceptions generated by V8 during function execution will be immediately rethrown. If an exception is rethrown any native code needs to immediately return. Exceptions should only be rethrown if there is a JS call higher in the call stack. For example, consider the following call stacks where "JS" is a JS function and "EF" is a native ExecuteFunction call: + +Stack 1: JS1 -> EF1 -> JS2 -> EF2 + +Stack 2: Native Menu -> EF1 -> JS2 -> EF2 + +With stack 1 rethrow should be true for both EF1 and EF2. With stack 2 rethrow should false for EF1 and true for EF2. + +This can be implemented by having two varieties of call sites for EF in the native code: + +1. Only called from a V8 handler. This covers EF 1 and EF2 in stack 1 and EF2 in stack 2. Rethrow is always true. + +2. Only called natively. This covers EF1 in stack 2. Rethrow is always false. + +Be very careful when rethrowing exceptions. Incorrect usage (for example, calling ExecuteFunction() immediately after exception has been rethrown) may cause your application to crash or malfunction in hard to debug ways. \ No newline at end of file diff --git a/docs/linking_different_runtime_libraries.md b/docs/linking_different_runtime_libraries.md new file mode 100644 index 000000000..e8738bdb3 --- /dev/null +++ b/docs/linking_different_runtime_libraries.md @@ -0,0 +1,47 @@ +This page explains how to link CEF against a different run-time library. + + +*** + +**Contents** + +- [Introduction](#introduction) +- [Details](#details) + - [Static Linking (without a CEF DLL)](#static-linking-without-a-cef-dll) + - [Dynamic Linking (with a CEF DLL)](#dynamic-linking-with-a-cef-dll) +- [Additional Information](#additional-information) + +--- + +# Introduction + +Visual Studio supports multiple run-time libraries. The different libraries are identified by flags such as `/MD`, `/MT` and `/LD`. By default, CEF uses the `/MT` flag that is also used by the Chromium project. Different applications, however, can sometimes require different run-time libraries. + +# Details + +There are two ways currently to link CEF with your application. + +## Static Linking (without a CEF DLL) + +If you wish to link CEF with your application statically then all Chromium and CEF projects must use the same run-time flag as your application. If your application already uses the `/MT` flag then you can build CEF statically as follows: + + 1. Set up the environment required to build Chromium and CEF as described on the project page and build it. + 1. Link your application against the resulting libcef\_static.lib file. + +If, however, your application does not use the `/MT` flag then you're effectively out of luck. Important parts of Chromium will not compile with a flag other than `/MT`. + +## Dynamic Linking (with a CEF DLL) + +If you prefer to link CEF with your application dynamically then the process is faster. CEF provides a binary distribution on the downloads page that contains everything you need to link CEF with your application including source code for the libcef\_dll\_wrapper project. If your application does not use the `/MT` flag then you will need to rebuild the libcef\_dll\_wrapper project with the same flags as your application. Unlike with static linking, you will not need to rebuild all of CEF or Chromium in order to do this. + + 1. Download a CEF binary release from the project downloads page. + 1. Run CMake with the additional `-DCEF_RUNTIME_LIBRARY_FLAG=/MD` command-line flag (`/MD` can be replaced with other flags as appropriate). + 1. Open cef.sln in Visual Studio. + 1. Right click on the libcef\_dll\_wrapper project and choose the "Project Only -> Build Only libcef\_dll\_wrapper" option. + +Sandbox support (linking `cef_sandbox.lib`) is only possible when your application is built with the `/MT` flag. To disable sandbox usage run CMake with the additional `-DUSE_SANDBOX=Off` command-line flag. + +# Additional Information + +More information on Microsoft run-time flags can be found here: +http://msdn.microsoft.com/en-us/library/2kzt1wy3.aspx \ No newline at end of file diff --git a/docs/master_build_quick_start.md b/docs/master_build_quick_start.md new file mode 100644 index 000000000..562f2ec5e --- /dev/null +++ b/docs/master_build_quick_start.md @@ -0,0 +1,389 @@ +This page provides a quick-start guide for creating a Debug build of CEF/Chromium using the current master (development) branch. + +**Contents** + +- [Overview](#overview) +- [File Structure](#file-structure) +- [Windows Setup](#windows-setup) +- [Mac OS X Setup](#mac-os-x-setup) +- [Linux Setup](#linux-setup) +- [Visual Studio Code Setup](#visual-studio-code-setup) +- [Next Steps](#next-steps) + +--- + +# Overview + +This page provides a quick-start guide for setting up a minimal development environment and building the master branch of Chromium/CEF for development purposes. For a comprehensive discussion of the available tools and configurations visit the [Branches And Building](branches_and_building.md) page. + +This guide is NOT intended for: + +- Those seeking a prebuilt binary distribution for use in third-party apps. Go [here](https://cef-builds.spotifycdn.com/index.html) instead. +- Those seeking to build the binary distribution in a completely automated manner. Go [here](branches_and_building.md#automated-method) instead. + +Development systems can be configured using dedicated hardware or a [VMware](http://www.vmware.com/products/player), [Parallels](http://www.parallels.com/eu/products/desktop/download/) or [VirtualBox](https://www.virtualbox.org/wiki/Downloads) virtual machine. + +The below steps can often be used to develop the most recent release branch of CEF/Chromium in addition to the master branch. Chromium build requirements change over time so review the build requirements listed on the [Branches And Building](branches_and_building.md#release-branches) page before attempting to build a release branch. Then just add `--branch=XXXX` to the automate-git.py command-line where "XXXX" is the branch number you wish to build. + +# File Structure + +The same file structure will be used on all platforms. "~" can be any path that does not include spaces or special characters. We'll be building this directory structure for each platform in the following sections. + +```text +~/code/ + automate/ + automate-git.py <-- CEF build script + chromium_git/ + cef/ <-- CEF source checkout + chromium/ + src/ <-- Chromium source checkout + update.[bat|sh] <-- Bootstrap script for automate-git.py + depot_tools/ <-- Chromium build tools +``` + +With this file structure you can develop multiple CEF/Chromium branches side-by-side. For example, repeat the below instructions using "chromium_git1" as the directory name instead of "chromium_git". + +# Windows Setup + +**What's Required** + +- Windows Build Requirements as listed on the [Branches And Building](branches_and_building.md#development) page. +- Install required Visual Studio sub-components as described [here](automated_build_setup.md#windows-configuration). +- Install the exact Windows SDK version specified in the default location to avoid build issues. +- At least 16GB of RAM (32GB+ recommended) and 150GB of free disk space (for a Debug build). +- Approximately 4 hours with a fast internet connection (100Mbps) and fast build machine (2.4Ghz, 16 logical cores, SSD). + +**Step-by-step Guide** + +All of the below commands should be run using the system "cmd.exe" and not a Cygwin shell. + +1\. Create the following directories. + +``` +c:\code\automate +c:\code\chromium_git +``` + +WARNING: If you change the above directory names/locations make sure to (a) use only ASCII characters and (b) choose a short file path (less than 35 characters total). Otherwise, some tooling may fail later in the build process due to invalid or overly long file paths. + +2\. Download [depot_tools.zip](https://storage.googleapis.com/chrome-infra/depot_tools.zip) and extract to "c:\code\depot_tools". Do not use drag-n-drop or copy-n-paste extract from Explorer, this will not extract the hidden ".git" folder which is necessary for depot_tools to auto-update itself. You can use "Extract all..." from the context menu though. [7-zip](http://www.7-zip.org/download.html) is also a good tool for this. + +3\. Run "update_depot_tools.bat" to install Python and Git. + +```sh +cd c:\code\depot_tools +update_depot_tools.bat +``` + +4\. Add the "c:\code\depot_tools" folder to your system PATH. For example, on Windows 10: + +- Run the "SystemPropertiesAdvanced" command. +- Click the "Environment Variables..." button. +- Double-click on "Path" under "System variables" to edit the value. + +5\. Download the [automate-git.py](https://github.com/chromiumembedded/cef/blob/master/tools/automate/automate-git.py) script to "c:\code\automate\automate-git.py". + +6\. Create the "c:\code\chromium_git\update.bat" script with the following contents. + +```sh +python3 ..\automate\automate-git.py --download-dir=c:\code\chromium_git --depot-tools-dir=c:\code\depot_tools --no-distrib --no-build +``` + +Run the "update.bat" script and wait for CEF and Chromium source code to download. CEF source code will be downloaded to "c:\code\chromium_git\cef" and Chromium source code will be downloaded to "c:\code\chromium_git\chromium\src". After download completion the CEF source code will be copied to "c:\code\chromium_git\chromium\src\cef". + +```sh +cd c:\code\chromium_git +update.bat +``` + +7\. Create the "c:\code\chromium_git\chromium\src\cef\create.bat" script with the following contents. + +```sh +set GN_DEFINES=is_component_build=true +set GN_ARGUMENTS=--ide=vs2022 --sln=cef --filters=//cef/* +call cef_create_projects.bat +``` + +NOTE: Remove the `GN_ARGUMENTS` line if you intend to use Visual Studio Code instead of Visual Studio. See the "Visual Studio Code Setup" section below. + +Run the "create.bat" script to generate Ninja and Visual Studio project files. + +```sh +cd c:\code\chromium_git\chromium\src\cef +create.bat +``` + +This will generate a "c:\code\chromium_git\chromium\src\out\Debug_GN_x86\cef.sln" file that can be loaded in Visual Studio for debugging and compiling individual files. Replace “x86” with “x64” in this path to work with the 64-bit build instead of the 32-bit build. Always use Ninja to build the complete project. Repeat this step if you change the project configuration or add/remove files in the GN configuration (BUILD.gn file). + +8\. Create a Debug build of CEF/Chromium using Ninja. Edit the CEF source code at "c:\code\chromium_git\chromium\src\cef" and repeat this step multiple times to perform incremental builds while developing. + +```sh +cd c:\code\chromium_git\chromium\src +autoninja -C out\Debug_GN_x86 cef +``` + +Replace "Debug" with "Release" to generate a Release build instead of a Debug build. Replace “x86” with “x64” to generate a 64-bit build instead of a 32-bit build. + +9\. Run the resulting cefclient sample application. + +```sh +cd c:\code\chromium_git\chromium\src +out\Debug_GN_x86\cefclient.exe +``` + +See the [Windows debugging guide](https://www.chromium.org/developers/how-tos/debugging-on-windows) for detailed debugging instructions. + +# Mac OS X Setup + +**What's Required** + +- macOS Build Requirements as listed on the [Branches And Building](branches_and_building.md#development) page. +- Building on an Intel Mac is supported with all versions. Building on an Apple Silicon (ARM64) Mac is supported starting with M93 (4577 branch). +- At least 16GB of RAM (32GB+ recommended) and 150GB of free disk space (for a Debug build). +- Approximately 4 hours with a fast internet connection (100Mbps) and fast build machine (2.4Ghz, 16 logical cores, SSD). + +**Step-by-step Guide** + +In this example "~" is "/Users/marshall". Note that in some cases the absolute path must be used. Environment variables described in this section can be added to your "~/.bash_profile" file to persist them across sessions. + +1\. Create the following directories. + +```sh +mkdir ~/code +mkdir ~/code/automate +mkdir ~/code/chromium_git +``` + +2\. Download "~/code/depot_tools" using Git. + +```sh +cd ~/code +git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +``` + +3\. Add the "~/code/depot_tools" directory to your PATH. Note the use of an absolute path here. + +```sh +export PATH=/Users/marshall/code/depot_tools:$PATH +``` + +4\. Download the [automate-git.py](https://github.com/chromiumembedded/cef/blob/master/tools/automate/automate-git.py) script to "~/code/automate/automate-git.py". + +5\. Create the "~/code/chromium_git/update.sh" script with the following contents. + +```sh +#!/bin/bash +python3 ../automate/automate-git.py --download-dir=/Users/marshall/code/chromium_git --depot-tools-dir=/Users/marshall/code/depot_tools --no-distrib --no-build --x64-build +``` + +**⚠** Replace `--x64-build` with `--arm64-build` if using an Apple Silicon Mac instead of an Intel Mac. + +Give it executable permissions. + +```sh +cd ~/code/chromium_git +chmod 755 update.sh +``` + +Run the "update.sh" script and wait for CEF and Chromium source code to download. CEF source code will be downloaded to "~/code/chromium_git/cef" and Chromium source code will be downloaded to "~/code/chromium_git/chromium/src". After download completion the CEF source code will be copied to "~/code/chromium_git/chromium/src/cef". + +```sh +cd ~/code/chromium_git +./update.sh +``` + +6\. Run the "~/code/chromium_git/chromium/src/cef/cef_create_projects.sh" script to create Ninja project files. Repeat this step if you change the project configuration or add/remove files in the GN configuration (BUILD.gn file). + +```sh +cd ~/code/chromium_git/chromium/src/cef +./cef_create_projects.sh +``` + +**⚠** Add `export GN_DEFINES=is_component_build=true` before running `cef_create_projects.sh` if using an Apple Silicon Mac instead of an Intel Mac. + +7\. Create a Debug build of CEF/Chromium using Ninja. Edit the CEF source code at "~/code/chromium_git/chromium/src/cef" and repeat this step multiple times to perform incremental builds while developing. + +```sh +cd ~/code/chromium_git/chromium/src +autoninja -C out/Debug_GN_x64 cef +``` + +**⚠** Replace "x64" with "arm64" if using an Apple Silicon Mac instead of an Intel Mac. Replace "Debug" with "Release" to generate a Release build instead of a Debug build. + +8\. Run the resulting cefclient, cefsimple and/or ceftests sample applications. + +```sh +cd ~/code/chromium_git/chromium/src +open out/Debug_GN_x64/cefclient.app +# Or run directly in the console to see log output: +./out/Debug_GN_x64/cefclient.app/Contents/MacOS/cefclient +``` + +See the [Mac OS X debugging guide](https://www.chromium.org/developers/how-tos/debugging-on-os-x) for detailed debugging instructions. + +# Linux Setup + +**What's Required** + +- Linux Build Requirements as listed on the [Branches And Building](branches_and_building.md#development) page. +- Building with other versions or distros has not been tested and may experience issues. +- At least 16GB of RAM (32GB+ recommended) and 120GB of free disk space (for a Debug build). +- Approximately 4 hours with a fast internet connection (100Mbps) and fast build machine (2.4Ghz, 16 logical cores, SSD). + +**Step-by-step Guide** + +In this example "~" is "/home/marshall". Note that in some cases the absolute path must be used. Environment variables described in this section can be added to your "~/.profile" or "~/.bashrc" file to persist them across sessions. + +1\. Create the following directories. + +```sh +mkdir ~/code +mkdir ~/code/automate +mkdir ~/code/chromium_git +``` + +2\. Download and run "~/code/install-build-deps.py" to install build dependencies. Answer Y (yes) to all of the questions. + +```sh +cd ~/code +sudo apt-get install curl file lsb-release procps python3 python3-pip +curl 'https://chromium.googlesource.com/chromium/src/+/main/build/install-build-deps.py?format=TEXT' | base64 -d > install-build-deps.py +sudo python3 ./install-build-deps.py --no-arm --no-chromeos-fonts --no-nacl +python3 -m pip install dataclasses importlib_metadata +``` + +3\. Download "~/code/depot_tools" using Git. + +```sh +cd ~/code +git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +``` + +4\. Add the "~/code/depot_tools" directory to your PATH. Note the use of an absolute path here. + +```sh +export PATH=/home/marshall/code/depot_tools:$PATH +``` + +5\. Download the "~/automate/automate-git.py" script. + +```sh +cd ~/code/automate +wget https://raw.githubusercontent.com/chromiumembedded/cef/master/tools/automate/automate-git.py +``` + +6\. Create the "~/code/chromium_git/update.sh" script with the following contents. + +```sh +#!/bin/bash +python3 ../automate/automate-git.py --download-dir=/home/marshall/code/chromium_git --depot-tools-dir=/home/marshall/code/depot_tools --no-distrib --no-build +``` + +Give it executable permissions. + +```sh +cd ~/code/chromium_git +chmod 755 update.sh +``` + +Run the "update.sh" script and wait for CEF and Chromium source code to download. CEF source code will be downloaded to "~/code/chromium_git/cef" and Chromium source code will be downloaded to "~/code/chromium_git/chromium/src". After download completion the CEF source code will be copied to "~/code/chromium_git/chromium/src/cef". + +```sh +cd ~/code/chromium_git +./update.sh +``` + +7\. Configure `GN_DEFINES` for your desired build environment. + +Chromium provides [sysroot images](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/linux/sysroot.md) for consistent builds across Linux distros. The necessary files will have downloaded automatically as part of step 6 above. Usage of Chromium's sysroot is recommended if you don't want to deal with potential build breakages due to incompatibilities with the package or kernel versions that you've installed locally. To use the sysroot image configure the following GN_DEFINES: + +```sh +export GN_DEFINES="use_sysroot=true use_allocator=none symbol_level=1 is_cfi=false use_thin_lto=false" +``` + +It is also possible to build using locally installed packages instead of the provided sysroot. Choosing this option may require additional debugging effort on your part to work through any build errors that result. On Ubuntu 18.04 the following GN_DEFINES have been tested to work reliably: + +```sh +export GN_DEFINES="use_sysroot=false use_allocator=none symbol_level=1 is_cfi=false use_thin_lto=false use_vaapi=false" +``` + +Note that the "cefclient" target cannot be built directly when using the sysroot image. You can work around this limitation by creating a [binary distribution](branches_and_building.md#manual-packaging) after completing step 9 below, and then building the cefclient target using that binary distribution. + +You can also create an [AddressSanitizer build](using_address_sanitizer.md) for enhanced debugging capabilities. Just add `is_asan=true dcheck_always_on=true` to the GN_DEFINES listed above and build the `out/Release_GN_x64` directory in step 9 below. Run with the `asan_symbolize.py` script as described in the AddressSanitizer link to get symbolized output. + +The various other listed GN arguments are based on recommendations from the [AutomateBuildSetup page](automated_build_setup.md#linux-configuration). You can [search for them by name](https://source.chromium.org/search?q=use_allocator%20gni&ss=chromium) in the Chromium source code to find more details. + +8\. Run the "~/code/chromium_git/chromium/src/cef/cef_create_projects.sh" script to create Ninja project files. Repeat this step if you change the project configuration or add/remove files in the GN configuration (BUILD.gn file). + +```sh +cd ~/code/chromium_git/chromium/src/cef +./cef_create_projects.sh +``` + +9\. Create a Debug build of CEF/Chromium using Ninja. Edit the CEF source code at "~/code/chromium_git/chromium/src/cef" and repeat this step multiple times to perform incremental builds while developing. Note the additional "chrome_sandbox" target may be required by step 10. The "cefclient" target will only build successfully if you set `use_sysroot=false` in step 7, so remove that target if necessary. + +```sh +cd ~/code/chromium_git/chromium/src +autoninja -C out/Debug_GN_x64 cefclient cefsimple ceftests chrome_sandbox +``` + +Replace "Debug" with "Release" to generate a Release build instead of a Debug build. + +10\. Set up the [Linux SUID sandbox](https://chromium.googlesource.com/chromium/src.git/+/HEAD/docs/linux/suid_sandbox_development.md) if you are using an older kernel (< 3.8). See [here](https://chromium.googlesource.com/chromium/src.git/+/HEAD/docs/linux/sandboxing.md) for more background on Linux sandboxing technology. + +```sh +# This environment variable should be set at all times. +export CHROME_DEVEL_SANDBOX=/usr/local/sbin/chrome-devel-sandbox + +# This command only needs to be run a single time. +cd ~/code/chromium_git/chromium/src +sudo BUILDTYPE=Debug_GN_x64 ./build/update-linux-sandbox.sh +``` + +11\. Run the cefclient, cefsimple and/or ceftests sample applications. Note that the cefclient application will only have built successfully if you set `use_sysroot=false` in step 7. + +```sh +cd ~/code/chromium_git/chromium/src +./out/Debug_GN_x64/cefclient +``` + +See the [Linux debugging guide](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/debugging.md) for detailed debugging instructions. + +# Visual Studio Code Setup + +[Visual Studio Code](https://code.visualstudio.com/) (VSCode) is a free, open source, lightweight and powerful code editor for Windows, macOS and Linux. CEF provides a preconfigured VSCode environment for CEF/Chromium development. This includes helpful features like: + +- Git integration (history, blame, etc). +- Clangd for C/C++ IntelliSense. +- Syntax highlighting and auto-completion in C++/Python/GN files. +- Clang-format on save. +- And [more](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/vscode.md). + +To setup/install the CEF VSCode environment first download CEF/Chromium code as described above (you can stop after the cef_create_projects step), and then run the following command. Follow the on-screen instructions to complete the setup process. + +```sh +cd /path/to/code/chromium_git/chromium/src/cef +python3 tools/setup_vscode.py +``` + +After setup you can launch VSCode with the following command. + +```sh +cd /path/to/code/chromium_git/chromium/src +code . +``` + +If you're new to VSCode usage see the [intro videos](https://code.visualstudio.com/docs/introvideos/basics) to get started. + +VSCode is configured via JSON files in the `chromium/src/.vscode` directory. The CEF configuration is based on the Chromium configuration which is documented [here](https://chromium.googlesource.com/chromium/src/+/main/docs/vscode.md). + +- Settings (`settings.json`) changes can be applied to the current window using Ctrl+Shift+P (Cmd+Shift+P on macOS) and typing "Reload Window". +- Tasks (`tasks.json`) can be run using Ctrl+Shift+P (Cmd+Shift+P on macOS), typing "task", selecting "Tasks: Run Task", and then the choice ([details](https://chromium.googlesource.com/chromium/src/+/main/docs/vscode.md#Tasks)). +- Launch commands (`launch.json`) can be run from the debug view accessible via Ctrl+Shift+D (Cmd+Shift+D on macOS) ([details](https://chromium.googlesource.com/chromium/src/+/main/docs/vscode.md#Launch-Commands)). + +# Next Steps + +- If you prefer a different editor Chromium provides tips/tutorials for [Visual Studio](https://www.chromium.org/developers/how-tos/visualstudio-tricks/), [Eclipse](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/eclipse_dev.md) and [Emacs](https://chromium.googlesource.com/chromium/src/+/main/docs/emacs.md). +- Review the [Tutorial](tutorial.md) and [General Usage](general_usage.md) Wiki pages for details on CEF implementation and usage. +- Review the Chromium debugging guide for [Windows](https://www.chromium.org/developers/how-tos/debugging-on-windows), [Mac OS X](https://www.chromium.org/developers/how-tos/debugging-on-os-x) or [Linux](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/debugging.md). +- When you’re ready to contribute your changes back to the CEF project see the [Contributing With Git](contributing_with_git.md) page for instructions on creating a pull request. \ No newline at end of file diff --git a/docs/sandbox_setup.md b/docs/sandbox_setup.md new file mode 100644 index 000000000..bc8ea9bfc --- /dev/null +++ b/docs/sandbox_setup.md @@ -0,0 +1,139 @@ +This page describes sandbox usage and requirements for CEF. + +**Contents** + +- [Overview](#overview) +- [Usage](#usage) + - [Windows](#windows) + - [macOS](#macos) + - [Linux](#linux) +- [Building cef_sandbox (Windows/macOS)](#building-cef_sandbox-windowsmacos) +- [Building bootstrap (Windows)](#building-bootstrap-windows) + +--- + +# Overview + +The Chromium/CEF [multi-process model](general_usage.md#processes) uses separate processes for the renderer, network stack, GPU, etc. This model allows Chromium to restrict access to system resources based on the sub-process type. For example, a renderer sub-process that executes JavaScript code does not need direct access to the file system or network stack. Allowing unnecessary access can be a security concern if a sub-process is compromised while executing content (e.g. JavaScript code) from a hostile website. + +The [Chromium sandbox](https://chromium.googlesource.com/chromium/src/+/master/docs/design/sandbox.md) is used to apply per-process access restrictions based on the process type. With the sandbox enabled a compromised sub-process will often be terminated before it can do any harm. CEF supports the Chromium sandbox on each platform as described below. + +# Usage + +Sandbox capabilities are OS-specific and different requirements apply to each platform. + +## Windows + +To enable the sandbox on Windows the following requirements must be met: + +1. Use the same executable for the browser process and all sub-processes. The `CefSettings.browser_subprocess_path` setting cannot be used in combination with the sandbox. +2. Link the executable with the `cef_sandbox` static library. +3. Call the `cef_sandbox_info_create()` function from within the executable (not from a separate DLL) and pass the resulting pointer into both the` CefExecutProcess()` and `CefInitialize()` functions via the `windows_sandbox_info` parameter. + +**New requirements starting with M138:** + +Starting with M138 the `cef_sandbox` static library can only be linked with applications built as part of the CEF/Chromium build. This is due to [unavoidable](https://github.com/chromiumembedded/cef/issues/3824) dependencies on Chromium's bundled Clang/LLVM/libc++ toolchain. CEF provides pre-built bootstrap executables that can be used "out of the box" with minimal client application changes. Usage is as follows: + +1. Build your client application as a DLL (`client.dll`) instead of an executable. For windows applications (`/SUBSYSTEM:WINDOWS`) implement/export the `RunWinMain` function and run with `bootstrap.exe`. For console applications (`/SUBSYSTEM:CONSOLE`) implement/export the `RunConsoleMain` function and run with `bootstrapc.exe`. Function signatures are provided in [cef_sandbox_win.h](https://github.com/chromiumembedded/cef/blob/9a115ea48f315887c531fa2988a20ba733977412/include/cef_sandbox_win.h#L98). +2. Run your client application using the provided bootstrap executable (`bootstrap[c].exe --module=client`) or rename `bootstrap[c].exe` to `client.exe` to have it load `client.dll` from the same directory by default. The bootstrap executable will load your client DLL and call the exported function, passing in a `void* sandbox_info` parameter in addition to the normal [wWinMain](https://learn.microsoft.com/en-us/windows/win32/learnwin32/winmain--the-application-entry-point) or [main](https://learn.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-170#the-main-function-signature) parameters. The `sandbox_info` parameter is then forwarded by the client DLL to `CefExecuteProcess` and `CefInitialize` in the usual manner. +3. Optionally customize the bootstrap executable for your client application. For example, resources such as icons, file information and error strings can be modified using [Visual Studio](https://learn.microsoft.com/en-us/cpp/windows/working-with-resource-files?view=msvc-170) or [Resource Hacker](https://www.angusj.com/resourcehacker/) tools ([example](https://github.com/chromiumembedded/cef/issues/3824#issuecomment-2895663576)). Alternately, you can build and modify the bootstrap executables from source code as part of a CEF/Chromium build (see the "Building bootstrap" section below). +4. Be sure to [code sign](https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool) all binaries after modification and before distribution to users ([example](https://github.com/chromiumembedded/cef/issues/3824#issuecomment-2892139995)). + +If you don't wish to use the provided bootstrap executables you have a few other options: + +1. Build your client application as part of the CEF/Chromium build using Chromium's bundled Clang/LLVM/libc++ toolchain. You will need to integrate your custom build into CEF's top-level [BUILD.gn file](https://github.com/chromiumembedded/cef/blob/master/BUILD.gn). See for example the "cefsimple targets" section in that file for how the cefsimple application is built. +2. Build your client application as an executable with the sandbox disabled. This requires no code changes to existing applications beyond passing nullptr as the `windows_sandbox_info` parameter to `CefExecuteProcess` and `CefInitialize`. + +See [cef_sandbox_win.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_sandbox_win.h) for additional details. See [cefsimple_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_win.cc) for an example implementation. + +## macOS + +To enable the sandbox on macOS the following requirements must be met: + +1. Distribute the `libcef_sandbox.dylib` shared library and load dynamically (M138 and newer) or link the helper process executable with the `cef_sandbox` static library (prior to M138). +2. Call the `cef_sandbox_initialize()` function at the beginning of the helper executable `main()` function and before loading the CEF framework library. + +See [cef_sandbox_mac.h](https://github.com/chromiumembedded/cef/blob/master/include/cef_sandbox_mac.h) and [cef_library_loader.h](https://github.com/chromiumembedded/cef/blob/master/include/wrapper/cef_library_loader.h) for additional details. See [cefsimple_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_mac.mm) and [process_helper_mac.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/process_helper_mac.cc) for an example implementation. + +The [V2 sandbox](https://chromium.googlesource.com/chromium/src/+/master/sandbox/mac/seatbelt_sandbox_design.md) was enabled starting with 3538 branch. See [this announcement](https://groups.google.com/d/msg/cef-announce/Fith0A3kWtw/6ds_mJVMCQAJ) for a description of the related changes. + +## Linux + +Different approaches are used based on system capabilities. See [this document](https://chromium.googlesource.com/chromium/src/+/refs/tags/57.0.2956.2/docs/linux_sandboxing.md) for details. + +# Building cef_sandbox (Windows/macOS) + +**Sandbox requirements have changed starting with M138. See the above Usage section for details.** + +In M138 and newer `cef_sandbox` is no longer distributed as a static library. On Windows it has been removed in favor of bootstrap executables. On macOS it has been replaced with `libcef_sandbox.dylib` which is included in the framework bundle `Libraries` directory and loaded via `dlopen()` at runtime. These new binaries use the same output directory as the standard CEF/Chromium build and there is no longer a need to build `cef_sandbox` independently. + +**Deprecated build instructions for older versions:** + +Prior to M138 linking the `cef_sandbox` static library is required for using the sandbox on Windows and macOS. This library must be built with special configuration settings in order to link successfully with third-party applications. For example, Chromium's custom bundled libc++ version must be disabled to avoid linker conflicts when using the default platform runtime library on Windows. + +The `cef_sandbox` library build is usually performed by the `automate_git.py` tool as part of the official binary distribution build (see the [Automated Build Setup](automated_build_setup.md) page). The special sandbox-specific configuration comes from the `GetConfigArgsSandbox` function in the [gn_args.py](https://github.com/chromiumembedded/cef/blob/master/tools/gn_args.py) tool and the sandbox build is performed by `automate_git.py` in a separate `out/[Config]_sandbox` output directory. A final post-processing action by the [make_distrib.py](https://github.com/chromiumembedded/cef/blob/master/tools/make_distrib.py) tool combines multiple lib files into a single `cef_sandbox.lib` (Windows) or `cef_sandbox.a` (macOS) file which is included with the binary distribution. + +The `cef_sandbox` library can also be built locally for development and testing purposes as described below. This example creates a build that is compatible with the official ARM64 macOS distribution available for download from [Spotify](https://cef-builds.spotifycdn.com/index.html). To perform this build you must first set up a local Chromium/CEF checkout as described on the [Master Build Quick Start](master_build_quick_start.md) page and check out the correct branch/version by passing the appropriate `--branch=XXXX` or `--checkout=HHHHHHHH` command-line flags to `automate_git.py`. You can then build the `cef_sandbox` library as follows: + +```sh +# Discover what `args.gn` contents are required: +cd /path/to/chromium/src/cef +export GN_DEFINES=is_official_build=true +export GN_OUT_CONFIGS=Debug_GN_arm64_sandbox +python3 tools/gn_args.py + +# Create the `chromium/src/out/Debug_GN_arm64_sandbox/args.gn` file with the specified contents. + +# Build the cef_sandbox target in the new output directory: +cd /path/to/chromium/src +gn gen out/Debug_GN_arm64_sandbox +ninja -C out/Debug_GN_arm64_sandbox cef_sandbox + +# Create a binary distribution for the cef_sandbox build: +cd /path/to/chromium/src/cef/tools +./make_distrib.sh --allow-partial --sandbox --ninja-build --arm64-build --no-archive --no-symbols --no-docs +``` + +The resulting `chromium/src/cef/binary_distrib/cef_binary_*_macosarm64_sandbox/Debug/cef_sandbox.a` file can then be tested in combination with an existing official binary distribution at the same version. + +If a different platform or configuration is desired you can find the appropriate `GN_DEFINES` on the [Automated Build Setup](automated_build_setup.md) page. + +# Building bootstrap (Windows) + +This section describes how to build the bootstrap executables (`bootstrap.exe` and `bootstrapc.exe`) used with M138 and newer. See the Usage section above for background and client integration instructions. + +The bootstrap executable build is usually performed by the `automate_git.py` tool as part of the official binary distribution build (see the [Automated Build Setup](automated_build_setup.md) page). It uses the same output directory as the standard CEF/Chromium build. + +Code for the bootstrap executables lives in the [cef\libcef_dll\bootstrap](https://github.com/chromiumembedded/cef/tree/master/libcef_dll/bootstrap) directory and can be built locally for development and testing purposes as described below. For example, you might change the default application [resources](https://github.com/chromiumembedded/cef/tree/master/libcef_dll/bootstrap/win) such as icons, file information or error strings. These executables depend only on the `cef_sandbox` and Chromium `//base` targets and run prior to CEF/Chromium initialization. They must therefore comply with the following restrictions: + +1. No access to CEF or Chromium APIs that require or trigger global initialization. +2. No access to WinAPI (or similar) functions when executing as a sandboxed sub-process. +3. No new (non-delay-loaded) DLL dependencies that may interfere with sandbox capabilities ([details](https://github.com/chromiumembedded/cef/blob/7581264dbb9a2a38bd7d6635d011050dc695b88f/cmake/cef_variables.cmake.in#L456)). + +The following example creates a build that is compatible with the official 64-bit Windows distribution available for download from [Spotify](https://cef-builds.spotifycdn.com/index.html). To perform this build you must first set up a local Chromium/CEF checkout as described on the [Master Build Quick Start](master_build_quick_start.md) page and check out the correct branch/version by passing the appropriate `--branch=XXXX` or `--checkout=HHHHHHHH` command-line flags to `automate_git.py`. You can then build the bootstrap binaries as follows: + +```sh +# Discover what `args.gn` contents are required: +cd c:\path\to\chromium\src\cef +set GN_DEFINES=is_official_build=true +set GN_OUT_CONFIGS=Debug_GN_x64 +python3 tools\gn_args.py + +# Create or update the `chromium\src\out\Debug_GN_x64\args.gn` file with the specified contents. + +# Build the bootstrap targets in the output directory: +cd c:\path\to\chromium\src +set DEPOT_TOOLS_WIN_TOOLCHAIN=0 +gn gen out\Debug_GN_x64 +ninja -C out\Debug_GN_x64 bootstrap bootstrapc + +# Create a binary distribution for the bootstrap build: +cd c:\path\to\chromium\src\cef\tools +make_distrib.bat --allow-partial --sandbox --ninja-build --x64-build --no-archive --no-symbols --no-docs +``` + +The resulting `chromium\src\cef\binary_distrib\cef_binary_*_windows64_sandbox\Debug\bootstrap.exe` (or `bootstrapc.exe`) file can then be tested in combination with an existing official binary distribution at the same version. + +If a different platform or configuration is desired you can find the appropriate `GN_DEFINES` on the [Automated Build Setup](automated_build_setup.md) page. + +If you don't wish to invalidate an existing CEF/Chromium build you can optionally create the bootstrap build using a custom output directory (e.g. replace `out\Debug_GN_x64` with `out\Debug_GN_x64_bootstrap`). However, you will then need to manually copy the bootstrap executables as the last step instead of running `make_distrib.bat`. \ No newline at end of file diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 000000000..90aa700d7 --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,264 @@ +This page explains how to create a simple application using CEF3. + +**Contents** + +- [Introduction](#introduction) +- [Getting Started](#getting-started) + - [Loading a Custom URL](#loading-a-custom-url) +- [Application Components](#application-components) +- [Architecture in 60 Seconds](#architecture-in-60-seconds) +- [Source Code](#source-code) + - [Entry Point Function](#entry-point-function) + - [SimpleApp](#simpleapp) + - [SimpleHandler](#simplehandler) +- [Build Steps](#build-steps) + - [Windows Build Steps](#windows-build-steps) + - [Linux Build Steps](#linux-build-steps) + - [MacOS Build Steps](#macos-build-steps) +- [Next Steps](#next-steps) + - [Explore More Features](#explore-more-features) + - [C API Development](#c-api-development) + - [Comprehensive Documentation](#comprehensive-documentation) + - [Using Claude Code for Implementation](#using-claude-code-for-implementation) + +--- + +# Introduction + +This tutorial explains how to create a simple application using CEF3 and the **CEF C++ API**. It references the [cefsimple example project](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/). For complete CEF3 usage information visit the [General Usage](general_usage.md) page. + +**Prefer hands-on learning?** The [Hands-On Tutorial](hands_on_tutorial.md) teaches CEF development by **modifying cefsimple step-by-step**. You'll progressively add features like JavaScript integration, custom popup windows, and multi-browser support. This architectural tutorial provides reference documentation, while the hands-on tutorial provides practical learning-by-doing. + +**Using the C API?** If you need a pure C implementation (no C++), see [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/) and the [Using the C API](using_the_capi.md) page instead. The architectural concepts in this tutorial apply to both APIs. + +# Getting Started + +**This tutorial uses CEF binary distributions.** If you're building from Chromium source, the build process is different (uses GN/Ninja instead of CMake). See the README.txt file in your checkout for source build instructions. + +CEF provides a sample project that makes it really easy to get started with CEF development using binary distributions. Simply browse over to the [cef-project](https://github.com/chromiumembedded/cef-project) website and follow the step-by-step instructions. The source files linked from this tutorial are for the current CEF3 master branch and may differ slightly from the versions that are downloaded by cef-project. + +## Loading a Custom URL + +The cefsimple application loads google.com by default but you can change it to load a custom URL instead. The easiest way to load a different URL is via the command-line. + +```sh +# Load the local file “c:\example\example.html” +cefsimple.exe --url=file://c:/example/example.html +``` + +You can also edit the source code in [cefsimple/simple\_app.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.cc) and recompile the application to load your custom URL by default. + +```cpp +// Load the local file “c:\example\example.html” +… +if (url.empty()) + url = "file://c:/example/example.html"; +… +``` + +# Application Components + +All CEF applications have the following primary components: + + 1. The CEF dynamic library (libcef.dll on Windows, libcef.so on Linux, “Chromium Embedded Framework.framework” on macOS). + 1. Support files (\*.pak and \*.bin binary blobs, etc). + 1. Resources (html/js/css for built-in features, strings, etc). + 1. Client executable (cefsimple in this example). + +The CEF dynamic library, support files and resources will be the same for every CEF-based application. They are included in the Debug/Release or Resources directory of the binary distribution. See the README.txt file included in the binary distribution for details on which of these files are required and which can be safely left out. See below for a detailed description of the required application layout on each platform. + +# Architecture in 60 Seconds + +The below list summarizes the items of primary importance for this tutorial: + + * CEF uses multiple processes. The main application process is called the "browser" process. Sub-processes will be created for renderers, plugins, GPU, etc. + * On Windows and Linux the same executable can be used for the main process and sub-processes. On macOS you are required to create a separate executable and app bundle for sub-processes. + * CEF supports two browser styles: Chrome style (full Chrome UI, used by default in cefsimple) and Alloy style (traditional CEF, use `--use-alloy-style` flag). + * CEF supports multiple UI frameworks: Views (cross-platform, used by default in cefsimple), native platform UI (`--use-native` flag), and off-screen rendering (OSR). + * Most processes in CEF have multiple threads. CEF provides functions and interfaces for posting tasks between these various threads. + * Some callbacks and functions may only be used in particular processes or on particular threads. Make sure you read the source code comments in the API headers before you begin using a new callback or function for the first time. + +Read the [General Usage](general_usage.md) page for complete discussion of the above points. + +# Source Code + +The cefsimple application initializes CEF and creates a single popup browser window. The application terminates when all browser windows have been closed. Program flow is as follows: + + 1. The OS executes the browser process entry point function (main or wWinMain). + 1. The entry point function: + 1. Creates an instance of SimpleApp which handles process-level callbacks. + 1. Initializes CEF and runs the CEF message loop. + 1. After initialization CEF calls SimpleApp::OnContextInitialized(). This method: + 1. Creates the singleton instance of SimpleHandler. + 1. Creates a browser window using CefBrowserHost::CreateBrowser(). + 1. All browsers share the SimpleHandler instance which is responsible for customizing browser behavior and handling browser-related callbacks (life span, loading state, title display, etc). + 1. When a browser window is closed SimpleHandler::OnBeforeClose() is called. When all browser windows have closed the OnBeforeClose implementation quits the CEF message loop to exit the application. + +Your binary distribution may include newer versions of the below files. However, the general concepts remain unchanged. + +## Entry Point Function + +Execution begins in the browser process entry point function. This function is responsible for initializing CEF and any OS-related objects. For example, it installs X11 error handlers on Linux and allocates the necessary Cocoa objects on macOS. macOS has a separate entry point function for helper processes. + + * Windows platform implementation: [cefsimple/cefsimple\_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_win.cc) + * Linux platform implementation: [cefsimple/cefsimple\_linux.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_linux.cc) + * MacOS platform implementation + * For the browser process: [cefsimple/cefsimple\_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/cefsimple_mac.mm) + * For sub-processes: [cefsimple/process\_helper\_mac.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/process_helper_mac.cc) + +## SimpleApp + +SimpleApp is responsible for handling process-level callbacks. It exposes some interfaces/methods that are shared by multiple processes and some that are only called in a particular process. The CefBrowserProcessHandler interface, for example, is only called in the browser process. There's a separate CefRenderProcessHandler interface (not shown in this example) that is only called in the render process. Note that GetBrowserProcessHandler() must return |this| because SimpleApp implements both CefApp and CefBrowserProcessHandler. See the [General Usage](general_usage.md) page or API header files for additional information on CefApp and related interfaces. + + * Shared implementation: [cefsimple/simple\_app.h](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.h), [cefsimple/simple\_app.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_app.cc) + +## SimpleHandler + +SimpleHandler is responsible for handling browser-level callbacks. These callbacks are executed in the browser process. In this example we use the same CefClient instance for all browsers, but your application can use different CefClient instances as appropriate. See the [General Usage](general_usage.md) page or API header files for additional information on CefClient and related interfaces. + + * Shared implementation: [cefsimple/simple\_handler.h](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler.h), [cefsimple/simple\_handler.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler.cc) + * Windows platform implementation: [cefsimple/simple\_handler\_win.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler_win.cc) + * Linux platform implementation: [cefsimple/simple\_handler\_linux.cc](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler_linux.cc) + * MacOS platform implementation: [cefsimple/simple\_handler\_mac.mm](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple/simple_handler_mac.mm) + +# Build Steps + +Build steps vary depending on the platform. Explore the CMake files included with the binary distribution for a complete understanding of all required steps. The build steps common to all platforms can generally be summarized as follows: + + 1. Compile the libcef\_dll\_wrapper static library. + 1. Compile the application source code files. Link against the libcef dynamic library and the libcef\_dll\_wrapper static library. + 1. Copy libraries and resources to the output directory. + +## Windows Build Steps + + 1. Compile the libcef\_dll\_wrapper static library. + 1. Compile/link cefsimple.exe. + * Required source code files include: cefsimple\_win.cc, simple\_app.cc, simple\_handler.cc, simple\_handler\_win.cc. + * Required link libraries include: comctl32.lib, shlwapi.lib, rcprt4.lib, libcef\_dll\_wrapper.lib, libcef.lib, cef\_sandbox.lib. Note that cef\_sandbox.lib (required for sandbox support) is a static library currently built with Visual Studio 2022 and it may not compile with other Visual Studio versions. See comments in cefsimple\_win.cc for how to disable sandbox support. + * Resource file is cefsimple.rc. + * Manifest files are cefsimple.exe.manifest and compatibility.manifest. + 1. Copy all files from the Resources directory to the output directory. + 1. Copy all files from the Debug/Release directory to the output directory. + +The resulting directory structure looks like this for 2526 branch: + +```text +Application/ + cefsimple.exe <= cefsimple application executable + libcef.dll <= main CEF library + icudtl.dat <= unicode support data + libEGL.dll, libGLESv2.dll, ... <= accelerated compositing support libraries + cef.pak, devtools_resources.pak, ... <= non-localized resources and strings + natives_blob.bin, snapshot_blob.bin <= V8 initial snapshot + locales/ + en-US.pak, ... <= locale-specific resources and strings +``` + +## Linux Build Steps + + 1. Compile the libcef\_dll\_wrapper static library. + 1. Compile/link cefsimple. + * Required source code files include: cefsimple\_linux.cc, simple\_app.cc, simple\_handler.cc, simple\_handler\_linux.cc. + * Required link libraries include: libcef\_dll\_wrapper.a, libcef.so and dependencies (identified at build time using the “pkg-config” tool). + * Configure the rpath to find libcef.so in the current directory (“-Wl,-rpath,.”) or use the LD\_LIBRARY\_PATH environment variable. + 1. Copy all files from the Resources directory to the output directory. + 1. Copy all files from the Debug/Release directory to the output directory. + 1. Set SUID permissions on the chrome-sandbox executable to support the sandbox. See binary distribution build output for the necessary command. + +The resulting directory structure looks like this for 2526 branch: + +```text +Application/ + cefsimple <= cefsimple application executable + chrome-sandbox <= sandbox support binary + libcef.so <= main CEF library + icudtl.dat <= unicode support data + cef.pak, devtools_resources.pak, ... <= non-localized resources and strings + natives_blob.bin, snapshot_blob.bin <= V8 initial snapshot + locales/ + en-US.pak, ... <= locale-specific resources and strings + files/ + binding.html, ... <= cefclient application resources +``` + +## MacOS Build Steps + + 1. Compile the libcef\_dll\_wrapper static library. + 1. Compile/link/package the “cefsimple Helper” app. + * Required source code files include: process\_helper\_mac.cc. + * Required link frameworks include: AppKit.framework. + * App bundle configuration is provided via “cefsimple/mac/helper-Info.plist”. + * Load the CEF Framework as described [here](https://groups.google.com/d/msg/cef-announce/Fith0A3kWtw/6ds_mJVMCQAJ). + 1. Compile/link/package the “cefsimple” app. + * Required source code files include: cefsimple\_mac.mm, simple\_app.cc, simple\_handler.cc, simple\_handler\_mac.mm. + * Required link frameworks include: AppKit.framework. + * App bundle configuration is provided via “cefsimple/mac/Info.plist”. + * Load the CEF Framework as described [here](https://groups.google.com/d/msg/cef-announce/Fith0A3kWtw/6ds_mJVMCQAJ). + 1. Create a Contents/Frameworks directory in the cefsimple.app bundle. Copy the following files to that directory: “cefsimple Helper.app”, “Chromium Embedded Framework.framework”. + +The resulting directory structure looks like this for 2526 branch: + +```text +cefsimple.app/ + Contents/ + Frameworks/ + Chromium Embedded Framework.framework/ + Chromium Embedded Framework <= main application library + Resources/ + cef.pak, devtools_resources.pak, ... <= non-localized resources and strings + icudtl.dat <= unicode support data + natives_blob.bin, snapshot_blob.bin <= V8 initial snapshot + en.lproj/, ... <= locale-specific resources and strings + cefsimple Helper.app/ + Contents/ + Info.plist + MacOS/ + cefsimple Helper <= helper executable + Pkginfo + Info.plist + MacOS/ + cefsimple <= cefsimple application executable + Pkginfo + Resources/ + cefsimple.icns, ... <= cefsimple application resources +``` + +# Next Steps + +Now that you understand the basics of CEF application structure, here are recommended next steps: + +## Explore More Features + + * **[cefclient](https://github.com/chromiumembedded/cef/blob/master/tests/cefclient/)** - A comprehensive sample application demonstrating advanced CEF features including: + * Both Chrome style and Alloy style browsers + * Off-screen rendering (OSR) + * JavaScript integration and bindings + * Custom scheme handlers + * Request interception + * Plugin and extension support + +## C API Development + + * **[cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/)** - A pure C implementation of cefsimple + * **[Using The CAPI](using_the_capi.md)** - Complete guide to the CEF C API including: + * Manual reference counting patterns + * Structure allocation and ownership + * String handling + * Thread safety and atomic operations + * Complete working examples + +## Comprehensive Documentation + + * **[General Usage](general_usage.md)** - Complete CEF API documentation covering: + * Multi-process architecture in detail + * Threading model and task posting + * Browser lifecycle management + * Request handling and network interception + * JavaScript integration + * All handler interfaces and callbacks + +## Using Claude Code for Implementation + +Want help implementing additional features in your CEF application? The CEF project includes instructions for using Claude Code to assist with tasks like adding custom URL schemes, JavaScript-to-C++ communication, request interception, and more. + +See the [CEF Client Development Guide](https://github.com/chromiumembedded/cef/blob/master/tools/claude/CLIENT_DEVELOPMENT.md) for step-by-step instructions. \ No newline at end of file diff --git a/docs/using_address_sanitizer.md b/docs/using_address_sanitizer.md new file mode 100644 index 000000000..b1f84c762 --- /dev/null +++ b/docs/using_address_sanitizer.md @@ -0,0 +1,196 @@ +This page explains how to use AddressSanitizer with CEF-based applications. + +**Contents** + +- [Overview](#overview) +- [System Setup](#system-setup) + - [Building CEF with ASan](#building-cef-with-asan) +- [Using CEF and ASan with third-party executables](#using-cef-and-asan-with-third-party-executables) + +--- + +# Overview + +[AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) (ASan) is a fast memory error detector based on compiler instrumentation (LLVM). The below instructions relate to using ASan with CEF-based applications on Linux. ASan is also supported on MacOS and Windows (experimental) but usage with CEF has not been tested on those platforms. For examples of ASan output see [this bug](https://github.com/chromiumembedded/cef/issues/1457) and [this bug](https://github.com/chromiumembedded/cef/issues/1458). + +# System Setup + +Follow the standard [Master Build Quick Start](master_build_quick_start.md#linux-setup) instructions for Linux to configure a local CEF/Chromium build environment (stop after step 7 and continue below). + +## Building CEF with ASan + +To build Chromium/CEF with ASan enabled follow these steps: + +1\. Configure Chromium to build using ASan (see [here](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/asan.md) for complete Chromium-related ASan instructions). For example, to build on Ubuntu 18.04 using locally installed packages instead of the provided sysroot: + +```sh +export GN_DEFINES="is_asan=true dcheck_always_on=true use_sysroot=false use_partition_alloc_as_malloc=false symbol_level=1 is_cfi=false use_thin_lto=false use_vaapi=false" +``` + +2\. Generate CEF project files. + +```sh +cd /path/to/chromium_git/chromium/src/cef +./cef_create_projects.sh +``` + +3\. Create a Release build of CEF. ASan must always be used with Release builds. + +```sh +cd /path/to/chromium_git/chromium/src +ninja -C out/Release_GN_x64 cef +``` + +4\. Run the resulting executable and pipe output to the ASan post-processing script so that stack traces will be symbolized. + +```sh +cd /path/to/chromium_git/chromium/src +./out/Release_GN_x64/cef_unittests 2>&1 | tools/valgrind/asan/asan_symbolize.py +``` + +# Using CEF and ASan with third-party executables + +**NOTE: This section was last updated for 2357 branch (April 2015) and specific details may be out of date.** + +ASan on Linux is built as a static library by default. This works fine with applications like cefclient and cef\_unittests that are built at the same time as libcef and consequently specify the “-fsanitize=address” flag. However, in order to use libcef and ASan with pre-built third-party executables (e.g. Java and [JCEF](https://github.com/chromiumembedded/java-cef)) it’s necessary to build ASan as a shared library (see [here](https://github.com/google/sanitizers/issues/271) for more information). This works as follows (see step 8 below for an example): + +A. The ASan library (“libclang\_rt.asan-x86\_64.so” on 64-bit Linux) is specified via LD\_PRELOAD so that it will be loaded into the main executable at runtime. + +B. The main executable delay loads “libcef.so” which depends on “libc++.so” and “libclang\_rt.asan-x86\_64.so” provided by the Chromium Clang build. + +C. Output is piped to the ASan post-processing script in order to symbolize stack traces. + +To build ASan as a shared library the following changes are required to Chromium’s default Clang build and GYP configuration: + +1\. Create a custom build of Clang with ASan configured as a shared library. + +A. Edit the “tools/clang/scripts/update.sh” script and add "-DCOMPILER\_RT\_BUILD\_SHARED\_ASAN=ON" to all CMake command-lines (see [AddressSanitizerAsDso](https://github.com/google/sanitizers/wiki/AddressSanitizerAsDso) and [AddressSanitizerHowToBuild](https://github.com/google/sanitizers/wiki/AddressSanitizerHowToBuild) for more information). + +``` +diff --git tools/clang/scripts/update.sh tools/clang/scripts/update.sh +index 10a4645..bd7c5ab 100755 +--- tools/clang/scripts/update.sh ++++ tools/clang/scripts/update.sh +@@ -472,6 +472,7 @@ if [[ -n "${bootstrap}" ]]; then + pushd "${LLVM_BOOTSTRAP_DIR}" + + cmake -GNinja \ ++ -DCOMPILER_RT_BUILD_SHARED_ASAN=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DLLVM_TARGETS_TO_BUILD=host \ +@@ -567,6 +568,7 @@ add_subdirectory(\${CHROMIUM_TOOLS_SRC} \${CMAKE_CURRENT_BINARY_DIR}/a) + EOF + rm -fv CMakeCache.txt + MACOSX_DEPLOYMENT_TARGET=${deployment_target} cmake -GNinja \ ++ -DCOMPILER_RT_BUILD_SHARED_ASAN=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DLLVM_ENABLE_THREADS=OFF \ +@@ -612,6 +614,7 @@ pushd "${COMPILER_RT_BUILD_DIR}" + + rm -fv CMakeCache.txt + MACOSX_DEPLOYMENT_TARGET=${deployment_target} cmake -GNinja \ ++ -DCOMPILER_RT_BUILD_SHARED_ASAN=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DLLVM_ENABLE_THREADS=OFF \ +@@ -655,6 +658,7 @@ if [[ -n "${with_android}" ]]; then + pushd ${LLVM_BUILD_DIR}/android + rm -fv CMakeCache.txt + MACOSX_DEPLOYMENT_TARGET=${deployment_target} cmake -GNinja \ ++ -DCOMPILER_RT_BUILD_SHARED_ASAN=ON \ + -DCMAKE_BUILD_TYPE=Release \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DLLVM_ENABLE_THREADS=OFF \ +``` + +B. Run the “tools/clang/scripts/update.sh” script to create a local build of Clang. + +```sh +cd /path/to/chromium_git/chromium/src +./tools/clang/scripts/update.sh --force-local-build --without-android +``` + +This will create “libclang\_rt.asan-x86\_64.so” (assuming 64-bit Linux) in the “third\_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/linux” directory. + +2\. Copy “libclang\_rt.asan-x86\_64.so” to the “out/Release/lib” directory so that binaries built as part of the Chromium build can find it. + +3\. Add '-shared-libasan' or modify related exclusions everywhere that ‘-fsanitize=address’ is mentioned for Linux in “build/common.gypi”, “build/sanitizers/sanitizers.gyp”, “sandbox/linux/sandbox\_linux.gypi” and “third\_party/libvpx/libvpx.gyp” (see [AddressSanitizerAsDso](https://github.com/google/sanitizers/wiki/AddressSanitizerAsDso) for details). Also, specify '-mllvm -asan-globals=0' in “base/common.gypi” (see [here](https://github.com/google/sanitizers/issues/82#c18) for details). + +``` +diff --git build/common.gypi build/common.gypi +index 066b0b4..6756a25 100644 +--- build/common.gypi ++++ build/common.gypi +@@ -4292,16 +4292,18 @@ + ['_toolset=="target"', { + 'cflags': [ + '-fsanitize=address', ++ '-shared-libasan', + # TODO(earthdok): Re-enable. http://crbug.com/427202 + #'-fsanitize-blacklist=<(asan_blacklist)', + ], + 'ldflags': [ + '-fsanitize=address', ++ '-shared-libasan', + ], + }], + ], + 'conditions': [ +- ['OS=="mac"', { ++ ['OS=="mac" or OS=="linux"', { + 'cflags': [ + '-mllvm -asan-globals=0', # http://crbug.com/352073 + ], +@@ -4865,9 +4867,11 @@ + # binaries on x86_64 host is problematic. + # TODO(eugenis): re-enable. + '-fsanitize=address', ++ '-shared-libasan', + ], + 'ldflags!': [ + '-fsanitize=address', ++ '-shared-libasan', + '-Wl,-z,noexecstack', + '-Wl,--gc-sections', + '-Wl,-O1', +diff --git build/sanitizers/sanitizers.gyp build/sanitizers/sanitizers.gyp +index 4126d22..1e3ef49 100644 +--- build/sanitizers/sanitizers.gyp ++++ build/sanitizers/sanitizers.gyp +@@ -45,6 +45,7 @@ + 'cflags/': [ + ['exclude', '-fsanitize='], + ['exclude', '-fsanitize-'], ++ ['exclude', '-shared-libasan'], + ], + 'direct_dependent_settings': { + 'ldflags': [ +diff --git sandbox/linux/sandbox_linux.gypi sandbox/linux/sandbox_linux.gypi +index 4305b41..9ca48de 100644 +--- sandbox/linux/sandbox_linux.gypi ++++ sandbox/linux/sandbox_linux.gypi +@@ -213,9 +213,11 @@ + # Do not use any sanitizer tools with this binary. http://crbug.com/382766 + 'cflags/': [ + ['exclude', '-fsanitize'], ++ ['exclude', '-shared-libasan'], + ], + 'ldflags/': [ + ['exclude', '-fsanitize'], ++ ['exclude', '-shared-libasan'], + ], + }, + { 'target_name': 'sandbox_services', +``` + +4\. Build CEF with ASan (see the "Building CEF with ASan" section above). + +5\. Copy “libcef.so”, “libc++.so” and “libclang\_rt.asan-x86\_64.so” from the “out/Release/lib” directory to the third-party project’s binary directory (e.g. “out/Debug” for JCEF). + +6\. Run the third-party executable pre-loading “libclang\_rt.asan-x86\_64.so” and piping output to the ASan post-processing script so that stack traces will be symbolized. For example, using JCEF’s [run.sh script](https://github.com/chromiumembedded/java-cef/blob/master/tools/run.sh): + +``` +LD_PRELOAD=$LIB_PATH/libclang_rt.asan-x86_64.so java -cp "$CLS_PATH" -Djava.library.path=$LIB_PATH tests.$RUN_TYPE.MainFrame "$@" 2>&1 | /path/to/chromium_git/chromium/src/tools/valgrind/asan/asan_symbolize.py +``` \ No newline at end of file diff --git a/docs/using_chrome_driver.md b/docs/using_chrome_driver.md new file mode 100644 index 000000000..6cc785ab3 --- /dev/null +++ b/docs/using_chrome_driver.md @@ -0,0 +1,104 @@ +This page explains how to use ChromeDriver and Selenium to automate CEF-based applications. + + +*** + +**Contents** + +- [Overview](#overview) +- [Java Tutorial](#java-tutorial) + +--- + +# Overview + +ChromeDriver and Selenium are tools for automated testing of Chromium-based applications. The tests themselves can be written in a number of languages including Java, JavaScript and Python. ChromeDriver communicates with the Chromium-based application using the DevTools remote debugging protocol (configured via the `--remote-debugging-port=XXXX` command-line flag passed to the application). Detailed ChromeDriver/Selenium usage information is available here: + + * https://sites.google.com/a/chromium.org/chromedriver/getting-started + * https://code.google.com/p/selenium/wiki/GettingStarted + +# Java Tutorial + +This tutorial demonstrates how to control the cefclient sample application using the Java programming language on Windows. Usage on other platforms and with other CEF-based applications is substantially similar. + +1\. Install the Java JDK and add its bin directory to your system PATH variable. + +2\. Create a directory that will contain all files. This tutorial uses `c:\temp`. + +3\. Download ChromeDriver from https://sites.google.com/a/chromium.org/chromedriver/downloads and extract (e.g. `chromedriver_win32.zip` provides `chomedriver.exe`). This tutorial was tested with version 2.14. + +4\. Download `selenium-server-standalone-x.y.z.jar` from http://selenium-release.storage.googleapis.com/index.html. This tutorial was tested with version 2.44.0. + +5\. Download a CEF binary distribution client from [Downloads](http://magpcss.net/cef_downloads/) and extract (e.g. `cef_binary_3.2171.1979_windows32_client.7z`). + +6\. Create `Example.java`: + +```cpp +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.chrome.ChromeDriver; +import org.openqa.selenium.chrome.ChromeOptions; + +public class Example { + public static void main(String[] args) { + // Path to the ChromeDriver executable. + System.setProperty("webdriver.chrome.driver", "c:/temp/chromedriver.exe"); + + ChromeOptions options = new ChromeOptions(); + // Path to the CEF executable. + options.setBinary("c:/temp/cef_binary_3.2171.1979_windows32_client/Release/cefclient.exe"); + // Port to communicate on. Required starting with ChromeDriver v2.41. + options.addArguments("remote-debugging-port=12345"); + + WebDriver driver = new ChromeDriver(options); + driver.get("http://www.google.com/xhtml"); + sleep(3000); // Let the user actually see something! + WebElement searchBox = driver.findElement(By.name("q")); + searchBox.sendKeys("ChromeDriver"); + searchBox.submit(); + sleep(3000); // Let the user actually see something! + driver.quit(); + } + + static void sleep(int time) { + try { Thread.sleep(time); } catch (InterruptedException e) {} + } +} +``` + +Your directory structure should now look similar to this: +```cpp +c:\temp\ + cef_binary_3.2171.1979_windows32_client\ + Release\ + cefclient.exe (and other files) + chromedriver.exe + Example.java + selenium-server-standalone-2.44.0.jar +``` + +7\. Compile `Example.java` to generate `Example.class`: + +``` +> cd c:\temp +> javac -cp ".;*" Example.java +``` + +8\. Run the example: + +``` +> cd c:\temp +> java -cp ".;*" Example +``` + +When the example is run ChromeDriver will: + + * Output to the console: +``` +Starting ChromeDriver 2.14.313457 (3d645c400edf2e2c500566c9aa096063e707c9cf) on port 28110 +Only local connections are allowed. +``` + * Launch `cefclient.exe`. + * Submit a Google search for "ChromeDriver". + * Close `cefclient.exe`. \ No newline at end of file diff --git a/docs/using_the_capi.md b/docs/using_the_capi.md new file mode 100644 index 000000000..b24d854da --- /dev/null +++ b/docs/using_the_capi.md @@ -0,0 +1,1742 @@ +This page provides information on how to use the CEF C API in a client application. + +**Contents** + +- [Introduction](#introduction) +- [Base Structure Types](#base-structure-types) + - [Reference-Counted Structures (`cef_base_ref_counted_t`)](#reference-counted-structures-cef_base_ref_counted_t) + - [Scoped Structures (`cef_base_scoped_t`)](#scoped-structures-cef_base_scoped_t) +- [Structure Allocation and Ownership](#structure-allocation-and-ownership) + - [Client-Side Structures (`source=client` in comments)](#client-side-structures-sourceclient-in-comments) + - [Library-Side Structures (`source=library` in comments)](#library-side-structures-sourcelibrary-in-comments) +- [Usage Pattern](#usage-pattern) + - [C++ Example (for comparison)](#c-example-for-comparison) + - [C API Equivalent](#c-api-equivalent) +- [Complete Minimal Example](#complete-minimal-example) + - [CefApp Creation](#cefapp-creation) + - [CefClient Creation](#cefclient-creation) + - [CefBrowser Creation](#cefbrowser-creation) + - [API Version Initialization](#api-version-initialization) + - [Putting It All Together](#putting-it-all-together) +- [Thread Checking and Task Posting](#thread-checking-and-task-posting) + - [Checking Current Thread](#checking-current-thread) + - [Posting Tasks to UI Thread](#posting-tasks-to-ui-thread) + - [Common Thread IDs](#common-thread-ids) + - [Thread Safety Notes](#thread-safety-notes) +- [Working with Strings](#working-with-strings) + - [String Type](#string-type) + - [Creating Strings](#creating-strings) + - [String Return Values](#string-return-values) + - [Const String Parameters](#const-string-parameters) + - [String Lists](#string-lists) + - [String Maps](#string-maps) + - [String Multimaps](#string-multimaps) +- [Reference Counting](#reference-counting) + - [Understanding Reference Counting: C++ vs C API Background](#understanding-reference-counting-c-vs-c-api-background) + - [How CefRefPtr Works (C++ API)](#how-cefrefptr-works-c-api) + - [What This Means for C API Users](#what-this-means-for-c-api-users) + - [Core Principles](#core-principles) + - [Reference Counting Rules with Examples](#reference-counting-rules-with-examples) + - [Rule 1: No ref-count change when calling own methods](#rule-1-no-ref-count-change-when-calling-own-methods) + - [Rule 2: Add reference before passing objects as non-self parameters](#rule-2-add-reference-before-passing-objects-as-non-self-parameters) + - [Rule 3: Add reference when returning objects to CEF](#rule-3-add-reference-when-returning-objects-to-cef) + - [Rule 4: Release parameters when done](#rule-4-release-parameters-when-done) + - [Rule 5: Keep long-term references](#rule-5-keep-long-term-references) + - [Rule 6: Use atomic operations](#rule-6-use-atomic-operations) + - [Rule 7: Delete when reference count reaches zero](#rule-7-delete-when-reference-count-reaches-zero) + - [Rule 8: Release at the end of handler lifetime](#rule-8-release-at-the-end-of-handler-lifetime) + - [Rule 9: Debugging reference counting](#rule-9-debugging-reference-counting) +- [Critical Implementation Notes](#critical-implementation-notes) + - [Structure Member Ordering](#structure-member-ordering) + - [Size Field Initialization](#size-field-initialization) + - [Thread Safety Requirements](#thread-safety-requirements) + - [Handler Return Values](#handler-return-values) + - [NULL Pointer Checks](#null-pointer-checks) +- [Atomic Operations for Reference Counting](#atomic-operations-for-reference-counting) + - [C11 Atomics (Recommended)](#c11-atomics-recommended) + - [Windows API (Older MSVC Versions)](#windows-api-older-msvc-versions) + - [GCC/Clang Built-ins (Legacy POSIX)](#gccclang-built-ins-legacy-posix) + - [OSAtomic (Legacy macOS)](#osatomic-legacy-macos) +- [Common Implementation Patterns](#common-implementation-patterns) + - [NULL Handler Pattern](#null-handler-pattern) + - [Safe Casting Pattern](#safe-casting-pattern) + - [Extracting Data Before Release](#extracting-data-before-release) + - [Storing User Data Pattern](#storing-user-data-pattern) + - [Callback Context Pattern](#callback-context-pattern) + - [Optional Handler Fields Pattern](#optional-handler-fields-pattern) + +--- + +# Introduction + +The CEF C API is a C-based interface exported by the CEF library/framework following certain [API versioning guidelines](api_versioning.md). The C header files which define this interface are automatically generated by the CEF [translator tool](https://github.com/chromiumembedded/cef/blob/master/tools/translator.README.txt) and mirror the CEF C++ API structure. + +**Example application:** [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/) - A minimal CEF browser application written in pure C, demonstrating proper C API usage including reference counting, handler callbacks, and cross-platform implementation. + +# Base Structure Types + +All CEF C API structures inherit from one of two base structure types, which determine how their memory and lifetime are managed. + +## Reference-Counted Structures (`cef_base_ref_counted_t`) + +Most CEF structures inherit from `cef_base_ref_counted_t` and require manual reference counting. These structures have a longer lifetime and may be shared across multiple owners. + +**Required function pointers:** + +- `add_ref` - Increment the reference count +- `release` - Decrement the reference count and free when it reaches zero +- `has_one_ref` - Check if reference count is exactly 1 +- `has_at_least_one_ref` - Check if reference count is at least 1 + +**Common examples:** + +- `cef_app_t` - Application handler +- `cef_client_t` - Client handler +- `cef_browser_t` - Browser instance +- `cef_frame_t` - Frame instance +- `cef_request_t` - Request object +- All handler interfaces (life span, request, display, etc.) + +## Scoped Structures (`cef_base_scoped_t`) + +Some structures inherit from `cef_base_scoped_t` for stack-based or temporary objects with simpler lifetime management. + +**Required function pointers:** + +- `del` - Destructor function (may be NULL if the object is not owned by you) + +**Common examples:** + +- `cef_window_info_t` - Window configuration +- `cef_browser_settings_t` - Browser settings +- `cef_settings_t` - CEF initialization settings + +These structures are typically used for configuration and are not ref-counted. + +# Structure Allocation and Ownership + +Understanding who allocates and owns each structure type is critical for correct CEF C API usage. + +## Client-Side Structures (`source=client` in comments) + +**You allocate, implement, and manage these structures.** They are typically handler interfaces that you implement to receive callbacks from CEF. + +**Examples:** + +- `cef_app_t` - Your application implementation +- `cef_client_t` - Your client handler +- `cef_life_span_handler_t` - Browser lifecycle events +- `cef_request_handler_t` - Request handling +- `cef_display_handler_t` - Display updates +- All other handler interfaces + +**Your responsibilities:** + +- Allocate the structure (usually with `calloc`) +- Set the `size` field +- Implement all required function pointers +- Implement reference counting (for ref-counted types) +- Free the structure when reference count reaches zero + +## Library-Side Structures (`source=library` in comments) + +**CEF allocates, implements, and manages these structures.** They are objects that CEF provides to you for reading data or calling methods. + +**Examples:** + +- `cef_browser_t` - Browser instance provided by CEF +- `cef_frame_t` - Frame instance provided by CEF +- `cef_request_t` - Request data provided by CEF +- `cef_response_t` - Response data provided by CEF +- Most data objects + +**Your responsibilities:** + +- Use the provided pointer to call methods +- Call `add_ref` if you need to keep the pointer beyond the current function +- Call `release` when you're done with a reference +- Never allocate or free these structures yourself + +# Usage Pattern + +In general, the C API is used similarly to the C++ API, but instead of defining new classes and overriding methods, you create structures and set fields to custom function pointers. + +## C++ Example (for comparison) + +```cpp +// A new class is defined and specific handlers are overridden +class SimpleApp: public CefApp, public CefBrowserProcessHandler { + public: + SimpleApp() {} + + CefRefPtr GetBrowserProcessHandler() override { + return this; + } + + void OnContextInitialized() override; + CefRefPtr GetDefaultClient() override; + + private: + // A default RC implementation can be used + IMPLEMENT_REFCOUNTING(SimpleApp); +} +``` + +## C API Equivalent + +```c +// Define a structure with the CEF type as the first member +typedef struct _my_app_t { + cef_app_t app; // MUST be first member + atomic_int ref_count; // Custom fields (reference count, state, etc.) +} my_app_t; + +// Implement reference counting functions +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + /* ... */ +} +int CEF_CALLBACK app_release(cef_base_ref_counted_t* self) { + /* ... */ +} +int CEF_CALLBACK app_has_one_ref(cef_base_ref_counted_t* self) { + /* ... */ +} +int CEF_CALLBACK app_has_at_least_one_ref(cef_base_ref_counted_t* self) { + /* ... */ +} + +// Implement handler methods as function pointers +cef_browser_process_handler_t* CEF_CALLBACK +get_browser_process_handler(cef_app_t* self) { + // Return your browser process handler implementation + return my_browser_process_handler; +} + +// Create and initialize the structure +my_app_t* create_my_app() { + my_app_t* app = (my_app_t*)calloc(1, sizeof(my_app_t)); + + // Set size and function pointers + app->app.base.size = sizeof(cef_app_t); + app->app.base.add_ref = app_add_ref; + app->app.base.release = app_release; + app->app.base.has_one_ref = app_has_one_ref; + app->app.base.has_at_least_one_ref = app_has_at_least_one_ref; + app->app.get_browser_process_handler = get_browser_process_handler; + + atomic_store(&app->ref_count, 1); + return app; +} +``` + +**Key differences from C++:** + +- **Structures instead of classes**: Use `typedef struct` to define types (see "Base Structure Types") +- **Function pointers instead of virtual methods**: Assign function pointers to structure fields +- **Manual reference counting**: Implement `add_ref`, `release`, `has_one_ref`, `has_at_least_one_ref` (see "Reference Counting" and "Atomic Operations for Reference Counting") +- **Manual memory management**: Use `calloc` to allocate, `free` in the release function (see "Structure Allocation and Ownership") + +See the "Complete Minimal Example" section for full working code. + +# Complete Minimal Example + +This section shows a complete CEF usage example using only the C API. This is a working starting point you can build upon. + +**For a complete working example**, see [cefsimple_capi](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/), which demonstrates all concepts from this guide in a buildable application. + +## CefApp Creation + +The `cef_app_t` structure is optional (you can pass NULL to `cef_initialize()`), but implementing it allows you to: + +- Provide handlers for browser process events (via `get_browser_process_handler`) +- Provide handlers for render process events (via `get_render_process_handler`) +- Customize command-line arguments (via `on_before_command_line_processing`) +- Register custom schemes (via `on_register_custom_schemes`) + +This example shows a minimal implementation with just reference counting. + +```c +#include +#include + +#include "include/capi/cef_app_capi.h" + +// Custom app structure +typedef struct _my_app_t { + cef_app_t app; // MUST be first member + atomic_int ref_count; // Reference counter +} my_app_t; + +// App handler - returns NULL for this simple example +cef_browser_process_handler_t* CEF_CALLBACK +app_get_browser_process_handler(cef_app_t* self) { + return NULL; // No browser process handler needed +} + +// Create app instance +my_app_t* create_app() { + // calloc zero-initializes all memory, so all fields start as 0/NULL + my_app_t* app = (my_app_t*)calloc(1, sizeof(my_app_t)); + + // Initialize base structure - CRITICAL: set size correctly + app->app.base.size = sizeof(cef_app_t); + + // Reference counting + // Implement app_add_ref, app_release, app_has_one_ref, + // app_has_at_least_one_ref following the pattern from + // "Atomic Operations for Reference Counting" + app->app.base.add_ref = app_add_ref; + app->app.base.release = app_release; + app->app.base.has_one_ref = app_has_one_ref; + app->app.base.has_at_least_one_ref = app_has_at_least_one_ref; + + // Only set the handlers we need (others already NULL from calloc) + app->app.get_browser_process_handler = app_get_browser_process_handler; + + // Start with ref count of 1 + atomic_store(&app->ref_count, 1); + + return app; +} +``` + +## CefClient Creation + +The `cef_client_t` structure provides handlers for browser events and is required to create a browser. This example shows a minimal implementation that returns NULL for all handlers (using default behavior). + +```c +#include +#include + +#include "include/capi/cef_client_capi.h" + +// Custom client structure +typedef struct _my_client_t { + cef_client_t client; // MUST be first member + atomic_int ref_count; // Reference counter +} my_client_t; + +// Create client instance +my_client_t* create_client() { + // calloc zero-initializes all memory, so all fields start as 0/NULL + my_client_t* client = (my_client_t*)calloc(1, sizeof(my_client_t)); + + // Initialize base structure + client->client.base.size = sizeof(cef_client_t); + + // Reference counting + // Implement client_add_ref, client_release, client_has_one_ref, + // client_has_at_least_one_ref following the pattern from + // "Atomic Operations for Reference Counting" + client->client.base.add_ref = client_add_ref; + client->client.base.release = client_release; + client->client.base.has_one_ref = client_has_one_ref; + client->client.base.has_at_least_one_ref = client_has_at_least_one_ref; + + // All handler getters are NULL from calloc, using default behavior + // Set client->client.get_life_span_handler, etc. if you need custom handlers + + // Start with ref count of 1 + atomic_store(&client->ref_count, 1); + + return client; +} +``` + +## CefBrowser Creation + +After initializing CEF, create a browser window using `cef_browser_host_create_browser()`. Pass the client instance from the previous section. + +```c +#ifdef _WIN32 +#include +#endif + +#include "include/capi/cef_browser_capi.h" + +void create_browser(cef_client_t* client) { + cef_window_info_t window_info = {}; + window_info.size = sizeof(cef_window_info_t); + + // Create as a top-level window (with NULL parent) +#ifdef _WIN32 + // Windows: CefWindowInfo::SetAsPopup equivalent + window_info.style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | + WS_CLIPSIBLINGS | WS_VISIBLE; + window_info.bounds.x = CW_USEDEFAULT; + window_info.bounds.y = CW_USEDEFAULT; + window_info.bounds.width = CW_USEDEFAULT; + window_info.bounds.height = CW_USEDEFAULT; +#else + // Linux/macOS: CefWindowInfo::SetAsChild equivalent + window_info.bounds.width = 800; + window_info.bounds.height = 600; +#endif + + cef_browser_settings_t browser_settings = {}; + browser_settings.size = sizeof(cef_browser_settings_t); + + cef_string_t url = {}; + cef_string_from_ascii("https://www.google.com", 22, &url); + + // Create browser asynchronously (recommended) + // The browser is created on the UI thread + // Your client's life span handler on_after_created will be called when ready + // IMPORTANT: We transfer our client reference to CEF - don't release it! + // CEF takes ownership and will release it when the browser closes. + cef_browser_host_create_browser( + &window_info, + client, + &url, + &browser_settings, + NULL, // extra_info + NULL // request_context + ); + + cef_string_clear(&url); + // Note: We DON'T release the client here - we transferred ownership to CEF +} +``` + +## API Version Initialization + +**CRITICAL:** Before calling any other CEF API functions, you must initialize the API version by calling `cef_api_hash()`. This function configures the CEF API version for your application. + +```c +#include "include/cef_api_hash.h" + +// Configure the CEF API version. This must be called before any other CEF +// API functions. +cef_api_hash(CEF_API_VERSION, 0); +``` + +**When to call:** + +- **macOS**: Immediately after `cef_load_library()` in both the main process and helper processes +- **Windows/Linux**: At the start of `main()` before any other CEF calls + +**Important:** On macOS, CEF uses dynamic library loading via `cef_load_library()`. The API hash initialization MUST occur after the library is loaded, otherwise CEF functions will not be available. See [cefsimple_capi/cefsimple_mac.m](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/cefsimple_mac.m) for the correct macOS implementation pattern. + +**Why this is required:** + +- CEF uses API versioning to maintain backward/forward compatibility +- The first call to `cef_api_hash()` locks in the API version for the entire process +- Calling other CEF functions before `cef_api_hash()` will result in undefined behavior + +For details on how CEF API versioning works, see [API Versioning](api_versioning.md). + +## Putting It All Together + +This example brings together all the pieces from the previous sections, showing a complete working application with browser process handler and browser creation. + +```c +#include +#include +#ifdef _WIN32 +#include +#endif + +#include "include/capi/cef_app_capi.h" +#include "include/capi/cef_browser_process_handler_capi.h" +#include "include/capi/cef_client_capi.h" +#include "include/capi/cef_browser_capi.h" +#include "include/cef_api_hash.h" + +// Browser process handler structure +typedef struct _my_browser_process_handler_t { + cef_browser_process_handler_t handler; + atomic_int ref_count; +} my_browser_process_handler_t; + +// Called after CEF initialization to create the browser +void CEF_CALLBACK on_context_initialized(cef_browser_process_handler_t* self) { + // Create client using the function from "CefClient Creation" section + my_client_t* client = create_client(); + + // Create browser using the function from "CefBrowser Creation" section + // We transfer our reference to CEF (don't release) + create_browser(&client->client); +} + +// Create browser process handler +my_browser_process_handler_t* create_browser_process_handler() { + my_browser_process_handler_t* handler = + (my_browser_process_handler_t*)calloc( + 1, sizeof(my_browser_process_handler_t)); + + handler->handler.base.size = sizeof(cef_browser_process_handler_t); + + // Reference counting + // Implement bph_add_ref, bph_release, bph_has_one_ref, + // bph_has_at_least_one_ref following the pattern from + // "Atomic Operations for Reference Counting" + handler->handler.base.add_ref = bph_add_ref; + handler->handler.base.release = bph_release; + handler->handler.base.has_one_ref = bph_has_one_ref; + handler->handler.base.has_at_least_one_ref = bph_has_at_least_one_ref; + + // Set the callback that will create the browser + handler->handler.on_context_initialized = on_context_initialized; + + atomic_store(&handler->ref_count, 1); + return handler; +} + +// Updated app structure that holds the browser process handler +typedef struct _my_app_complete_t { + cef_app_t app; + atomic_int ref_count; + my_browser_process_handler_t* browser_process_handler; +} my_app_complete_t; + +// Updated app release to clean up browser process handler +int CEF_CALLBACK app_complete_release(cef_base_ref_counted_t* self) { + my_app_complete_t* app = (my_app_complete_t*)self; + int count = atomic_fetch_sub(&app->ref_count, 1) - 1; + if (count == 0) { + if (app->browser_process_handler) { + app->browser_process_handler->handler.base.release( + &app->browser_process_handler->handler.base); + } + free(app); + return 1; + } + return 0; +} + +// Return browser process handler (adds reference before returning) +cef_browser_process_handler_t* CEF_CALLBACK +app_complete_get_browser_process_handler(cef_app_t* self) { + my_app_complete_t* app = (my_app_complete_t*)self; + if (app->browser_process_handler) { + app->browser_process_handler->handler.base.add_ref( + &app->browser_process_handler->handler.base); + return &app->browser_process_handler->handler; + } + return NULL; +} + +// Create complete app with browser process handler +my_app_complete_t* create_app_complete() { + my_app_complete_t* app = + (my_app_complete_t*)calloc(1, sizeof(my_app_complete_t)); + + app->app.base.size = sizeof(cef_app_t); + + // Reference counting + // Implement app_add_ref, app_has_one_ref, app_has_at_least_one_ref + // following the pattern from "Atomic Operations for Reference Counting". + // app_complete_release is custom to clean up the browser process handler. + app->app.base.add_ref = app_add_ref; + app->app.base.release = app_complete_release; + app->app.base.has_one_ref = app_has_one_ref; + app->app.base.has_at_least_one_ref = app_has_at_least_one_ref; + + app->app.get_browser_process_handler = + app_complete_get_browser_process_handler; + + // Create and store browser process handler + app->browser_process_handler = create_browser_process_handler(); + + atomic_store(&app->ref_count, 1); + return app; +} + +// Complete main() function (Windows/Linux pattern) +// NOTE: On macOS, you must call cef_load_library() first, then cef_api_hash(). +// See cefsimple_capi/cefsimple_mac.m for the macOS implementation. +int main(int argc, char* argv[]) { + // Configure the CEF API version. This must be called before any other CEF + // API functions. + cef_api_hash(CEF_API_VERSION, 0); + + cef_main_args_t main_args = {}; +#ifdef _WIN32 + main_args.instance = GetModuleHandle(NULL); +#else + main_args.argc = argc; + main_args.argv = argv; +#endif + + // Create app with browser process handler (with 1 reference) + my_app_complete_t* app = create_app_complete(); + + // Add a reference before cef_execute_process. Both cef_execute_process and + // cef_initialize will take ownership of a reference, so we need 2 total. + app->app.base.add_ref(&app->app.base); + + // Execute sub-processes if needed + int exit_code = cef_execute_process(&main_args, &app->app, NULL); + if (exit_code >= 0) { + // The sub-process has completed so return here. + // cef_execute_process took ownership of one reference. + // Release only the additional reference we added. + app->app.base.release(&app->app.base); + return exit_code; + } + + // Initialize CEF for the browser process + cef_settings_t settings = {}; + settings.size = sizeof(cef_settings_t); + settings.no_sandbox = 1; + + if (!cef_initialize(&main_args, &settings, &app->app, NULL)) { + // cef_initialize took ownership of the remaining app reference so we don't + // need to release any. + return cef_get_exit_code(); + } + + // Run the CEF message loop + // on_context_initialized will be called, which creates the browser + cef_run_message_loop(); + + // Shutdown CEF + cef_shutdown(); + + // Note: We DON'T release the app here. The 2 total references have been + // given to cef_execute_process and cef_initialize. If cef_initialize + // succeeded the final reference will be released during cef_shutdown. + + return 0; +} +``` + +This complete example demonstrates: + +- **Browser process handler**: Implements `on_context_initialized` callback where the browser is created +- **Integration**: Uses `create_client()` and `create_browser()` from previous sections +- **Reference counting**: Properly manages references for app, browser process handler, and client +- **Complete workflow**: Shows the full lifecycle from initialization through browser creation to shutdown + +# Thread Checking and Task Posting + +CEF uses multiple threads internally. Many APIs must be called on specific threads, particularly the UI thread (TID_UI). Always verify you're on the correct thread before calling CEF APIs. + +## Checking Current Thread + +Use `cef_currently_on()` to check if you're on a specific thread: + +```c +#include "include/capi/cef_task_capi.h" + +void some_function() { + // Check if we're on the UI thread + if (cef_currently_on(TID_UI)) { + // Safe to call UI thread APIs here + // ... + } else { + // Not on UI thread - need to post a task + } +} +``` + +## Posting Tasks to UI Thread + +If you need to call a UI thread API from another thread, post a task to the UI thread: + +```c +#include +#include +#include + +#include "include/capi/cef_task_capi.h" + +// Custom task structure +typedef struct _my_task_t { + cef_task_t task; // MUST be first + atomic_int ref_count; + + // Task-specific data + cef_browser_t* browser; // Example: browser to navigate + cef_string_t url; // Example: URL to navigate to +} my_task_t; + +// Custom task release that cleans up task resources +int CEF_CALLBACK task_release(cef_base_ref_counted_t* self) { + my_task_t* task = (my_task_t*)self; + int count = atomic_fetch_sub(&task->ref_count, 1) - 1; + if (count == 0) { + // Clean up task resources + if (task->browser) { + task->browser->base.release(&task->browser->base); + } + cef_string_clear(&task->url); + free(task); + return 1; + } + return 0; +} + +// Task execution - called on the UI thread +void CEF_CALLBACK task_execute(cef_task_t* self) { + my_task_t* task = (my_task_t*)self; + + // This executes on the UI thread + // Safe to call UI thread APIs here + cef_frame_t* frame = task->browser->get_main_frame(task->browser); + if (frame) { + frame->load_url(frame, &task->url); + frame->base.release(&frame->base); + } +} + +// Create and post task +void navigate_from_any_thread(cef_browser_t* browser, const char* url_str) { + // Create task + my_task_t* task = (my_task_t*)calloc(1, sizeof(my_task_t)); + + // Initialize base structure + task->task.base.size = sizeof(cef_task_t); + + // Reference counting + // Implement task_add_ref, task_has_one_ref, task_has_at_least_one_ref + // following the pattern from "Atomic Operations for Reference Counting". + // task_release is shown above with custom cleanup logic. + task->task.base.add_ref = task_add_ref; + task->task.base.release = task_release; + task->task.base.has_one_ref = task_has_one_ref; + task->task.base.has_at_least_one_ref = task_has_at_least_one_ref; + + // Set execute callback + task->task.execute = task_execute; + + // Store task data (keep browser reference, copy URL) + task->browser = browser; + browser->base.add_ref(&browser->base); + cef_string_from_ascii(url_str, strlen(url_str), &task->url); + + // Initialize ref count + atomic_store(&task->ref_count, 1); + + // Post to UI thread + // cef_post_task takes ownership of the reference + cef_post_task(TID_UI, &task->task); +} +``` + +## Common Thread IDs + +- **TID_UI** - Main UI thread (most APIs require this thread) +- **TID_IO** - IO thread for network operations +- **TID_FILE_USER_BLOCKING** - File operations affecting immediate UI +- **TID_FILE_USER_VISIBLE** - File operations for future UI updates +- **TID_RENDERER** - Renderer thread (render process only) + +## Thread Safety Notes + +- Reference counting functions (`add_ref`, `release`) can be called from ANY thread +- Some CEF APIs require the a specific thread (check documentation) +- Handler callbacks are usually invoked on the UI thread (check documentation) +- `cef_initialize()` and `cef_run_message_loop()` must be called on the main application thread + +# Working with Strings + +CEF uses UTF-16 strings by default. Understanding string handling is essential for C API usage. + +## String Type + +The default string type is UTF-16 (`cef_string_t` is aliased to `cef_string_utf16_t`): + +```c +typedef struct _cef_string_utf16_t { + char16_t* str; // Pointer to UTF-16 string data + size_t length; // Number of char16_t elements in the array (not bytes) + void (*dtor)(char16_t* str); // Destructor function (can be NULL) +} cef_string_utf16_t; + +typedef cef_string_utf16_t cef_string_t; +``` + +## Creating Strings + +To create a string from ASCII or UTF-8: + +```c +cef_string_t my_string = {}; +cef_string_from_ascii("Hello World", 11, &my_string); + +// Use the string... + +// Remember to free when done +cef_string_clear(&my_string); +``` + +For UTF-8 input: + +```c +cef_string_t my_string = {}; +const char* utf8_text = "Hello 世界"; +// strlen() returns byte count, not character count, which is correct here +// because cef_string_from_utf8() expects the UTF-8 byte length +cef_string_from_utf8(utf8_text, strlen(utf8_text), &my_string); + +// Use the string... + +cef_string_clear(&my_string); +``` + +## String Return Values + +Functions that return `cef_string_userfree_t` transfer ownership to you. You must free these strings: + +```c +// Get the URL from a frame (transfers ownership) +cef_string_userfree_t url = frame->get_url(frame); + +// Use the string... +// (url->str, url->length) + +// Free it when done - REQUIRED +cef_string_userfree_free(url); +``` + +## Const String Parameters + +When passing strings to CEF functions, you typically pass a pointer to `cef_string_t`: + +```c +void navigate_to_url(cef_browser_t* browser, const char* url_str) { + cef_string_t url = {}; + cef_string_from_ascii(url_str, strlen(url_str), &url); + + cef_frame_t* frame = browser->get_main_frame(browser); + frame->load_url(frame, &url); + + // Release the frame (get_main_frame returns a new reference) + frame->base.release(&frame->base); + + cef_string_clear(&url); +} +``` + +## String Lists + +String lists are used for arrays of strings (like command-line arguments): + +```c +// Create a string list +cef_string_list_t list = cef_string_list_alloc(); + +// Add items +cef_string_t item = {}; +cef_string_from_ascii("item1", 5, &item); +cef_string_list_append(list, &item); +cef_string_clear(&item); + +cef_string_from_ascii("item2", 5, &item); +cef_string_list_append(list, &item); +cef_string_clear(&item); + +// Get the size +size_t count = cef_string_list_size(list); + +// Retrieve items +cef_string_t retrieved = {}; +cef_string_list_value(list, 0, &retrieved); +// Use retrieved.str and retrieved.length +cef_string_clear(&retrieved); + +// Free the list when done +cef_string_list_free(list); +``` + +## String Maps + +String maps store key-value pairs: + +```c +// Create a string map +cef_string_map_t map = cef_string_map_alloc(); + +// Add key-value pairs +cef_string_t key = {}, value = {}; +cef_string_from_ascii("User-Agent", 10, &key); +cef_string_from_ascii("MyBrowser/1.0", 13, &value); +cef_string_map_append(map, &key, &value); +cef_string_clear(&key); +cef_string_clear(&value); + +// Get the size +size_t count = cef_string_map_size(map); + +// Retrieve values by key +cef_string_from_ascii("User-Agent", 10, &key); +cef_string_map_find(map, &key, &value); +// Use value.str and value.length +cef_string_clear(&key); +cef_string_clear(&value); + +// Free the map when done +cef_string_map_free(map); +``` + +## String Multimaps + +String multimaps allow multiple values per key (useful for HTTP headers): + +```c +// Create a string multimap +cef_string_multimap_t map = cef_string_multimap_alloc(); + +// Add multiple values for the same key +cef_string_t key = {}, value = {}; +cef_string_from_ascii("Set-Cookie", 10, &key); + +cef_string_from_ascii("cookie1=value1", 14, &value); +cef_string_multimap_append(map, &key, &value); +cef_string_clear(&value); + +cef_string_from_ascii("cookie2=value2", 14, &value); +cef_string_multimap_append(map, &key, &value); +cef_string_clear(&value); +cef_string_clear(&key); + +// Enumerate all values for a key +cef_string_from_ascii("Set-Cookie", 10, &key); +size_t count = cef_string_multimap_find_count(map, &key); +for (size_t i = 0; i < count; ++i) { + cef_string_multimap_enumerate(map, &key, i, &value); + // Use value.str and value.length + cef_string_clear(&value); +} +cef_string_clear(&key); + +// Free the multimap when done +cef_string_multimap_free(map); +``` + +# Reference Counting + +Understanding reference counting is the most challenging part of working with the CEF C API. The reference counting concept used by CEF is similar to COM (Component Object Model). + +Unlike the C++ API, which provides automatic reference counting through `CefRefPtr` and the `IMPLEMENT_REFCOUNTING` macro, the C API requires manual reference counting. You must implement the reference counting logic yourself, typically using atomic operations to store the reference count. + +## Understanding Reference Counting: C++ vs C API Background + +To understand why the C API reference counting rules exist, it helps to understand how the C++ API handles this automatically through the `CefRefPtr` smart pointer template class. + +### How CefRefPtr Works (C++ API) + +`CefRefPtr` is a smart pointer that automatically manages reference counts: + +- **On construction/assignment**: Automatically calls `AddRef()` on the object +- **On destruction (going out of scope)**: Automatically calls `Release()` on the object +- **When stored in member variables**: Holds a reference for the object's lifetime + +**Example of automatic behavior in C++:** + +```cpp +void UseFrameInCpp(CefRefPtr browser) { + // browser parameter: CefRefPtr automatically added a reference when called + + CefRefPtr frame = browser->GetMainFrame(); + // frame: GetMainFrame() returned a CefRefPtr with a reference + + frame->LoadURL("https://example.com"); + + // Exiting function: + // - frame goes out of scope → CefRefPtr automatically calls Release() + // - browser goes out of scope → CefRefPtr automatically calls Release() + // No manual memory management needed! +} +``` + +### What This Means for C API Users + +In the C API, you must perform ALL the operations that `CefRefPtr` does automatically. The reference counting rules in the following sections directly correspond to `CefRefPtr` behavior: + +- **Rule 2** (add_ref before passing parameters): Mirrors `CefRefPtr` adding a ref when you pass it +- **Rule 3** (add_ref when returning objects): Mirrors `CefRefPtr` transferring a reference +- **Rule 4** (release parameters when done): Mirrors `CefRefPtr` releasing when it goes out of scope +- **Rule 5** (keep long-term references): Mirrors storing a `CefRefPtr` as a member variable + +**Same example in C API (manual version):** + +```c +void use_frame_in_c(cef_browser_t* browser) { + // browser parameter: CEF already added a reference before calling us + + cef_frame_t* frame = browser->get_main_frame(browser); + // frame: get_main_frame() returns a pointer with a reference + + cef_string_t url = {}; + cef_string_from_ascii("https://example.com", 19, &url); + frame->load_url(frame, &url); + cef_string_clear(&url); + + // Exiting function - MUST manually release: + frame->base.release(&frame->base); // Manual (CefRefPtr does automatically) + browser->base.release(&browser->base); // Manual (CefRefPtr does automatically) +} +``` + +Understanding that you're manually implementing what `CefRefPtr` does automatically makes the rules easier to remember and apply correctly. + +## Core Principles + +**Memory management rule:** An object is deleted when its reference count reaches zero. + +**Threading rule:** Reference counting functions may be called from any thread, so atomic operations are required. + +**Ownership rule:** Each reference represents one owner. When you're done with an object, release your reference. + +**Critical callback rule:** When CEF calls your callback with object parameters (browser, frame, request, etc.), you MUST call `release()` on each object parameter (other than `self`) before returning. CEF has already added a reference for each parameter, and it expects you to release it. Failing to do so will cause memory leaks. + +## Reference Counting Rules with Examples + +### Rule 1: No ref-count change when calling own methods + +When calling a method on a structure, don't change its reference count: + +```c +// CORRECT: No reference counting change for the self parameter +struct->call_func(struct, params); +``` + +### Rule 2: Add reference before passing objects as non-self parameters + +When calling CEF methods that take object parameters (beyond the self parameter), CEF takes ownership of those parameters. You must add a reference before calling: + +```c +// Example: Adding a child view to a panel +cef_panel_t* panel = ...; +cef_view_t* child_view = ...; + +// Add reference before passing child_view to CEF method +child_view->base.add_ref(&child_view->base); + +// panel is "self" (no ownership transfer) +// child_view is a non-self parameter (ownership transferred to CEF) +panel->add_child_view(panel, child_view); + +// DON'T release child_view here - add_child_view consumed the reference +``` + +**Important distinction:** + +- **Self parameter** (first parameter, the structure itself): No ownership transfer +- **Non-self parameters** (additional object parameters): Ownership IS transferred - add_ref first + +**Shortcut:** If you received the object as a callback parameter and are immediately passing it to a CEF function, you can transfer CEF's reference directly without add_ref/release: + +```c +void CEF_CALLBACK on_before_close( + cef_life_span_handler_t* self, + cef_browser_t* browser) { + + // browser has +1 ref from CEF callback + + // Transfer CEF's reference directly to is_same + stored_browser->is_same(stored_browser, browser); + + // DON'T release browser - is_same consumed CEF's reference + // DON'T add_ref before calling - we transferred the callback's reference +} +``` + +### Rule 3: Add reference when returning objects to CEF + +When you return an object to CEF (or pass it to a CEF function), you're transferring ownership of one reference to CEF. Add a reference before returning because CEF will release it when done: + +```c +// Example: Returning a handler from a getter function +cef_life_span_handler_t* CEF_CALLBACK +my_get_life_span_handler(cef_client_t* self) { + my_client_t* client = (my_client_t*)self; + + // Add a reference because we're giving ownership to CEF + // CEF will call release() on this reference when it's done with the handler + client->life_span_handler->base.add_ref( + &client->life_span_handler->base); + + return client->life_span_handler; +} +``` + +**Why?** You still have your own reference (stored in `client->life_span_handler`), and now CEF has a separate reference. When CEF no longer needs the handler, it will release its reference, but yours remains until you explicitly release it. + +### Rule 4: Release parameters when done + +When CEF calls your callback with structure parameters, it has already added a reference for each one. You MUST release them before returning: + +```c +void CEF_CALLBACK on_before_browse( + cef_request_handler_t* self, + cef_browser_t* browser, + cef_frame_t* frame, + cef_request_t* request, + int user_gesture, + int is_redirect) { + + // Use the objects... + cef_string_userfree_t url = request->get_url(request); + // ... do something with the URL + cef_string_userfree_free(url); + + // MUST release all object parameters before returning + // CEF added a reference for each parameter before calling this function + browser->base.release(&browser->base); + frame->base.release(&frame->base); + request->base.release(&request->base); + + return 0; // Allow navigation +} +``` + +**Exception:** Do NOT release the `self` parameter - that's your own structure. + +**To keep a parameter longer:** If you need to store a parameter beyond the callback, call `add_ref` on it BEFORE releasing the original reference (see Rule 5). + +### Rule 5: Keep long-term references + +If you store a pointer beyond the current function, you need to keep a reference. You have two options: + +**Option 1: Simply don't release the parameter (recommended)** + +```c +typedef struct { + cef_life_span_handler_t handler; + cef_browser_t* browser; // Long-term storage + atomic_int ref_count; +} my_handler_t; + +void CEF_CALLBACK on_after_created( + cef_life_span_handler_t* self, + cef_browser_t* browser) { + + my_handler_t* handler = (my_handler_t*)self; + + // Store the browser and keep CEF's reference + handler->browser = browser; + // Don't call release() - we're keeping the reference CEF gave us +} + +// Remember to release when you're done with it +int CEF_CALLBACK my_handler_release(cef_base_ref_counted_t* self) { + my_handler_t* handler = (my_handler_t*)self; + int count = atomic_fetch_sub(&handler->ref_count, 1) - 1; + if (count == 0) { + // Release the browser reference we kept + if (handler->browser) { + handler->browser->base.release(&handler->browser->base); + } + free(handler); + return 1; + } + return 0; +} +``` + +**Option 2: Add your own reference and release the parameter** + +This is more explicit but does the same thing: + +```c +void CEF_CALLBACK on_after_created( + cef_life_span_handler_t* self, + cef_browser_t* browser) { + + my_handler_t* handler = (my_handler_t*)self; + + // Add our own reference + handler->browser = browser; + browser->base.add_ref(&browser->base); + + // Release the reference CEF gave us + browser->base.release(&browser->base); + // Net effect: ref count unchanged, but we "own" the reference now +} +``` + +Both approaches end up with the same reference count. Option 1 is simpler and more efficient. + +### Rule 6: Use atomic operations + +Reference counting functions are called from multiple threads. Always use thread-safe atomic operations. + +See the "Atomic Operations for Reference Counting" section below for complete platform-specific implementations. + +```c +// CORRECT: Thread-safe +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + atomic_fetch_add(&app->ref_count, 1); +} + +// WRONG: Not thread-safe! +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + app->ref_count++; // RACE CONDITION! +} +``` + +### Rule 7: Delete when reference count reaches zero + +The `release` function should delete the object when the count reaches zero: + +```c +int CEF_CALLBACK app_release(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + int count = atomic_fetch_sub(&app->ref_count, 1) - 1; + if (count == 0) { + // Clean up any resources this structure owns + if (app->some_browser) { + app->some_browser->base.release(&app->some_browser->base); + } + // Free the structure itself + free(app); + return 1; // Indicate the object was deleted + } + return 0; // Object still alive +} +``` + +### Rule 8: Release at the end of handler lifetime + +Make sure to release any references you've stored when your handler is destroyed. For browser-related handlers, the last opportunity is typically in the life span handler's `on_before_close` callback: + +```c +void CEF_CALLBACK on_before_close( + cef_life_span_handler_t* self, + cef_browser_t* browser) { + + my_handler_t* handler = (my_handler_t*)self; + + // Release our stored browser reference + if (handler->browser) { + handler->browser->base.release(&handler->browser->base); + handler->browser = NULL; + } + + // Release the browser reference passed to this function + browser->base.release(&browser->base); +} +``` + +### Rule 9: Debugging reference counting + +You'll know reference counting is working correctly when: + +- Your application doesn't crash +- You don't see DebugObjCt assertion failures on shutdown +- Memory leak detectors don't report CEF object leaks + +If you're having issues, add logging to your `add_ref` and `release` functions to track the reference count. + +# Critical Implementation Notes + +These are common mistakes that will cause crashes or undefined behavior. Pay close attention to these details. + +## Structure Member Ordering + +The CEF base structure MUST be the first member of your custom structure. This allows safe casting between the base type and your type. + +```c +// CORRECT: Base structure first +typedef struct { + cef_app_t app; // CEF structure FIRST + atomic_int ref_count; + void* user_data; +} my_app_t; + +// WRONG: Will cause crashes! +typedef struct { + atomic_int ref_count; + void* user_data; + cef_app_t app; // Not first - WRONG! +} broken_app_t; +``` + +This ordering requirement exists because CEF will cast the pointer to the base type and expects the base structure to start at offset zero. + +## Size Field Initialization + +Always set the `size` field to the size of the CEF structure type, NOT your wrapper structure: + +```c +my_app_t* app = (my_app_t*)calloc(1, sizeof(my_app_t)); + +// CORRECT: Size of the CEF structure +app->app.base.size = sizeof(cef_app_t); + +// WRONG: Don't use the size of your wrapper! +app->app.base.size = sizeof(my_app_t); // WRONG! +``` + +The `size` field is used for versioning and validation by CEF. It must match the size of the CEF API structure. + +## Thread Safety Requirements + +Reference counting functions (`add_ref`, `release`, `has_one_ref`, `has_at_least_one_ref`) are called from multiple threads. You MUST use atomic operations or platform-specific thread-safe functions. + +**Never use plain integer operations:** + +```c +// WRONG - RACE CONDITION! +void CEF_CALLBACK bad_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + app->ref_count++; // NOT THREAD-SAFE! +} +``` + +**Use platform-appropriate atomic operations:** + +- **C11 Standard**: `atomic_int` with `atomic_fetch_add()`, `atomic_fetch_sub()`, `atomic_load()` +- **Windows**: `InterlockedIncrement()`, `InterlockedDecrement()` +- **GCC/Clang**: `__sync_fetch_and_add()`, `__sync_fetch_and_sub()` +- **macOS**: `OSAtomicIncrement32()`, `OSAtomicDecrement32()` + +## Handler Return Values + +When implementing methods that return structures (like `get_browser_process_handler`): + +```c +cef_browser_process_handler_t* CEF_CALLBACK +get_browser_process_handler(cef_app_t* self) { + my_app_t* app = (my_app_t*)self; + + if (app->browser_process_handler) { + // Add reference before returning - CEF will release when done + app->browser_process_handler->base.add_ref( + &app->browser_process_handler->base); + return app->browser_process_handler; + } + + // Return NULL if no handler needed + return NULL; +} +``` + +**Key points:** + +- Return a pointer with an added reference (CEF will release it) +- Return NULL if you don't need that handler +- CEF will call `release` when it's done with the returned handler + +## NULL Pointer Checks + +Check parameters for NULL before dereferencing them. The CEF API documentation indicates which parameters may be NULL: + +```c +void CEF_CALLBACK some_handler( + cef_handler_t* self, + cef_browser_t* browser) { + + // NOTE: 'self' is never NULL - CEF is calling your callback on your structure + + // Check other parameters that may be NULL (see API docs) + if (!browser) { + return; + } + + // Now safe to use + cef_frame_t* frame = browser->get_main_frame(browser); + if (frame) { + // Methods can return NULL - always check return values + // Use frame... + frame->base.release(&frame->base); + } + + browser->base.release(&browser->base); +} +``` + +**Important notes:** + +- The `self` parameter is never NULL - it's always your own structure +- Other parameters may be NULL if the API documentation says so - always check before use +- Methods can return NULL (e.g., `get_main_frame()` may return NULL), so always check return values +- Only release non-NULL pointers + +# Atomic Operations for Reference Counting + +Different platforms require different approaches to implementing thread-safe atomic operations for reference counting. + +## C11 Atomics (Recommended) + +**Use this approach if you can.** Modern compilers support the C11 standard `` header, which provides portable atomic operations across all platforms: + +- **Linux/macOS**: GCC 4.9+, Clang 3.1+ +- **Windows**: Visual Studio 2022 17.5+, MinGW, Clang + +If you need to support older platform versions, see the sections below. + +**Compiler flags required:** + +- **Linux/macOS**: `-std=c11` (GCC/Clang) +- **Windows MSVC**: `/std:c11 /experimental:c11atomics` +- **Windows MinGW/Clang**: `-std=c11` + +Without these flags, the compiler will use an older C standard (typically C89/C90) and `` will not be available. + +```c +#include +#include + +typedef struct { + cef_app_t app; + atomic_int ref_count; // C11 atomic type +} my_app_t; + +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + atomic_fetch_add(&app->ref_count, 1); +} + +int CEF_CALLBACK app_release(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + int count = atomic_fetch_sub(&app->ref_count, 1) - 1; + if (count == 0) { + free(app); + return 1; + } + return 0; +} + +int CEF_CALLBACK app_has_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + return atomic_load(&app->ref_count) == 1; +} + +int CEF_CALLBACK app_has_at_least_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + return atomic_load(&app->ref_count) >= 1; +} +``` + +## Windows API (Older MSVC Versions) + +Use this approach for compatibility with older Visual Studio versions (before 2022 17.5): + +```c +#include +#include + +typedef struct { + cef_app_t app; + volatile LONG ref_count; // Use LONG for Interlocked functions +} my_app_t; + +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + InterlockedIncrement(&app->ref_count); +} + +int CEF_CALLBACK app_release(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + LONG count = InterlockedDecrement(&app->ref_count); + if (count == 0) { + free(app); + return 1; + } + return 0; +} + +int CEF_CALLBACK app_has_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + // InterlockedCompareExchange(ptr, 0, 0) atomically reads the value + return InterlockedCompareExchange(&app->ref_count, 0, 0) == 1; +} + +int CEF_CALLBACK app_has_at_least_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + // InterlockedCompareExchange(ptr, 0, 0) atomically reads the value + return InterlockedCompareExchange(&app->ref_count, 0, 0) >= 1; +} +``` + +## GCC/Clang Built-ins (Legacy POSIX) + +Use this approach for older GCC (before 4.9) or Clang (before 3.1) on Linux/macOS that don't support C11 atomics: + +```c +#include + +typedef struct { + cef_app_t app; + int ref_count; // Plain int, protected by GCC built-ins +} my_app_t; + +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + __sync_fetch_and_add(&app->ref_count, 1); +} + +int CEF_CALLBACK app_release(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + int count = __sync_fetch_and_sub(&app->ref_count, 1) - 1; + if (count == 0) { + free(app); + return 1; + } + return 0; +} + +int CEF_CALLBACK app_has_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + // __sync_fetch_and_add(ptr, 0) atomically reads the value + return __sync_fetch_and_add(&app->ref_count, 0) == 1; +} + +int CEF_CALLBACK app_has_at_least_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + // __sync_fetch_and_add(ptr, 0) atomically reads the value + return __sync_fetch_and_add(&app->ref_count, 0) >= 1; +} +``` + +## OSAtomic (Legacy macOS) + +Use this approach for older macOS versions. Note that `OSAtomic` functions are deprecated in modern macOS - use C11 atomics instead if possible: + +```c +#include +#include + +typedef struct { + cef_app_t app; + int32_t ref_count; // Must be int32_t for OSAtomic functions +} my_app_t; + +void CEF_CALLBACK app_add_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + OSAtomicIncrement32(&app->ref_count); +} + +int CEF_CALLBACK app_release(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + int32_t count = OSAtomicDecrement32(&app->ref_count); + if (count == 0) { + free(app); + return 1; + } + return 0; +} + +int CEF_CALLBACK app_has_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + // OSAtomicAdd32(0, ptr) atomically reads the value + return OSAtomicAdd32(0, &app->ref_count) == 1; +} + +int CEF_CALLBACK app_has_at_least_one_ref(cef_base_ref_counted_t* self) { + my_app_t* app = (my_app_t*)self; + // OSAtomicAdd32(0, ptr) atomically reads the value + return OSAtomicAdd32(0, &app->ref_count) >= 1; +} +``` + +# Common Implementation Patterns + +These patterns solve common scenarios you'll encounter when using the CEF C API. + +## NULL Handler Pattern + +Many handler methods can simply return NULL if you don't need custom behavior. Since `calloc` zero-initializes all memory, you can either: + +**Option 1:** Don't set the function pointer at all (it's already NULL): + +```c +my_client_t* client = (my_client_t*)calloc(1, sizeof(my_client_t)); +// client->client.get_render_handler is already NULL - nothing to do! +// client->client.get_request_handler is already NULL - nothing to do! +``` + +**Option 2:** Implement the getter to explicitly return NULL (useful for clarity): + +```c +// Don't need a render handler? Just return NULL +cef_render_handler_t* CEF_CALLBACK +client_get_render_handler(cef_client_t* self) { + return NULL; // Use default rendering +} + +// Don't need a request handler? Return NULL +cef_request_handler_t* CEF_CALLBACK +client_get_request_handler(cef_client_t* self) { + return NULL; // Use default request handling +} +``` + +Both approaches are valid. Option 1 is simpler (no code needed), while Option 2 provides better documentation of your intent. Only implement handlers for the functionality you actually need. + +**Important note about default implementations:** The C++ API provides default implementations for many handler methods (often defined in the header files). The C API does **not** automatically provide these defaults. If you don't implement a method in the C API, CEF will use its internal default behavior, which may differ from the C++ API's documented defaults. + +For example, `CefWindowDelegate::CanResize()` defaults to `true` in the C++ header. To get the same behavior in the C API, you must explicitly implement `can_resize` and return `1` (true). See [cefsimple_capi/simple_views.c](https://github.com/chromiumembedded/cef/blob/master/tests/cefsimple_capi/simple_views.c) for examples of implementing methods like `can_resize`, `can_maximize`, and `can_minimize` that replicate C++ default behavior. + +## Safe Casting Pattern + +When casting from a CEF structure back to your custom structure, verify integrity: + +```c +my_handler_t* safe_cast_to_my_handler(cef_life_span_handler_t* handler) { + // Verify the structure is valid + if (!handler) { + return NULL; + } + + // Verify the size matches (helps catch version mismatches) + if (handler->base.size != sizeof(cef_life_span_handler_t)) { + return NULL; + } + + // Safe to cast because our structure has the handler as the first member + return (my_handler_t*)handler; +} +``` + +## Extracting Data Before Release + +Always extract any data you need from a structure before releasing it: + +```c +void CEF_CALLBACK on_before_close( + cef_life_span_handler_t* self, + cef_browser_t* browser) { + + // Extract data BEFORE releasing + int browser_id = browser->get_identifier(browser); + + // Now safe to release + browser->base.release(&browser->base); + + // Use the extracted data + printf("Browser %d is closing\n", browser_id); +} +``` + +## Storing User Data Pattern + +Use your custom structure to store application-specific data: + +```c +typedef struct { + cef_client_t client; + atomic_int ref_count; + + // Application-specific data + void* user_data; + cef_browser_t* main_browser; + int window_id; +} my_client_t; + +// Access your data in callbacks +void CEF_CALLBACK on_after_created( + cef_life_span_handler_t* self, + cef_browser_t* browser) { + + my_handler_t* handler = (my_handler_t*)self; + + // Access application-specific data + printf("Window ID: %d\n", handler->window_id); + + // Store browser reference and keep CEF's reference + handler->main_browser = browser; + // Don't call release() - we're keeping the reference CEF gave us +} + +// Remember to release stored references when cleaning up +int CEF_CALLBACK my_handler_release(cef_base_ref_counted_t* self) { + my_handler_t* handler = (my_handler_t*)self; + int count = atomic_fetch_sub(&handler->ref_count, 1) - 1; + if (count == 0) { + // Release the browser reference we kept + if (handler->main_browser) { + handler->main_browser->base.release(&handler->main_browser->base); + } + free(handler); + return 1; + } + return 0; +} +``` + +## Callback Context Pattern + +Pass context through handler structures: + +```c +typedef struct { + cef_load_handler_t handler; + atomic_int ref_count; + + // Context for callbacks + void (*on_load_complete)(void* user_data, const char* url); + void* callback_user_data; +} my_load_handler_t; + +void CEF_CALLBACK on_load_end( + cef_load_handler_t* self, + cef_browser_t* browser, + cef_frame_t* frame, + int httpStatusCode) { + + my_load_handler_t* handler = (my_load_handler_t*)self; + + // Get the URL + cef_string_userfree_t url = frame->get_url(frame); + + // Call application callback if set + if (handler->on_load_complete) { + // Convert to UTF-8 for the callback + cef_string_utf8_t url_utf8 = {}; + cef_string_to_utf8(url->str, url->length, &url_utf8); + + handler->on_load_complete( + handler->callback_user_data, + url_utf8.str); + + cef_string_utf8_clear(&url_utf8); + } + + cef_string_userfree_free(url); + browser->base.release(&browser->base); + frame->base.release(&frame->base); +} +``` + +## Optional Handler Fields Pattern + +When using `calloc`, all function pointers are automatically NULL, so you only need to set the ones you actually implement: + +```c +my_client_t* create_client() { + // calloc zeros all memory - all function pointers are NULL by default + my_client_t* client = (my_client_t*)calloc(1, sizeof(my_client_t)); + + // Set up base structure + client->client.base.size = sizeof(cef_client_t); + client->client.base.add_ref = client_add_ref; + client->client.base.release = client_release; + client->client.base.has_one_ref = client_has_one_ref; + client->client.base.has_at_least_one_ref = client_has_at_least_one_ref; + + // Only set the handlers you actually implement + client->client.get_life_span_handler = client_get_life_span_handler; + client->client.get_load_handler = client_get_load_handler; + // All other handlers (render, request, display, etc.) are already NULL + + atomic_store(&client->ref_count, 1); + return client; +} +``` + +**Important note about `malloc` vs `calloc`:** + +If you use `malloc` instead of `calloc`, you MUST explicitly initialize all function pointers to NULL: + +```c +my_client_t* create_client_with_malloc() { + // malloc does NOT initialize memory - fields contain garbage + my_client_t* client = (my_client_t*)malloc(sizeof(my_client_t)); + + // MUST explicitly zero or set every function pointer + memset(client, 0, sizeof(my_client_t)); // Or set each field individually + + // Now continue with initialization... + client->client.base.size = sizeof(cef_client_t); + // ... rest of setup +} +``` + +**Recommendation:** Use `calloc` for CEF structures. It's safer and requires less code. \ No newline at end of file