Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How Chromium Displays Web Pages(中文) #1

Open
zhuzhuaicoding opened this issue Mar 28, 2017 · 0 comments
Open

How Chromium Displays Web Pages(中文) #1

zhuzhuaicoding opened this issue Mar 28, 2017 · 0 comments

Comments

@zhuzhuaicoding
Copy link
Owner

zhuzhuaicoding commented Mar 28, 2017

本文档介绍了如何从底部向上在Chromium中显示网页。 确保您已阅读multi-process architecture设计文档。 您将特别想了解主要组件的框图。 您可能还对 multi-process resource loading 感兴趣,了解如何从网络中提取页面。

应用层

(The original Google Doc for this illustration is http://goo.gl/MsEJX which is open for editing by any @chromium.org)
每个框代表一个概念应用层。 没有层应该具有任何更高层次的知识或依赖关系。

  • Webkit:Safari,Chromium和所有其他基于WebKit的浏览器之间共享渲染引擎。 该接口是与基于平台的系统服务(如资源加载和图形)集成的WebKit的一部分。
  • Glue:将WebKit类型转换为Chromium类型。 这是我们的“WebKit嵌入层”。 它是两个浏览器,Chromium和test_shell(允许我们测试WebKit)的基础。
  • Render / Render Host:这是Chromium的“多进程嵌入层”。 它在整个流程边界代理通知和命令。
  • Webcontents:一个可重用的组件,它是内容模块的主要类。 它很容易嵌入,允许HTML的多进程渲染到一个视图。 有关详细信息,请参阅内容模块页面。
  • Browser:浏览器窗口,它包含多个WebContentses。
  • Tab Helpers:可以连接到WebContents的单个对象(通过WebContentsUserData mixin)。 浏览器将它们分类到它所拥有的WebContentses(一个用于favicons,一个用于infobar信息栏等)。

Webkit

我们使用WebKit开源项目来布局网页。 这个代码从苹果公司提取并存储在/third_party/WebKit目录中。 WebKit主要由代表核心布局功能的“WebCore”和运行JavaScript的“JavaScriptCore”组成。 我们只运行JavaScriptCore进行测试,通常我们将其替换为我们的高性能V8 JavaScript引擎。 我们实际上并没有使用Apple称之为“WebKit”的层,它是WebCore和OS X应用程序(如Safari)之间的嵌入API。 为方便起见,我们通常将Apple的代码统称为“WebKit”。

The WebKit port

在最底层我们有我们的WebKit“接口”。 这是我们实现与平台无关的WebCore代码所需的平台特定功能。 这些文件位于WebKit树中,通常在chromium目录或Chromium后缀文件中。 我们接口的大部分实际上并不是操作系统特定的:您可以将其视为WebCore的“Chromium接口”。 某些部分,如字体渲染,必须对每个平台进行不同的处理。

  • 网络流量由我们的多进程资源加载系统处理,而不是直接从渲染过程切换到操作系统。
  • 图形使用为Android开发的Skia图形库。 这是一个跨平台的图形库,并处理除文本之外的所有图像和图形图元。 Skia位于/third_party/skia, 主要代码在/webkit/port/platform/graphics/GraphicsContextSkia.cpp。 它用到了同一目录和/base/gfx中的其他文件。

The WebKit glue

Chromium应用程序使用与第三方WebKit代码不同的类型,编码风格和代码布局。 WebKit“glue”使用Google编码规范和类型为WebKit提供了更方便的API(例如,我们使用std::string而不是WebCore::String和GURL而不是KURL)。glue代码位于/webkit/glue。glue对象命名和WebKit对象类似,但在开头使用“Web”。例如,WebCore::Frame变成WebFrame。
WebKit“glue”层将Chromium代码库的其余部分与WebCore数据类型隔离,以帮助最小化WebCore更改对Chromium代码库的影响。因此,WebCore数据类型从不直接由Chromium使用。当需要在某些WebCore对象上捅时,API将被添加到WebKit“胶”中,以获得Chromium的优势。

“test_shell”应用程序是用于测试我们的WebKit接口和glue code的Web浏览器。它使用与Chromium相同的glue接口与WebKit进行通信。它为开发人员提供了一种更简单的方法来测试新代码,而不需要许多复杂的浏览器功能,线程和进程。此应用程序也用于运行自动WebKit测试。然而,“测试shell”的缺点是它不像Chromium那样以多进程的方式运行WebKit。内容模块嵌入到一个名为“内容shell”的应用程序中,该应用程序将很快运行测试。

The render process

Chromium的渲染过程使用胶接口嵌入我们的WebKit端口。它不包含非常多的代码:它的工作主要是IPC浏览器的渲染器端。
渲染器中最重要的类是RenderView,位于/content/renderer/render_view_impl.cc中。此对象表示网页。它处理与浏览器进程有关的所有导航相关命令。它来自提供绘画和输入事件处理的RenderWidget。 RenderView通过全局(每个渲染过程)RenderProcess对象与浏览器进程进行通信。

常见问题:RenderWidget和RenderView有什么区别? RenderWidget映射到一个WebCore :: Widge对象,通过实现名为c的粘贴层中的抽象接口。这基本上是一个屏幕上接收输入事件的窗口,并且我们绘制。RenderView从RenderWidget继承,是tab或弹出窗口的内容。除了绘图和输入事件外,它还处理导航命令。只有一种情况下,RenderWidget不存在RenderView,这是网页上的选择框。这些是带有向下箭头的框弹出选项列表。选择框必须使用本机窗口进行渲染,以便它们可以显示在所有其他窗口上方,并在必要时弹出框架。这些窗口需要绘制和接收输入,但是没有一个单独的“网页”(RenderView)。

Threads in the renderer

每个渲染器都有两个线程( multi-process architecture,或者 threading in Chromium )。 渲染线程是运行RenderView和所有WebKit代码的主要对象。 当它与浏览器进行通信时,首先将消息发送到主线程,然后将消息发送到浏览器进程。 除此之外,这允许我们从渲染器同步发送消息到浏览器。 这是因为浏览器的结果需要继续进行的一小组操作。 一个例子是在JavaScript请求时获取页面的Cookie。 渲染线程将阻塞,并且主线程将排队所有收到的消息,直到找到正确的响应。 随后收到的任何消息随后都会发布到渲染器线程进行正常处理。

The browser process

The browser process

Low-level browser process objects

与渲染进程的所有IPC通信都在浏览器的I/O线程上完成。该线程还处理所有网络通信,防止其干扰用户界面。

当RenderProcessHost在主线程(用户界面运行时)上初始化时,它将使用命名管道创建新的渲染器进程和ChannelProxy IPC对象到渲染器。该对象运行在浏览器的I / O线程上,监听命名管道到渲染器,并自动将所有消息转发回UI线程上的RenderProcessHost。将在此通道中安装ResourceMessageFilter,该过滤器将过滤掉可在I / O线程上直接处理的某些消息,例如网络请求。此过滤发生在ResourceMessageFilter :: OnMessageReceived中。

UI线程上的RenderProcessHost负责将所有视图特定的消息分派到适当的RenderViewHost(它处理有限数量的非视图特定消息本身)。此调度发生在RenderProcessHost :: OnMessageReceived中。

High-level browser process objects

视图特定的消息进入RenderViewHost :: OnMessageReceived。 大多数消息在这里处理,其余消息转发到RenderWidgetHost基类。 这两个对象映射到渲染器中的RenderView和RenderWidget(请参阅上面的“渲染过程”)。 每个平台都有一个视图类(RenderWidgetHostView [Aura | Gtk | Mac | Win])来实现与本机视图系统的集成。

RenderView/Widget上层是WebContents对象,大多数消息实际上最终作为该对象的函数调用。 WebContents表示网页的内容。 它是内容模块中的顶级对象,并负责在矩形视图中显示网页。 有关详细信息,请参阅content module

WebContents对象包含在TabContentsWrapper中。 这是在chrome/,并负责一个选项卡。

例子

Life of a "set cursor" message

设置光标是从渲染器发送到浏览器的典型消息的示例。 这里是在渲染器中发生了的过程:

  • 设置游标消息是由WebKit内部生成的,通常是响应于输入事件。 设置的游标消息将在content/render/ render_widget.cc中的RenderWidget :: SetCursor中开始。
  • 调用RenderWidget :: Send来发送消息。 RenderView也可以使用此方法将消息发送到浏览器。 它会调用RenderThread :: Send。
  • 调用IPC :: SyncChannel,它将内部将消息代理到渲染器的主线程,并将其发布到命名管道以发送到浏览器。

然后浏览器获得控制:

  • RenderProcessHost中的IPC :: ChannelProxy在浏览器的I / O线程上收到所有消息。它首先通过ResourceMessageFilter发送它们,直接在I / O线程上调度网络请求和相关消息。由于我们的消息未被过滤掉,它继续到浏览器的UI线程(IPC :: ChannelProxy内部)。
  • RenderProcessHost :: OnMessageReceived 在content/browser/renderer_host/render_process_host_impl.cc中在对应的渲染进程中得到所有视图的消息。它直接处理几种类型的消息,其余的转发到对应于发送消息的源RenderView的适当的RenderViewHost。
  • 消息到达content/browser/renderer_host/render_view_host_impl.cc中的RenderViewHost :: OnMessageReceived。许多消息都在这里处理,但是我们的消息不是因为它是从RenderWidget发送并由RenderWidgetHost处理的消息。
  • RenderViewHost中的所有未处理的消息都将自动转发到RenderWidgetHost,包括我们设置的游标消息。
  • content/browser/renderer_host/render_view_host_impl.cc中的消息映射最终在RenderWidgetHost :: OnMsgSetCursor中收到消息,并调用相应的UI功能来设置鼠标光标。

Life of a "mouse click" message

发送鼠标点击是从浏览器到渲染器的消息的典型示例。

  • RenderWidgetHostViewWin :: OnMouseEvent在浏览器的UI线程上收到Windows消息,然后在同一个类中调用ForwardMouseEventToRenderer。
  • 转发器功能将输入事件打包到跨平台WebMouseEvent中,最终将其发送到与其关联的RenderWidgetHost。
  • RenderWidgetHost :: ForwardInputEvent创建一个IPC消息ViewMsg_HandleInputEvent,将WebInputEvent序列化到它,并调用RenderWidgetHost :: Send。
  • 这只是转发给拥有的RenderProcessHost :: Send函数,它又向IPC :: ChannelProxy提供消息。
    在内部,IPC :: ChannelProxy会将消息代理到浏览器的I/O线程,并将其写入相应渲染器的命名管道。

请注意,WebContents中还会创建许多其他类型的消息,特别是导航消息。它们遵循从WebContents到RenderViewHost的类似路径。

然后渲染器获得控制:

  • 渲染器主线程上的IPC :: Channel读取浏览器发送的消息,并将IPC :: ChannelProxy代理到渲染器线程。
  • RenderView :: OnMessageReceived获取消息。许多类型的消息在这里直接处理。由于点击消息不是,它通过(与所有其他未处理的消息)到RenderWidget :: OnMessageReceived,而后者又将其转发到RenderWidget :: OnHandleInputEvent。
  • 将输入事件提供给WebWidgetImpl :: HandleInputEvent,将其转换为WebKit PlatformMouseEvent类,并将其提供给WebKit中的WebCore :: Widget类。

Ref:https://www.chromium.org/developers/design-documents/displaying-a-web-page-in-chrome

@zhuzhuaicoding zhuzhuaicoding changed the title How Chromium Displays Web Pages How Chromium Displays Web Pages(中文) Mar 28, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant