Chromium网页Graphics Layer Tree创建过程分析
在前面一文中,我们分析了网页Render Layer Tree的创建过程。在创建Render Layer的同时,WebKit还会为其创建Graphics Layer。这些Graphics Layer形成一个Graphics Layer Tree。Graphics Layer可看作是一个图形缓冲区,被若干Render Layer共用。本文接下来就分析Graphics Layer Tree的创建过程。
老罗的新浪微博: http://weibo.com/shengyangluo,欢迎关注!
网页的Render Layer Tree与Graphics Layer Tree的关系可以通过图1描述,如下所示:
图1 Graphics Layer Tree与DOM Tree、Render Object Tree和Render Layer Tree的关系
在WebKit中,Graphics Layer又称为Composited Layer。我们可以将Graphics Layer看作是Composited Layer的一种具体实现。这种具体实现是由WebKit的使用者Chromium提供的。Composited Layer描述的是一个具有后端存储的图层,因此可以将它看作是一个图形缓冲区。在软件渲染方式中,这个图形缓冲区就是一块系统内存;在硬件渲染方式中,这个图形缓冲区就是一个OpenGL里面的一个Frame Buffer Object(FBO)。
Composited Layer涉及到的一个重要概念是“Layer Compositing”。Layer Compositing是现代UI框架普遍采用的一种渲染机制。例如,Android系统的UI子系统(Surface Flinger)就是通过Compositing Surface来获得最终要显示在屏幕上的内容的。这里的Surface就相当于是Chromium的Layer。关于Android系统的Surface Flinger的详细分析,可以参考 Android系统Surface机制的SurfaceFlinger服务简要介绍和学习计划这个系列的文章。
Layer Compositing的三个主要任务是:
1. 确定哪些内容应该在哪些Composited Layer上绘制;
2. 绘制每一个Composited Layer;
3. 将所有已经绘制好的Composited Layer再次将绘制在一个最终的、可以显示在屏幕上进行显示的图形缓冲区中。
其中,第1个任务它完成之后就可以获得一个Graphics Layer Tree,第3个任务要求按照一定的顺序对Composited Layer进行绘制。注意,这个绘制顺序非常重要,否则最终合成出来的UI就会出现不正确的Overlapping。同时,这个绘制顺序对理解Graphics Layer Tree的组成也非常重要。因此,接下来我们首先介绍与这个绘制顺序有关的概念。为了方便描述,本文将上述绘制顺序称为Composited Layer的绘制顺序。
在介绍Composited Layer的绘制顺序之前,我们还需要回答一个问题:为什么要采用Layer Compositing这种UI渲染机制?主要有两个原因:
1. 避免不必要的重绘。考虑一个网页有两个Layer。在网页的某一帧显示中,Layer 1的元素发生了变化,Layer 2的元素没有发生变化。这时候只需要重新绘制Layer 1的内容,然后再与Layer 2原有的内容进行Compositing,就可以得到整个网页的内容。这样就可以避免对没有发生变化的Layer 2进行不必要的绘制。
2. 利用硬件加速高效实现某些UI特性。例如网页的某一个Layer设置了可滚动、3D变换、透明度或者滤镜,那么就可以通过GPU来高效实现。
在默认情况下,网页元素的绘制是按照Render Object Tree的先序遍历顺序进行的,并且它们在空间上是按照各自的display属性值依次进行布局的。例如,如果一个网页元素的display属性值为"inline",那么它就会以内联元素方式显示,也就是紧挨在前一个绘制的元素的后面进行显示。又如,如果一个网页元素的display属性值为"block",那么它就会以块级元素进行显示,也就是它的前后会各有一个换行符。我们将这种网页元素绘制方式称为Normal Flow或者In Flow。
有默认情况,就会例外情况。例如,如果一个网页元素同时设置了position和z-index属性,那么它可能就不会以In Flow的方式进行显示,而是以Out of Flow的方式进行显示。在默认情况下,一个网页元素的position和z-index属性值被设置为“static”和"auto"。网页元素的position属性还可以取值为“relative”、“absolute”和“fixed”,这一类网页元素称为Positioned元素。当一个Positioned元素的z-index属性值不等于"auto"时,它就会以Out of Flow的方式进行显示。
CSS 2.1规范规定网页渲染引擎要为每一个z-index属性值不等于"auto"的Positioned元素创建一个Stacking Context。对于其它的元素,它们虽然没有自己的Stacking Context,但是它们会与最近的、具有自己的Stacking Context的元素共享同相同的Stacking Context。不同Stacking Context的元素的绘制顺序是不会相互交叉的。假设有两个Stacking Context,一个包含有A和B两个元素,另一个包含有C和D两个元素,那么A、B、C和D四个元素的绘制顺序只可能为:
1. A、B、C、D
2. B、A、C、D
3. A、B、D、C
4. B、A、D、C
5. C、D、A、B
6. C、D、B、A
7. D、C、A、B
8. D、C、B、A
Stacking Context的这个特性,使得它可以成为一个观念上的原子类型绘制层(Atomic Conceptual Layer for Painting)。也就是说,只要我们定义好Stacking Context内部元素的绘制顺序,那么再根据拥有Stacking Context的元素的z-index属性值,那么就可以得到网页的所有元素的绘制顺序。
我们可以通过图2所示的例子直观地理解Stacking Context的上述特性,如下所示:
图2 Stacking Context
在图2的左边,一共有4个Stacking Context。最下面的Stacking Context的z-index等于-1;中间的Stacking Context的z-index等于0;最上面的Stacking Context的z-index等于1,并且嵌套了另外一个z-index等于6的Stacking Context。我们观察被嵌套的z-index等于6的Stacking Context,它包含了另外一个z-index也是等于6的元素,但是这两个z-index的含义是不一样的。其中,Stacking Context的z-index值是放在父Stacking Context中讨论才有意义,而元素的z-index放在当前它所在的Stacking Context讨论才有意义。再者,我们是下面和中间的两个Stacking Context,虽然它们都包含有三个z-index分别等于7、8和9的元素,但是它们是完全不相干的。
如果我们将图2左边中间的Stacking Context的z-index修改为2,那么它就会变成最上面的Stacking Context,并且会重叠在z-index等于1的Stacking Context上,以及嵌套在这个Stacking Context里面的那个Stacking Context。
这样,我们就得到了Stacking Context的绘制顺序。如前所述,接下来只要定义好Stacking Context内的元素的绘制顺序,那么就可以网页的所有元素的绘制顺序。Stacking Context内的元素的绘制顺序如下所示:
1. 背景(Backgrounds)和边界(Borders),也就是拥有Stacking Context的元素的背景和边界。
2. Z-index值为负数的子元素。
3. 内容(Contents),也就是拥有Stacking Context的元素的内容。
4. Normal Flow类型的子元素。
5. Z-index值为正数的子元素。
以上就是与Composited Layer的绘制顺序有关的背景知识。这些背景知识在后面分析Graphics Layer Tree的创建过程时就会用到。
从图1可以看到,Graphics Layer Tree是根据Render Layer Tree创建的。也就是说,Render Layer与Graphics Layer存在对应关系,如下所示:
图3 Render Layer Tree与Graphics Layer的关系
原则上,Render Layer Tree中的每一个Render Layer都对应有一个Composited Layer Mapping,每一个Composited Layer Mapping又包含有若干个Graphics Layer。但是这样将会导致创建大量的Graphics Layer。创建大量的Graphics Layer意味着需要耗费大量的内存资源。这个问题称为”Layer Explosion“问题。
为了解决“Layer Explosion”问题,每一个需要创建Composited Layer Mapping的Render Layer都需要给出一个理由。这个理由称为“Compositing Reason”,它描述的实际上是Render Layer的特证。例如,如果一个Render Layer关联的Render Object设置了3D Transform属性,那么就需要为该Render Layer创建一个Composited Layer Mapping。
WebKit一共定义了54个Compositing Reason,如下所示:
// Intrinsic reasons that can be known right away by the layer const uint64_t CompositingReason3DTransform = UINT64_C(1) << 0; const uint64_t CompositingReasonVideo = UINT64_C(1) << 1; const uint64_t CompositingReasonCanvas = UINT64_C(1) << 2; const uint64_t CompositingReasonPlugin = UINT64_C(1) << 3; const uint64_t CompositingReasonIFrame = UINT64_C(1) << 4; const uint64_t CompositingReasonBackfaceVisibilityHidden = UINT64_C(1) << 5; const uint64_t CompositingReasonActiveAnimation = UINT64_C(1) << 6; const uint64_t CompositingReasonTransitionProperty = UINT64_C(1) << 7; const uint64_t CompositingReasonFilters = UINT64_C(1) << 8; const uint64_t CompositingReasonPositionFixed = UINT64_C(1) << 9; const uint64_t CompositingReasonOverflowScrollingTouch = UINT64_C(1) << 10; const uint64_t CompositingReasonOverflowScrollingParent = UINT64_C(1) << 11; const uint64_t CompositingReasonOutOfFlowClipping = UINT64_C(1) << 12; const uint64_t CompositingReasonVideoOverlay = UINT64_C(1) << 13; const uint64_t CompositingReasonWillChangeCompositingHint = UINT64_C(1) << 14; // Overlap reasons that require knowing what's behind you in paint-order before knowing the answer const uint64_t CompositingReasonAssumedOverlap = UINT64_C(1) << 15; const uint64_t CompositingReasonOverlap = UINT64_C(1) << 16; const uint64_t CompositingReasonNegativeZIndexChildren = UINT64_C(1) << 17; const uint64_t CompositingReasonScrollsWithRespectToSquashingLayer = UINT64_C(1) << 18; const uint64_t CompositingReasonSquashingSparsityExceeded = UINT64_C(1) << 19; const uint64_t CompositingReasonSquashingClippingContainerMismatch = UINT64_C(1) << 20; const uint64_t CompositingReasonSquashingOpacityAncestorMismatch = UINT64_C(1) << 21; const uint64_t CompositingReasonSquashingTransformAncestorMismatch = UINT64_C(1) << 22; const uint64_t CompositingReasonSquashingFilterAncestorMismatch = UINT64_C(1) << 23; const uint64_t CompositingReasonSquashingWouldBreakPaintOrder = UINT64_C(1) << 24; const uint64_t CompositingReasonSquashingVideoIsDisallowed = UINT64_C(1) << 25; const uint64_t CompositingReasonSquashedLayerClipsCompositingDescendants = UINT64_C(1) << 26; // Subtree reasons that require knowing what the status of your subtree is before knowing the answer const uint64_t CompositingReasonTransformWithCompositedDescendants = UINT64_C(1) << 27; const uint64_t CompositingReasonOpacityWithCompositedDescendants = UINT64_C(1) << 28; const uint64_t CompositingReasonMaskWithCompositedDescendants = UINT64_C(1) << 29; const uint64_t CompositingReasonReflectionWithCompositedDescendants = UINT64_C(1) << 30; const uint64_t CompositingReasonFilterWithCompositedDescendants = UINT64_C(1) << 31; const uint64_t CompositingReasonBlendingWithCompositedDescendants = UINT64_C(1) << 32; const uint64_t CompositingReasonClipsCompositingDescendants = UINT64_C(1) << 33; const uint64_t CompositingReasonPerspectiveWith3DDescendants = UINT64_C(1) << 34; const uint64_t CompositingReasonPreserve3DWith3DDescendants = UINT64_C(1) << 35; const uint64_t CompositingReasonReflectionOfCompositedParent = UINT64_C(1) << 36; const uint64_t CompositingReasonIsolateCompositedDescendants = UINT64_C(1) << 37; // The root layer is a special case that may be forced to be a layer, but also it needs to be // a layer if anything else in the subtree is composited. const uint64_t CompositingReasonRoot = UINT64_C(1) << 38; // CompositedLayerMapping internal hierarchy reasons const uint64_t CompositingReasonLayerForAncestorClip = UINT64_C(1) << 39; const uint64_t CompositingReasonLayerForDescendantClip = UINT64_C(1) << 40; const uint64_t CompositingReasonLayerForPerspective = UINT64_C(1) << 41; const uint64_t CompositingReasonLayerForHorizontalScrollbar = UINT64_C(1) << 42; const uint64_t CompositingReasonLayerForVerticalScrollbar = UINT64_C(1) << 43; const uint64_t CompositingReasonLayerForScrollCorner = UINT64_C(1) << 44; const uint64_t CompositingReasonLayerForScrollingContents = UINT64_C(1) << 45; const uint64_t CompositingReasonLayerForScrollingContainer = UINT64_C(1) << 46; const uint64_t CompositingReasonLayerForSquashingContents = UINT64_C(1) << 47; const uint64_t CompositingReasonLayerForSquashingContainer = UINT64_C(1) << 48; const uint64_t CompositingReasonLayerForForeground = UINT64_C(1) << 49; const uint64_t CompositingReasonLayerForBackground = UINT64_C(1) << 50; const uint64_t CompositingReasonLayerForMask = UINT64_C(1) << 51; const uint64_t CompositingReasonLayerForClippingMask = UINT64_C(1) << 52; const uint64_t CompositingReasonLayerForScrollingBlockSelection = UINT64_C(1) << 53;这些Compositing Reason定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/CompositingReasons.h中。
其中,有3个Compositing Reason比较特殊,如下所示:
const uint64_t CompositingReasonComboSquashableReasons = CompositingReasonOverlap | CompositingReasonAssumedOverlap | CompositingReasonOverflowScrollingParent;它们是CompositingReasonOverlap、CompositingReasonAssumedOverlap和CompositingReasonOverflowScrollingParent,称为Squashable Reason。WebKit不会为具有这三种特征的Render Layer之一的Render Layer创建Composited Layer Mapping。
如果启用了Overlap Testing,那么WebKit会根据上述的Stacking Context顺序计算每一个Render Layer的后面是否有其它的Render Layer与其重叠。如果有,并且与其重叠的Render Layer有一个对应的Composited Layer Mapping,那么就会将位于上面的Render Layer的Compositing Reason设置为CompositingReasonOverlap。
如果没有启用Overlap Testing,那么WebKit会根据上述的Stacking Context顺序检查每一个Render Layer的后面是否有一个具有Composited Layer Mapping的Render Layer。只要有,不管它们是否重叠,那么就会将位于上面的Render Layer的Compositing Reason设置为CompositingReasonAssumedOverlap。
最后,如果一个Render Layer包含在一个具有overflow属性为"scroll"的Render Block中,并且该Render Block所对应的Render Layer具有Composited Layer Mapping,那么该Render Layer的Compositing Reason就会被设置为CompositingReasonOverflowScrollingParent。
WebKit会将位于一个具有Composited Layer Mapping的Render Layer的上面的那些有着Squashable Reason的Render Layer绘制在同一个Graphics Layer中。这种Graphics Layer称为Squashing Graphics Layer。这种机制也相应地称为“Layer Squashing”。通过Layer Squashing机制,就可以在一定程度上减少Graphics Layer的数量,从而在一定程度上解决“Layer Explosion”问题。
我们思考一下,为什么WebKit会将具有上述3种Compositing Reason的Render Layer绘制在一个Squashing Graphics Layer中?考虑具有CompositingReasonOverlap和CompositingReasonAssumedOverlap的Render Layer,当它们需要重绘,或者它们下面的具有Composited Layer Mapping的Render Layer重绘时,都不可避免地对它们以及它们下面的具有Composited Layer Mapping的Render Layer进行Compositing。这是由于它们相互之间存在重叠区域,只要其中一个发生变化,就会牵一发而动全身。类似地,当一个overflow属性为"scroll"的Render Block滚动时,包含在该Render Block内的Render Layer在执行完成重绘操作之后,需要参与到Compositing操作去。
WebKit定义了两个函数,用来判断一个Render Layer是需要Compositing还是Squashing,如下所示:
// Any reasons other than overlap or assumed overlap will require the layer to be separately compositing. inline bool requiresCompositing(CompositingReasons reasons) { return reasons & ~CompositingReasonComboSquashableReasons; } // If the layer has overlap or assumed overlap, but no other reasons, then it should be squashed. inline bool requiresSquashing(CompositingReasons reasons) { return !requiresCompositing(reasons) && (reasons & CompositingReasonComboSquashableReasons); }这两个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/CompositingReasons.h中。
参数reasons描述的是一个Render Layer的Compositing Reason,函数requiresCompositing判断该Render Layer是否需要Compositing,也就是是否要为该Render Layer创建一个Composited Layer Mapping,而函数requiresSquashing判断该Render Layer需要Squashing,也就是绘制在一个Squashing Graphics Layer中。
除了Compositing Render Layer和Squashing Render Layer,剩下的其它Render Layer称为Non-Compositing Render Layer。这些Render Layer将会与离其最近的具有Composited Layer Mapping的父Render Layer绘制同样的Graphics Layer中。
WebKit是根据Graphics Layer Tree来绘制网页内容的。在绘制一个Graphics Layer的时候,除了绘制Graphics Layer本身所有的内容之外,还会在Render Layer Tree中。找到与该Graphics Layer对应的Render Layer,并且从该Render Layer开始,将那些Non-Compositing类型的子Render Layer也一起绘制,直到遇到一个具有Composited Layer Mapping的子Render Layer为止。这个过程在后面的文章中分析网页内容的绘制过程时就会看到。
前面提到,Composited Layer Mapping包含有若干个Graphics Layer,这些Graphics Layer在Composited Layer Mapping,也是形成一个Graphics Layer Sub Tree的,如图4所示:
图4 Composited Layer Mapping
图4的左边是一个Render Layer Tree。其中红色的Render Layer有对应的Composited Layer Mapping。每一个Composited Layer Mapping内部都有一个Graphics Layer Sub Tree。同时,这些Graphics Layer Sub Tree又会组合在一起,从而形成整个网页的Graphics Layer Tree。
一个典型的Composited Layer Mapping对应的部分Graphics Layer Sub Tree如图5所示:
图5 一个Composited Layer Mapping对应的Graphics Layer Sub Tree的一部分
注意,图5描述的是仅仅是一个Composited Layer Mapping对应的Graphics Layer Sub Tree的一部分。例如,如果拥有该Composited Layer Mapping的Render Layer的上面存在Squashing Render Layer,那么上述Graphics Layer Sub Tree还包含有一个Squashing Graphics Layer。不过这一部分Graphics Layer Sub Tree已经足于让我们理解Composited Layer Mapping的组成。
在图5中,只有Main Layer是必须存在的,它用来绘制一个Render Layer自身的内容。其它的Graphics Layer是可选,其中:
1. 如果一个Render Layer被父Render Layer设置了裁剪区域,那么就会存在Clip Layer。
2. 如果一个Render Layer为子Render Layer设置了裁剪区域,那么就会存在Children Clip Layer。
3. 如果一个Render Layer是可滚动的,那么就会存在Scrolling Container。
4. Negative z-order children、Normal flow children和Positive z-order children描述的是按照Stacking Context规则排序的子Render Layer对应的Composited Layer Mapping描述的Graphics Layer Sub Tree,它们均以父Render Layer的Scrolling Container为父Graphics Layer。
5. 如果一个Render Layer是根Render Layer,并且它的背景被设置为固定的,即网页的body标签的CSS属性background-attachment被设置为“fixed”,那么就会存在Background Layer。
6. 当Negative z-order children存在时,就会存在Foreground Layer。从前面描述的Stacking Context规则可以知道,Negative z-order childrenc对应的Graphics Layer Sub Tree先于当前Graphics Layer Sub Tree绘制。Negative z-order childrenc对应的Graphics Layer Sub Tree在绘制的时候可能会设置了偏移位置。这些偏移位置不能影响后面的Normal flow children和Positive z-order children对应的Graphics Layer Sub Tree的绘制,因此就需要在中间插入一个Foreground Layer,用来抵消Negative z-order children对应的Graphics Layer Sub Tree设置的偏移位置。
7. 如果一个Render Layer的上面存在Squashing Render Layer,那么就会存在Squashing Layer。
了解了Composited Layer Mapping对应的Graphics Layer Sub Tree的结构之后,接下来我们就可以结合源码分析网页的Graphics Layer Tree的创建过程了。网页的Graphics Layer Tree的创建主要是分三步进行:
1. 计算各个Render Layer Tree中的Render Layer的Compositing Reason;
2. 为有需要的Render Layer创建Composited Layer Mapping;
3. 将各个Composited Layer Mapping描述Graphics Layer Sub Tree连接起来形成Graphics Layer Tree。
上述过程主要是发生在网页的Layout过程中。对网页进行Layout是网页渲染过程的一个重要步骤,以后我们分析网页的渲染过程时就会看到这一点。在WebKit中,每一个正在加载的网页都关联有一个FrameView对象。当需要对网页进行Layout时,就会调用这个FrameView对象的成员函数updateLayoutAndStyleForPainting,它的实现如下所示:
void FrameView::updateLayoutAndStyleForPainting() { // Updating layout can run script, which can tear down the FrameView. RefPtr<FrameView> protector(this); updateLayoutAndStyleIfNeededRecursive(); if (RenderView* view = renderView()) { ...... view->compositor()->updateIfNeededRecursive(); ...... } ...... }
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/frame/FrameView.cpp中。
FrameView类的成员函数updateLayoutAndStyleForPainting是通过调用另外一个成员函数updateLayoutAndStyleIfNeededRecursive对网页进行Layout的。
执行完成Layout操作之后,FrameView类的成员函数updateLayoutAndStyleForPainting又调用成员函数renderView获得一个RenderView对象。从前面 Chromium网页DOM Tree创建过程分析一文可以知道,网页的DOM Tree的根节点对应的Render Object就是一个RenderView对象。因此,前面获得的RenderView对象描述的就是正在加载的网页的Render Layer Tree的根节点。
再接下来,FrameView类的成员函数updateLayoutAndStyleForPainting又调用上述RenderView对象的成员函数compositor获得一个RenderLayerCompositor对象,如下所示:
RenderLayerCompositor* RenderView::compositor() { if (!m_compositor) m_compositor = adoptPtr(new RenderLayerCompositor(*this)); return m_compositor.get(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderView.cpp中。
这个RenderLayerCompositor对象负责管理网页的Render Layer Tree,以及根据Render Layer Tree创建Graphics Layer Tree。
回到FrameView类的成员函数updateLayoutAndStyleForPainting中,它获得了正在加载的网页对应的RenderLayerCompositor对象之后,接下来就调用这个RenderLayerCompositor对象的成员函数updateIfNeededRecursive根据Render Layer Tree创建或者更新Graphics Layer Tree。
RenderLayerCompositor类的成员函数updateIfNeededRecursive的实现如下所示:
void RenderLayerCompositor::updateIfNeededRecursive() { ...... updateIfNeeded(); ...... }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
RenderLayerCompositor类的成员函数updateIfNeededRecursive调用另外一个成员函数updateIfNeeded创建Graphics Layer Tree,如下所示:
void RenderLayerCompositor::updateIfNeeded() { CompositingUpdateType updateType = m_pendingUpdateType; m_pendingUpdateType = CompositingUpdateNone; if (!hasAcceleratedCompositing() || updateType == CompositingUpdateNone) return; RenderLayer* updateRoot = rootRenderLayer(); Vector<RenderLayer*> layersNeedingRepaint; if (updateType >= CompositingUpdateAfterCompositingInputChange) { bool layersChanged = false; ...... CompositingRequirementsUpdater(m_renderView, m_compositingReasonFinder).update(updateRoot); { ...... CompositingLayerAssigner(this).assign(updateRoot, layersChanged, layersNeedingRepaint); } ...... if (layersChanged) updateType = std::max(updateType, CompositingUpdateRebuildTree); } if (updateType != CompositingUpdateNone) { ...... GraphicsLayerUpdater updater; updater.update(layersNeedingRepaint, *updateRoot); if (updater.needsRebuildTree()) updateType = std::max(updateType, CompositingUpdateRebuildTree); ...... } if (updateType >= CompositingUpdateRebuildTree) { GraphicsLayerVector childList; { ...... GraphicsLayerTreeBuilder().rebuild(*updateRoot, childList); } if (childList.isEmpty()) destroyRootLayer(); else m_rootContentLayer->setChildren(childList); ...... } ...... }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
当RenderLayerCompositor类的成员变量pendingUpdateType的值不等于CompositingUpdateNone的时候,就表明网页的Graphics Layer Tree需要进行更新。此外,要对网页的Graphics Layer Tree需要进行更新,还要求浏览器开启硬件加速合成。当调用RenderLayerCompositor类的成员函数hasAcceleratedCompositing得到的返回值等于true的时候,就表明浏览器开启了硬件加速合成。
当RenderLayerCompositor类的成员变量pendingUpdateType的值大于等于CompositingUpdateAfterCompositingInputChange的时候,表示Graphics Layer Tree的输入发生了变化,例如,Render Layer Tree中的某一个Render Layer的内容发生了变化。在这种情况下,RenderLayerCompositor类的成员函数updateIfNeeded会构造一个CompositingRequirementsUpdater对象,并且调用这个CompositingRequirementsUpdater对象的成员函数update从网页的Render Layer Tree的根节点开始,递归计算每一个Render Layer的Compositing Reason,主要就是根据各个Render Layer包含的Render Object的CSS属性来计算。
计算好网页的Render Layer Tree中的每一个Render Layer的Compositing Reason之后,RenderLayerCompositor类的成员函数updateIfNeeded接着再构造一个CompositingLayerAssigner对象,并且调用这个CompositingLayerAssigner对象的成员函数assign根据每一个Render Layer新的Compositing Reason决定是否需要为它创建一个新的Composited Layer Mapping或者删除它原来拥有的Composited Layer Mapping。如果有的Render Layer原来是没有Composited Layer Mapping的,现在有了Composited Layer Mapping,或者原来有Composited Layer Mapping,现在没有了Composited Layer Mapping,那么本地变量layersChanged的值就会被设置为true。这时候本地变量updateType的值会被更新为CompositingUpdateRebuildTree。
在本地变量updateType的值是否不等于CompositingUpdateNone的情况下,RenderLayerCompositor类的成员函数updateIfNeeded接下来又会构造一个GraphicsLayerUpdater对象,并且调用这个GraphicsLayerUpdater对象的成员函数update检查每一个拥有Composited Layer Mapping的Render Layer更新它的Composited Layer Mapping所描述的Graphics Layer Sub Tree。如果有Render Layer更新了它的Composited Layer Mapping所描述的Graphics Layer Sub Tree,那么调用上述GraphicsLayerUpdater对象的成员函数needsRebuildTree获得的返回值就会等于true。这时候本地变量updateType的值也会被更新为CompositingUpdateRebuildTree。
一旦本地变量updateType的值被更新为CompositingUpdateRebuildTree,或者它本来的值,也就是RenderLayerCompositor类的成员变量pendingUpdateType的值,原本就等于CompositingUpdateRebuildTree,那么RenderLayerCompositor类的成员函数updateIfNeeded又会构造一个GraphicsLayerTreeBuilder对象,并且调用这个GraphicsLayerTreeBuilder对象的成员函数rebuild从Render Layer Tree的根节点开始,递归创建一个新的Graphics Layer Tree。
注意,前面调用GraphicsLayerTreeBuilder类的成员函数rebuild的时候,传递进去的第一个参数updateRoot是Render Layer Tree的根节点,第二个参数childList是一个输出参数,它里面保存的是Graphics Layer Tree的根节点的子节点。Graphics Layer Tree的根节点由RenderLayerCompositor类的成员函数m_rootContentLayer指向的GraphicsLayer对象描述,因此当参数childList描述的Vector不为空时,它里面所保存的Graphics Layer都会被设置为RenderLayerCompositor类的成员函数m_rootContentLayer指向的GraphicsLayer对象的子Graphics Layer。
接下来我们主要分析CompositingLayerAssigner类的成员函数assign、GraphicsLayerUpdater类的成员函数update以及GraphicsLayerTreeBuilder类的成员函数rebuild的实现,以及了解Graphics Layer Tree的创建过程。
CompositingLayerAssigner类的成员函数assign主要是为Render Layer创建或者删除Composited Layer Mapping,它的实现如下所示:
void CompositingLayerAssigner::assign(RenderLayer* updateRoot, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint) { SquashingState squashingState; assignLayersToBackingsInternal(updateRoot, squashingState, layersChanged, layersNeedingRepaint); ...... }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp中。
从前面的分析可以知道,参数updateRoot描述的是Render Layer Tree的根节点,CompositingLayerAssigner类的成员函数assign主要是调用另外一个成员函数assignLayersToBackingsInternal从这个根节点开始,递归是否需要为每一个Render Layer创建或者删除Composited Layer Mapping。
CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal的实现如下所示:
void CompositingLayerAssigner::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, bool& layersChanged, Vector<RenderLayer*>& layersNeedingRepaint) { ...... CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer); if (m_compositor->allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) { layersNeedingRepaint.append(layer); layersChanged = true; } // Add this layer to a squashing backing if needed. if (m_layerSquashingEnabled) { if (updateSquashingAssignment(layer, squashingState, compositedLayerUpdate, layersNeedingRepaint)) layersChanged = true; ...... } if (layer->stackingNode()->isStackingContext()) { RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); while (RenderLayerStackingNode* curNode = iterator.next()) assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, layersNeedingRepaint); } if (m_layerSquashingEnabled) { // At this point, if the layer is to be "separately" composited, then its backing becomes the most recent in paint-order. if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) { ASSERT(!requiresSquashing(layer->compositingReasons())); squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping()); } } RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); while (RenderLayerStackingNode* curNode = iterator.next()) assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, layersNeedingRepaint); ...... }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp中。
CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal首先调用成员函数computeCompositedLayerUpdate计算参数layer描述的Render Layer的Compositing State Transition,如下所示:
CompositingStateTransitionType CompositingLayerAssigner::computeCompositedLayerUpdate(RenderLayer* layer) { CompositingStateTransitionType update = NoCompositingStateChange; if (needsOwnBacking(layer)) { if (!layer->hasCompositedLayerMapping()) { update = AllocateOwnCompositedLayerMapping; } } else { if (layer->hasCompositedLayerMapping()) update = RemoveOwnCompositedLayerMapping; if (m_layerSquashingEnabled) { if (!layer->subtreeIsInvisible() && requiresSquashing(layer->compositingReasons())) { // We can't compute at this time whether the squashing layer update is a no-op, // since that requires walking the render layer tree. update = PutInSquashingLayer; } else if (layer->groupedMapping() || layer->lostGroupedMapping()) { update = RemoveFromSquashingLayer; } } } return update; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp中。
一个Render Layer的Compositing State Transition分为4种:
1. 它需要Compositing,但是还没有创建Composited Layer Mapping,这时候Compositing State Transition设置为AllocateOwnCompositedLayerMapping,表示要创建一个新的Composited Layer Mapping。
2. 它不需要Compositing,但是之前已经创建有Composited Layer Mapping,这时候Compositing State Transition设置为RemoveOwnCompositedLayerMapping,表示要删除之前创建的Composited Layer Mapping。
3. 它需要Squashing,这时候Compositing State Transition设置为PutInSquashingLayer,表示要将它绘制离其最近的一个Render Layer的Composited Layer Mapping里面的一个Squashing Layer上。
4. 它不需要Squashing,这时候Compositing State Transition设置为RemoveFromSquashingLayer,表示要将它从原来对应的Squashing Layer上删除。
注意,后面2种Compositing State Transition,只有在CompositingLayerAssigner类的成员变量layerSquashingEnabled的值在true的时候才会进行设置。默认情况下,浏览器是开启Layer Squashing机制的,不过可以通过设置“disable-layer-squashing”选项进行关闭,或者通过设置“enable-layer-squashing”选项显式开启。
判断一个Render Layer是否需要Compositing,是通过调用CompositingLayerAssigner类的成员函数needsOwnBacking进行的,它的实现如下所示:
bool CompositingLayerAssigner::needsOwnBacking(const RenderLayer* layer) const { if (!m_compositor->canBeComposited(layer)) return false; // If squashing is disabled, then layers that would have been squashed should just be separately composited. bool needsOwnBackingForDisabledSquashing = !m_layerSquashingEnabled && requiresSquashing(layer->compositingReasons()); return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (m_compositor->staleInCompositingMode() && layer->isRootLayer()); }
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp中。
CompositingLayerAssigner类的成员变量m_compositor指向的是一个RenderLayerCompositor对象,CompositingLayerAssigner类的成员函数needsOwnBacking首先调用它的成员函数canBeComposited判断参数layer描述的Render Layer是否需要Compositing,如下所示:
bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const { // FIXME: We disable accelerated compositing for elements in a RenderFlowThread as it doesn't work properly. // See http://webkit.org/b/84900 to re-enable it. return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer() && !layer->subtreeIsInvisible() && layer->renderer()->flowThreadState() == RenderObject::NotInsideFlowThread; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
一个Render Layer可以Compositing,需要同时满足以下4个条件:
1. 浏览器开启硬件加速合成,即RenderLayerCompositor类的成员变量m_hasAcceleratedCompositing的值等于true。
2. Render Layer本身有Compositing绘制的需求,也就是调用它的成员函数isSelfPaitingLayer得到的返回值为true。从前面 Chromium网页Render Layer Tree创建过程分析一文可以知道,Render Layer的类型一般为NormalLayer,但是如果将overflow属性设置为“hidden‘,那么Render Layer的类型被设置为OverflowClipLayer。对于类型为OverflowClipLayer的Render Layer,如果它的内容没有出现overflow,那么就没有必要对它进行Compositing。
3. Render Layer描述的网页内容是可见的,也就是调用它的成员函数subtreeIsInvisible得到的返回值等于false。
4. Render Layer的内容不是渲染在一个RenderFlowThread中,也就是与Render Layer关联的Render Object的Flow Thread State等于RenderObject::NotInsideFlowThread。从注释可以知道,在RenderFlowThread中渲染的元素是禁用硬件加速合成的,因为不能正确地使用。RenderFlowThread是CSS 3定义的一种元素显示方式,更详细的信息可以参考CSS文档: CSS Regions Module Level 1。
回到CompositingLayerAssigner类的成员函数needsOwnBacking中,如果RenderLayerCompositor类的成员函数canBeComposited告诉它参数layer描述的Render Layer不可进行Compositing,那么就不需要为它创建一个Composited Layer Mapping。
另一方面,如果RenderLayerCompositor类的成员函数canBeComposited告诉CompositingLayerAssigner类的成员函数needsOwnBacking,参数layer描述的Render Layer可以进行Compositing,那么CompositingLayerAssigner类的成员函数needsOwnBacking还需要进一步判断该Render Layer是否真的需要进行Compositing。
如果参数layer描述的Render Layer满足以下3个条件之一,那么CompositingLayerAssigner类的成员函数needsOwnBacking就会认为它需要进行Compositing:
1. Render Layer的Compositing Reason表示它需要Compositing,这是通过调用前面提到的函数requiresCompositing判断的。
2. Render Layer的Compositing Reason表示它需要Squashing,但是浏览器禁用了“Layer Squashing”机制。当浏览器禁用“Layer Squashing”机制时,CompositingLayerAssigner类的成员变量m_layerSquashingEnabled会等于false。调用前面提到的函数requiresSquashing可以判断一个Render Layer是否需要Squashing。
3. Render Layer是Render Layer Tree的根节点,并且Render Layer Compositor处于Compositing模式中。除非设置了Render Layer Tree的根节点无条件Compositing,否则的话,当在Render Layer Tree根节点的子树中,没有任何Render Layer需要Compositing时, Render Layer Tree根节点也不需要Compositing,这时候Render Layer Compositor就会被设置为非Compositing模式。判断一个Render Layer是否是Render Layer Tree的根节点,调用它的成员函数isRootLayer即可,而判断一个Render Layer Compositor是否处于Compositing模式,调用它的成员函数staleInCompositingMode即可。
回到CompositingLayerAssigner类的成员函数computeCompositedLayerUpdate中,当它调用结束后,再返回到CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal中,这时候CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal就知道了参数layer描述的Render Layer的Compositing State Transition Type。
知道了参数layer描述的Render Layer的Compositing State Transition Type之后,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal接下来调用成员变量m_compositor描述的一个RenderLayerCompositor对象的成员函数allocateOrClearCompositedLayerMapping为其创建或者删除Composited Layer Mapping,如下所示:
bool RenderLayerCompositor::allocateOrClearCompositedLayerMapping(RenderLayer* layer, const CompositingStateTransitionType compositedLayerUpdate) { bool compositedLayerMappingChanged = false; ...... switch (compositedLayerUpdate) { case AllocateOwnCompositedLayerMapping: ...... layer->ensureCompositedLayerMapping(); compositedLayerMappingChanged = true; ...... break; case RemoveOwnCompositedLayerMapping: // PutInSquashingLayer means you might have to remove the composited layer mapping first. case PutInSquashingLayer: if (layer->hasCompositedLayerMapping()) { ...... layer->clearCompositedLayerMapping(); compositedLayerMappingChanged = true; } break; case RemoveFromSquashingLayer: case NoCompositingStateChange: // Do nothing. break; } ...... return compositedLayerMappingChanged || nonCompositedReasonChanged; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
RenderLayerCompositor类的成员函数allocateOrClearCompositedLayerMapping主要是根据Render Layer的Compositing State Transition Type决定是要为其创建Composited Layer Mapping,还是删除mposited Layer Mapping。
对于Compositing State Transition Type等于AllocateOwnCompositedLayerMapping的Render Layer,RenderLayerCompositor类的成员函数allocateOrClearCompositedLayerMapping会调用它的成员函数ensureCompositedLayerMapping为其创建一个Composited Layer Mapping
对于Compositing State Transition Type等于RemoveOwnCompositedLayerMapping或者PutInSquashingLayer的Render Layer,RenderLayerCompositor类的成员函数allocateOrClearCompositedLayerMapping会调用它的成员函数clearCompositedLayerMapping删除原来为它创建的Composited Layer Mapping。
对于Compositing State Transition Type其它值的Render Layer,则不需要进行特别的处理。
这一步执行完成之后,回到CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal中,它接下来判断成员变量m_layerSquashingEnabled的值是否等于true。如果等于true,那么就说明浏览器开启了”Layer Squashing“机制。这时候就需要调用成员函数updateSquashingAssignment判断是否需要将参数layer描述的Render Layer绘制在一个Squashing Graphics Layer中。
CompositingLayerAssigner类的成员函数updateSquashingAssignment的实现如下所示:
bool CompositingLayerAssigner::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate, Vector<RenderLayer*>& layersNeedingRepaint) { ...... if (compositedLayerUpdate == PutInSquashingLayer) { ...... bool changedSquashingLayer = squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, squashingState.mostRecentMapping->owningLayer(), squashingState.nextSquashedLayerIndex); ...... return true; } if (compositedLayerUpdate == RemoveFromSquashingLayer) { if (layer->groupedMapping()) { ...... layer->setGroupedMapping(0); } ...... return true; } return false; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositingLayerAssigner.cpp中。
CompositingLayerAssigner类的成员函数updateSquashingAssignment也是根据Render Layer的Compositing State Transition Type决定是否要将它绘制在一个Squashing Graphics Layer中,或者将它从一个Squashing Graphics Layer中删除。
对于Compositing State Transition Type等于PutInSquashingLayer的Render Layer,它将会绘制在一个Squashing Graphics Layer中。这个Squashing Graphics Layer保存在一个Composited Layer Mapping中。这个Composited Layer Mapping关联的Render Layer处于要Squashing的Render Layer的下面,并且前者离后者是最近的,记录在参数squashingState描述的一个SquashingState对象的成员变量mostRecentMapping中。通过调用CompositedLayerMapping类的成员函数updateSquashingLayerAssignment可以将一个Render Layer绘制在一个Composited Layer Mapping内部维护的一个quashing Graphics Layer中。
对于Compositing State Transition Type等于RemoveFromSquashingLayer的Render Layer,如果它之前已经被设置绘制在一个Squashing Graphics Layer中,那么就需要将它从这个Squashing Graphics Layer中删除。如果一个Render Layer之前被设置绘制在一个Squashing Graphics Layer中,那么调用它的成员函数groupedMapping就可以获得一个Grouped Mapping。这个Grouped Mapping描述的也是一个Composited Layer Mapping,并且Render Layer所绘制在的Squashing Graphics Layer就是由这个Composited Layer Mapping维护的。因此,要将一个Render Layer从一个Squashing Graphics Layer中删除,只要将它的Grouped Mapping设置为0即可。这是通过调用RenderLayer类的成员函数setGroupedMapping实现的。
再回到CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal中,它接下来判断参数layer描述的Render Layer所关联的Render Object是否是一个Stacking Context。如果是的话,那么就递归调用成员函数assignLayersToBackingsInternal遍历那些z-index为负的子Render Object对应的Render Layer,确定是否需要为它们创建Composited Layer Mapping。
到目前为止,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal就处理完成参数layer描述的Render Layer,以及那些z-index为负数的子Render Layer。这时候,参数layer描述的Render Layer可能会作为那些z-index为0或者正数的子Render Layer的Grouped Mapping,因此在继续递归处理z-index为0或者正数的子Render Layer之前,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal需要将参数layer描述的Render Layer对应的Composited Layer Mapping记录下来,前提是这个Render Layer拥有Composited Layer Mapping。这是通过调用参数squashingState描述的一个SquashingState对象的成员函数updateSquashingStateForNewMapping实现的,实际上就是记录在该SquashingState对象的成员变量mostRecentMapping中。这样前面分析的CompositingLayerAssigner类的成员函数updateSquashingAssignment就可以知道将其参数layer描述的Render Layer绘制在哪一个Squashing Graphics Layer中。
最后,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal就递归调用自己处理那些z-index为0或者正数的子Render Layer。递归调有完成之后,整个Render Layer Tree就处理完毕了。这时候哪些Render Layer具有Composited Layer Mapping就可以确定了。
前面分析RenderLayerCompositor类的成员函数allocateOrClearCompositedLayerMapping时提到,调用RenderLayer类的成员函数ensureCompositedLayerMapping可以为一个Render Layer创建一个Composited Layer Mapping,接下来我们就继续分析这个函数的实现,以便了解Composited Layer Mapping的创建过程。
RenderLayer类的成员函数ensureCompositedLayerMapping的实现如下所示:
CompositedLayerMappingPtr RenderLayer::ensureCompositedLayerMapping() { if (!m_compositedLayerMapping) { m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this)); ...... } return m_compositedLayerMapping.get(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayer.cpp中。
RenderLayer类的成员变量compositedLayerMapping描述的就是一个Composited Layer Mapping。如果这个Composited Layer Mapping还没有创建,那么当RenderLayer类的成员函数ensureCompositedLayerMapping被调用时,就会进行创建。
Composited Layer Mapping的创建过程,也就是CompositedLayerMapping类的构造函数的实现,如下所示:
CompositedLayerMapping::CompositedLayerMapping(RenderLayer& layer) : m_owningLayer(layer) , ...... { ...... createPrimaryGraphicsLayer(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
正在创建的Composited Layer Mapping被参数layer描述的Render Layer拥有,因此这个Render Layer将会被保存在在创建的Composited Layer Mapping的成员变量m_owningLayer中。
从图5可以知道,一个Composited Layer Mapping一定存在一个Main Graphics Layer。这个Main Graphics Layer是CompositedLayerMapping类的构造函数通过调用另外一个成员函数createPrimaryGraphicsLayer创建的,如下所示:
void CompositedLayerMapping::createPrimaryGraphicsLayer() { m_graphicsLayer = createGraphicsLayer(m_owningLayer.compositingReasons()); ...... }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
Composited Layer Mapping中的Main Graphics Layer由成员变量m_graphicsLayer描述,并且这个Main Graphics Layer是通过调用成员函数createGraphicsLayer创建的。如果我们分析CompositedLayerMapping类的其它代码,就会发现Composited Layer Mapping中的其它Graphics Layer也是通过调用成员函数createGraphicsLayer创建的。
CompositedLayerMapping类的成员函数createGraphicsLayer的实现如下所示:
PassOwnPtr<GraphicsLayer> CompositedLayerMapping::createGraphicsLayer(CompositingReasons reasons) { GraphicsLayerFactory* graphicsLayerFactory = 0; if (Page* page = renderer()->frame()->page()) graphicsLayerFactory = page->chrome().client().graphicsLayerFactory(); OwnPtr<GraphicsLayer> graphicsLayer = GraphicsLayer::create(graphicsLayerFactory, this); graphicsLayer->setCompositingReasons(reasons); if (Node* owningNode = m_owningLayer.renderer()->generatingNode()) graphicsLayer->setOwnerNodeId(InspectorNodeIds::idForNode(owningNode)); return graphicsLayer.release(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
CompositedLayerMapping类的成员函数createGraphicsLayer在创建一个Graphics Layer之前,首先会获得一个GraphicsLayerFactory对象。这个GraphicsLayerFactory对象是由WebKit的使用者提供的。在我们这个情景中,WebKit的使用者就是Chromium,它提供的GraphicsLayerFactory对象的实际类型为GraphicsLayerFactoryChromium。
获得了GraphicsLayerFactory对象之后,CompositedLayerMapping类的成员函数createGraphicsLayer接下来就以它为参数,调用GraphicsLayer类的静态成员函数create创建一个Graphics Layer,如下所示:
PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerFactory* factory, GraphicsLayerClient* client) { return factory->createGraphicsLayer(client); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。
GraphicsLayer类的静态成员函数create调用参数factory描述的一个GraphicsLayerFactoryChromium对象的成员函数createGraphicsLayer创建一个Graphics Layer,如下所示:
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中。
从这里可以看到,GraphicsLayerFactoryChromium类的成员函数createGraphicsLayer返回的是一个GraphicsLayer对象。
这一步执行完成后,一个Composited Layer Mapping及其内部的Main Graphics Layer就创建完成了。
前面分析CompositingLayerAssigner类的成员函数updateSquashingAssignment时提到,调用CompositedLayerMapping类的成员函数updateSquashingLayerAssignment可以将一个Render Layer绘制在其内部维护的一个Squashing Graphics Layer中。CompositedLayerMapping类的成员函数updateSquashingLayerAssignment的实现如下所示:
bool CompositedLayerMapping::updateSquashingLayerAssignment(RenderLayer* squashedLayer, const RenderLayer& owningLayer, size_t nextSquashedLayerIndex) { ...... GraphicsLayerPaintInfo paintInfo; paintInfo.renderLayer = squashedLayer; ...... // Change tracking on squashing layers: at the first sign of something changed, just invalidate the layer. // FIXME: Perhaps we can find a tighter more clever mechanism later. bool updatedAssignment = false; if (nextSquashedLayerIndex < m_squashedLayers.size()) { if (!paintInfo.isEquivalentForSquashing(m_squashedLayers[nextSquashedLayerIndex])) { ...... updatedAssignment = true; m_squashedLayers[nextSquashedLayerIndex] = paintInfo; } } else { ...... m_squashedLayers.append(paintInfo); updatedAssignment = true; } squashedLayer->setGroupedMapping(this); return updatedAssignment; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/GraphicsLayerFactoryChromium.cpp中。
CompositedLayerMapping类有一个成员变量m_squashedLayers,它描述的是一个类型为GraphicsLayerPaintInfo的Vector,如下所示:
class CompositedLayerMapping FINAL : public GraphicsLayerClient { WTF_MAKE_NONCOPYABLE(CompositedLayerMapping); WTF_MAKE_FAST_ALLOCATED; ...... private: ...... OwnPtr<GraphicsLayer> m_squashingLayer; // Only used if any squashed layers exist, this is the backing that squashed layers paint into. Vector<GraphicsLayerPaintInfo> m_squashedLayers; ...... };这个函数定义在文件external/chromium_org/third_party/WebKit/Source/web/GraphicsLayerFactoryChromium.h中。
上述Vector中保存在的每一个GraphicsLayerPaintInfo描述的都是一个Squashing Render Layer,这些Squashing Render Layer最终将会绘制在CompositedLayerMapping类的成员变量m_squashingLayer描述的一个Graphics Layer中。
CompositedLayerMapping类的成员函数updateSquashingLayerAssignment所做的事情就是将参数squashedLayer描述的一个Squashing Render Layer封装在一个GraphicsLayerPaintInfo对象,然后将这个GraphicsLayerPaintInfo对象保存在CompositedLayerMapping类的成员变量m_squashedLayers描述的一个Vector中。
这样,我们就分析完成了为Render Layer Tree中的Render Layer创建Composited Layer Mapping的过程,也就是CompositingLayerAssigner类的成员函数assign的实现。回到RenderLayerCompositor类的成员函数updateIfNeeded中,它接下来调用GraphicsLayerUpdater类的成员函数update为Composited Layer Mapping创建Graphics Layer Sub Tree。
GraphicsLayerUpdater类的成员函数update的实现如下所示:
void GraphicsLayerUpdater::update(Vector<RenderLayer*>& layersNeedingPaintInvalidation, RenderLayer& layer, UpdateType updateType, const UpdateContext& context) { if (layer.hasCompositedLayerMapping()) { CompositedLayerMappingPtr mapping = layer.compositedLayerMapping(); ...... if (mapping->updateGraphicsLayerConfiguration(updateType)) m_needsRebuildTree = true; ...... } UpdateContext childContext(context, layer); for (RenderLayer* child = layer.firstChild(); child; child = child->nextSibling()) update(layersNeedingPaintInvalidation, *child, updateType, childContext); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerUpdater.cpp。
从前面的调用过程可以知道,参数layer描述的Render Layer是Render Layer Tree的根节点,GraphicsLayerUpdater类的成员函数update检查它是否拥有Composited Layer Mapping。如果有的话,那么就会调用这个Composited Layer Mapping的成员函数updateGraphicsLayerConfiguration更新它内部的Graphics Layer Sub Tree。GraphicsLayerUpdater类的成员函数update最后还会递归调用自身遍历Render Layer Tree的根节点的子孙节点,这样就可以对所有的Graphics Layer Sub Tree进行更新。
接下来我们继续分析CompositedLayerMapping类的成员函数updateGraphicsLayerConfiguration的实现,以便了解每一个Graphics Layer Sub Tree的更新过程,如下所示:
bool CompositedLayerMapping::updateGraphicsLayerConfiguration(GraphicsLayerUpdater::UpdateType updateType) { ...... bool layerConfigChanged = false; ...... // The background layer is currently only used for fixed root backgrounds. if (updateBackgroundLayer(m_backgroundLayerPaintsFixedRootBackground)) layerConfigChanged = true; if (updateForegroundLayer(compositor->needsContentsCompositingLayer(&m_owningLayer))) layerConfigChanged = true; bool needsDescendantsClippingLayer = compositor->clipsCompositingDescendants(&m_owningLayer); ...... bool needsAncestorClip = compositor->clippedByNonAncestorInStackingTree(&m_owningLayer); ...... if (updateClippingLayers(needsAncestorClip, needsDescendantsClippingLayer)) layerConfigChanged = true; ...... if (updateScrollingLayers(m_owningLayer.needsCompositedScrolling())) { layerConfigChanged = true; ...... } bool hasPerspective = false; if (RenderStyle* style = renderer->style()) hasPerspective = style->hasPerspective(); bool needsChildTransformLayer = hasPerspective && (layerForChildrenTransform() == m_childTransformLayer.get()) && renderer->isBox(); if (updateChildTransformLayer(needsChildTransformLayer)) layerConfigChanged = true; ...... if (updateSquashingLayers(!m_squashedLayers.isEmpty())) layerConfigChanged = true; if (layerConfigChanged) updateInternalHierarchy(); ....... }
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
CompositedLayerMapping类的成员函数updateGraphicsLayerConfiguration依次检查它内部维护的Background Layer、Foreground Layer、Clip Layer、Scrolling Layer、Child Transform Layer和Squashing Layer是否需要更新,也就是创建或者删除等。只要其中的一个Graphics Layer发生更新,本地变量layerConfigChanged的值就会被设置为true,这时候CompositedLayerMapping类的另外一个成员函数updateInternalHierarchy就会被调用来更新内部的Graphics Layer Sub Tree。
接下来我们以Squashing Layer的更新过程为例,即CompositedLayerMapping类的成员函数updateSquashingLayers的实现,分析CompositedLayerMapping类内部维护的Graphics Layer的更新过程,如下所示:
bool CompositedLayerMapping::updateSquashingLayers(bool needsSquashingLayers) { bool layersChanged = false; if (needsSquashingLayers) { ...... if (!m_squashingLayer) { m_squashingLayer = createGraphicsLayer(CompositingReasonLayerForSquashingContents); ...... layersChanged = true; } if (m_ancestorClippingLayer) { if (m_squashingContainmentLayer) { m_squashingContainmentLayer->removeFromParent(); m_squashingContainmentLayer = nullptr; layersChanged = true; } } else { if (!m_squashingContainmentLayer) { m_squashingContainmentLayer = createGraphicsLayer(CompositingReasonLayerForSquashingContainer); layersChanged = true; } } ...... } else { if (m_squashingLayer) { m_squashingLayer->removeFromParent(); m_squashingLayer = nullptr; layersChanged = true; } if (m_squashingContainmentLayer) { m_squashingContainmentLayer->removeFromParent(); m_squashingContainmentLayer = nullptr; layersChanged = true; } ...... } return layersChanged; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
从前面的调用过程可以知道,当CompositedLayerMapping类的成员变量m_squashedLayers描述的Vector不等于空时,这里的参数needsSquashingLayers的值就会等于true,表示需要对CompositedLayerMapping类内部维护的Squashing Layer进行更新。更新过程如下所示:
1. 如果Squashing Layer还没有创建,那么就会调用我们前面分析过的CompositedLayerMapping类的成员函数createGraphicsLayer进行创建,并且保存在成员变量m_squashingLayer中。
2. CompositedLayerMapping类的成员变量m_ancestorClippingLayer描述的是图5所示的Clip Layer。当存在Squashing Layer时,但Clip Layer又不存在的时候,需要创建一个Squashing Containment Layer,用来作为Squashing Layer的父Graphics Layer。否则的话,Squashing Layer的父Graphics Layer就是Clip Layer。
3. 基于上述第2点,当Clip Layer存在时,若Squashing Containment Layer存在,则需要将它从Graphics Layer Sub Tree中移除。另一方面,当Clip Layer不存在时,若Squashing Containment Layer也不存在,则需要创建Squashing Containment Layer。换句话说,当存在Squashing Layer时,Clip Layer和Squashing Containment Layer至少存在一个,并且只能存在一个,Clip Layer优先Squashing Containment Layer存在。
如果CompositedLayerMapping类的成员变量m_squashedLayers描述的Vector等于空时,参数needsSquashingLayers的值就会等于false,表示需CompositedLayerMapping类不需要在内部维护一个Squashing Layer。这时候如果存在Squashing Layer,那么就需要将它从Graphics Layer Sub Tree中移除。如果Squashing Containment Layer也存在,那么也要将它一起从Graphics Layer Sub Tree中移除。这是因为Squashing Containment Layer本来就是为Squashing Layer创建的,现在既然Squashing Layer不需要了,那么它自然也不再需要了。
回到CompositedLayerMapping类的成员函数updateGraphicsLayerConfiguration中,接下来我们继续分析它调用另外一个成员函数updateInternalHierarchy更新内部维护的raphics Layer Sub Tree的过程,如下所示:
void CompositedLayerMapping::updateInternalHierarchy() { // m_foregroundLayer has to be inserted in the correct order with child layers, // so it's not inserted here. if (m_ancestorClippingLayer) m_ancestorClippingLayer->removeAllChildren(); m_graphicsLayer->removeFromParent(); if (m_ancestorClippingLayer) m_ancestorClippingLayer->addChild(m_graphicsLayer.get()); if (m_childContainmentLayer) m_graphicsLayer->addChild(m_childContainmentLayer.get()); else if (m_childTransformLayer) m_graphicsLayer->addChild(m_childTransformLayer.get()); if (m_scrollingLayer) { GraphicsLayer* superLayer = m_graphicsLayer.get(); if (m_childContainmentLayer) superLayer = m_childContainmentLayer.get(); if (m_childTransformLayer) superLayer = m_childTransformLayer.get(); superLayer->addChild(m_scrollingLayer.get()); } // The clip for child layers does not include space for overflow controls, so they exist as // siblings of the clipping layer if we have one. Normal children of this layer are set as // children of the clipping layer. if (m_layerForHorizontalScrollbar) m_graphicsLayer->addChild(m_layerForHorizontalScrollbar.get()); if (m_layerForVerticalScrollbar) m_graphicsLayer->addChild(m_layerForVerticalScrollbar.get()); if (m_layerForScrollCorner) m_graphicsLayer->addChild(m_layerForScrollCorner.get()); // The squashing containment layer, if it exists, becomes a no-op parent. if (m_squashingLayer) { ASSERT(compositor()->layerSquashingEnabled()); ASSERT((m_ancestorClippingLayer && !m_squashingContainmentLayer) || (!m_ancestorClippingLayer && m_squashingContainmentLayer)); if (m_squashingContainmentLayer) { m_squashingContainmentLayer->removeAllChildren(); m_squashingContainmentLayer->addChild(m_graphicsLayer.get()); m_squashingContainmentLayer->addChild(m_squashingLayer.get()); } else { // The ancestor clipping layer is already set up and has m_graphicsLayer under it. m_ancestorClippingLayer->addChild(m_squashingLayer.get()); } } }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
从这里我们就可以看到,通过调用GraphicsLayer类的成员函数addChild,就可以将一个Graphics Layer作为另外一个Graphics Layer的子Graphics Layer,这样就可以形成一个Graphics Layer Sub Tree。CompositedLayerMapping类的成员函数updateInternalHierarchy构建出来的Graphics Layer Sub Tree大致就如图5所示。
CompositedLayerMapping类内部维护的Graphics Layer Sub Tree,除了前面描述的Clip Layer和Squashing Containment Layer不能并存之外,另外两个Layer,即Child Containment Layer和Child Tranform Layer,也是不能并存的。这些Graphics Layer的具体作用,以及什么在情况下会存在,可以通过阅读ompositedLayerMapping类的代码获悉,这里就不再展开描述。
还有一点需要注意的是,CompositedLayerMapping类内部维护的Background Layer和Foreground Layer也是属于CompositedLayerMapping类描述的Graphics Layer Sub Tree的一部分,但是它们不是由CompositedLayerMapping类的成员函数updateInternalHierarchy插入到Graphics Layer Sub Tree中去的。等到将Graphics Layer Sub Tree连接在一起形成整个Graphics Layer Tree的时候,它们才会插入到各自的Graphics Layer Sub Tree中去,因为处理它们需要更多的信息。
由于各个Graphics Layer Sub Tree需要连接在一起形成一个完整的Graphics Layer Tree,因此每一个Graphics Layer Sub Tree都需要提供两个对外的Graphics Layer,一个作为其父Graphics Layer Sub Tree的子Graphics Layer,另一个作为其子Graphics Layer Sub Tree的父Graphics Layer。CompositedLayerMapping类提供了两个成员函数childForSuperlayers和parentForSublayers,分别提供上述两个Graphics Layer。
CompositedLayerMapping类的成员函数childForSuperlayers的实现如下所示:
GraphicsLayer* CompositedLayerMapping::childForSuperlayers() const { if (m_squashingContainmentLayer) return m_squashingContainmentLayer.get(); return localRootForOwningLayer(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
从这里可以看到,如果存在Squashing Containment Layer,那么它就会作为父Graphics Layer Sub Tree的子Graphics Layer。另一方面,如果不存在Squashing Containment Layer,那么CompositedLayerMapping类的成员函数childForSuperlayers调用另外一个成员函数localRootForOwningLayer返回另外一个Graphics Layer作为父Graphics Layer Sub Tree的子Graphics Layer。
CompositedLayerMapping类的成员函数localRootForOwningLayer的实现如下所示:
GraphicsLayer* CompositedLayerMapping::localRootForOwningLayer() const { if (m_ancestorClippingLayer) return m_ancestorClippingLayer.get(); return m_graphicsLayer.get(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
从这里可以看到,如果存在Clip Layer,那么它就会作为父Graphics Layer Sub Tree的子Graphics Layer。否则的话,Main Layer就会作为父Graphics Layer Sub Tree的子Graphics Layer。从图5可以知道,Main Layer是一定会存在的,因此就一定可以找到一个Graphics Layer,作为父Graphics Layer Sub Tree的子Graphics Layer。
CompositedLayerMapping类的成员函数parentForSublayers的实现如下所示:
GraphicsLayer* CompositedLayerMapping::parentForSublayers() const { if (m_scrollingBlockSelectionLayer) return m_scrollingBlockSelectionLayer.get(); if (m_scrollingContentsLayer) return m_scrollingContentsLayer.get(); if (m_childContainmentLayer) return m_childContainmentLayer.get(); if (m_childTransformLayer) return m_childTransformLayer.get(); return m_graphicsLayer.get(); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/CompositedLayerMapping.cpp中。
CompositedLayerMapping类的成员函数parentForSublayers按照Scrolling Block Selection Layer、Scrolling Contents Layer、Child Containment Layer、Child Transform Layer和Main Layer的顺序检查,先检查的Graphics Layer若存在,那么它就优先作为子Graphics Layer Sub Tree的父Graphics Layer。同样,由于最后检查的Main Layer是一定存在的,因此就一定可以找到一个Graphics Layer,作为子Graphics Layer Sub Tree的父Graphics Layer。
了解了Graphics Layer Sub Tree的构建过程之后,回到RenderLayerCompositor类的成员函数updateIfNeeded中,它最后就可以调用GraphicsLayerTreeBuilder类的成员函数rebuild将所有的Graphics Layer Sub Tree连接起来形成一个完整的Graphics Layer Tree了。
GraphicsLayerTreeBuilder类的成员函数rebuild的实现如下所示:
void GraphicsLayerTreeBuilder::rebuild(RenderLayer& layer, GraphicsLayerVector& childLayersOfEnclosingLayer) { ...... const bool hasCompositedLayerMapping = layer.hasCompositedLayerMapping(); CompositedLayerMappingPtr currentCompositedLayerMapping = layer.compositedLayerMapping(); // If this layer has a compositedLayerMapping, then that is where we place subsequent children GraphicsLayers. // Otherwise children continue to append to the child list of the enclosing layer. GraphicsLayerVector layerChildren; GraphicsLayerVector& childList = hasCompositedLayerMapping ? layerChildren : childLayersOfEnclosingLayer; ...... if (layer.stackingNode()->isStackingContext()) { RenderLayerStackingNodeIterator iterator(*layer.stackingNode(), NegativeZOrderChildren); while (RenderLayerStackingNode* curNode = iterator.next()) rebuild(*curNode->layer(), childList); // If a negative z-order child is compositing, we get a foreground layer which needs to get parented. if (hasCompositedLayerMapping && currentCompositedLayerMapping->foregroundLayer()) childList.append(currentCompositedLayerMapping->foregroundLayer()); } RenderLayerStackingNodeIterator iterator(*layer.stackingNode(), NormalFlowChildren | PositiveZOrderChildren); while (RenderLayerStackingNode* curNode = iterator.next()) rebuild(*curNode->layer(), childList); if (hasCompositedLayerMapping) { bool parented = false; if (layer.renderer()->isRenderPart()) parented = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(layer.renderer())); if (!parented) currentCompositedLayerMapping->parentForSublayers()->setChildren(layerChildren); ...... if (shouldAppendLayer(layer)) childLayersOfEnclosingLayer.append(currentCompositedLayerMapping->childForSuperlayers()); } }
这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.cpp中。
从前面的调用过程可以知道,参数layer描述的是网页Render Layer Tree的根节点,另外一个参数childLayersOfEnclosingLayer是一个输出参数,用来保存参数layer描述的Render Layer的子Render Layer的Child For Super Layers,也就是前面描述的一个Composited Layer Mapping中作为父Graphics Layer Sub Tree的子Graphics Layer。
GraphicsLayerTreeBuilder类的成员函数rebuild根据Stacking Context顺序从Render Layer Tree的根节点开始,不断地递归调用自己,不过只会处理那些具有Composited Layer Mapping的Render Layer。对于那些不具有Composited Layer Mapping的Render Layer,仅仅是用作跳板找到具有Composited Layer Mapping的Render Layer。这一点容易理解,因为GraphicsLayerTreeBuilder类的成员函数rebuild是用来构建整个网页的Graphics Layer Tree的,只有具有Composited Layer Mapping的Render Layer才对应的Graphics Layer。
GraphicsLayerTreeBuilder类的成员函数rebuild处理具有Composited Layer Mapping的Render Layer的过程如下所示:
1. 收集z-index为负数的子Render Layer的Child For Super Layers,并且保存在本地变量layerChildren描述的一个Vector中。
2. 如果正在处理的Render Layer具有z-index为负数的子Render Layer,那么根据前面的分析可以知道,正在处理的Render Layer的Composited Layer Mapping内部有一个Foreground Layer。这个Foreground Layer也会保存在本地变量layerChildren描述的一个Vector中,并且是位于那些z-index为负数的子Render Layer的Child For Super Layers之后。这就是为什么Foreground Layer不是由CompositedLayerMapping类的成员函数updateInternalHierarchy直接插入到Graphics Layer Sub Tree去的原因,因为CompositedLayerMapping类不知道一个Render Layer有哪些z-index为负数的子Render Layer。
3. 收集z-index为0和正数的子Render Layer的Child For Super Layers,并且保存在本地变量layerChildren描述的一个Vector中。
4. 经过前面三个收集操作,当前正在处理的Render Layer的Foreground Layer,以及它所有的子Render Layer的Child For Super Layers,就都保存在了本地变量layerChildren描述的一个Vector中。这时候只要找到当前正在处理的Render Layer的Parent For Sub Layers,再将前者作为后者的Children,就可以将具有父子关系的Graphics Layer Sub Tree连接起来。从前面的分析可以知道,当前正在处理的Render Layer的Parent For Sub Layers,可以通过调用它的Composited Layer Mapping的成员函数parentForSublayers获得。
5. 当前正在处理的Render Layer的Child For Super Layers,要保存在参数childLayersOfEnclosingLayer描述的Vector中,以便作为其父Render Layer的Parent For Sub Layers的Children。
其中,第4步对应的代码为:
bool parented = false; if (layer.renderer()->isRenderPart()) parented = RenderLayerCompositor::parentFrameContentLayers(toRenderPart(layer.renderer())); if (!parented) currentCompositedLayerMapping->parentForSublayers()->setChildren(layerChildren);它的执行有一个前提条件,就是本地变量parented的值为false。这是什么意思呢?当一个Render Layer的宿主Render Object对应的HTML Element是一个frame/iframe或者embed标签时,该Render Object是从RenderPart类继承下来的,称为Render Part。Render Part可能会具有自己的Render Layer Compositor,这可以通过调用enderLayerCompositor类的静态成员函数parentFrameContentLayers进行判断。如果一个Render Part具有自己的Render Layer Compositor,那么它的子Render Object就由这个Render Layer Compositor进行具体的绘制,绘制好之后再交给Render Part的父Render Object对应的Render Layer Compositor进行合成。因此,在这种情况下,Render Part的子Render Object所对应的Graphics Layer就不会插入在Render Part的父Render Object所对应的Graphics Layer Tree中。从另外一个角度理解就是,每一个Render Layer Compositor都有一个Graphics Layer Tree,而一个Graphics Layer不能同时位于两个Graphics Layer Tree中。
第5步对应的代码为:
if (shouldAppendLayer(layer)) childLayersOfEnclosingLayer.append(currentCompositedLayerMapping->childForSuperlayers());它的执行也有一个前提条件,就是当前正在处理的Render Layer对应的Graphcis Layer需要插入Graphics Layer Tree的时候才会执行,这可以通过调用函数shouldAppendLayer进行判断,如下所示:
static bool shouldAppendLayer(const RenderLayer& layer) { if (!RuntimeEnabledFeatures::overlayFullscreenVideoEnabled()) return true; Node* node = layer.renderer()->node(); if (node && isHTMLMediaElement(*node) && toHTMLMediaElement(node)->isFullscreen()) return false; return true; }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/GraphicsLayerTreeBuilder.cpp中。
当一个Render Layer的宿主Render Object对应的HTML Element是一个audio或者video标签时,并且它们是全屏播放、以及浏览器允许全屏播放时,那么它对应的Graphcis Layer就不需要插入Graphics Layer Tree中去,因为毕竟就只有它是需要渲染的,其他的网页内容都是不可见的。
GraphicsLayerTreeBuilder类的成员函数rebuild递归执行完成后,网页的Graphics Layer Tree就创建完成了。不过细心的读者会发现,还有一种类型的Graphics Layer还没有被插入到Graphics Layer Tree中去,就是图5所示的Background Layer。
前面提到,只有根Render Layer的Composited Layer Mapping,才可能存在Background Layer。也就是只有当body标签的CSS属性background-attachment被设置为“fixed”时,根Render Layer的Composited Layer Mapping才会存在Background Layer。其他的Render Layer的Composited Layer Mapping,都不可能存在Background Layer。
前面还提到,一个Graphics Layer Tree是由一个Render Layer Compositor进行管理。Render Layer Compositor内部也维护有一个Graphics Layer Sub Tree,充当根Graphics Layer Sub Tree的角色。这个Graphics Layer Sub Tree的结构如下所示:
+Overflow Controls Host Layer +Container Layer +Background Layer +Scroll Layer +Root Content Layer其中,GraphicsLayerTreeBuilder类的成员函数rebuild构建的Graphics Layer Tree的根节点是Root Content Layer,而Container Layer充当图5所示的Clip Layer的角色,这时候Background Layer就作为它的子Graphics Layer。Render Layer Compositor对应的Graphics Layer Sub Tree是由RenderLayerCompositor类的成员函数ensureRootLayer构建的,如下所示:
void RenderLayerCompositor::ensureRootLayer() { ...... 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()); ...... } ...... }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
当网页的body标签的CSS属性background-attachment被设置为“fixed”时,RenderLayerCompositor类的成员函数rootFixedBackgroundsChanged就会被调用,用来插入Background Layer,如下所示:
void RenderLayerCompositor::rootFixedBackgroundsChanged() { ...... if (GraphicsLayer* backgroundLayer = fixedRootBackgroundLayer()) m_containerLayer->addChildBelow(backgroundLayer, m_scrollLayer.get()); }这个函数定义在文件external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。
RenderLayerCompositor类的成员函数rootFixedBackgroundsChanged调用另外一个成员函数fixedRootBackgroundLayer获得Background Layer,然后再将它作为上述Container Layer的Child,并且位于Scroll Layer的下面。
这样,我们就分析完成网页Graphics Layer Tree的构建过程了,它是通过连接Graphics Layer Sub Tree得来的。每一个Graphics Layer Sub Tree又是由一个Composited Layer Mapping维护的。每一个需要Compositing的Render Layer都具有一个Composited Layer Mapping。这就意味着网页的Graphics Layer Tree是根据Render Layer Tree的内容构建的,并且Render Layer和Graphics Layer是多对一的关系。
至此,我们就学习完成Chromium网页加载过程这个系列的文章,重新学习可以参考 Chromium网页加载过程简要介绍和学习计划一文。这个过程主要是由WebKit完成的,一共构建了五个Tree,分别Frame Tree、DOM Tree、Render Object Tree、Render Layer Tree和Graphics Layer Tree。其中,最终输出给Chromium的是Graphics Layer Tree。有了Graphics Layer Tree之后,Chromium就可以绘制/渲染网页的UI了,这个过程我们在后面系列的文章再进行分析。敬请关注!更多的信息也可以关注老罗的新浪微博: http://weibo.com/shengyangluo。