Chromium Embedded Framework (CEF) is a framework for embedding Chromium-based browsers in other applications. Chromium itself isn’t a extensible library. It helps you to embed a chromium browser in a native desktop application. The project was started by Marshall Greenblatt in 2009 as an open source project and since then it has been used by a number of popular applications like Spotify, Amazon Music, Unreal Engine, Adobe Acrobat, Steam and many more (full list can be found in this wiki). CEF is supported for Windows, Linux and macOS platforms.
There are 2 versions of CEF – CEF1 and CEF3. CEF1 is a single process implementation based in Chrome Webkit API. It’s no longer supported or maintained. CEF3 is a multiprocess implementation based on Chromium Content API and has performance similar to Google Chrome.
The purpose of writing this article is to document the work that I did while working on the CEF project. The major focus is on the Print Preview addition to CEF upstream project where I worked on.
For the past 1 year I have been working on CEF as a part of my day job. Initially the work was to maintain updates of CEF with every Chromium version released. We had a fork of the CEF open source project in which we applied some extra patches as per the requirements of the custom desktop application that used it. Building CEF was quite similar to building Chromium. It had a build script which was mostly used from downloading the code, building and packaging the binaries. Everything is documented here in this link . Upgrading the CEF was quite some task since building CEF took a lot of time and resources (a lot of CPU cores and a lot of Memory) and since CEF was based out of chromium I had to skim through parts of chromium code. Chromium has a nice developer documentation and a good code search engine that eased a lot of things. But owing to the fact that chromium has a huge codebase the documentation was outdated in few areas.
The interesting part of the CEF project came when I was handed over a work of a missing piece in CEF. Chromium supports in browser print preview where you can preview pages before printing, similar to one shown in the picture below.
CEF didn’t support this feature and had the legacy print menu where you cannot preview the pages to be printed.
This meant applications that used CEF couldn’t support print preview within them. The task was to make print preview available in CEF.
The work started with CEF version 3112 (supported chromium v60) and was in a working state in CEF 3239 (supported chromium v63) in our CEF fork. Then the change was supported only in Windows since our desktop application that used it was a Windows only application. I was handed over the work in CEF 3325 (supported chromium v65) where the following specs already existed in the Print Preview patch. The relevant blocks of code is available in the CEF source code now.
enable_service_discoveryis disabled now
CefPrintViewManager::PrintPreviewNow()will handle print-preview
CefPrintViewManagerwill not handle the print now. It handles the
PrintToPdffunction exposed through
browserHost. Also, it listens to two print preview message
PrintHostMsg_ShowScriptedPrintPreviewand generate the
browserInfofor print preview dialog
- Define interfaces from
web_modal::WebContentsModalDialogHostrequired by the constrained window of print preview dialog
- Define platform specific definitions of
GetMaximumDialogSize()used by browser platform_delegate
Profilepreferences required for printing
ConstrainerWindowsViewsClientclass which is called in
CefPrintViewManager::InitializePrintPreview()initializes the print preview dialog which further calls
PrintPreviewHelper::Initialize()which generates the
browser_inforequired by print preview
CefPrintViewManagerBaseand its associated methods from
CefPrintViewManager. Those methods are redundant after the print preview changes
- Check for
CefPrintRenderFrameHelperDelegate::IsPrintPreviewEnabled()to determine whether print preview is enabled
- Add chromium patch to fix errors in debug build
My Contribution to CEF Print Preview
After I took over the CEF print preview work I did a number of changes to print preview, specs of which is documented below
print_preview_resources.pakin BUILD.gn to fix blank screen error which came from chromium v72 onwards because of updated print preview UI
CefContentBrowserClient::AppendExtraCommandLineSwitches()to disable print preview on using
--disable-print-previewcommand line switch
print_header_footer_1478_1565chromium patch since it’s no longer required to disable print preview by default
web_modal::WebContentsModalDialogHostinterface methods. Move it in a separate header and cc file
- Add support for disabling print preview via chromium preferences
- Disable print preview for OSR mode
- For ui print this is done by using
- For scripted print this is done by passing the
CefContentRendererClient::MaybeCreateBrowser()method in content_renderer_client.cc
- For ui print this is done by using
DownloadPrefs::FromBrowserContextfor CEF use case. Add
CefBrowserContextand use that to get the
- Fix MacOS build. Add
GetNativeView()method for MacOS platform delegate and update
- Disable print preview for MacOS (in
extensions::PrintPreviewEnabled()) since the print dialog crashes on print
- Disable print preview if pdf extension is not enabled
- Use CEF file chooser instead of chromium while saving to pdf in print preview. Add
Integrating print preview was a big and non-trivial change in CEF since not only it needed good understanding of the printing code in chromium but also the print preview feature was getting constant updates from Chromium. The code was constantly changing with every chromium version released and the print preview chromium documentation was outdated.
CEF3 has a multiprocess architecture similar to chromium’s documented here . There is a main browser process and multiple renderer processes. Debugging multiprocess applications can be trickier. I used Visual Studio which made things a bit easier as it has the Child process Debugging power tool which is a extension that would automatically attach Child processes and helped to debug into the child processes whenever they spawned up.
The chromium v72 version introduced a new print preview UI which broke the renderer, we got a blank screen in print previw. It took weeks to figure out what was wrong. Finally it came out that a pak file was missing which needed to be included in BUILD.gn. I had to spend multiple debugging session with my team to figure that out.
Also it had to be supported for all platforms (Windows, Linux, macOS) to qualify to be merged to the CEF upstream repo. Each platform had a different way of rendering dialogs. Though the windows support was working the Linux and MacOS weren’t supported in the changes yet. I added the support for Linux platform after building CEF in a linux VM. The MacOS support finally didn’t work out and we had to keep using legacy print for Mac platform. Though I needed to ensure the change built fine in Mac, so I had to build it for Mac as well (I was given a separate Mac machine just because of this since Mac doesn’t ship VM images) and in fact the change broke the MacOS build so the issues had to be fixed.
Even after all these changes the functionality broke after a architectural change was made in CEF in version 3770 (supported chromium v75) in this commit which rendered blank screen during print preview. Marshall took over the work from there and made a number of changes in the patch which can be seen in this PR chromiumembedded/cef#126 . The change was added manually in master revision 1669c0a on 20th July. It will be supported from the next CEF version (supported chromium v77). The current implementation supports print preview in Windows and Linux platforms via a