Chromium网页Render Layer Tree创建过程分析.docx
- 文档编号:24871248
- 上传时间:2023-06-02
- 格式:DOCX
- 页数:16
- 大小:64.28KB
Chromium网页Render Layer Tree创建过程分析.docx
《Chromium网页Render Layer Tree创建过程分析.docx》由会员分享,可在线阅读,更多相关《Chromium网页Render Layer Tree创建过程分析.docx(16页珍藏版)》请在冰豆网上搜索。
Chromium网页RenderLayerTree创建过程分析
Chromium网页RenderLayerTree创建过程分析
在前面一文中,我们分析了网页RenderObjectTree的创建过程。
在创建RenderObjectTree的同时,WebKit还会创建RenderLayerTree,但不是每一个RenderObject都有对应的RenderLayer。
RenderLayer是一个最小渲染单元,被若干RenderObject共用。
本文接下来就分析RenderLayerTree的创建过程。
网页的RenderObjectTree与RenderLayerTree的关系可以通过图1描述,如下所示:
图1RenderLayerTree与DOMTree、RenderObjectTree和GraphicsLayerTree的关系
从图1还可以看到,RenderLayerTree创建完成之后,WebKit还会继续创建一个GraphicsLayerTree。
本文主要关注RenderLayerTree的创建过程。
DOMTree和RenderObjectTree的创建过程可以参考和这两篇文章。
GraphicsLayerTree的创建过程在接下来一篇文章分析。
网页的RenderLayerTree是在创建RenderObjectTree的过程中创建的。
确切地说,是在设置RenderObject的CSS属性的过程中创建的。
从前面一文可以知道,当DOMTree中的HTMLElement节点需要进行渲染的时候,WebKit就会为其创建一个RenderObject。
这个RenderObject在创建完成之后,就会被设置CSS属性,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderTreeBuilder:
:
createRendererForElementIfNeeded()
{
......
Element*element=toElement(m_node);
RenderStyle&style=this->style();
if(!
element->rendererIsNeeded(style))
return;
RenderObject*newRenderer=element->createRenderer(&style);
......
RenderObject*parentRenderer=this->parentRenderer();
......
element->setRenderer(newRenderer);
newRenderer->setStyle(&style);//setStyle()candependonrenderer()alreadybeingset.
parentRenderer->addChild(newRenderer,nextRenderer);
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/dom/RenderTreeBuilder.cpp中。
从这里可以看到,新创建的RenderObject的CSS属性是通过调用RenderObject类的成员函数setStyle设置的,它的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderObject:
:
setStyle(PassRefPtr
{
......
if(m_style==style){
......
return;
}
StyleDifferencediff;
unsignedcontextSensitiveProperties=ContextSensitivePropertyNone;
if(m_style)
diff=m_style->visualInvalidationDiff(*style,contextSensitiveProperties);
......
RefPtr
setStyleInternal(style);
......
styleDidChange(diff,oldStyle.get());
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderObject.cpp中。
RenderObject类的成员变量m_style指向的是一个RenderStyle对象,它描述的是当前正在处理的RenderObject对象的CSS属性。
RenderObject类的成员函数setStyle首先比较成员变量m_style指向的RenderStyle对象和参数style指向的RenderStyle对象所描述的CSS属性是否是一样的。
如果是一样的,那么就不再重新设置当前正在处理的RenderObject对象的CSS属性。
如果成员变量m_style指向的RenderStyle对象和参数style指向的RenderStyle对象所描述的CSS属性不一样。
那么RenderObject类的成员函数setStyle接下来就会计算出它们的差异,并且调用成员函数setStyleInternal将参数style指向的RenderStyle对象保存在成员变量m_style中,作为当前正在处理的RenderObject对象的CSS属性,最后调用成员函数styleDidChange通知子类当前正在处理的RenderObject对象的CSS属性发生了变化。
在前面一文中,我们假设创建的RenderObject实际上是一个RenderBlockFlow对象,也就是当前正在处理的是一个RenderBlockFlow对象。
RenderBlockFlow类是从RenderObject类继承下来的,并且重写了成员函数styleDidChange。
因此,接下来RenderBlockFlow类的成员函数styleDidChange就会被调用。
在调用的过程中,就会检查是否需要创建一个RenderLayer。
RenderBlockFlow类的成员函数styleDidChange的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderBlockFlow:
:
styleDidChange(StyleDifferencediff,constRenderStyle*oldStyle)
{
RenderBlock:
:
styleDidChange(diff,oldStyle);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderBlockFlow.cpp中。
RenderBlockFlow类的成员函数styleDidChange又会调用父类RenderBlock的成员函数styleDidChange通知它当前正在处理的RenderObject的CSS属性发生了变化。
RenderBlock类的成员函数styleDidChange的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderBlock:
:
styleDidChange(StyleDifferencediff,constRenderStyle*oldStyle)
{
RenderBox:
:
styleDidChange(diff,oldStyle);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderBlock.cpp中。
RenderBlock类的成员函数styleDidChange又会调用父类RenderBox的成员函数styleDidChange通知它当前正在处理的RenderObject的CSS属性发生了变化。
RenderBox类的成员函数styleDidChange的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderBox:
:
styleDidChange(StyleDifferencediff,constRenderStyle*oldStyle)
{
......
RenderBoxModelObject:
:
styleDidChange(diff,oldStyle);
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderBox.cpp中。
RenderBox类的成员函数styleDidChange又会调用父类RenderBoxModelObject的成员函数styleDidChange通知它当前正在处理的RenderObject的CSS属性发生了变化。
RenderBoxModelObject类就是用来描述在前面一文提到的CSSBoxModel的,它的成员函数styleDidChange是从父类RenderLayerModelObject继承下来的,因此接下来我们继续分析RenderLayerModelObject类的成员函数styleDidChange的实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderLayerModelObject:
:
styleDidChange(StyleDifferencediff,constRenderStyle*oldStyle)
{
......
LayerTypetype=layerTypeRequired();
if(type!
=NoLayer){
if(!
layer()&&layerCreationAllowedForSubtree()){
......
createLayer(type);
......
}
}elseif(layer()&&layer()->parent()){
......
layer()->removeOnlyThisLayer();//callsdestroyLayer()whichclearsm_layer
......
}
if(layer()){
......
layer()->styleChanged(diff,oldStyle);
}
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp中。
RenderLayerModelObject类的成员函数styleDidChange首先调用成员函数layerTypeRequired判断是否需要为当前正在处理的RenderObject创建一个RenderLayer。
如果需要创建,那么RenderLayerModelObject类的成员函数layerTypeRequired的返回值就不等于NoLayer。
在这种情况下,RenderLayerModelObject类的成员函数就会调用成员函数layer检查当前正在处理的RenderObject是否已经关联有一个RenderLayer了。
如果已经关联有,那么调用RenderLayerModelObject类的成员函数layer的返回值就不等于NULL。
这时候就不需要为当前正在处理的RenderObject创建一个RenderLayer。
如果还没有关联,那么RenderLayerModelObject类的成员函数styleDidChange继续调用成员函数layerCreationAllowedForSubtree判断在当前正在处理的RenderObject的祖先节点中,是否存在一个类型为RenderSVGHiddenContainer的RenderObject。
类型为RenderSVGHiddenContainer的RenderObject是不需要绘制的,并且它的子节点也是不需要绘制的。
因此,如果在当前正在处理的RenderObject的祖先节点中存在一个类型为RenderSVGHiddenContainer的RenderObject,那么就不需要为当前正在处理的RenderObject创建一个RenderLayer了。
另一方面,如果此时在当前正在处理的RenderObject的祖先节点中不存在一个类型为RenderSVGHiddenContainer的RenderObject,那么就需要为当前正在处理的RenderObject创建一个RenderLayer,这是通过调用RenderLayerModelObject类的成员函数createLayer创建一个RenderLayer。
如果前面RenderLayerModelObject类的成员函数layerTypeRequired的返回值等于NoLayer,并且当前正在处理的RenderObject关联有RenderLayer,以及这个RenderLayer位于RenderLayerTree中,也就是这个RenderLayer有父节点,那么就需要将这个RenderLayer从RenderLayerTree中删除,这是通过调用RenderLayer类的成员函数removeOnlyThisLayer实现的。
最后,如果前面RenderLayerModelObject类的成员函数styleDidChange为当前正在处理的RenderObject创建了一个RenderLayer,或者当前正在处理的RenderObject本来就已经关联有一个RenderLayer,那么RenderLayerModelObject类的成员函数styleDidChange还会通知这个RenderLayer,它所关联的RenderObject的CSS属性发生了变化,这是通过调用RenderLayer类的成员函数styleChanged实现的。
RenderLayer类的成员函数styleChanged在调用期间,会判断是否需要为当前正在处理的RenderLayer创建一个GraphicsLayer。
创建出来的GraphicsLayer就会形成图1所示的GraphicsLayerTree。
在接下来一篇文章中,我们再详细分析GraphicsLayerTree的创建过程。
接下来,我们继续分析RenderLayerModelObject类的成员函数layerTypeRequired和createLayer的实现,以便了解一个RenderObject在什么情况下创建一个RenderLayer,以及这个RenderLayer的创建过程。
前面提到,当前正在处理的RenderObject实际上是一个RenderBlockFlow对象。
RenderBlockFlow类是从RenderBox类继承下来的,RenderBox类又是从RenderLayerModelObject类继承下来的,并且它重写了RenderLayerModelObject类的成员函数layerTypeRequired,因此,前面分析的RenderLayerModelObject类的成员函数styleDidChange实际上是调用了子类RenderBox类的成员函数layerTypeRequired判断是否需要为当前正在处理的RenderObject创建一个RenderLayer。
RenderBox类的成员函数layerTypeRequired的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
classRenderBox:
publicRenderBoxModelObject{
public:
......
virtualLayerTypelayerTypeRequired()constOVERRIDE
{
if(isPositioned()||createsGroup()||hasClipPath()||hasTransform()||hasHiddenBackface()||hasReflection()||style()->specifiesColumns()||!
style()->hasAutoZIndex()||style()->shouldCompositeForCurrentAnimations())
returnNormalLayer;
if(hasOverflowClip())
returnOverflowClipLayer;
returnNoLayer;
}
......
};
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderBox.h中。
一个RenderObject的CSS属性如果具有以下10种情况之一,那么就需要为它创建一个RenderLayer:
1.isPositioned:
position属性值不等于默认值static;
2.createsGroup:
设置有透明度(transparent)、遮罩(mask)、滤镜(filter)或者混合模式(mix-blend-mode);
3.hasClipPath:
设置有剪切路径(clip-path);
4.hasTransform:
设置有2D或者3D转换(matrix、translate、scale、rotate、skew、perspective);
5.hasHiddenBackface:
隐藏背面(backface-visibility:
hidden);
6.hasReflection:
设置有倒影(box-reflect);
7.specifiesColumns:
设置有列宽和列数(columns:
column-widthcolumn-count);
8.!
hasAutoZIndex:
z-index属性值不等于默认值auto,即指定了z-index值;
9.shouldCompositeForCurrentAnimations:
指定了不透明度(opacity)、变换(transform)或者滤镜(filter)动画;
10.hasOverflowClip:
剪切溢出内容(overflow:
hidden)。
其中,前9种情况创建的RenderLayer的类型为NormalLayer,第10种情况创建的RenderLayer的类型为OverflowClipLayer。
这两种类型的RenderLayer在本质上并没有区别,将一个RenderLayer的类型设置为OverflowClipLayer只为Bookkeeping目的,即在需要的时候可以在RenderLayerTree中找到一个类型为OverflowClipLayer的RenderLayer做相应的处理。
RenderLayerModelObject类的成员函数createLayer的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
voidRenderLayerModelObject:
:
createLayer(LayerTypetype)
{
ASSERT(!
m_layer);
m_layer=adoptPtr(newRenderLayer(this,type));
setHasLayer(true);
m_layer->insertOnlyThisLayer();
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp中。
RenderLayerModelObject类的成员函数createLayer首先是创建了一个RenderLayer对象,并且保存在成员变量m_layer中。
这个RenderLayer对象描述的就是与当前正在处理的RenderObject关联的RenderLayer。
RenderLayerModelObject类的成员函数createLayer接下来又调用另外一个成员函数setHasLayer将当前正在处理的RenderObject标记为是关联有RenderLayer的。
RenderLayer对象的创建过程,即RenderLayer类的构造函数的实现如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
RenderLayer:
:
RenderLayer(RenderLayerModelObject*renderer,LayerTypetype)
:
m_layerType(type)
......
m_renderer(renderer)
m_parent(0)
......
{
......
}
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayer.cpp中。
RenderLayer类的构造函数主要是将参数renderer和type描述的RenderObject和LayerType分别保存在成员变量m_renderer和m_layerType中,并且将成员变量m_parent的值初始化为0,表示当前正在创建的RenderLayer还未插入到网页的RenderLayerTree中。
回到RenderLayerModelObject类的成员函数createLayer中,它最后调用前面创建的RenderLayer对象的成员函数insertOnlyThisLayer将其插
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Chromium网页Render Layer Tree创建过程分析 Chromium 网页 Render Tree 创建 过程 分析