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.

Servo: The Embeddable Browser Engine的更多相关文章

  1. Vedis - An Embeddable Datastore Engine

    Vedis - An Embeddable Datastore Engine     An Embeddable Datastore Engine         Tweet        Follo ...

  2. 关于Servo项目中Rust代码行数的数据来源

    我两个月之前的一篇博客<为什么我说Rust是靠谱的编程语言>(下面简称原文),在当中"6. 两个半大型成功案例"一节.我以前写道: Servo: 下一代浏览器渲染引擎( ...

  3. Browser Page Parsing Details

    Browser Work: 1.输入网址.  2.浏览器查找域名的IP地址.  3. 浏览器给web服务器发送一个HTTP请求  4. 网站服务的永久重定向响应  5. 浏览器跟踪重定向地址 现在,浏 ...

  4. Architecture options to run a workflow engine

    This week a customer called and asked (translated into my own words and shortened): “We do composite ...

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

    一.A web browser engine A rendering engine is software that draws text and images on the screen. The ...

  6. 实现ECMAScript的引擎

    list of ECMAScript engines From Wikipedia, the free encyclopedia     An ECMAScript engine is a progr ...

  7. SharpBrowser

    SharpBrowser is the fastest open source C# web browser there is! Slightly faster than Google Chrome ...

  8. OSCP Learning Notes - Privilege Escalation

    Privilege Escalation Download the Basic-pentesting vitualmation from the following website: https:// ...

  9. Web自动化测试工具调研

    背景 Web自动化测试越来越被重视, 因为现在Web已经是工程化的状态. 如何通过工具测试, 保证Web开发的质量,提升开发效率,是Web工具的诞生的来由. Web测试分为以下几个方面: 1. 界面测 ...

随机推荐

  1. vim的全局替换

    本文出自   http://blog.csdn.net/shuangde800 本文是在学习<使用vi编辑器, Lamb & Robbins编著>时在所记的笔记. 本文内容: 基本 ...

  2. c语言中的 %u 什么意思啊?

    %d 有符号10进制整数 %i 有符号10进制整数 %o 无符号8进制整数 %u 无符号10进制整数 %x 无符号的16进制数字,并以小写abcdef表示%X 无符号的16进制数字,并以大写ABCDE ...

  3. Windows下Memcached在.Net程序中的实际运用(从Memcached客户端Enyim的库的编译到实际项目运用)

    1.一点基础概念 2.获取EnyimMemcached客户端的源代码并编译出动态库 3.Memcached的服务器安装(windows server) 4.在web项目中实战 一.基础概念 memca ...

  4. Java基础知识强化之集合框架笔记55:Map集合之HashMap集合(HashMap<Integer,String>)的案例

    1. HashMap集合(键是Integer,值是String的案例) 2. 代码示例: package cn.itcast_02; import java.util.HashMap; import ...

  5. Android(java)学习笔记195:三重for循环的优化(Java面试题)

    1.首先我们看一段代码: for(int i=0;i<1000;i++){ for(int j=0;j<100;j++){ for(int k=0;k<10;k++){ testFu ...

  6. VOL.1 利用vmware ThinApp 制作非XP下可以运行的IE6 【无插件版】(windows vista/7/8 x86/x64 )

    作为一名前端开发工程师,不免要考虑IE6的兼容性,但是大部分挑剔的同行们估计都不会用XP,所以基本上IE6的兼容性测试,都是使用IE Tester或者虚拟机. IE Tester的话,很多地方模拟的还 ...

  7. 项目打包 weblogic部署

    工作流打包:   由于没有集成单点,配置文件要修改 将webnocas.xml内容复制覆盖 web.xml   到这里修改完毕 选择weblogic项目,右键maven install,生成.ear文 ...

  8. sendkeys && appactivate

    sendkeys    用于输入键盘按键 appactivate 用于聚焦程序 on error resume next set ws = createObject("wscript.she ...

  9. Android pulltorefresh引用遇到的一个问题

    今天在使用pulltorefresh插件的时候遇到了一个让人头疼的问题,在Eclipse中导入要用到的library项目,然后新建一个项目引入Library,显示的是引入成功,如图 而且project ...

  10. .NET下的加密解密大全(2):对称加密

    本博文列出了.NET下常用的对称加密算法,并将它们制作成小DEMO,希望能对大家有所帮助. 公共代码[csharp]static byte[] CreateKey(int num) {     byt ...