http://blog.csdn.net/zengwh/article/details/4285792
- Chromium如何显示网页
-
- 概念上的应用层
- WebKit
- WebKit Port
- Webkit胶粘层
- 浏览器进程
- 底层浏览器进程对象
- 高层浏览器进程对象
- 演示示例
- “设置光标”消息的处理过程
- 鼠标单击消息处理过程
-
译:whzeng@126.com
本文档从底层到上层描述了chromium显示网页。确认您已经月度了多进程架构? 的设计文档。您将特别想了解主要的组成方块图。您同时也可能有兴趣了解多进程资源加载? ,以了解网页如何从网络下载。
概念上的应用层
每个方框表示一个概念层。通过选取或者取代各层之上的层可以构建不同的浏览器应该是可能的。因此,任何层都不应该依赖任何比它层次更高的层或者需要更高层次的相关信息。
- WebKit? :Safari、Chromium和任何其他基于Webkit的浏览器的渲染引擎。Port是WebKit的一部分,它与依赖于系统服务的平台集成,如资源加载和图形。
- Glue:转换Webkit类型成Chromium类型。这是我们的Webkit嵌入层。它是Chromium和test_shell(允许我们测试Webkit)这辆个浏览器基本的部分。
- Render/Render host:这是Chromium的多进程嵌入层。它穿透进程边界代理各种通知和命令。您应该可以想象其他多进程浏览器正在使用这层,它应该依赖浏览器的其他服务。
- Tab contents:浏览器特定的层表示标签的内容。它与历史系统、口令管理登应用服务绑定。它不应该,而且决不假设它嵌入在一个Chromium浏览器窗口里(它也可被其他浏览器组件像HTML对话框使用)。
- Broeser:表示浏览器窗口,它嵌入了多个标签内容(TabContentses? )。
WebKit?
我们使用WebKit开源工程布局网页。这些代码来自苹果而且存在/third_party/WebKit目录。WebKit主要由表示内核布局功能的 WebCore、执行JavaScript的JavaScriptCore组成。我们仅运行JavaScriptCore进行测试,通常我们以我们更高性能的V8引擎取代它。我们并没有实际使用苹果称为WebKit的那一层,这一层是嵌入WebCore和OSX应用Safari之间的API。为了方便,我们把参考苹果这一层的代码称为WebKit。
WebKit? Port
在最底层我们有我们的WebKit Port。这是平台无关的WebCore的代码的接口在特定平台的我们的实现。这些文件位于/webkit/port,且与WebCore的目录层次相似。我们的port大部分都是与实际OS无关:您可以认为是Chromium port的WebCore。少数部分像字体渲染的处理在每个平台不同。
- 通过多进程资源加载? 系统处理网络资源和响应。而不是直接从render进程交由OS处理。
- 图形上使用为Android开发的Skia图形库。这是一个跨平台的图形库而且可以处理许多图象和除文本外的基本图形元素。skia位于 /third_party/skia。主要的图形操作的入口是/webkit/port/platform/graphics /GraphicsContextSkia.cpp。它也被许多在同一目录的其他文件如/base/gfx使用。
Webkit胶粘层
Chromium应用使用不同的类型、代码风格和代码布局而不是第三方的WebKit代码。WebKit胶粘层提供许多方便的嵌入的API为 WebKit使用Goole代码方便和类型转换(如,我们使用std::string取代WebCore::String,GURL取代KURL)。胶粘层位于/webkit/glue。胶粘对象都与Webkit对象相似,只是以"Web"作为前缀。例如,WebCore::Frame编程 WebFrame。
WebKit? 胶粘层隔离了基于Chromium的代码库与WebCore数据类型,以便基于Chromium代码修改最小化对于WebCore的影响。基于次,WebCore的数据类型决不直接在Chromium使用。API都被加到WebKit胶粘层,以方便Chromium(when it needs to poke at some WebCore? object) 。
test_shell应用是缺少网页浏览器骨架的应用,用于测试我们的WebKit port和胶粘层代码。它像Chromium一样使用相同的胶粘(glue)接口与webkit通讯。它没有许多复杂的浏览器特性、线程和进程,但是提供了一个简单的方法给开发者测试新代码。这个应用也用于自动运行WebKit测试。
Chromium的渲染进程使用glue接口嵌入了我们的webkit port。它没有包含非常多的代码:它的主要任务是成为渲染器连接浏览器的IPC通道。
渲染器中最重要的类是RenderView,位于/chrome/renderer/render_view.cc。这个对象表示一个网页。它处理所有来自或者到浏览器进程的浏览相关的命令。它由RenderWidget驱动,RenderWidget提供绘制和事件处理。 RenderView与浏览器进程通讯通过全局的(每个渲染进程一个)RenderProcess对象。
FAQ:RenderWidget与RenderView的区别是什么?RenderWidget通过实现在glue层称为 WebWidgetDelegate的抽象接口映射成WebCore::Widget对象。基本上它可以认为是屏幕上接收输入事件和我们需要绘制的窗口。 RenderView继承了RenderWidget而且是标签或者弹出窗口的内容。它处理浏览命令另外处理绘制和widget的输入事件。
每个渲染器有2个线程(见chrome多进程架构? 中的图或者chroimum的线程? )。渲染器线程执行RenderView等主要对象和所有WebKit代码。当它与浏览器通讯时,消息首先发送给主线程,主线程分发消息给浏览器进程。另外就是这种方式允许发送从渲染器到浏览器的同步消息。这种方式提供了浏览器等待渲染器的一组操作完成后继续。一个简单的例子是当JavaScript读取cookie时。渲染器线程将阻塞而且主线程将投递所有接收到的消息直到收到正确的响应。正常的处理都是一旦主线程收到消息就顺序地发送给渲染器。
浏览器进程
底层浏览器进程对象
所有与渲染器进程的通讯都有浏览器的IO线程完成。 这个线程同时处理所有网络通讯? 这也保持了与用户接口进行交互。当主线程(用户接口在此执行)初始化RenderProcessHost。RenderProcessHost创建新的渲染器进程和ChannelProxy对象(与渲染器通过有名管道通讯)。RenderProcessHost在浏览器的IO线程中执行,同时侦听来自渲染器的有名管道数据,而且自动前向通知所有消息给UI线程中的RenderProcess。ResourceMessageFilter安装在这个通道里,这可以查到某种需要直接在IO线程处理的消息(如网络请求)。ResourceMessageFilter::OnMessageReceived执行消息过滤。
UI线程的RenderProcessHost负责分发视图相关的消息给合适的RenderViewHost(它处理有限的自身的非视图相关的消息)。RenderProcessHost::OnMessageReceived进行这些消息的分发。
高层浏览器进程对象
当视图相关的消息进入RenderViewHOst::OnMessageReceived,大多数这些消息在次处理,剩下的消息交给集成 RenderWidgetHost的类处理。渲染器中对应与这两对象的分别是RenderView和RenderWidget(关于这些对象见渲染器进程)。在微软的Windows上,我们将每个RenderWidgetHost与RenderWidgetHostHWND关联。 RenderWidgetHost管理事件和绘制到本地的HWND。其他的系统我们采用相似的类管理本地输入和绘制。
在RenderView/Widget之上的是WebContents对象,大多数的消息实际上都以在这个对象上的函数调用方式结束。每个WebContents表示显示网络数据的标签的内容。它受一般的TabContents类(有许多其他TabContents的规范,如历史和下载。)驱动。WebContents是大多数浏览和顶层浏览器UI更新的切换点。
FAQ:为什么将WebContents和RenderViewHost分离?这两个对象提供了不同的功能层次。您可以认为 RenderViewHost是Chromium的多进程嵌入层。RenderViewHost对象能用于(实际上不是)渲染内容的其他部分。例如,您可想象成一个带有web视图的对话框。它能使用RenderViewHost去管理绘制且与渲染进程通讯,但是它不能有标签或者常见的浏览命令。 RenderViewHost通过抽象接口RenderViewHostDelegate前向传递许多消息给WebContents。 WebContents处理浏览状态和任何与web浏览器UI相关的操作。我们假设的对话框不必需要任何这些功能,仅需要实现它关心的 RenderViewHostDelegate的部分接口。
演示示例
其他关于浏览和启动的例子在获取Chrome源码? .
“设置光标”消息的处理过程
设置光标是由渲染器发送给浏览器的一个典型的消息。在渲染器按下面过程处理:
- 设置光标消息由WebKit内部生成。典型地一般是响应输入事件。设置光标消息由RenderWidget::SetCursor(chrome/render/render_widget.cc)发出。
- 它将调用RenderWidget::Send去分发消息。这个方法也被RenderView使用去发送消息给浏览器。然后调用RenderThread::Send。
- 接着调用IPC::SyncChannel,这个方法实现内部代理消息给渲染器的主线程同时投递消息给发送消息给浏览器的命名管道。
接着浏览器接管该消息:
- RenderProcessHost? 的IPC::ChannelProxy接收所有浏览器IO线程的消息。它首先发送它们给 RenderMessageFilter,RenderMessageFilter将直接在IO线程分发网络请求和相关的消息。既然我们的消息没有被过滤掉,它将继续交由浏览器的UI线程(IPC::ChannelProxy内部如此实现)。
- RenderProcessHost? ::OnMessageReceived(chrome/browser/render_process_host.cc)获取所有响应渲染器进程的视图的消息。它直接处理几种类型的消息,且对于剩下的前向通知相应的RenderViewHost去响应来自RenderView的消息。
- 消息到达RenderViewHost::OnMessageReceived(chrome/browser /render_view_host.cc)。许多消息在这里处理,但是设置光标的消息不在此处,因为它是一个来自RenderWidget的消息应该交给RenderWidgetHost处理。
- 所有RenderViewHost未处理的消息都自动地前向通知给RenderWidgetHost,包括设置光标消息。
- 在chrome/browser/render_widget_host.cc中的消息映射最终接收RenderWidgetHost::OnMsgSetCusor然后调用合适的UI函数去设置鼠标的光标。
鼠标单击消息处理过程
发送鼠标消息是一个从浏览器发送给渲染器的典型消息。
- 浏览器的UI线程通过RenderWidetHostHWND::OnMouseEvent接收到窗口消息,然后调用ForwardMouseEventToRenderer。
- 这个前向通知函数将输入事件包装成跨平台的WebMouseEvent且发送给与之相关的RenderWidgetHost后结束。
- RenderWidgetHost::ForwardInputEvent创建一个IPC消息 ViewMsg_HandleInputEvent,序列化成WebInputEvnet。然后调用 RenderWigetHost::Send 发送。
- 这将事件前向传递给RenderProcessHost::Send函数,这个函数按顺序将消息传递给IPC::ChannelProxy。
- 内部里,IPC::ChannnelProxy将代理此消息给浏览器的IO线程。然后写入与之相应的渲染器的命名管道。
注意:许多由WebContents创建的其他类型的消息,特别是浏览功能的消息,这些也按照相似的过程从WebContents传递到RenderViewHost。
然后渲染器接管该消息。
- 渲染器的主线程的IPC::Channel读取由浏览器发送的消息,且IPC::ChannelProxy代理给渲染线程。
- RenderView? ::OnMessageReceived获取这个消息。许多种类型的消息都在此直接处理。但是单击消息却不是,它将继续(和其他所有未处理消息一起)通过此传递给RenderWidget::OnMessageReceived(它按照顺序前向通知 RenderWidget::OnHandleInputEvent)。
- 输入事件最终交给WebWidgetImpl::HandleInputEvent。这个函数将它转成WebKit的PlatformMouseEvent类且交给WebKit内部的WebCore::Widget类处理。