Chromium網頁Graphics Layer Tree創建過程分析

zhou110 8年前發布 | 10K 次閱讀 安卓開發 前端技術 Chromium OS

來自: http://blog.csdn.net/luoshengyang/article/details/50661553

在前面一文中,我們分析了網頁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;</pre>

這些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); }</pre>

這兩個函數定義在文件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();

    ......
}

......

}</pre>

這個函數定義在文件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();

}</pre>

這個函數定義在文件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();

......

}</pre>

這個函數定義在文件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);

    ......
}

......

}</pre>

這個函數定義在文件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);

......

}</pre>

這個函數定義在文件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;

}</pre>

這個函數定義在文件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());

}</pre>

這個函數定義在文件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;

}</pre>

這個函數定義在文件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;

}</pre>

這個函數定義在文件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();

}</pre>

這個函數定義在文件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());

......

}</pre>

這個函數定義在文件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();

}</pre>

這個函數定義在文件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;

}</pre>

這個函數定義在文件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;

......

};</pre>

這個函數定義在文件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);

}</pre>

這個函數定義在文件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();

.......

}</pre>

這個函數定義在文件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;

}</pre>

這個函數定義在文件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());
    }
}

}</pre>

這個函數定義在文件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();

}</pre>

這個函數定義在文件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();

}</pre>

這個函數定義在文件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();

}</pre>

這個函數定義在文件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());
}

}</pre>

這個函數定義在文件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);</pre> 

它的執行有一個前提條件,就是本地變量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());

    ......
}

......

}</pre>

這個函數定義在文件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());

}</pre>

這個函數定義在文件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

</div>

 本文由用戶 zhou110 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!