`
hyshucom
  • 浏览: 811212 次
文章分类
社区版块
存档分类
最新评论

Chromium如何显示网页(how Chromium displays web pages)

 
阅读更多

本文档从底层原理开始介绍了Chromium如何显示网页。阅读本文之前你应该首先阅读“Chromium的多进程架构”这篇文章,重点要理解主要组件结构图。您可能也有兴趣阅读“多进程资源加载“这篇文章来了解网页是如何从网络获取的。

应用层次概念图

layers

layers

每个盒子代表一个概念中的应用层。通常情况下应该有可能通过替换任意一层及其上层组建来生成一个新的浏览器。因此,没有任何层应该与其更高层次有依赖关系。

  • WebKit的:Safari,Chromium和其他所有基于WebKit的浏览器都使用Webkit作为渲染引擎。WebKit Port是WebKit的一部分,处理与具体平台相关的操作,如资源加载和图形。
  • Glue: 将WebKit类型转换成Chromium类型 。这就是我们的“WebKit嵌入层”。这是浏览器Chromium和test_shell(允许我们测试WebKit)的基础。
  • Renderer/Render Host: 这是Chromium的“多进程嵌入层。”由它代理传递跨进程的消息和命令。你可以想象,其他的多进程浏览器也可以使用这一层,它对其他的浏览器服务没有依赖。
  • Tab contents: Chrome的特有层,来表示标签显示的内容。它与应用服务绑定, 例如密码管理器和history系统。本层不应该假设它嵌入在Chromium浏览器窗口中(还有其他Chromium组件如”HTML对话框“使用本层)。
  • 浏览器:展现浏览器窗口,它嵌入了多个TabContentses。

WebKit

我们使用 WebKit这个开源项目来展示网页。此代码主要是由Apple编写的并存放在/third_party/WebKit目录中。WebKit主要包括两部分:“WebCore”负责核心布局功能,“JavaScriptCore”用来执行JavaScript。我们只将JavaScriptCore用于测试目的,通常我们使用高性能的V8 JavaScript引擎取代它。我们实际不使用苹果称之为“WebKit”的软件层(译注:就是WebKit/Source/WebKit目录下的内容,Webkit/Source目录下同样有WebCore和JavaScriptCore目录),这个软件层用在如Safari这样的应用程序中,用来衔接WebCore和OS X。为了方便,我们通常将从Apple获取的代码称作“WebKit”。(译注,其实只使用了WebCore)

The WebKit Port

在最底层,我们有我们的WebKit“Port”。这是我们实现的平台相关的代码,它用来衔接平台和WebCore。这些文件位于WebKit目录中,通常在Chromium目录中或者以Chromium为后缀名。实际上Port的大部分代码不是和操作系统相关的:你可以把它看成是WebCore的Chromium Port(译注:用来衔接WebKit和Chromium的)。有些部分,如字体渲染,必须针对每个操作系统平台分别处理。

  • 网络流量是由我们的多进程资源加载系统处理的,而不是由渲染进程直接调用操作系统完成。
  • 图形使用为Android开发的Skia图形库。这是一个跨平台的图形库,原生的处理除了文字以外的所有图形、图像。Skia位于/third_party/skia。图形操作的主要入口点是 / WebKit/port/platform/graphics/GraphicsContextSkia.cpp。它使用了同目录及/base/gfx目录中的许多其他文件 。

WebKit glue

Chromium使用了和WebKit代码不同的类型,编码方式和代码结构。WebKit“glue”提供一个更方便的嵌入WebKit的API,以便使用谷歌编码约定和数据类型(例如我们使用std::string,而不是WebCore::String,使用GURL,而不是KURL)。glue代码位于 / WebKit/glue 。glue对象命名通常和WebKit对象类似,但以“Web”开头。例如, WebCore::Frame 成为WebFrame。

WebKit的“glue”将WebCore的数据类型和Chromium其余代码隔离,以帮助减少WebCore对Chromium代码库编程风格的影响。因此,Chromium从来不会直接使用WebCore的数据类型。glue也增加了一些API,用于Chromium直接访问WebCore对象。

“test shell”是一个用于测试WebKit Port和Glue代码的简单浏览器。它和Chromim一样使用Glue与WebKit通信。它为开发人员提供了一个测试新代码的简单方法,而不必使用许多复杂的浏览器特性,多线程以及多进程。此应用程序也被用来运行WebKit的自动测试。

渲染进程

rendering renderer2

rendering renderer2

Chromium的渲染进程中通过Glue嵌入Webit port。它的代码不是很多:它的工作主要是作为IPC通道将渲染器部分和浏览器连接.

在渲染器里最重要的类是的RenderView,位于/chrome/renderer/render_view.cc中。这个对象表示一个网页。它处理所有从浏览器进程出入的与导航有关的命令。它继承自RenderWidget,负责提供绘画和输入的处理。RenderView通过全局的(对每个渲染进程来说是全局,即每个进程一个)RenderProcess对象与浏览器进程通信。

常见问题:RenderView和RenderWidget的有什么差异?RenderWidget通过实现名为WebWidgetDelegateglue层的抽象接口WebWidgetDelegate映射到一个的WebCore::Widget这基本上是屏幕上的一个窗口,它绘制窗口并接收窗口中的输入事件。RenderView从RenderWidget继承,它表示一个标签或弹出窗口的内容。它处理所有导航命令并完成窗口绘制和响应输入事件。只有一种情况下如RenderWidget独立于RenderView存在:网页上select boxes。它是个有向下箭头和很多选项的弹出列表。在选择框必须使用原声窗口渲染,以便他们能够在显示在其他东西之上,并在必要时弹出框架。这些窗口需要绘制并接收输入,但是他们不是一个单独的“网页”(RenderView)。

渲染器中的线程

每个渲染器中运行着两个线程:渲染线程和主线程。渲染线程是RenderView和其他所有的WebKit代码运行的线程。当它和浏览器之间进行通信时,首先将消息送到主线程,然后主线程再将消息传递给浏览器进程。只有主线程收到浏览器的回复之后渲染才可以继续进行,这样可以使我们同步地将消息从渲染器传递给浏览器。例如,当页面中的JavaScript请求cookie时,渲染线程将被阻塞,主线程将所有收到的消息放入队列直到接收到浏览器的正确回复。在这期间收到的任何消息都将按照顺序发送给渲染线程进行处理。

浏览器进程

rendering browser

rendering browser

浏览器进程的底层对象

所有和渲染进程之间的通信都通过浏览器进程中的I/O线程实现的。它同样也处理所有的网络通信,这样可以不阻塞用户界面。
当主线程初始化RenderProcessHost完毕后(用户界面运行时),它建立新的渲染进程并新建名为ChanelProxy的IPC对象通过命名管道与之通信。这个对象运行于Browser的I/O线程中,监听连接到渲染进程的命名管道,并将所有消息转发到UI线程的RenderProcess对象。ResourceMessageFilter会过滤掉能够直接执行的I/O处理消息,比如说网络请求。过滤使用ResourceMessageFilter::OnMessageReceived方法。

Ui线程中的RenderProcessHost负责分发所有显示相关的消息给RenderViewHost(同时它也会处理有限的几种非显示相关的消息)。消息的分发在RenderProcessHost::OnMessageReceived函数执行。

浏览器进程的高层对象

显示相关的消息会进入RenderViewHost::OnMessageReceived。大部分消息在这里处理,其他的则被转发到RenderWidgetHost。渲染进程中有两个对象对应到RenderView和RenderWidget对象。在Microsoft Windows上,对于每个RenderWigetHost都有一个RenderWidgetHostHWND与之对应,这个类专门负责管理消息事件并绘制原生的HWND。其他系统上也有类似的负责原生输入和绘图的对象。

在renderView/Widget对象之上是WebContent对象,大部分的消息都是在这个对象中响应的。WebContents表示一个tab中的内容。它继承自通用的TabContents对象(还有其他集中TabContents的子类,比如下载页面或历史页面)。它是大部分导航和顶层浏览器UI更新的结合点(switching point)。

FAQ:为什么要分离WebContents和RenderViewHost对象?
原因有二:这两个对象提供不同层面的功能。你可以认为RenderViewHost是Chromium的“多进程潜入层”(译注:屏蔽多进程通信的细节)。除了渲染进程RenderViewHost也可以用在应用的其他部分(目前还没有)。例如,可以想象一个显示网页内容的对话框,它可以使用RenderViewHost管理绘图并和渲染进程通信但是没有通常的导航栏或者“tab”。RenderViewHost将很多消息都通过RenderViewHostDelegate抽象接口转发给WebContents。WebContents处理导航状态和其他所有和浏览器UI相关的数据。 我们设想的对话框不需这样的功能,所以只需实现RenderViewHostDelegate中它关心的接口就可以了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics