Support chrome windows with CEF callbacks

Issue #2969 new
Marshall Greenblatt created an issue

The Chromium code base is composed of architectural layers, with the primary application layers being “content” and “chrome”. The “content” layer includes WebContents 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 as the primary browser object and provides implementations for many advanced features including datalist/autofill (issue #906), extensions (issue #1947), gamepad (issue #1751), webhid (issue #2847), webmidi (issue #1028), async clipboard (issue #2921), input_type=color (issue #899), etc.

For historical reasons CEF browser windows are based on the “content” layer WebContents object. Adding support for additional “chrome” layer features is a serious effort because it involves careful understanding and cherry-picking of the related functionality from “chrome” into the CEF code base. Over time we have added dependencies on the “chrome” layer targets to support some features in CEF (extensions, print preview, etc) and to avoid code duplication. As a result, CEF binaries already contain most/all of the code that would be required to launch a stand-alone “chrome” Browser window.

If we could create a CEF browser window based on the “chrome” Browser object we would get much of the “chrome” layer functionality “for free”. To be usable in CEF the “chrome” window would need to support a subset of existing CEF callbacks/intercepts (e.g. loading progress, network requests, etc.), and be inserted into the existing Views framework structure (issue #1749). The “chrome” window would not support off-screen rendering, though parenting to a native (non-Views) window should be possible and likely required on macOS.

Given the above, the scope for this issue is to identify the subset of “chrome” initialization code that is required to launch and embed a Views-based Browser window object, and then hook up a TBD minimum subset of existing CEF callbacks to work with that object. MVP is an off-by-default option to create “chrome”-based browsers in cefclient/cefsimple. These browsers will initially contain many chrome-specific UI features (shortcut keys, dialogs, etc.) that might not be desired in release-quality client applications. Additional callback functionality and behavioral tweaks may be added over time as needed/appropriate.

Official response

  • Marshall Greenblatt reporter

    Add chrome runtime support for more callbacks and ceftests (see issue #2969)

    This change adds support for:

    • Protocol and request handling.
    • Loading and navigation events.
    • Display and focus events.
    • Mouse/keyboard events.
    • Popup browsers.
    • Callbacks in the renderer process.
    • Misc. functionality required for ceftests.

    This change also adds a new CefBrowserProcessHandler::GetCookieableSchemes callback for configuring global state that will be applied to all CefCookieManagers by default. This global callback is currently required by the chrome runtime because the primary ProfileImpl is created via ChromeBrowserMainParts::PreMainMessageLoopRun (CreatePrimaryProfile) before OnContextCreated can be called.

    ProfileImpl will use the "C:\Users[user]\AppData\Local\CEF\User Data\Default" directory by default (on Windows). Cookies may persist in this directory when running ceftests and may need to be manually deleted if those tests fail.

    Remaining work includes:

    • Support for client-created request contexts.
    • Embedding the browser in a Views hierarchy (cefclient support).
    • TryCloseBrowser and DoClose support.
    • Most of the CefSettings configuration.
    • DevTools protocol and window control (ShowDevTools, ExecuteDevToolsMethod).
    • CEF-specific WebUI pages (about, license, webui-hosts).
    • Context menu customization (CefContextMenuHandler).
    • Auto resize (SetAutoResizeEnabled).
    • Zoom settings (SetZoomLevel).
    • File dialog runner (RunFileDialog).
    • File and JS dialog handlers (CefDialogHandler, CefJSDialogHandler).
    • Extension loading (LoadExtension, etc).
    • Plugin loading (OnBeforePluginLoad).
    • Widevine loading (CefRegisterWidevineCdm).
    • PDF and print preview does not display.
    • Crash reporting is untested.
    • Mac: Web content loads but does not display.

    The following ceftests are now passing when run with the "--enable-chrome-runtime" command-line flag:

    CorsTest.*
    DOMTest.*
    DisplayTest.*:-DisplayTest.AutoResize
    DraggableRegionsTest.*
    ImageTest.*
    MessageRouterTest.*
    NavigationTest.*
    ParserTest.*
    RequestContextTest.*Global*
    RequestTest.*
    ResourceManagerTest.*
    ResourceRequestHandlerTest.*
    ResponseTest.*
    SchemeHandlerTest.*
    ServerTest.*
    StreamResourceHandlerTest.*
    StreamTest.*
    StringTest.*
    TaskTest.*
    TestServerTest.*
    ThreadTest.*
    URLRequestTest.*Global*
    V8Test.*:-V8Test.OnUncaughtExceptionDevTools
    ValuesTest.*
    WaitableEventTest.*
    XmlReaderTest.*
    ZipReaderTest.*
    

    They can be run with this command-line:

    ceftests --enable-chrome-runtime --gtest_filter=CorsTest.*:DisplayTest.*:DOMTest.*:DraggableRegionsTest.*:ImageTest.*:MessageRouterTest.*:NavigationTest.*:ParserTest.*:RequestContextTest.*Global*:RequestTest.*:ResourceManagerTest.*:ResourceRequestHandlerTest.*:ResponseTest.*:SchemeHandlerTest.*:ServerTest.*:StreamResourceHandlerTest.*:StreamTest.*:StringTest.*:TaskTest.*:TestServerTest.*:ThreadTest.*:URLRequestTest.*Global*:V8Test.*:ValuesTest.*:WaitableEventTest.*:XmlReaderTest.*:ZipReaderTest.*:-V8Test.OnUncaughtExceptionDevTools:DisplayTest.AutoResize
    

    → <<cset 4fbd2472310b>>

Comments (18)

  1. Marshall Greenblatt reporter

    One important technical aspect of this change is the usage of BUILDFLAG(ENABLE_CEF) when patching Chromium code. We will need to introduce a runtime check for choosing between CEF and Chrome behaviors in these patches, instead of just compiling in the CEF-specific behaviors when building CEF.

  2. Marshall Greenblatt reporter

    GTK is required for the Chrome runtime on Linux (see here), so use_gtk=true must be specified via GN_DEFINES on that platform.

  3. Marshall Greenblatt reporter

    Refactor process execution logic (see issue #2969)

    CefContext implements the public CEF API functions and delegates the stages of content & service_manager process execution to CefMainRunner. CEF-specific runtime logic (which may be replaced with chrome-specific runtime logic) is then delegated to CefMainDelegate which implements content::ContentMainDelegate.

    → <<cset 049caf913106>>

  4. Marshall Greenblatt reporter

    Add initial chrome runtime support (see issue #2969)

    Running cefsimple --enable-chrome-runtime will create and run a Chrome browser window using the CEF app methods, and call CefApp::OnContextInitialized as expected. CEF task methods also work as expected in the main process. No browser-related methods or callbacks are currently supported for the Chrome window, and the application will exit when the last Chrome window closes.

    The Chrome runtime requires resources.pak, chrome_100_percent.pak and chrome_200_percent.pak files which were not previously built with CEF. It shares the existing locales pak files which have been updated to include additional Chrome-specific strings.

    On Linux, the Chrome runtime requires GTK so use_gtk=true must be specified via GN_DEFINES when building.

    This change also refactors the CEF runtime, which can be tested in the various supported modes by running: $ cefclient $ cefclient --multi-threaded-message-loop $ cefclient --external-message-pump

    → <<cset 117499421184>>

  5. Marshall Greenblatt reporter

    Set enable_background_mode=false by default (see issue #2969)

    This mode doesn't make sense with CEF, and it was causing strange shutdown crashes when running with Chrome mode enabled.

    → <<cset f5587b74f0aa>>

  6. Marshall Greenblatt reporter

    Rename the current CEF runtime to Alloy (see issue #2969)

    As part of introducing the Chrome runtime we now need to distinguish between the classes that implement the current CEF runtime and the classes the implement the shared CEF library/runtime structure and public API. We choose the name Alloy for the current CEF runtime because it describes a combination of Chrome and other elements.

    Shared CEF library/runtime classes will continue to use the Cef prefix. Classes that implement the Alloy or Chrome runtime will use the Alloy or Chrome prefixes respectively. Classes that extend an existing Chrome-prefixed class will add the Cef or Alloy suffix, thereby following the existing naming pattern of Chrome-derived classes.

    This change applies the new naming pattern to an initial set of runtime-related classes. Additional classes/files will be renamed and moved as the Chrome runtime implementation progresses.

    → <<cset 84f3ff2afda7>>

  7. Marshall Greenblatt reporter

    Add CefAppManager and remove global ContentClient accessors (see issue #2969)

    This is the first pass in removing direct dependencies on the Alloy runtime from code that can potentially be shared between runtimes.

    CefBrowserHost and CefRequestContext APIs (including CefCookieManager, CefURLRequest, etc.) are not yet implemented for the Chrome runtime. Assert early if these API methods are called while the Chrome runtime is enabled.

    → <<cset b3a8da9b25dc>>

  8. Marshall Greenblatt reporter

    Make CefBrowserContext an abstract base class (see issue #2969)

    Existing CefBrowserContext functionality is now split between CefBrowserContext and AlloyBrowserContext. Runtime implementations of CefBrowserContext will provide access to the content::BrowserContext and Profile types via different inheritance paths. For example, the Alloy runtime uses ChromeProfileAlloy and the Chrome runtime uses ProfileImpl.

    This change also renames CefResourceContext to CefIOThreadState to more accurately represent its purpose as it no longer needs to extend content::ResourceContext.

    → <<cset 48fc0bd2206d>>

  9. Marshall Greenblatt reporter

    Move browser runtime-specific logic to CefBrowserPlatformDelegate (see issue #2969)

    This change moves the runtime-specific implementations of CefBrowserHostImpl methods to CefBrowserPlatformDelegate. Some WebContentsDelegate methods implemented by CefBrowserHostImpl set state or trigger client callbacks. Those implementations will likely stay with CefBrowserHostImpl and will need to be called from the Browser equivalents when using the Chrome runtime.

    → <<cset 6cb9f0c695b9>>

  10. Marshall Greenblatt reporter

    Add initial Chrome runtime support for browser APIs (see issue #2969)

    This change adds basic Chrome runtime implementations for CefBrowserContext and CefBrowserPlatformDelegate. A Chrome browser window with default frame and styling can now be created using CefBrowserHost::CreateBrowser and some CefClient callbacks will be triggered via the WebContentsObserver implementation in CefBrowserHostImpl.

    Any additional browser windows created via the Chrome UI will be unmanaged by CEF. The application message loop will block until all browser windows have been closed by the user.

    → <<cset e9bf3cdb9852>>

  11. Marshall Greenblatt reporter

    Move Alloy-specific logic to CefBrowserPlatformDelegateAlloy (see issue #2969)

    Also remove OSR-related methods where the attributes can instead be passed to the OSR platform delegate constructor directly.

    → <<cset 02cdf05848ea>>

  12. Marshall Greenblatt reporter

    Fix build and initial Chrome runtime issues on macOS (see issue #2969)

    This change moves shared resource initialization to a common location and disables crash reporting initialization in chrome/ code via patch files.

    When using the Chrome runtime on macOS the Chrome application window will display, but web content is currently blank and the application does not exit cleanly. This will need to be debugged further in the future.

    → <<cset 03c9156c803c>>

  13. Marshall Greenblatt reporter

    The next step is supporting observers and delegates on the chrome Browser object.

  14. Marshall Greenblatt reporter

    Create a ChromeBrowserHostImpl for every Chrome tab (see issue #2969)

    The Browser object represents the top-level Chrome browser window. One or more tabs (WebContents) are then owned by the Browser object via TabStripModel. A new Browser object can be created programmatically using "new Browser" or Browser::Create, or as a result of user action such as dragging a tab out of an existing window. New or existing tabs can also be added to an already existing Browser object.

    The Browser object acts as the WebContentsDelegate for all attached tabs. CEF integration requires WebContentsDelegate callbacks and notification of tab attach/detach. To support this integration we add a cef::BrowserDelegate (ChromeBrowserDelegate) member that is created in the Browser constructor and receives delegation for the Browser callbacks. ChromeBrowserDelegate creates a new ChromeBrowserHostImpl when a tab is added to a Browser for the first time, and that ChromeBrowserHostImpl continues to exist until the tab's WebContents is destroyed. The associated WebContents object does not change, but the Browser object will change when the tab is dragged between windows.

    CEF callback logic is shared between the chrome and alloy runtimes where possible. This shared logic has been extracted from CefBrowserHostImpl to create new CefBrowserHostBase and CefBrowserContentsDelegate classes. The CefBrowserHostImpl class is now only used with the alloy runtime and will be renamed to AlloyBrowserHostImpl in a future commit.

    → <<cset 38d8acfa186c>>

  15. Marshall Greenblatt reporter

    Add chrome runtime support for more callbacks and ceftests (see issue #2969)

    This change adds support for:

    • Protocol and request handling.
    • Loading and navigation events.
    • Display and focus events.
    • Mouse/keyboard events.
    • Popup browsers.
    • Callbacks in the renderer process.
    • Misc. functionality required for ceftests.

    This change also adds a new CefBrowserProcessHandler::GetCookieableSchemes callback for configuring global state that will be applied to all CefCookieManagers by default. This global callback is currently required by the chrome runtime because the primary ProfileImpl is created via ChromeBrowserMainParts::PreMainMessageLoopRun (CreatePrimaryProfile) before OnContextCreated can be called.

    ProfileImpl will use the "C:\Users[user]\AppData\Local\CEF\User Data\Default" directory by default (on Windows). Cookies may persist in this directory when running ceftests and may need to be manually deleted if those tests fail.

    Remaining work includes:

    • Support for client-created request contexts.
    • Embedding the browser in a Views hierarchy (cefclient support).
    • TryCloseBrowser and DoClose support.
    • Most of the CefSettings configuration.
    • DevTools protocol and window control (ShowDevTools, ExecuteDevToolsMethod).
    • CEF-specific WebUI pages (about, license, webui-hosts).
    • Context menu customization (CefContextMenuHandler).
    • Auto resize (SetAutoResizeEnabled).
    • Zoom settings (SetZoomLevel).
    • File dialog runner (RunFileDialog).
    • File and JS dialog handlers (CefDialogHandler, CefJSDialogHandler).
    • Extension loading (LoadExtension, etc).
    • Plugin loading (OnBeforePluginLoad).
    • Widevine loading (CefRegisterWidevineCdm).
    • PDF and print preview does not display.
    • Crash reporting is untested.
    • Mac: Web content loads but does not display.

    The following ceftests are now passing when run with the "--enable-chrome-runtime" command-line flag:

    CorsTest.*
    DOMTest.*
    DisplayTest.*:-DisplayTest.AutoResize
    DraggableRegionsTest.*
    ImageTest.*
    MessageRouterTest.*
    NavigationTest.*
    ParserTest.*
    RequestContextTest.*Global*
    RequestTest.*
    ResourceManagerTest.*
    ResourceRequestHandlerTest.*
    ResponseTest.*
    SchemeHandlerTest.*
    ServerTest.*
    StreamResourceHandlerTest.*
    StreamTest.*
    StringTest.*
    TaskTest.*
    TestServerTest.*
    ThreadTest.*
    URLRequestTest.*Global*
    V8Test.*:-V8Test.OnUncaughtExceptionDevTools
    ValuesTest.*
    WaitableEventTest.*
    XmlReaderTest.*
    ZipReaderTest.*
    

    They can be run with this command-line:

    ceftests --enable-chrome-runtime --gtest_filter=CorsTest.*:DisplayTest.*:DOMTest.*:DraggableRegionsTest.*:ImageTest.*:MessageRouterTest.*:NavigationTest.*:ParserTest.*:RequestContextTest.*Global*:RequestTest.*:ResourceManagerTest.*:ResourceRequestHandlerTest.*:ResponseTest.*:SchemeHandlerTest.*:ServerTest.*:StreamResourceHandlerTest.*:StreamTest.*:StringTest.*:TaskTest.*:TestServerTest.*:ThreadTest.*:URLRequestTest.*Global*:V8Test.*:ValuesTest.*:WaitableEventTest.*:XmlReaderTest.*:ZipReaderTest.*:-V8Test.OnUncaughtExceptionDevTools:DisplayTest.AutoResize
    

    → <<cset 4fbd2472310b>>

  16. Log in to comment