Chromium网页Layer Tree创建过程分析
Posted 罗升阳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Chromium网页Layer Tree创建过程分析相关的知识,希望对你有一定的参考价值。
在Chromium中,WebKit会创建一个Graphics Layer Tree描述网页。Graphics Layer Tree是和网页渲染相关的一个Tree。网页渲染最终由Chromium的CC模块完成,因此CC模块又会根据Graphics Layer Tree创建一个Layer Tree,以后就会根据这个Layer Tree对网页进行渲染。本文接下来就分析网页Layer Tree的创建过程。
老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!
《android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!
从前面Chromium网页Graphics Layer Tree创建过程分析一文可以知道,网页的Graphics Layer Tree是根据Render Layer Tree创建的,Render Layer Tree又是根据Render Object Tree创建的。Graphics Layer Tree与Render Layer Tree、Render Layer Tree与Render Object Tree的节点是均是一对多的关系,然而Graphics Layer Tree与CC模块创建的Layer Tree的节点是一一对应的关系,如图1所示:
图1 Graphics Layer Tree与CC Layer Tree的关系
也就是说,每一个Graphics Layer都对应有一个CC Layer。不过,Graphics Layer与CC Layer不是直接的一一对应的,它们是透过另外两个Layer才对应起来的,如图2所示:
图2 Graphics Layer与CC Layer的对应关系
中间的两个Layer分别是WebContentLayerImpl和WebLayerImpl,它们是属于Content层的对象。关于Chromium的层次划分,可以参考前面Chromium网页加载过程简要介绍和学习计划一文的介绍。Graphics Layer与CC Layer的对应关系,是在Graphics Layer的创建过程中建立起来的,接下来我们就通过源码分析这种对应关系的建立过程。
从前面Chromium网页Graphics Layer Tree创建过程分析一文可以知道,Graphics Layer是通过调用GraphicsLayerFactoryChromium类的成员函数createGraphicsLayer创建的,如下所示:
PassOwnPtr<GraphicsLayer> GraphicsLayerFactoryChromium::createGraphicsLayer(GraphicsLayerClient* client)
{
OwnPtr<GraphicsLayer> layer = adoptPtr(new GraphicsLayer(client));
......
return layer.release();
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/GraphicsLayerFactoryChromium.cpp中。
参数client指向的实际上是一个CompositedLayerMapping对象,这个CompositedLayerMapping对象会用来构造一个Graphics Layer。Graphics Layer的构造过程,也就是GraphicsLayer类的构造函数的实现,如下所示:
GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
: m_client(client)
, ......
{
......
m_opaqueRectTrackingContentLayerDelegate = adoptPtr(new OpaqueRectTrackingContentLayerDelegate(this));
m_layer = adoptPtr(Platform::current()->compositorSupport()->createContentLayer(m_opaqueRectTrackingContentLayerDelegate.get()));
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。
GraphicsLayer类的构造函数首先是将参数client指向的CompositedLayerMapping对象保存在成员变量m_client中,接着又创建了一个OpaqueRectTrackingContentLayerDelegate对象保存在成员变量opaqueRectTrackingContentLayerDelegate中。
再接下来GraphicsLayer类的构造函数通过Platform类的静态成员函数current获得一个RendererWebKitPlatformSupportImpl对象。这个RendererWebKitPlatformSupportImpl对象定义在Content模块中,它实现了由WebKit定义的Platform接口,用来向WebKit层提供平台相关的实现。
通过调用RendererWebKitPlatformSupportImpl类的成员函数compositorSupport可以获得一个WebCompositorSupportImpl对象。有了这个WebCompositorSupportImpl对象之后,就可以调用它的成员函数createContentLayer创建一个WebContentLayerImpl对象,并且保存在GraphicsLayer类的成员变量m_layer中。
WebCompositorSupportImpl类的成员函数createContentLayer的实现如下所示:
WebContentLayer* WebCompositorSupportImpl::createContentLayer(
WebContentLayerClient* client) {
return new WebContentLayerImpl(client);
}
这个函数定义在文件external/chromium_org/content/renderer/compositor_bindings/web_compositor_support_impl.cc中。
从这里可以看到,WebCompositorSupportImpl类的成员函数createContentLayer创建了一个WebContentLayerImpl对象返回给调用者。
WebContentLayerImpl对象的创建过程,即WebContentLayerImpl类的构造函数的实现,如下所示:
WebContentLayerImpl::WebContentLayerImpl(blink::WebContentLayerClient* client)
: client_(client), ...... {
if (WebLayerImpl::UsingPictureLayer())
layer_ = make_scoped_ptr(new WebLayerImpl(PictureLayer::Create(this)));
else
layer_ = make_scoped_ptr(new WebLayerImpl(ContentLayer::Create(this)));
......
}
这个函数定义在文件external/chromium_org/content/renderer/compositor_bindings/web_content_layer_impl.cc中。
从前面的调用过程可以知道,参数client指向的实际上是一个OpaqueRectTrackingContentLayerDelegate对象,WebContentLayerImpl类的构造函数首先将它保存在成员变量client_中 。
WebContentLayerImpl类的构造函数接下来调用WebLayerImpl类的静态成员函数UsingPictureLayer判断Render进程是否启用Impl Side Painting特性。如果启用的话,就会调用PictureLayer类的静态成员函数Create创建一个Picture Layer;否则的话,就会调用ContentLayer类的静态成员函数Create创建一个Content Layer。有了Picture Layer或者Content Layer之后,再创建一个WebLayerImpl对象,保存在WebContentLayerImpl类的成员变量layer_中。
当Render进程设置了enable-impl-side-painting启动选项时,就会启用Impl Side Painting特性,也就是会在Render进程中创建一个Compositor线程,与Render进程中的Main线程一起协作完成网页的渲染。在这种情况下,Graphics Layer在绘制网页内容的时候,实际上只是记录了绘制命令。这些绘制命令就记录在对应的Picture Layer中。
另一方面,如果Render进程没有设置enable-impl-side-painting启动选项,那么Graphics Layer在绘制网页内容的时候,就会通过Content Layer提供的一个Canvas真正地把网页内容对应的UI绘制在一个内存缓冲区中。
无论是Picture Layer还是Content Layer,它们都是在cc::Layer类继承下来的,也就是说,它们对应于图2所示的CC Layer。不过,我们只考虑Picture Layer的情况,因此接下来我们继续分析Picture Layer的创建过程,也就是PictureLayer类的静态成员函数Create的实现,如下所示:
scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) {
return make_scoped_refptr(new PictureLayer(client));
}
这个函数定义在文件external/chromium_org/cc/layers/picture_layer.cc中。
从这里可以看到,PictureLayer类的静态成员函数Create创建了一个PictureLayer对象返回给调用者。
PictureLayer对象的创建过程,也就是PictureLayer类的构造函数的实现,如下所示:
PictureLayer::PictureLayer(ContentLayerClient* client)
: client_(client),
pile_(make_scoped_refptr(new PicturePile())),
...... {
}
这个函数定义在文件external/chromium_org/cc/layers/picture_layer.cc中。
从前面的调用过程可以知道,参数client指向的实际上是一个WebContentLayerImpl对象,PictureLayer类的构造函数将它保存在成员变量client_中。
PictureLayer类的构造函数还做了另外一件重要的事情,就是创建了一个PicturePile对象,并且保存在成员变量pile_中。这个PicturePile对象是用来将Graphics Layer的绘制命令记录在Pictrue Layer中的,后面我们分析网页内容的绘制过程时就会看到这一点。
回到WebContentLayerImpl类的构造函数中,它创建了一个Pictrue Layer之后,接下来就会以这个Pictrue Layer为参数,创建一个WebLayerImpl对象,如下所示:
WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) : layer_(layer) {
......
}
这个函数定义在文件external/chromium_org/content/renderer/compositor_bindings/web_layer_impl.cc中。
WebLayerImpl类的构造函数主要就是将参数layer描述的一个PictrueLayer对象保存在成员变量layer_中。
从前面Chromium网页Graphics Layer Tree创建过程分析一文还可以知道,Graphics Layer与Graphics Layer是通过GraphicsLayer类的成员函数addChild形成父子关系的(从而形成Graphics Layer Tree),如下所示:
void GraphicsLayer::addChild(GraphicsLayer* childLayer)
{
addChildInternal(childLayer);
updateChildList();
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。
GraphicsLayer类的成员函数addChild首先调用成员函数addChildInternal将参数childLayer描述的一个Graphics Layer作为当前正在处理的Graphics Layer的子Graphics Layer,如下所示:
void GraphicsLayer::addChildInternal(GraphicsLayer* childLayer)
{
......
childLayer->setParent(this);
m_children.append(childLayer);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。
这一步执行完成后,Graphics Layer之间就建立了父子关系。回到GraphicsLayer类的成员函数addChild中,它接下来还会调用另外一个成员函数updateChildList,用来在CC Layer之间建立父子关系,从而形CC Layer Tree。
GraphicsLayer类的成员函数updateChildList的实现如下所示:
void GraphicsLayer::updateChildList()
{
WebLayer* childHost = m_layer->layer();
......
for (size_t i = 0; i < m_children.size(); ++i)
childHost->addChild(m_children[i]->platformLayer());
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。
从前面的分析可以知道,GraphicsLayer类的成员变量m_layer指向的是一个WebContentLayerImpl对象,调用这个WebContentLayerImpl对象的成员函数layer获得的是一个WebLayerImpl对象,如下所示:
blink::WebLayer* WebContentLayerImpl::layer() {
return layer_.get();
}
这个函数定义在文件external/chromium_org/content/renderer/compositor_bindings/web_content_layer_impl.cc中。
从前面的分析可以知道,WebContentLayerImpl类的成员变量layer_指向的是一个WebLayerImpl对象,因此WebContentLayerImpl类的成员函数layer返回的是一个WebLayerImpl对象。
回到GraphicsLayer类的成员函数updateChildList中,它接下来调用GraphicsLayer类的成员函数platformLayer获得当前正在处理的Graphics Layer的所有子Graphics Layer对应的WebLayerImpl对象,如下所示:
WebLayer* GraphicsLayer::platformLayer() const
{
return m_layer->layer();
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。
这些子Graphics Layer对应的WebLayerImpl对象也就是通过调用它们的成员变量m_layer指向的WebContentLayerImpl对象的成员函数layer获得的。
再回到GraphicsLayer类的成员函数updateChildList中,获得当前正在处理的Graphics Layer对应的WebLayerImpl对象,以及其所有的子Graphics Layer对应的WebLayerImpl对象之后,就可以通过调用WebLayerImpl类的成员函数addChild在它们之间也建立父子关系,如下所示:
void WebLayerImpl::addChild(WebLayer* child) {
layer_->AddChild(static_cast<WebLayerImpl*>(child)->layer());
}
这个函数定义在文件external/chromium_org/content/renderer/compositor_bindings/web_layer_impl.cc中。
从前面的分析可以知道,WebLayerImpl类的成员变量layer_指向的是一个PictrueLayer对象,因此WebLayerImpl类的成员函数addChild所做的事情就是在两个PictrueLayer对象之间建立父子关系,这是通过调用PictrueLayer类的成员函数AddChild实现的。
PictrueLayer类的成员函数AddChild是父类Layer继承下来的,它的实现如下所示:
void Layer::AddChild(scoped_refptr<Layer> child) {
InsertChild(child, children_.size());
}
这个函数定义在文件external/chromium_org/cc/layers/layer.cc中。
Layer类的成员函数AddChild将参数child描述的Pictrue Layer设置为当前正在处理的Picture Layer的子Picture Layer,这是通过调用Layer类的成员函数InsertChild实现的,如下所示:
void Layer::InsertChild(scoped_refptr<Layer> child, size_t index) {
DCHECK(IsPropertyChangeAllowed());
child->RemoveFromParent();
child->SetParent(this);
child->stacking_order_changed_ = true;
index = std::min(index, children_.size());
children_.insert(children_.begin() + index, child);
SetNeedsFullTreeSync();
}
这个函数定义在文件external/chromium_org/cc/layers/layer.cc中。
Layer类的成员函数InsertChild所做的第一件事情是将当前正在处理的Picture Layer设置为参数child描述的Pictrue Layer的父Picture Layer,并且将参数child描述的Pictrue Layer保存在当前正在处理的Picture Layer的子Picture Layer列表中。
Layer类的成员函数InsertChild所做的第二件事情是调用另外一个成员函数SetNeedsFullTreeSync发出一个通知,要在CC Layer Tree与CC Pending Layer Tree之间做一个Tree结构同步。
Layer类的成员函数SetNeedsFullTreeSync的实现如下所示:
void Layer::SetNeedsFullTreeSync() {
if (!layer_tree_host_)
return;
layer_tree_host_->SetNeedsFullTreeSync();
}
这个函数定义在文件external/chromium_org/cc/layers/layer.cc中。
Layer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象,这个LayerTreeHost是用来管理CC Layer Tree的,后面我们再分析它的创建过程。Layer类的成员函数SetNeedsFullTreeSync所做的事情就是调用这个LayerTreeHost对象的成员函数SetNeedsFullTreeSync通知它CC Layer Tree结构发生了变化,需要将这个变化同步到CC Pending Layer Tree中去。
LayerTreeHost类的成员函数SetNeedsFullTreeSync的实现如下所示:
void LayerTreeHost::SetNeedsFullTreeSync() {
needs_full_tree_sync_ = true;
SetNeedsCommit();
}
这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。
LayerTreeHost类的成员函数SetNeedsFullTreeSync将成员变量needs_full_tree_sync_设置为true,以标记要在CC Layer Tree和CC Pending Layer Tree之间做一次结构同步,然后再调用另外一个成员函数SetNeedsCommit请求在前面Chromium网页渲染机制简要介绍和学习计划一文中提到的调度器将CC Layer Tree同步到CC Pending Tree去。至于这个同步操作什么时候会执行,就是由调度器根据其内部的状态机决定了。这一点我们在后面的文章再分析。
这一步执行完成之后,就可以在CC模块中得到一个Layer Tree,这个Layer Tree与WebKit中的Graphics Layer Tree在结构上是完全同步的,并且这个同步过程是由WebKit控制的。这个同步过程之所以要由WebKit控制,是因为CC Layer Tree是根据Graphics Layer Tree创建的,而Graphics Layer Tree又是由WebKit管理的。
WebKit现在还需要做的另外一件重要的事情是告诉CC模块,哪一个Picture Layer是CC Layer Tree的根节点,这样CC模块才可以对整个CC Layer Tree进行管理。很显然,Graphics Layer Tree的根节点对应的Picture Layer,就是CC Layer Tree的根节点。因此,WebKit会在创建Graphics Layer Tree的根节点的时候,将该根节点对应的Picture Layer设置到CC模块中去,以便后者将其作为CC Layer Tree的根节点。
Graphics Layer Tree的根节点是什么时候创建的呢?从前面Chromium网页加载过程简要介绍和学习计划这个系列的文章可以知道,Graphics Layer Tree的根节点对应于Render Layer Tree的根节点,Render Layer Tree的根节点又对应于Render Object Tree的根节点,因此我们就从Render Object Tree的根节点的创建过程开始,分析Graphics Layer Tree的根节点的创建过程。
从前面Chromium网页DOM Tree创建过程分析一文可以知道,Render Object Tree的根节点是在Document类的成员函数attach中创建的,如下所示:
void Document::attach(const AttachContext& context)
{
......
m_renderView = new RenderView(this);
......
m_renderView->setStyle(StyleResolver::styleForDocument(*this));
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/dom/Document.cpp中。
Document类的成员函数attach首先创建了一个RenderView对象,保存在成员变量m_renderView中。这个RenderView对象就是Render Object Tree的根节点。Document类的成员函数attach接下来还会调用RenderView类的成员函数setStyle给前面创建的RenderView对象设置CSS属性。
从前面Chromium网页Render Layer Tree创建过程分析一文可以知道,在给Render Object Tree的节点设置CSS属性的过程中,会创建相应的Render Layer。这一步发生在RenderLayerModelObject类的成员函数styleDidChange中,如下所示:
void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
......
LayerType type = layerTypeRequired();
if (type != NoLayer) {
if (!layer() && layerCreationAllowedForSubtree()) {
......
createLayer(type);
......
}
} else if (layer() && layer()->parent()) {
......
layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer
......
}
if (layer()) {
......
layer()->styleChanged(diff, oldStyle);
}
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp中。
RenderLayerModelObject类的成员函数styleDidChange的详细分析可以参考Chromium网页Render Layer Tree创建过程分析一文。其中,Render Layer的创建是通过调用RenderLayerModelObject类的成员函数createLayer实现的,并且创建出来的Render Layer的成员函数styleChanged会被调用,用来设置它的CSS属性。
在设置Render Layer Tree的根节点的CSS属性的过程中,会触发Graphics Layer Tree的根节点的创建,因此接下来我们继续分析RenderLayer类的成员函数styleChanged的实现,如下所示:
void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
{
......
m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayer.cpp中。
RenderLayer类的成员变量m_stackingNode指向的是一个RenderLayerStackingNode对象。这个RenderLayerStackingNode对象描述的是一个Stacking Context。关于Stacking Context,可以参考前面Chromium网页Graphics Layer Tree创建过程分析一文。RenderLayer类的成员函数styleChanged调用上述RenderLayerStackingNode对象的成员函数updateStackingNodesAfterStyleChange通知它所关联的Render Layer的CSS属性发生了变化,这样它可能就需要更新自己的子元素。
RenderLayerStackingNode类的成员函数updateStackingNodesAfterStyleChange的实现如下所示:
void RenderLayerStackingNode::updateStackingNodesAfterStyleChange(const RenderStyle* oldStyle)
{
bool wasStackingContext = oldStyle ? !oldStyle->hasAutoZIndex() : false;
int oldZIndex = oldStyle ? oldStyle->zIndex() : 0;
bool isStackingContext = this->isStackingContext();
if (isStackingContext == wasStackingContext && oldZIndex == zIndex())
return;
dirtyStackingContextZOrderLists();
if (isStackingContext)
dirtyZOrderLists();
else
clearZOrderLists();
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp中。
RenderLayerStackingNode类的成员函数updateStackingNodesAfterStyleChange判断当前正在处理的RenderLayerStackingNode对象关联的Render Layer的CSS属性变化,是否导致它从一个Stacking Context变为一个非Stacking Context,或者从一个非Stacking Context变为一个Stacking Context。
在从非Stacking Context变为Stacking Context的情况下,RenderLayerStackingNode类的成员函数updateStackingNodesAfterStyleChange就会调用另外一个成员函数dirtyZOrderLists将Stacking Context标记为Dirty状态,这样以后在需要的时候就会根据该Stacking Context的子元素的z-index重新构建Graphics Layer Tree。
RenderLayerStackingNode类的成员函数dirtyZOrderLists的实现如下所示:
void RenderLayerStackingNode::dirtyZOrderLists()
{
......
if (m_posZOrderList)
m_posZOrderList->clear();
if (m_negZOrderList)
m_negZOrderList->clear();
m_zOrderListsDirty = true;
if (!renderer()->documentBeingDestroyed())
compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree);
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp中。
RenderLayerStackingNode类的成员函数dirtyZOrderLists首先是将用来保存子元素的两个列表清空。其中一个列表用来保存z-index为正数的子元素,另一个列表用来保存z-index为负数的子元素。这些子元素在各自的列表中均是按照从小到大的顺序排列的。有了这个顺序之后,Graphics Layer Tree就可以方便地按照z-index顺序创建出来。
RenderLayerStackingNode类的成员函数dirtyZOrderLists接下来将成员变量m_zOrderListsDirty的值设置为true,就将自己的状态标记为Dirty,以后就会重新根据子元素的z-index值,将它们分别保存在对应的列表中。
RenderLayerStackingNode类的成员函数dirtyZOrderLists最后判断当前加载的网页有没有被销毁。如果没有被销毁,就会调用另外一个成员函数compositor,获得一个RenderLayerCompositor对象。这个RenderLayerCompositor对象是用来管理当前加载的网页的Graphics Layer Tree的。有了这个RenderLayerCompositor对象之后,就可以调用它的成员函数setNeedsCompositingUpdate,用来通知它需要重建Graphics Layer Tree。
RenderLayerCompositor类的成员函数setNeedsCompositingUpdate的实现如下所示:
void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType updateType)
{
......
if (!m_renderView.needsLayout())
enableCompositingModeIfNeeded();
m_pendingUpdateType = std::max(m_pendingUpdateType, updateType);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
RenderLayerCompositor类的成员变量m_renderView描述的是一个RenderView对象。这个RenderView对象就是在前面分析的Document类的成员函数attach中创建的RenderView对象。RenderLayerCompositor类的成员函数setNeedsCompositingUpdate判断它是否需要重新Layout。如果需要的话,就会调用另外一个成员函数enableCompositingModeIfNeeded将网页的Render Layer Tree的根节点设置为一个Compositing Layer,也就是要为它创建一个Graphics Layer。
在我们这个情景中,RenderLayerCompositor类的成员变量m_renderView描述的RenderView对象是刚刚创建的,这意味它需要执行一个Layout操作,因此接下来RenderLayerCompositor类的成员函数setNeedsCompositingUpdate会调用成员函数enableCompositingModeIfNeeded为Render Layer Tree的根节点创建一个Graphics Layer,作为Graphics Layer Tree的根节点。
RenderLayerCompositor类的成员函数enableCompositingModeIfNeeded的实现如下所示:
void RenderLayerCompositor::enableCompositingModeIfNeeded()
{
......
if (rootShouldAlwaysComposite()) {
......
setCompositingModeEnabled(true);
}
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
RenderLayerCompositor类的成员函数enableCompositingModeIfNeeded首先调用成员函数rootShouldAlwaysComposite判断是否要为网页Render Layer Tree的根节点创建一个Graphics Layer。如果需要的话,就调用另外一个成员函数setCompositingModeEnabled进行创建。
RenderLayerCompositor类的成员函数rootShouldAlwaysComposite的实现如下所示:
bool RenderLayerCompositor::rootShouldAlwaysComposite() const
{
if (!m_hasAcceleratedCompositing)
return false;
return m_renderView.frame()->isMainFrame() || m_compositingReasonFinder.requiresCompositingForScrollableFrame();
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
只有在采用硬件加速渲染网页的情况下,才需要创建Graphics Layer。当RenderLayerCompositor类的成员变量m_hasAcceleratedCompositing的值等于true的时候,就表示描述网页采用硬件加速渲染。因此,当RenderLayerCompositor类的成员变量m_hasAcceleratedCompositing的值等于false的时候,RenderLayerCompositor类的成员函数就返回一个false值给调用者,表示不需要为网页Render Layer Tree的根节点创建Graphics Layer。
在采用硬件加速渲染网页的情况下,在两种情况下,需要为Render Layer Tree的根节点创建Graphics Layer。第一种情况是当前网页加载在Main Frame中。第二种情况是当前网页不是加载在Main Frame,例如是通过iframe嵌入在Main Frame中,但是它是可滚动的。
我们假设当前网页是加载在Main Frame中的,因此RenderLayerCompositor类的成员函数rootShouldAlwaysComposite的返回值为true,这时候RenderLayerCompositor类的成员函数enableCompositingModeIfNeeded就会调用另外一个成员函数setCompositingModeEnabled为网页Render Layer Tree的根节点创建Graphics Layer。
RenderLayerCompositor类的成员函数setCompositingModeEnabled的实现如下所示:
void RenderLayerCompositor::setCompositingModeEnabled(bool enable)
{
......
m_compositing = enable;
......
if (m_compositing)
ensureRootLayer();
else
destroyRootLayer();
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
从前面的调用过程可以知道,参数enable的值等于true,这时候RenderLayerCompositor类的成员函数setCompositingModeEnabled会调用另外一个成员函数ensureRootLayer创建Graphics Layer Tree的根节点。
RenderLayerCompositor类的成员函数ensureRootLayer的实现如下所示:
void RenderLayerCompositor::ensureRootLayer()
{
RootLayerAttachment expectedAttachment = m_renderView.frame()->isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame;
......
if (!m_rootContentLayer) {
m_rootContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this);
......
}
if (!m_overflowControlsHostLayer) {
......
// Create a layer to host the clipping layer and the overflow controls layers.
m_overflowControlsHostLayer = GraphicsLayer::create(graphicsLayerFactory(), this);
// Create a clipping layer if this is an iframe or settings require to clip.
m_containerLayer = GraphicsLayer::create(graphicsLayerFactory(), this);
......
m_scrollLayer = GraphicsLayer::create(graphicsLayerFactory(), this);
......
// Hook them up
m_overflowControlsHostLayer->addChild(m_containerLayer.get());
m_containerLayer->addChild(m_scrollLayer.get());
m_scrollLayer->addChild(m_rootContentLayer.get());
......
}
......
attachRootLayer(expectedAttachment);
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
RenderLayerCompositor类的成员函数ensureRootLayer的详细分析可以参考前面Chromium网页Graphics Layer Tree创建过程分析一文,现在我们关注的重点是它最后调用另外一个成员函数attachRootLayer将Graphics Layer Tree的根节点设置给WebKit的使用者,即Chromium的Content层。
RenderLayerCompositor类的成员函数attachRootLayer的实现如下所示:
void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment)
{
......
switch (attachment) {
......
case RootLayerAttachedViaChromeClient: {
LocalFrame& frame = m_renderView.frameView()->frame();
Page* page = frame.page();
if (!page)
return;
page->chrome().client().attachRootGraphicsLayer(rootGraphicsLayer());
break;
}
......
}
m_rootLayerAttachment = attachment;
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
从前面的调用过程可以知道,如果当前网页是在Main Frame中加载的,那么参数attachment的值就等于RootLayerAttachedViaChromeClient,这时候RenderLayerCompositor类的成员函数attachRootLayer与当前加载网页关联的一个ChromeClientImpl对象,并且调用这个ChromeClientImpl对象的成员函数attachRootGraphicsLayer将Graphics Layer Tree的根节点传递给它处理。Graphics Layer Tree的根节点可以通过调用RenderLayerCompositor类的成员函数rootGraphicsLayer获得。
ChromeClientImpl类的成员函数attachRootGraphicsLayer的实现如下所示:
void ChromeClientImpl::attachRootGraphicsLayer(GraphicsLayer* rootLayer)
{
m_webView->setRootGraphicsLayer(rootLayer);
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/ChromeClientImpl.cpp中。
ChromeClientImpl类的成员变量m_webView指向的是一个WebViewImpl对象。这个WebViewImpl对象的创建过程可以参考前面Chromium网页Frame Tree创建过程分析一文。ChromeClientImpl类的成员函数attachRootGraphicsLayer所做的事情就是调用这个WebViewImpl对象的成员函数setRootGraphicsLayer,以便将Graphics Layer Tree的根节点传递给它处理。
WebViewImpl类的成员函数setRootGraphicsLayer的实现如下所示:
void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer)
{
if (pinchVirtualViewportEnabled()) {
PinchViewport& pinchViewport = page()->frameHost().pinchViewport();
pinchViewport.attachToLayerTree(layer, graphicsLayerFactory());
if (layer) {
m_rootGraphicsLayer = pinchViewport.rootGraphicsLayer();
m_rootLayer = pinchViewport.rootGraphicsLayer()->platformLayer();
......
}
......
} else {
m_rootGraphicsLayer = layer;
m_rootLayer = layer ? layer->platformLayer() : 0;
......
}
setIsAcceleratedCompositingActive(layer);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/WebViewImpl.cpp中。
如果浏览器设置了"enable-pinch-virtual-viewport"启动选项,调用WebViewImpl类的成员函数pinchVirtualViewportEnabled得到的返回值就会为true。这时候网页有两个Viewport,一个称为Inner Viewport,另一个称为Outer Viewport。Outer Viewport有两个特性。第一个特性是它的大小不跟随页面进行缩放,第二个特性是fixed positioned元素的位置是根据它来计算的。这种体验的特点是fixed positioned元素的位置不会随页面的缩放发生变化。为实现这种体验,需要在Graphics Layer Tree中增加一些Graphics Layer。这些Graphics Layer通过一个PinchViewport管理。这时候Graphics Layer Tree的根节点就不再是参数layer描述的Graphics Layer,而是PinchViewport额外创建的一个Graphics Layer。关于Pinch Virtual Viewport特性的更多信息,可以参考官方文档:Layer-based Solution for Pinch Zoom / Fixed Position。
为简单起见,我们假设没有设置"enable-pinch-virtual-viewport"启动选项,这时候WebViewImpl类的成员函数setRootGraphicsLayer会将参数layer指向的一个Graphics Layer,也就是Graphics Layer Tree的根节点,保存在成员变量m_rootGraphicsLayer中,并且调用它的成员函数platformLayer获得与它关联的一个WebLayerImpl对象,保存在另外一个成员变量m_rootLayer中。
再接下来,WebViewImpl类的成员函数setRootGraphicsLayer调用另外一个成员函数setIsAcceleratedCompositingActive激活网页的硬件加速渲染,它的实现如下所示:
void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
{
......
if (!active) {
m_isAcceleratedCompositingActive = false;
......
} else if (m_layerTreeView) {
m_isAcceleratedCompositingActive = true;
......
} else {
......
m_client->initializeLayerTreeView();
m_layerTreeView = m_client->layerTreeView();
if (m_layerTreeView) {
m_layerTreeView->setRootLayer(*m_rootLayer);
......
}
......
m_isAcceleratedCompositingActive = true;
......
}
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/WebViewImpl.cpp中。
从前面的调用过程可以知道,参数active的值是等于true的,WebViewImpl类的成员变量m_isAcceleratedCompositingActive的值将被设置为参数active的值,用来表示网页是否已经激活网页硬件加速渲染。
WebViewImpl类还有两个重要的成员变量m_client和m_layerTreeView。其中,成员变量m_client的初始化过程可以参考前面Chromium网页Frame Tree创建过程分析一文,它指向的是一个在Chromium的Content层创建的RenderViewImpl对象。
另外一个成员变量m_layerTreeView是一个类型为WebLayerTreeView指针,它的值开始的时候是等于NULL的。WebViewImpl类的成员函数setIsAcceleratedCompositingActive被调用的时候,如果参数active的值是等于true,并且成员变量m_layerTreeView的值也等于NULL,那么WebKit就会先请求使用者,也就是Chromium的Content层,初始化CC Layer Tree。这是通过调用成员变量m_client指向的一个RenderViewImpl对象的成员函数initializeLayerTreeView实现的。Layer Tree View初始化完成之后,WebViewImpl类再将成员变量m_rootLayer描述的WebLayerImpl对象关联的Picture Layer设置为CC Layer Tree的根节点。
接下来我们先分析RenderViewImpl类的成员函数initializeLayerTreeView初始化CC Layer Tree的过程,然后再分析设置CC Layer Tree根节点的过程。
RenderViewImpl类的成员函数initializeLayerTreeView的实现如下所示:
void RenderViewImpl::initializeLayerTreeView() {
RenderWidget::initializeLayerTreeView();
......
}
这个函数定义在文件external/chromium_org/content/renderer/render_view_impl.cc中。
RenderViewImpl类的成员函数initializeLayerTreeView主要是调用父类RenderWidget的成员函数initializeLayerTreeView初始化一个CC Layer Tree,如下所示:
void RenderWidget::initializeLayerTreeView() {
compositor_ = RenderWidgetCompositor::Create(
this, is_threaded_compositing_enabled_);
......
if (init_complete_)
StartCompositor();
}
这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。
RenderWidget类的成员函数initializeLayerTreeView首先是调用RenderWidgetCompositor类的静态成员函数Create创建一个RenderWidgetCompositor对象,并且保存在成员变量compositor_中。在创建这个RenderWidgetCompositor对象期间,也会伴随着创建一个CC Layer Tree。
RenderWidget类有一个成员变量init_complete_,当它的值等于true的时候,表示Browser进程已经为当前正在加载的网页初始化好Render View,这时候RenderWidget类的成员函数initializeLayerTreeView就会调用另外一个成员函数StartCompositor激活前面Chromium网页加载过程简要介绍和学习计划一文中提到的调度器,表示它可以开始进行调度工作了。
接下来我们先分析RenderWidget类的成员变量init_complete_被设置为true的过程。从前面Chromium网页Frame Tree创建过程分析一文可以知道,当Browser进程为在Render进程中加载的网页创建了一个Render View之后,会向Render进程发送一个类型为ViewMsg_New的消息。这个IPC消息被RenderThreadImpl类的成员函数OnCreateNewView处理。在处理期间,会创建一个RenderViewImpl对象,并且调用它的成员函数Initialize对其进行初始化,如下所示:
void RenderViewImpl::Initialize(RenderViewImplParams* params) {
......
main_render_frame_.reset(RenderFrameImpl::Create(
this, params->main_frame_routing_id));
......
WebLocalFrame* web_frame = WebLocalFrame::create(main_render_frame_.get());
main_render_frame_->SetWebFrame(web_frame);
......
webwidget_ = WebView::create(this);
......
// If this is a popup, we must wait for the CreatingNew_ACK message before
// completing initialization. Otherwise, we can finish it now.
if (opener_id_ == MSG_ROUTING_NONE) {
......
CompleteInit();
}
webview()->setMainFrame(main_render_frame_->GetWebFrame());
......
}
这个函数定义在文件external/chromium_org/content/renderer/render_view_impl.cc中。
RenderViewImpl类的成员函数Initialize的详细分析可以参考前面Chromium网页Frame Tree创建过程分析一文。这里我们看到,当RenderViewImpl类的成员变量opener_id_的值等于MSG_ROUTING_NONE的时候,另外一个成员函数CompleteInit就会被调用。RenderViewImpl类的成员变量opener_id_什么时候会等于MSG_ROUTING_NONE呢?如果正在加载的网页不是在一个Popup Window显示时,它的值就会等于MSG_ROUTING_NONE,否则它的值等于将它Popup出来的网页的Routing ID。从代码注释我们还可以看到,如果当前加载的网页是在一个Popup Window显示时,RenderViewImpl类的成员函数CompleteInit将会延迟到Render进程接收到Broswer发送另外一个类型为ViewMsg_CreatingNew_ACK的IPC消息时才会被调用。
我们假设正在加载的网页不是一个Popup Window显示,这时候RenderViewImpl类的成员函数CompleteInit就会被调用。RenderViewImpl类的成员函数CompleteInit是从父类RenderWidget继承下来的,它的实现如下所示:
void RenderWidget::CompleteInit() {
......
init_complete_ = true;
if (compositor_)
StartCompositor();
......
}
这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。
从这里就可以看到,RenderWidget类的成员变量init_complete_将会被设置为true,并且在成员变量compositor_的值不等于NULL的情况下,会调用前面提到的成员函数StartCompositor激活前面Chromium网页加载过程简要介绍和学习计划一文中提到的调度器。
回到前面分析的RenderWidget类的成员函数initializeLayerTreeView中,我们假设正在加载的网页不是在一个Popup Window显示,因此当RenderWidget类的成员函数initializeLayerTreeView被调用时,Browser进程已经为正在加载的网页初始化好了Render View,这意味着此时RenderWidget类的成员变量init_complete_已经被设置为true,于是RenderWidget类的成员函数initializeLayerTreeView就会先调用RenderWidgetCompositor类的静态成员函数Create创建一个RenderWidgetCompositor对象,然后再调用另外一个成员函数StartCompositor激活前面Chromium网页加载过程简要介绍和学习计划一文中提到的调度器。接下来我们就先分析RenderWidgetCompositor类的静态成员函数Create的实现,在接下来一篇文章中再分析RenderWidget类的成员函数StartCompositor激活调度器的过程。
RenderWidgetCompositor类的静态成员函数Create的实现如下所示:
scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
RenderWidget* widget,
bool threaded) {
scoped_ptr<RenderWidgetCompositor> compositor(
new RenderWidgetCompositor(widget, threaded));
CommandLine* cmd = CommandLine::ForCurrentProcess();
cc::LayerTreeSettings settings;
......
settings.initial_debug_state.show_debug_borders =
cmd->HasSwitch(cc::switches::kShowCompositedLayerBorders);
settings.initial_debug_state.show_fps_counter =
cmd->HasSwitch(cc::switches::kShowFPSCounter);
settings.initial_debug_state.show_layer_animation_bounds_rects =
cmd->HasSwitch(cc::switches::kShowLayerAnimationBounds);
settings.initial_debug_state.show_paint_rects =
cmd->HasSwitch(switches::kShowPaintRects);
settings.initial_debug_state.show_property_changed_rects =
cmd->HasSwitch(cc::switches::kShowPropertyChangedRects);
settings.initial_debug_state.show_surface_damage_rects =
cmd->HasSwitch(cc::switches::kShowSurfaceDamageRects);
settings.initial_debug_state.show_screen_space_rects =
cmd->HasSwitch(cc::switches::kShowScreenSpaceRects);
settings.initial_debug_state.show_replica_screen_space_rects =
cmd->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects);
settings.initial_debug_state.show_occluding_rects =
cmd->HasSwitch(cc::switches::kShowOccludingRects);
settings.initial_debug_state.show_non_occluding_rects =
cmd->HasSwitch(cc::switches::kShowNonOccludingRects);
......
compositor->Initialize(settings);
return compositor.Pass();
}
这个函数定义在文件external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。
RenderWidgetCompositor类的静态成员函数Create首先创建一个RenderWidgetCompositor对象,接着根据Render进程的启动选项初始化一个LayerTreeSettings对象,最后以这个LayerTreeSettings对象为参数,对前面创建的RenderWidgetCompositor对象进行初始化,这是通过调用RenderWidgetCompositor类的成员函数Initialize实现的。
接下来我们先分析RenderWidgetCompositor对象的创建过程,也就是RenderWidgetCompositor类的构造函数的实现,接下来再分析RenderWidgetCompositor对象的初始化过程,也就是RenderWidgetCompositor类的成员函数Initialize的实现。
RenderWidgetCompositor类的构造函数的实现如下所示:
RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget* widget,
bool threaded)
: threaded_(threaded),
......,
widget_(widget) {
}
这个函数定义在文件external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。
RenderWidgetCompositor类的构造函数主要是将参数widget指向的RenderViewImpl对象保存在成员变量widget_中,并且将参数threaded的值保存在成员变量threaded_中。参数threaded用来描述Render进程是否要采用线程化渲染,也就是是否需要创建一个Compositor线程来专门执行渲染相关的工作。
从前面的调用过程可以知道,参数threaded是从RenderWidget类的成员函数initializeLayerTreeView中传递过来的,它的值等于RenderWidget类的成员变量is_threaded_compositing_enabled_的值。RenderWidget类的成员变量is_threaded_compositing_enabled_是在构造函数初始化的,如下所示:
RenderWidget::RenderWidget(blink::WebPopupType popup_type,
const blink::WebScreenInfo& screen_info,
bool swapped_out,
bool hidden,
bool never_visible)
: ...... {
......
is_threaded_compositing_enabled_ =
CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableThreadedCompositing);
}
这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。
这意味着当Render进程设置了“enable-threaded-compositing”启动选项时,Render进程就会采用线程化渲染机制。我们接下来以及以后的文章只考虑线程化渲染机制这种情况。
回到RenderWidgetCompositor类的构造函数中,这意味着它的成员变量threaded_会被设置为true。
接下来我们继续分析RenderWidgetCompositor对象的初始化过程,也就是RenderWidgetCompositor类的成员函数Initialize的实现,如下所示:
void RenderWidgetCompositor::Initialize(cc::LayerTreeSettings settings) {
scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy;
RenderThreadImpl* render_thread = RenderThreadImpl::current();
......
// render_thread may be NULL in tests.
if (render_thread) {
compositor_message_loop_proxy =
render_thread->compositor_message_loop_proxy();
......
}
if (compositor_message_loop_proxy.get()) {
layer_tree_host_ = cc::LayerTreeHost::CreateThreaded(
this, shared_bitmap_manager, settings, compositor_message_loop_proxy);
} else {
layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(
this, this, shared_bitmap_manager, settings);
}
......
}
这个函数定义在文件external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。
RenderWidgetCompositor类的成员函数Initialize首先调用RenderThreadImpl类的静态成员函数current获得一个RenderThreadImpl对象。这个RenderThreadImpl对象描述的实际上是Render进程的Render线程,也就是Main线程。这个Main线程是在Render进程启动的时候创建的,是一定会存在的,具体可以参考Chromium的Render进程启动过程分析一文。
RenderWidgetCompositor类的成员函数Initialize接下来调用前面获得的RenderThreadImpl对象的成员函数compositor_message_loop_proxy获得Render进程的Compositor线程的消息循环代理对象。当这个消息循环代理对象存在时,就会调用cc::LayerTreeHost类的静态成员函数CreateThreaded创建一个支持线程化渲染的LayerTreeHost对象,并且保存在成员变量layer_tree_host_中。另一方面,如果Render进程中不存在Compositor线程,那么RenderWidgetCompositor类的成员函数Initialize就会调用cc::LayerTreeHost类的静态成员函数CreateSingleThreaded创建一个不支持线程化渲染的LayerTreeHost对象。在后一种情况下,所有的渲染操作都将在Render进程的Main线程中执行。
接下来我们首先分析Render进程的Compositor线程的创建过程。前面提到,当Browser进程为Render进程中加载的网页创建了一个Render View时,就会发送一个类型为ViewMsg_New的IPC消息给Render进程。Render进程通过RenderThreadImpl类的成员函数OnCreateNewView接收和处理该消息,如下所示:
void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {
EnsureWebKitInitialized();
// When bringing in render_view, also bring in webkit's glue and jsbindings.
RenderViewImpl::Create(params.opener_route_id,
params.window_was_created_with_opener,
params.renderer_preferences,
params.web_preferences,
params.view_id,
params.main_frame_routing_id,
params.surface_id,
params.session_storage_namespace_id,
params.frame_name,
false,
params.swapped_out,
params.proxy_routing_id,
params.hidden,
params.never_visible,
params.next_page_id,
params.screen_info,
params.accessibility_mode);
}
这个函数定义在文件external/chromium_org/content/renderer/render_thread_impl.cc中。
除了调用RenderViewImpl类的静态成员函数Create创建一个RenderViewImpl对象,RenderThreadImpl类的成员函数OnCreateNewView还会调用另外一个成员函数EnsureWebKitInitialized确保WebKit已经初始化好。
RenderThreadImpl类的成员函数EnsureWebKitInitialized的实现如下所示:
void RenderThreadImpl::EnsureWebKitInitialized() {
if (webkit_platform_support_)
return;
webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl);
blink::initialize(webkit_platform_support_.get());
......
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
bool enable = command_line.HasSwitch(switches::kEnableThreadedCompositing);
if (enable) {
......
if (!compositor_message_loop_proxy_.get()) {
compositor_thread_.reset(new base::Thread("Compositor"));
compositor_thread_->Start();
......
compositor_message_loop_proxy_ =
compositor_thread_->message_loop_proxy();
......
}
......
}
......
}
这个函数定义在文件external/chromium_org/content/renderer/render_thread_impl.cc中。
除了执行初始化WebKit的工作,RenderThreadImpl类的成员函数EnsureWebKitInitialized还做的另外一件重要事情是检查Render进程是否设置了“enable-threaded-compositing”启动选项。如果设置了,那么就会创建和启动一个Compositor线程,并且将这个Compositor线程的消息循环代理对象保存在成员变量compositor_message_loop_proxy_中。这样当RenderThreadImpl类的成员函数compositor_message_loop_proxy被调用时,Compositor线程的消息循环代理对象就会被返回给调用者,如下所示:
class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
public ChildThread,
public GpuChannelHostFactory {
public:
......
scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy() const {
return compositor_message_loop_proxy_;
}
......
};
这个函数定义在文件external/chromium_org/content/renderer/render_thread_impl.h中。
有了这个消息循环代理对象之后,就可以向Compositor线程发送消息请求其执行相应的操作了。
回到RenderWidgetCompositor类的成员函数Initialize,它获得了Compositor线程的消息循环代理对象之后,接下来就调用cc::LayerTreeHost类的静态成员函数CreateThreaded创建一个支持线程化渲染的LayerTreeHost对象,如下所示:
scoped_ptr<LayerTreeHost> LayerTreeHost::CreateThreaded(
LayerTreeHostClient* client,
SharedBitmapManager* manager,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
DCHECK(impl_task_runner);
scoped_ptr<LayerTreeHost> layer_tree_host(
new LayerTreeHost(client, manager, settings));
layer_tree_host->InitializeThreaded(impl_task_runner);
return layer_tree_host.Pass();
}
这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。
LayerTreeHost类的静态成员函数CreateThreaded首先创建了一个LayerTreeHost对象,如下所示:
LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client,
SharedBitmapManager* manager,
const LayerTreeSettings& settings)
: ......,
client_(client),
...... {
......
}
这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。
从前面的调用过程可以知道,参数client指向的是一个RenderWidgetCompositor对象,这个RenderWidgetCompositor对象将会被保存LayerTreeHost类的成员变量client_中。
回到LayerTreeHost类的静态成员函数CreateThreaded中,它创建了一个LayerTreeHost对象之后,接下来会调用它的成员函数InitializeThreaded对其进行初始化,如下所示:
void LayerTreeHost::InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
InitializeProxy(ThreadProxy::Create(this, impl_task_runner));
}
这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。
从前面的调用过程可以知道,参数impl_task_runner描述的是Compositor线程的消息循环,LayerTreeHost类的成员函数InitializeThreaded首先调用ThreadProxy类的静态成员函数Create创建一个ThreadProxy对象,接着用这个ThreadProxy对象初始化当前正在处理的LayerTreeHost对象,这是通过调用LayerTreeHost类的成员函数IntializeProxy实现的。
接下来我们先分析ThreadProxy类的静态成员函数Create创建ThreadProxy对象的过程,接着再分析LayerTreeHost类的成员函数IntializeProxy初始化LayerTreeHost对象的过程。
ThreadProxy类的静态成员函数Create的实现如下所示:
scoped_ptr<Proxy> ThreadProxy::Create(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
return make_scoped_ptr(new ThreadProxy(layer_tree_host, impl_task_runner))
.PassAs<Proxy>();
}
这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。
从这里可以看到,ThreadProxy类的静态成员函数Create创建了一个ThreadProxy对象返回给调用者。
ThreadProxy对象的创建过程,即ThreadProxy类的构造函数的实现,如下所示:
ThreadProxy::ThreadProxy(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
: Proxy(impl_task_runner),
...... {
......
}
这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。
ThreadProxy类的构造函数主要是调用了父类Proxy的构造函数执行初始化工作,如下所示:
Proxy::Proxy(scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
: main_task_runner_(base::MessageLoopProxy::current()),
......
impl_task_runner_(impl_task_runner),
...... {
......
}
这个函数定义在文件external/chromium_org/cc/trees/proxy.cc中。
从前面的分析可以知道,参数impl_task_runner描述的是Compositor线程的消息循环,它将被保存在Proxy类的成员变量impl_task_runner_中。此外,Proxy类的构造函数还会通过调用MessageLoopProxy类的静态成员函数current获得当前线程的消
以上是关于Chromium网页Layer Tree创建过程分析的主要内容,如果未能解决你的问题,请参考以下文章
Chromium网页Graphics Layer Tree创建过程分析
Chromium网页Pending Layer Tree激活为Active Layer Tree的过程分析