cisen / blog

Time waits for no one.
134 stars 20 forks source link

servo相关文件收集备份 #618

Open cisen opened 5 years ago

cisen commented 5 years ago

Servo 的目录结构

来源:https://github.com/anjia/blog/issues/4

Servo 的目录结构 components bluetooth 实现蓝牙线程 bluetooth_traits 考虑到构建速度,提取出来的一些 API canvas 实现绘制 2d 和 WebGL 的线程 canvas_traits 考虑到构建速度,提取出来的一些 API compositing 集成OS窗口/渲染和事件循环 constellation 管理高级浏览上下文(比如页签)的资源 devtools 进程内服务器,允许通过远程Firefox开发人员工具客户端操作浏览器实例 devtools_traits 考虑到构建速度,提取出来的一些 API gfx 绘制布局页面的结果,并将结果发送到合成器 gfx_traits 考虑到构建速度,提取出来的一些 API layout 将页面内容转换成定位的样式框,并将结果传送到渲染器 layout_thread 运行布局线程,并和脚本线程进行通信,同时调用布局包进行布局 layout_traits 考虑到构建速度,提取出来的一些 API msg 共享API,用于特定线程和crates间的通信 net 网络协议的实现,状态和资源管理(缓存,cookie等) net_traits 考虑到构建速度,提取出来的一些 API plugins 语法扩展,自定义属性和lint profile 内存和时间的分析器 profile_traits 考虑到构建速度,提取出来的一些 API script DOM 的实现(原生 Rust 代码,绑定到 SpiderMonkey) script_layout_interface 脚本包提供给布局包的 API script_traits 考虑到构建速度,提取出来的一些 API servo 入口,包括 servo 应用程序和 libservo 嵌入库 style API,为解析 CSS、样式表和样式元素间的交互 style_traits 考虑到构建速度,提取出来的一些 API util 整个项目中常用的各种实用方法和类型 webdriver_server 进程内服务器,允许通过 WebDriver 客户端操作浏览器实例 etc 对开发人员有用的工具和脚本 mach 一个帮助开发人员执行任务的命令行工具 ports glutin glutin 窗口库的实现 python servo servo 专用的 mach 命令的实现 tidy 在合并更改之前自动运行的 Python 包代码 lints resources 运行时使用的文件。在分发二进制构建时需要以某种方式包含 support android 构建 Android 平台时,需要特殊处理的库 rust-task_info 用于获取进程内存使用情况信息的库 target debug 构建由 ./mach build --debug 生成的东东 doc 当运行 ./mach doc 时,由 rustdoc 工具生成的文档 release 构建由 ./mach build --release 生成的东东 tests dromaeo 自动运行 Dromaeo 测试套件的 Harness heartbeats 心跳检测的工具 html 手动测试和实验 jquery 自动运行 jQuery 测试套件的 Harness power 用于测量功耗的工具 unit 单元测试,使用 rust 的内置测试线 wpt W3C web-platform-tests 和 csswg-tests,以及运行它们和预期错误的工具 主要依赖 https://github.com/servo/rust-mozjs/, https://github.com/servo/mozjs/: 绑定到 SpiderMonkey https://github.com/hyperium/hyper/: HTTP 实现 https://github.com/servo/html5ever/: HTML5 解析器 https://github.com/servo/ipc-channel/: IPC 实现(进程间通信) https://github.com/PistonDevelopers/image/: 图像解码器 https://github.com/tomaka/glutin/: 跨平台窗口和输入 https://github.com/servo/rust-azure/: 绑定到 Moz2D/Azure(跨平台 2D 渲染库) https://github.com/servo/rust-cssparser/: CSS 解析器 https://github.com/servo/rust-selectors/: CSS 选择器匹配库 https://github.com/cyderize/rust-websocket/: WebSocket 协议实现 https://github.com/servo/rust-url/: URL 规范的实现 https://github.com/servo/webrender/: GPU 渲染器 参考 https://github.com/servo/servo/blob/master/docs/ORGANIZATION.md

cisen commented 5 years ago

Servo 的环境搭建

来源:https://github.com/anjia/blog/issues/5 需要安装的软件 以 MAC 为例:

Homebrew 一个软件包管理工具,让 Mac 上安装软件变得方便 它是将软件安装到自己的目录,然后再软链到 /usr/local Python 和 pip 若是用 brew install python 安装的 python,则会自动安装 pip pip 是 Python 的包管理工具 版本的灵活选用,非常方便 python --version 是电脑里默认的 python 版本 python3 --version 则是直接调用 python3 pip3 --version 则是直接调用与 python3 匹配的包管理 pip Rust 和 Cargo 安装 rustup,它是 Rust 语言的 installer rustup 会自动安装 Rust 和 Cargo Cargo 是 Rust 的包管理(非常方便且强大的工具,类似 npm 于 node) 安装其它依赖,详见 https://github.com/servo/servo#other-dependencies brew install automake pkg-config python cmake yasm pip3 install virtualenv,或者需要加选项 --user 构建 Servo,详见 https://github.com/servo/servo#building ./mach build --dev 0:38:02 ./mach build --release 0:42:16 virtualenv 能创建一个隔绝的 python 环境(新的文件夹),里面包含所有必要的可执行文件,诸如对应的 Python 和 pip 等。

e.g.

1. 安装 homebrew

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2. 安装 Python 和 pip

brew install python # Homebrew 会安装 pip3, pip3 是 Homebrew 版 Python 3 的 pip 的别名 python3 --version # Python 3.5.2 pip3 --version # pip 18.0 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)

4. 安装 virtualenv

pip3 install virtualenv virtualenv --version # 16.0.0

安装 proxychains-ng

brew install proxychains-ng # pywb 要用代理模式

run with proxychains4,

e.g. Python

python # 将打开 python 解释器 python2 # python2 解释器 python3 # python3 解释器 python --version python3 --version e.g. virtualenv

virtualenv -p python3 venv # 指定python的版本,用virtualenv创建一个虚拟环境,虚拟环境的名字是“venv”,会创建一个文件夹,包含了python的可执行文件+pip库的拷贝,这样就随便安装其它包了) source venv/bin/activate # 激活虚拟环境 pip3 install git+https://github.com/ikreymer/pywb.git

4.1 为工程创建一个虚拟环境

cd my_project_folder virtualenv my_project # 会在当前的目录中创建一个文件夹

包含了Python可执行文件,以及 pip 库的一份拷贝,这样就能安装其他包了。

虚拟环境的名字(my_project)可以是任意的,若省略则会将文件均放在当前目录

or

virtualenv -p /usr/bin/python2.7 my_project # 指定python解释器

4.2 开始使用虚拟环境,需要先被激活

source my_project/bin/activate

4.3 停用虚拟环境,如果您在虚拟环境中暂时完成了工作

$ deactivate # 这将会回到系统默认的Python解释器,包括已安装的库也会回到默认的。 rm -rf my_project # 要删除一个虚拟环境,只需删除它的文件夹

然后过了一段时间,你可能会有很多个虚拟环境散落在系统各处,有可能已经忘了它们的名字/位置

还有其它工具,方便你管理虚拟环境。略。

e.g. Rust 的 Hello world

cargo 和 rust 语言及其编译器 rustc 本身的各种特性紧密结合

基本上 rust 开发管理中所需的手段,cargo 都有

$ cargo new hello_world --bin

使用 cargo new 在当前目录下新建了基于 cargo 管理的 rust 项目

项目名称为 hello_world

--bin 表示该项目将生成可执行文件

$ cd hello_world $ tree . # 瞄眼目录结构

$ cargo build # cargo 自动构建好全部 $ cargo run # 运行

$ cargo clean # 清理 target 文件夹 $ cargo update # 根据 toml 描述文件重新检索并更新各种依赖项的信息,并写入 lock 文件 $ cargo install # 实际的生产部署

两个核心文件:

cargo.homl 项目数据描述文件,直接面向rust开发人员,决定了项目如何构建、测试、运行

cargo.lock 项目依赖详细清单文件,一般不管

cisen commented 5 years ago

Servo 的设计架构

来源:https://github.com/anjia/blog/issues/3 Quantum 初探:介绍了 Quantum 项目的由来和概况,也顺便介绍了 Servo 的小历史 Servo 的设计架构:即本篇文章,将介绍 Servo 的基于任务的设计架构,重点介绍并行并发的策略 Servo 的设计架构 对,我就是 Servo 的官方 Logo

Servo 是一款现代化的高性能浏览器引擎,既支持常规应用,也支持嵌入使用。官网 https://servo.org

她由 Mozilla 开发,由三星集团移植到 Android 系统和 ARM 处理器,旨在创造一个大规模并行计算的环境,Servo 也与 Rust 编程语言有着共生的关系。源自 https://zh.wikipedia.org/wiki/Servo

  1. 设计简介 Servo 是一个新的 Web 浏览器引擎。她的目标是创建一个多层级的高并发架构,同时在架构层面消除与错误的内存管理、数据竞争相关的常见 bug 和安全漏洞。

因为 C++ 不适合处理这类问题,所以 Servo 是用 Rust 语言编写的。Rust 在设计的时候充分考虑了 Servo 的需求,它提供了任务并行的基础架构和强类型系统,从而保证了内存安全、避免了数据竞争。

在设计的时候,Servo 的架构师们会优先考虑现代 Web 平台的以下特性:高性能、动态、富媒体应用,可能会牺牲一些无法优化的特性。他们想知道一个快速响应的 Web 平台是什么样子的,然后再实现它。

Servo 专注于实现一个功能完备的 Web 浏览器引擎和可靠的嵌入式引擎,前者(Web 浏览器引擎)使用了基于 HTML 的用户界面 Browser.html。尽管 Servo 最初只是一个研究型项目,但在开发它的时候就以提供可用于生产环境的代码为目标。目前,Servo 的一些组件已经迁移到了 Firefox 浏览器。

关于集成到 Firefox 中的 Servo 组件,可查看 Jack Moffitt 的演讲视频 Web Engines Hackfest

并行并发的策略 并发是拆分任务以便交叉执行;并行是同时执行多个任务以提高速度。Servo 在以下环节中用到了并行和并发。

基于任务的架构:系统的主要组件应该有独立的堆,以便有明确的失败/恢复的边界。这也让整个系统的耦合度降低,以便可以轻松地替换掉某些组件,供我们实验和研究。 并发渲染:将渲染和合成从布局中分离出来,以保证良好的响应性。渲染和合成都是单独的线程;合成线程手动管理自己的内存,以避免垃圾回收暂停。 瓦片渲染:将屏幕划分成瓦片网格,并行渲染每一个瓦片。暂且忽略由此带来的收益,移动端渲染的时候是需要这种瓦片的。 层渲染:将显示列表分成子树,并行渲染子树,并将其内容保留在 GPU 上。 选择器匹配:这是一个令人尴尬的并行问题。与 Gecko 不同,Servo 在流树结构的单独传递中进行选择器匹配,这样会让并行更容易。 并行布局:通过并行遍历 DOM 来构建流树,这种遍历遵守由元素(比如浮动元素)生成的顺序依赖关系。 文本形状:作为内联布局的关键部分,文本形状的成本非常高,它很有并行的潜力。未实现。 解析:用 Rust 新写了一个 HTML 解析器,专注于安全性和符合规范。尚未在解析中添加预测性和并行性。 图像解码:并行解码多个图像非常简单。 其他资源的解码:这可能不如图像解码重要,但页面加载的所有内容都是可以并行处理的,比如解析整个样式表、解码视频。 GC JS 和布局的并发:在大多数具有并发 JS 和布局的设计中,当查询布局的时候,JS 有时需要等待,而且有可能是非常频繁的。这将是运行 GC 的最佳时机。 GC,Garbage Collection,垃圾回收

挑战 库不利于并行:用到的一些第三方库在多线程环境下不能很好地运行;字体尤其困难;即使从技术角度讲库是线程安全的,但是,通常是通过库的互斥锁来实现线程安全的,而这不利于实现并行。 线程太多:如果在各个方面都抛到最大的并行量和并发量,那么最终会因为线程太多而压垮系统。

  1. 任务架构 tasks-sup 图1. 任务监管图,源自 servo/wiki/Design

tasks-comm 图2. 任务通信图,源自 servo/wiki/Design

每一个框代表一个 Rust 任务 (注:一个任务就是一个线程) 蓝色框是浏览器管道里的主要任务 灰色框是浏览器管道的辅助任务 白色框是 worker 任务,它表示会有多个任务,具体的任务数要根据工作量来确定 虚线表示主管关系 实线表示通信信道 说明 我们可以把每个 constellation(见“附录.术语”小节)实例看做是浏览器的单个页签或者窗口,它管理着接收输入的任务管道,针对 DOM 运行 JavaScript,执行布局,构建显示列表,将显示列表渲染到瓦片上,最后把最终图像合成到屏幕上。

这个管道由四个主要任务组成:

脚本(Script):创建和拥有 DOM,执行 JavaScript 引擎。它接收来自多个源的事件,包括导航事件。当内容任务(Content)需要查询布局相关的信息时,脚本任务必须向布局任务发送一个请求。每个内容任务都有自己的 JavaScript 运行时。 布局(Layout):获取 DOM 快照,计算样式,构造主要的布局数据结构-流树(flow tree)。流树用于计算节点的布局,从它那可以构建显示列表,显示列表会被发送到渲染任务。 渲染(Renderer):接收显示列表,并将可见部分渲染到一个或多个瓦片上,尽可能并行。 合成(Compositor):合成渲染的瓦片,并将它们发送到屏幕上进行显示。作为 UI 线程,合成任务也是 UI 事件的第一个接收器,UI 事件通常会被立即发送到内容任务以供处理(尽管一些事件,比如滚动事件,首先由合成任务处理并响应)。 管道中的多任务通信涉及到两种复杂的数据结构:DOM 和显示列表。DOM 从内容传到布局,显示列表从布局传到渲染。找出一种有效且类型安全的方式来表示、共享和传递这两种数据结构是该项目的诸多挑战之一。

写时复制 DOM Servo 的 DOM 树节点是有版本控制的,它们可以在单个 writer 和多个 reader 之间共享。DOM 使用写时复制(copy-on-write)的策略允许当有多个 reader 时 writer 也能修改 DOM。writer 总是内容任务,reader 总是布局任务或其子任务。

DOM 节点是 Rust 值(Rust value),而 Rust 值的生命周期由 JavaScript 垃圾收集器管理。JavaScript 直接访问 DOM 节点,而没有依赖 XPCOM 或其它类似的基础设施。

DOM 接口目前不是类型安全的,这可能会导致不正确的节点管理。消除这类不安全是该项目的一个必要的高优先级目标;由于 DOM 节点具有复杂的生命周期,这将会带来一些挑战。

显示列表 Servo 的渲染完全由显示列表驱动,显示列表是由布局任务创建的一系列高级绘图命令。Servo 的显示列表是完全不可变的,因此它可以被同时运行的多个渲染任务所共享。这与 Webkit 和 Gecko 的渲染器不同:WebKit 的渲染器没有使用显示列表;Gecko 的渲染器使用了显示列表,但它在渲染期间还会查询额外的信息。

  1. JavaScript 和 DOM 绑定 目前,Servo 使用的脚本引擎是 SpiderMonkey(可插拔引擎是一个长期的、低优先级的目标)。每个内容任务都有自己的 JavaScript 运行时。DOM 绑定使用原生的 JavaScript 引擎 API 而不是 XPCOM。从 WebIDL 自动生成绑定是一个高优任务。

  2. 多进程架构 与 Chromium 和 WebKit2 类似,Servo 的架构师们打算做一个可信任的应用程序进程和多个不太可信的引擎进程。高级 API 实际上是基于 IPC 的,非 IPC 实现可能用于测试和单进程用例(虽然预计最糟糕的时候也会用于多进程)。引擎进程将使用操作系统沙箱工具来限制对系统资源的访问。

目前,Servo 并不打算像 Chromium 那样采用极端沙箱(extreme sandboxing),主要是因为锁定沙箱会导致大量的开发工作(特别是在 Windows XP 和旧版 Linux 等低优先级的平台上),并且该项目的其它方面的优先级更高一点。Rust 的类型系统还为内存安全漏洞增加了一层重要的防御功能,虽然仅凭这一点并不能使沙箱在防御不安全代码、类型系统中的错误以及第三方/主机库等方面变得不那么紧迫,但相对于其他浏览器引擎它确实能显著减少 Servo 的攻击面。此外,Servo 的架构师们对某些沙箱技术有性能方面的顾虑(例如,将所有 OpenGL 调用代理到单独的进程)。

  1. I/O和资源管理 网页依赖于各种各样的外部资源,而这些资源具有很多的检索和解码机制。这些资源会被缓存在多处,比如磁盘、内存。在并行浏览器的设置中,这些资源一定会在并发的多个 worker 之间调度。

通常,浏览器是单线程的,会在“主线程”上执行 I/O,而“主线程”同时又担负着大部分的计算任务,这就会导致延迟问题。而 Servo 中没有“主线程”,所有外部资源的加载都由一个资源管理任务来处理。

浏览器有很多缓存,而 Servo 的基于任务的架构意味着它可能会拥有比现有浏览器引擎还多的缓存(例如,我们在拥有全局任务缓存的同时,也拥有着一个本地任务缓存,它存储着来自全局缓存的结果,以通过调度程序来保存往返记录)。Servo 应该有一个统一的缓存机制,以便在低内存的环境中也运行良好。

附录. 术语 constellation:该线程控制相关网页内容。在支持多页签的浏览器中,可以把它当做单个页签的拥有者;它封装了会话历史记录,知道 frame 树中的所有 frame,是每个 frame 管道的拥有者。 管道(pipeline):为特定文档封装了脚本线程、布局线程和渲染线程之间的通信。每个管道都有一个全局唯一的 id,可以从 constellation 里访问到它。 脚本线程/脚本任务(script thread/script task):这个线程执行 JavaScript,并存储同源下所有文档的 DOM 表示。它可以把从 constellation 接收到的输入事件转换为规范里定义的 DOM 事件,也可以在收到新页面的时候调用 HTML 解析,也可以为事件评估 JS。 布局线程(layout thread):这个线程负责将 DOM 树布局到特定文档的层(layer)上。它会收到来自脚本线程的命令,要么是为渲染线程生成一个新的显示列表,要么是为脚本线程返回页面的布局结果。 显示列表(display list):一个具体的渲染说明(高级绘图命令)列表。显示列表是发生在布局之后的,因此所有的项都有相对堆叠上下文的像素位置,并且已经应用了 z-index,所以后加入显示列表的项将始终在其它项的上面。 渲染线程/绘制线程(renderer thread/paint thread):这个线程负责将显示列表转换成一系列的绘图命令。该绘图命令会将关联文档的内容渲染在一个缓冲区里,之后会被发送到合成器。 合成/合成器(Compositor):负责 Web 内容的合成渲染,并将它们尽可能快地显示在屏幕上。也负责从操作系统接收输入事件,并将它们转发到 constellation 线程。 小结 本文主要介绍了 Servo 的设计概况,重点介绍了它基于任务的整体架构及其四个主要任务(也称“线程”,在 Servo 的这个上下文里),即脚本任务、布局任务、渲染任务、合成任务。下图便是对上述内容的一个总结,希望对大家有所帮助和启发。

servo 图3. Servo 概况

下一步 后续,我会继续探索更多详细内容,敬请期待。关于 Quantum 和 Servo,如果您有其它更想知道的,欢迎留言。

致谢 感谢 cncuckoo(李松峰老师)和 liuguanyu(二哥)对本文提出的指导意见和建议。手动送花花。🌹

参考 https://github.com/servo/servo/wiki/Design https://github.com/servo/servo/blob/master/docs/glossary.md

cisen commented 5 years ago

Servo 的 style 系统

Servo 的 style 系统 style 的文档 style 概况:是 Boris Zbarsky 和 Patrick Walton 之间的对话,关于style 如何共享 selector 的实现 style 系统通用了很多东西,为了能和 Servo 的 layout 系统、Stylo 共享(Stylo 项目旨在把 Servo 的 style 系统集成到 Gecko 中) 主要的通用特性是选择器的 SelectorImpl,这里有解析伪元素和其它伪类的所有逻辑。对应的规范是 Selectors Level 4 / Tree-Structural pseudo-classes Servo 扩展了这一特性,以便在 Stylo 和 Servo 间分享更多的东西 主要的 Servo 实现(用在常规构建中)是 SelectorImpl DOM glue(胶水) 为了让 DOM、layout 和 style 能在不同的模块库里,这里涉及了一些特性 style 的 dom 特性(TDocument TElement TNode TRestyleDamage)就是 layout 和 style 之间的主要的“墙” layout 的 wrapper 模块可确保 layout 的特性 stylelist stylelist 结构保存文档的所有选择器和设备特征 样式表的 CSS 规则被转成 Rule,并根据伪元素(见 PerPseudoElementSelectorMap)、样式表的来源(见PerOriginSelectorMap)和优先级(见PerOriginSelectormap的normal和important字段),将其引入到 SelectorMap 每个 pipeline 创建一次 stylelist 结构,在该管道对应的 LayoutThread 中 properties 模块 properties 模块是一个 mako 模板,所有 properties、computed value 的计算和层叠逻辑都在那 它是一个包含大量代码的复杂模板。主函数是 cascase 函数,这里执行所有计算 伪元素的处理 介绍 伪元素是 style 系统中棘手的一块。并非所有的伪元素都非常常见,因此有些伪元素可能会跳过层叠 截止目前,Servo 有五个伪元素 ::before 和 ::after ::selection ::-servo-details-summary ::-servo-details-content 两个 ::-servo-details- 伪类都是私有的,i.e. 它们只解析来自 User-Agent 样式表里的 Servo 有三个不同的方式去层叠伪元素,它们定义在 PseudoElementCascadeType Eager 层叠 这个模块计算 computed values 给定节点的伪类,通过 style 系统的第一个 pass 这用于所有的伪类元素,到目前为止,它是唯一方式一个公共的伪元素应该被层叠(关于它的解释见下方) Precomputed 层叠 根本就没有层叠。被标记为这样的伪元素不被层叠 应用于这类伪类元素的唯一规则是全局规则(|选择器的规则),它们被直接应用到元素的 style,如果展示 ::-servo-details-content是这种伪类元素的一个例子,在 UA 样式表中的所有规则-有选择器 |::-servo-details-content(也仅有这些)被评估通过元素的style(除去display的值,那会被layout重写) 私有伪类元素的首选类型(尽管它们中的而一些可能需要选择器,往下看) Lazy 层叠 Lazy 层叠允许懒计算伪元素的样式,即,仅在需要的时候才会计算 目前(对于 Servo,对于 stylo 而言不是那么多),支持这种伪元素的选择器只是可以在布局树上匹配的选择器的子集,它不能保存来自 DOM 树的所有数据 该子集包括标签和属性选择器,足以制作::-servo-details-summary lazy伪元素(关于它,只需要知道它是否在open细节元素中) 由于没有其他选择器适用于它,这(至少现在)不是公共伪元素的可接受类型,但应考虑用于私有伪元素 https://github.com/servo/servo/blob/master/docs/components/style.md

cisen commented 5 years ago

Quantum 初探

Quantum 初探:即本篇文章,将介绍 Quantum 项目的由来和概况,引出它的强大“后台” Servo Servo 的设计架构:介绍了 Servo 的基于任务的设计架构,重点介绍了并行并发的策略 Quantum 初探 quantum 这个词来自拉丁语 quantus,意思是 how great - 多么伟大

Quantum 是 Mozilla 为了构建下一代 Web 引擎的项目。在正式介绍它之前,我们需要先了解一些浏览器的相关知识。

浏览器相关 浏览器的结构

图1. 浏览器结构,源自 How Browsers Work

用户界面(User Interface):除了用于显示网页内容的视口之外,你能看到的其它所有部分都属于用户界面,诸如地址栏、前进/后退按钮、书签菜单等。 浏览器引擎(Browser Engine):在用户界面和渲染引擎之间传送指令。 渲染引擎(Rendering Engine):负责显示浏览器请求回来的资源内容。资源可以是 HTML 文档、PDF、图片或其它类型,它们的位置都是用 URI 指定的。如果请求的资源是 HTML,那渲染引擎就负责解析 HTML 和 CSS,并将解析后的内容显示在屏幕上。 网络(Networking):负责网络调用,比如 HTTP 请求。不同平台的实现会有所差异。 JS 解释器(Javascript Interpreter):用于解析和执行 JavaScript 代码。 用户界面后端(UI Backend):用于绘制基础小部件,比如组合框和窗口等。此层会公开平台无关的通用接口,而它的底层则是调用操作系统的用户界面方法。 数据持久化存储(Data Persistence):浏览器的客户端持久化存储,诸如 Cookie、Local Storage、Session Storage、 IndexDB、WebSQL 等。 渲染引擎 渲染引擎(Rendering Engine)也叫布局引擎(Layout Engine)。浏览器的渲染引擎,有时也简称为浏览器引擎(Browser Engine)。

注意:这里的 Browser Engine 不同于图1中的 Browser engine

所以,以下名词往往是等价的: 浏览器的渲染引擎 ~ 浏览器引擎 ~ 渲染引擎 ~ 布局引擎

主流浏览器用到的渲染引擎如下:

浏览器 渲染引擎(开发语言) 脚本引擎(开发语言)
Chrome Blink (c++) V8 (c++)
Opera Blink (c++) V8 (c++)
Safari WebKit (c++) JavaScript Core (nitro)
FireFox Gecko (c++) SpiderMonkey (c/c++)
Edge EdgeHTML (c++) Chakra JavaScript Engine (c++)
IE Trident (c++) Chakra JScript Engine (c++)

之所以列出“脚本引擎”,旨在强调渲染引擎不负责 JS。对 JS 的解释和执行是由独立的引擎完成的,比如大名鼎鼎的 V8 引擎。

对 HTML 文档来说,渲染引擎的主要任务就是解析 HTML 和 CSS,再把最终的结果绘制到屏幕上。

下面是各个渲染引擎的时间线,我们可以很直观地看出她们的生日和年龄。其中,Trident、KHTML、Presto 已经停止更新;Gecko、WebKit、Blink 和 Edge 依然在持续更新中。

图2. 浏览器引擎,源自维基百科 Browser engine

Quantum 背景 2013年,Mozilla 启动了一项研究型项目 Servo。这是一个从零开始设计的浏览器引擎,目标是提高并发性和并行性,同时减少内存安全漏洞。它是由 Rust 语言编写的,而 Rust 有更好的内存安全属性和并发功能。

2016年4月,考虑到 Servo 还需要几年才能成为功能完备的浏览器引擎。所以,Mozilla 决定启动 Quantum 项目,将 Servo 的稳定部分带到 Firefox 里。

关于集成到 Firefox 中的 Servo 组件,可查看 Jack Moffitt 的演讲视频 Web Engines Hackfest

Quantum 项目 Gecko 是 Mozilla 的一个成熟且功能健全的 Web 浏览器引擎,它起源于1997年的 Netscape。Mozilla 采用渐进式的方法,将 Servo 里已稳定的组件迁移到 Gecko 中,用户将不必等很长时间就能看到 Firefox 在稳定性和性能上的显著改进。

2017年11月发布的 Firefox 57 是第一版启用了 Servo 组件的浏览器,之后便在此版本的基础上进行迭代开发。

Quantum 以 Gecko 引擎为基础,同时利用了 Rust 的良好并发性和 Servo 的高性能组件,为 Firefox 带来了更多的并行化和 GPU 运算,让 Firefox 更快更可靠。

多个子项目 Quantum 是一个将 Mozilla 的多个社区及其代码仓库联系在一起的大项目,它包含多个子项目:

rust-bindgen:是 Rust 语言的 C++ 绑定生成器。Quantum 用它生成的代码,可用在 Firefox 的 C++ 代码和 Servo 的 Rust 组件之间。感兴趣的朋友可以查看 Contributing to rust-bindgen。 Quantum CSS:也叫 Stylo,旨在把 Servo 的并行 CSS 系统集成到 Gecko 中,可以充分利用多核 CPU 的硬件特性。 Quantum Render:旨在将 WebRender 作为 Firefox 的图形后端。WebRender 是 Servo 针对 GPU 渲染进行了优化的下一代渲染器,它用保留模式模型替换立即模式绘制模型,通过利用 CSS/DOM 和场景图的相似性,让 GPU 加速更容易。 Quantum Compositor:将 Gecko 现有的合成器移到自己的进程中,将图形驱动程序相关的崩溃和浏览器页签隔离开来,以让 Firefox 更稳定。此特性已经在 Firefox 53 里发布了。 Quantum DOM:在 DOM 中使用协同调度线程来提高响应速度,而不用增加进程数和内存,这会让 Gecko 更具响应性,尤其是当有大量后台页签打开的时候。不同页签(也可能是不同 iframe)的 JS 代码将运行在独立的线程中,某些后台页签的代码将永远不会被运行。更多可查看 Bill McCloskey 的博客。 Quantum Flow:探讨了目前尚未被涵盖的性能改进,例如 UI 性能优化。 下一步 至此,大家对 Quantum 项目的由来和概况有了初步的认识。后续,我会继续探索更多详细内容。敬请期待。

参考 https://wiki.mozilla.org/Quantum https://en.wikipedia.org/wiki/Quantum_(Mozilla) https://en.wikipedia.org/wiki/Browser_engine https://www.html5rocks.com/en/tutorials/internals/howbrowserswork