Servo: The Embeddable Browser Engine

Embedding, in the context of this article, is the process of hosting a web rendering engine inside another application. This engine displays content exactly as a regular web browser would, but allows the application author to customize the user’s experience further than what is possible in the typical display of a normal website. Development time can be reduced by keeping part of the content of an application in web-related languages due to the relative ease of writing web content and the widespread knowledge of HTML5.

The technique of embedding web content is used in many places by many companies, including:

  • Popular Linux applications such as Rhythmbox, Kate, Eclipse, and Evolution have support for embedding web content.
  • Microsoft Entourage and Apple Mail for Mac OS both utilize embedding for displaying web content and parts of the UI.
  • Adobe products, including their constantly-running updater, embed full web runtimes.
  • Valve’s Steam client also depends heavily on embedding web content, as they reuse the content from their online store to display in their native application.
  • Many applications in mobile app stores are simply a native wrapper around a web browser control and HTML5 resources.

HTML5 has been gaining significant traction in the mobile and embedded world. According to a recent survey HTML5 is a leading platform for application development in all markets, and this figure is likely to increase as the number of mobile platforms grows in the future. Finally, HTML5 is a widely known cross-platform solution which guarantees portability.

The Need for A Common, Embeddable API

There are very few common APIs for embedding content into applications, and until a couple years ago, the most prevalent API was WebKit. This was problematic because WebKit’s API is not considered stable, forcing developers to rewrite parts of their application in order to keep up with changes in the underlying browser engine. In recent years, Blink was forked from WebKit, creating yet another embeddable API. Unfortunately, in addition to being confined to C++, Blink’s embedding API is also not stable, perpetuating the increased workload for application developers.

One solution for these problems is to use the Chromium Embedded Framework. Launched in 2008, the project is based on the Blink browser engine but aims to completely insulate its users from underlying engine changes. It provides a base C API with C++ extensions; allowing support at the lowest levels of software development. Currently, this API is used extensively by Valve for their Steam client, and by Adobe, for various products.

The Servo Solution

The Servo browser engine aims to be embeddable in order to provide maximum flexibility to developers. To this end, it must provide a stable API and ABI for developers to rely on. It is written in Rust because it provides an API usable from C. Designing yet another embeddable web API is an extremely complex task which requires a tremendous amount of consideration and review. It also requires extensive documentation to be written, frameworks to be tested, and the resulting product to be promoted and accepted into general usage. Based on this, we decided to take a different approach.

Servo implements the Chromium Embedded Framework API: if it’s good enough for Valve, it’s good enough for us. This means developers who currently use CEF will not need to make any application changes to compare performance between the Blink and Servo engines, and prospective developers will not have yet another browser API to review and consider. Hopefully, this also means Servo will reach an embeddable state much more quickly.

The methodology for this implementation is twofold: ensure full symbol coverage, and attempt to mimic the exact functionality of each method call as closely as possible. Since this is not a common practice, let’s break it down a little further. Symbol coverage refers to the externally visible symbols provided by a library. Rust, using the extern “C” keywords, allows any function written in Rust to be directly accessible from C with no extra work needed. So in this regard, full symbol coverage would mean that every CEF function call is able to be hooked by Servo’s embedding library. It also requires that any time an externally-used struct is allocated, it must match the size and member positioning as a similar struct allocated by the real CEF.

pub struct cef_string_utf8 {
   pub str: *mut u8,
   pub length: size_t,
   pub dtor: extern "C" fn(str: *mut u8),
}

Mimicking functionality is a bit trickier. This requires full understanding of each CEF function and how it ties into the browser engine. Then, the same order of operations must be replicated using the underlying Servo browser engine. This can be quite a complex process, as CEF makes internal function calls back and forth between itself and Blink, sometimes requiring functions to operate recursively.

The method for implementing and testing the success of this endeavor has been a bit complex. First, a symbol list was needed. Using standard utilities, specifically the nm tool on Linux, we copied the undefined symbols from some of the example CEF applications. This provided an easy starting point to begin implementing functions and functionality. With the list of target symbols, it became much easier to track the execution of the application through the CEF library and determine what was happening in each function call. From here it became a case of using Rust/Servo to replicate the expected and observed behavior.

A Few Hitches Along The Way

The process of writing this implementation for embedding has not come very far because it was only recently begun; at present, there is only a very small team focusing on it. However, there have been some difficulties that may be interesting to other developers. One such difficulty that was immediately apparent was tracking the C API’s execution through the C++ extensions provided by CEF. The example applications all use the C++ extensions which required a bit of legwork to understand how they utilize and wrap the C API and what was going on internally. The solution here was extremely rudimentary, just read a whole bunch of source code. Eventually, even the most high-level wrapper would come down to one or two function calls which could then be written and tested more thoroughly.

Another difficulty that took quite a while to track down is a byproduct of the testing environment. In order to run the CEF examples with the Servo backend, we needed to use some library preloading hacks (LD_PRELOAD and friends on Linux) so the running environment would inject the Servo embedding symbols for use in the application, effectively overriding the CEF-provided functions. However, as long as the CEF library is used in any function call it will invoke the underlying Blink runtime, which uses the tcmalloc allocator. The reason this is problematic is because tcmalloc uses different function calls for allocating memory between C and C++ than what is expected, and it complains quite loudly when it detects any deviation from this behavior. As a result, the Servo embedding library needed to provide wrappers to allow calling these functions directly for memory allocation, but only when using the preload hack:

pub fn new(size: size_t) -> *mut c_void {
   unsafe {
      tc_new(size)
   }
}

The embedding support is now sufficient to run Servo within the cefsimple application, and a number of tasks are currently open to improve support in other directions. For more information check out the GitHub page.

Guest Author: Lars Bergstrom

Lars Bergstrom is a researcher at Mozilla, currently working on the servo parallel web browser project.He received his Ph.D. from the University of Chicago‘s Computer Science department, studying under Dr. John Reppy. His Master’s paper was on the implementation of analysis and optimization passes in our parallel compiler, Manticore. His Ph.D. research was on how to add mutation safely and efficiently into a functional parallel programming language. He has also been doing work on a runtime, garbage collector, and most recently some extensions to control-flow analysis. Before that, he was a manager and a developer at Microsoft in the Visual Studio organization, working on next-generation software development tools technology out at the Redmond, WA offices.

时间: 2024-10-11 16:44:15

Servo: The Embeddable Browser Engine的相关文章

Rendering Engine 主流的浏览器内核(排版引擎、渲染引擎、解释引擎)有哪几种,分别的特点

一.A web browser engine A rendering engine is software that draws text and images on the screen. The engine draws structured text from a document (often HTML), and formats it properly based on the given style declarations (often given in CSS). Example

Google Chrome Browser源代码

Google Chrome 浏览器使用的内核源码来自开源浏览器引擎 WebKit Open Source Project.Google Chrome 的源码,同样亦是开源的.在 Google 的中文官方Blog - Google 黑板报中,提到: 我们对很多开发开源项目的人心存感激,我们承诺会沿着前人的路继续前行. 我们借鉴了一些源自 AppleWebKit 和 Mozilla Firefox 的技术,怀着同样开源的精神,Google浏览器所有的代码全部开源.我们希望能与整个业界合作从而促进互联

Architecture options to run a workflow engine

This week a customer called and asked (translated into my own words and shortened): “We do composite services, orchestrating two or three CRUD-Services to do something more useful. Our architects want to use your workflow engine for this because the

浏览器的组成结构

浏览器的组成结构 用户界面(User Interface) - 包括地址栏.前进/后退按钮.书签菜单等.除了浏览器主窗口显示的您请求的页面外,其他显示的各个部分都属于用户界面. 浏览器引擎(Browser engine) - 在用户界面和渲染引擎之间传送指令. 渲染引擎(Rendering engine) - 负责显示请求的内容.如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上. 也可以叫呈现引擎(Rendering Engine)或者布局引擎(

Threads Events QObjects

Events and the event loop Being an event-driven toolkit, events and event delivery play a central role in Qt architecture. In this article we'll not give a comprehensive coverage about this topic; we'll instead focus on some thread-related key concep

浏览器的工作原理

[1]浏览器的功能:将用户选择的web资源呈现出来,需要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式通常是HTML,也包括PDF.image及其他格式,用户用URI来指定所请求资源的位置. [2]浏览器的结构 [用户接口 user interface]包括地址栏.书签选项.前进后退.刷新.暂停.主页等窗口上除了网页显示区域以外的部分 [浏览器引擎 browser engine]查询与操作渲染引擎的接口 [渲染引擎 rendering engine]显示用CSS格式化的HTML与图片 [

从零基础入门JavaScript(1)

从零基础入门JavaScript(1) 1.1  Javascript的简史 1995年的时候   由网景公司开发的,当时的名字叫livescript    为了推广自己的livescript,搭了java顺风车,改名为javascript 与此同时,     微软因此在自身的浏览器里,也推出了自己的脚本语言 jscript 1997年时候,  由ECMA(欧洲计算机制造商协会)出面,推出了一套javascript的规范,Ecmascript ,规范提出js由三部分组成 JS的组成: ECMAS

JavaScript判断浏览器类型及版本

说明:以下内容参考了一些网上资料以及同事间的一些讨论. 浏览器对于我们来说,可能是最熟悉的工具了.记得最早那会Netscape,到后来的Internet Explorer一统江湖,再到现在的FireFox大行其道,浏览器市场的争夺,可谓是硝烟弥漫.除了我们常见的IE, Firefox, Opera, Safari四大金刚以外,新近又出了一位Chrome,虽然新出,但是出于Google这个名门,Chrome所受到的关注绝不亚于先前的四大金刚,看来以后要改为5朵金花了,呵呵.除了这些熟知的浏览器以外

WebBrowser与IE的关系,如何设置WebBrowser工作在IE9模式下?

原文:WebBrowser与IE的关系,如何设置WebBrowser工作在IE9模式下? 一.问题的提出 偶然发现,Winform里的WebBrowser和IE实际安装的版本似乎并不同步,很有趣! 下面有张图,里面一个窗口是用IE9打开某网站,另一个窗口是用Winform+WebBrowser打开同样的网站,有意思的事情出现了. 在IE9窗口中,这个网站左边菜单树无法显示,原因是IE9使用的技术较新,而网站使用的技术较旧,未能及时同步更新到支持IE9所致.该如何办呢? 微软在IE9中提供一个兼容