• 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,欢迎关注!

    《Android系统源代码情景分析》一书正在进击的程序猿网(http://0xcc0xcd.com)中连载,点击进入。

           网页的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 children相应的Graphics Layer Sub Tree先于当前Graphics Layer Sub Tree绘制。Negative z-order children相应的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类的成员变量m_pendingUpdateType的值不等于CompositingUpdateNone的时候,就表明网页的Graphics Layer Tree须要进行更新。此外,要对网页的Graphics Layer Tree须要进行更新。还要求浏览器开启硬件加速合成。当调用RenderLayerCompositor类的成员函数hasAcceleratedCompositing得到的返回值等于true的时候。就表明浏览器开启了硬件加速合成。

          当RenderLayerCompositor类的成员变量m_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类的成员变量m_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类的成员变量m_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绘制的需求,也就是调用它的成员函数isSelfPaintingLayer得到的返回值为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,还是删除Composited 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更新内部维护的Graphics 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的详细作用。以及什么在情况下会存在,能够通过阅读CompositedLayerMapping类的代码获悉,这里就不再展开描写叙述。


           还有一点须要注意的是,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。这一点easy理解,由于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。这能够通过调用RenderLayerCompositor类的静态成员函数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

  • 相关阅读:
    2018-2019-1 20165227 20165228 20165237 实验五 通讯协议设计
    2018-2019-1 20165227 20165228 20165237 实验四 外设驱动程序设计
    2018-2019-1 20165237 20165227 20165228 实验三 实时系统
    2018-2019-1 20165237 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165227 20165228 20165237 实验二 固件程序设计
    2018-2019-1 20165237 《信息安全系统设计基础》第六周学习总结
    2018-2019-1 20165237 《信息安全系统设计基础》第五周学习总结
    2018-2019-1 20165237 《信息安全系统设计基础》第四周学习总结
    2018-2019-1 20165228 20165237 20165227 实验一 开发环境的熟悉
    20165237 2018-2019-1《信息安全系统设计基础》第三周学习总结
  • 原文地址:https://www.cnblogs.com/llguanli/p/8458823.html
Copyright © 2020-2023  润新知