1. 程式人生 > >Chromium網頁Layer Tree建立過程分析

Chromium網頁Layer Tree建立過程分析

       在Chromium中,WebKit會建立一個Graphics Layer Tree描述網頁。Graphics Layer Tree是和網頁渲染相關的一個Tree。網頁渲染最終由Chromium的CC模組完成,因此CC模組又會根據Graphics Layer Tree建立一個Layer Tree,以後就會根據這個Layer Tree對網頁進行渲染。本文接下來就分析網頁Layer Tree的建立過程。

《Android系統原始碼情景分析》一書正在進擊的程式設計師網(http://0xcc0xcd.com)中連載,點選進入!

       從前面Chromium網頁Graphics Layer Tree建立過程分析

一文可以知道,網頁的Graphics Layer Tree是根據Render Layer Tree建立的,Render Layer Tree又是根據Render Object Tree建立的。Graphics Layer Tree與Render Layer Tree、Render Layer Tree與Render Object Tree的節點是均是一對多的關係,然而Graphics Layer Tree與CC模組建立的Layer Tree的節點是一一對應的關係,如圖1所示:


圖1 Graphics Layer Tree與CC Layer Tree的關係

     也就是說,每一個Graphics Layer都對應有一個CC Layer。不過,Graphics Layer與CC Layer不是直接的一一對應的,它們是透過另外兩個Layer才對應起來的,如圖2所示:


圖2 Graphics Layer與CC Layer的對應關係

       中間的兩個Layer分別是WebContentLayerImpl和WebLayerImpl,它們是屬於Content層的物件。關於Chromium的層次劃分,可以參考前面Chromium網頁載入過程簡要介紹和學習計劃一文的介紹。Graphics Layer與CC Layer的對應關係,是在Graphics Layer的建立過程中建立起來的,接下來我們就通過原始碼分析這種對應關係的建立過程。

       從前面Chromium網頁Graphics Layer Tree建立過程分析一文可以知道,Graphics Layer是通過呼叫GraphicsLayerFactoryChromium類的成員函式createGraphicsLayer建立的,如下所示:

PassOwnPtr<GraphicsLayer> GraphicsLayerFactoryChromium::createGraphicsLayer(GraphicsLayerClient* client)  
{  
    OwnPtr<GraphicsLayer> layer = adoptPtr(new GraphicsLayer(client));  
    ......  
    return layer.release();  
}  
      這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/web/GraphicsLayerFactoryChromium.cpp中。

      引數client指向的實際上是一個CompositedLayerMapping物件,這個CompositedLayerMapping物件會用來構造一個Graphics Layer。Graphics Layer的構造過程,也就是GraphicsLayer類的建構函式的實現,如下所示:

GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
    : m_client(client)
    , ...... 
{
    ......

    m_opaqueRectTrackingContentLayerDelegate = adoptPtr(new OpaqueRectTrackingContentLayerDelegate(this));
    m_layer = adoptPtr(Platform::current()->compositorSupport()->createContentLayer(m_opaqueRectTrackingContentLayerDelegate.get()));
    
    ......
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。

       GraphicsLayer類的建構函式首先是將引數client指向的CompositedLayerMapping物件儲存在成員變數m_client中,接著又建立了一個OpaqueRectTrackingContentLayerDelegate物件儲存在成員變數opaqueRectTrackingContentLayerDelegate中。

       再接下來GraphicsLayer類的建構函式通過Platform類的靜態成員函式current獲得一個RendererWebKitPlatformSupportImpl物件。這個RendererWebKitPlatformSupportImpl物件定義在Content模組中,它實現了由WebKit定義的Platform介面,用來向WebKit層提供平臺相關的實現。

       通過呼叫RendererWebKitPlatformSupportImpl類的成員函式compositorSupport可以獲得一個WebCompositorSupportImpl物件。有了這個WebCompositorSupportImpl物件之後,就可以呼叫它的成員函式createContentLayer建立一個WebContentLayerImpl物件,並且儲存在GraphicsLayer類的成員變數m_layer中。

       WebCompositorSupportImpl類的成員函式createContentLayer的實現如下所示:

WebContentLayer* WebCompositorSupportImpl::createContentLayer(
    WebContentLayerClient* client) {
  return new WebContentLayerImpl(client);
}
       這個函式定義在檔案external/chromium_org/content/renderer/compositor_bindings/web_compositor_support_impl.cc中。

       從這裡可以看到,WebCompositorSupportImpl類的成員函式createContentLayer建立了一個WebContentLayerImpl物件返回給呼叫者。

       WebContentLayerImpl物件的建立過程,即WebContentLayerImpl類的建構函式的實現,如下所示:

WebContentLayerImpl::WebContentLayerImpl(blink::WebContentLayerClient* client)
    : client_(client), ...... {
  if (WebLayerImpl::UsingPictureLayer())
    layer_ = make_scoped_ptr(new WebLayerImpl(PictureLayer::Create(this)));
  else
    layer_ = make_scoped_ptr(new WebLayerImpl(ContentLayer::Create(this)));
  ......
}
       這個函式定義在檔案external/chromium_org/content/renderer/compositor_bindings/web_content_layer_impl.cc中。

       從前面的呼叫過程可以知道,引數client指向的實際上是一個OpaqueRectTrackingContentLayerDelegate物件,WebContentLayerImpl類的建構函式首先將它儲存在成員變數client_中 。

       WebContentLayerImpl類的建構函式接下來呼叫WebLayerImpl類的靜態成員函式UsingPictureLayer判斷Render程序是否啟用Impl Side Painting特性。如果啟用的話,就會呼叫PictureLayer類的靜態成員函式Create建立一個Picture Layer;否則的話,就會呼叫ContentLayer類的靜態成員函式Create建立一個Content Layer。有了Picture Layer或者Content Layer之後,再建立一個WebLayerImpl物件,儲存在WebContentLayerImpl類的成員變數layer_中。

       當Render程序設定了enable-impl-side-painting啟動選項時,就會啟用Impl Side Painting特性,也就是會在Render程序中建立一個Compositor執行緒,與Render程序中的Main執行緒一起協作完成網頁的渲染。在這種情況下,Graphics Layer在繪製網頁內容的時候,實際上只是記錄了繪製命令。這些繪製命令就記錄在對應的Picture Layer中。

       另一方面,如果Render程序沒有設定enable-impl-side-painting啟動選項,那麼Graphics Layer在繪製網頁內容的時候,就會通過Content Layer提供的一個Canvas真正地把網頁內容對應的UI繪製在一個記憶體緩衝區中。

       無論是Picture Layer還是Content Layer,它們都是在cc::Layer類繼承下來的,也就是說,它們對應於圖2所示的CC Layer。不過,我們只考慮Picture Layer的情況,因此接下來我們繼續分析Picture Layer的建立過程,也就是PictureLayer類的靜態成員函式Create的實現,如下所示:

scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) {
  return make_scoped_refptr(new PictureLayer(client));
}
       這個函式定義在檔案external/chromium_org/cc/layers/picture_layer.cc中。

       從這裡可以看到,PictureLayer類的靜態成員函式Create建立了一個PictureLayer物件返回給呼叫者。

       PictureLayer物件的建立過程,也就是PictureLayer類的建構函式的實現,如下所示:

PictureLayer::PictureLayer(ContentLayerClient* client)
    : client_(client),
      pile_(make_scoped_refptr(new PicturePile())),
      ...... {
}
       這個函式定義在檔案external/chromium_org/cc/layers/picture_layer.cc中。

       從前面的呼叫過程可以知道,引數client指向的實際上是一個WebContentLayerImpl物件,PictureLayer類的建構函式將它儲存在成員變數client_中。

       PictureLayer類的建構函式還做了另外一件重要的事情,就是建立了一個PicturePile物件,並且儲存在成員變數pile_中。這個PicturePile物件是用來將Graphics Layer的繪製命令記錄在Pictrue Layer中的,後面我們分析網頁內容的繪製過程時就會看到這一點。

       回到WebContentLayerImpl類的建構函式中,它建立了一個Pictrue Layer之後,接下來就會以這個Pictrue Layer為引數,建立一個WebLayerImpl物件,如下所示:

WebLayerImpl::WebLayerImpl(scoped_refptr<Layer> layer) : layer_(layer) {
  ......
}
       這個函式定義在檔案external/chromium_org/content/renderer/compositor_bindings/web_layer_impl.cc中。

       WebLayerImpl類的建構函式主要就是將引數layer描述的一個PictrueLayer物件儲存在成員變數layer_中。

       從前面Chromium網頁Graphics Layer Tree建立過程分析一文還可以知道,Graphics Layer與Graphics Layer是通過GraphicsLayer類的成員函式addChild形成父子關係的(從而形成Graphics Layer Tree),如下所示:

void GraphicsLayer::addChild(GraphicsLayer* childLayer)
{
    addChildInternal(childLayer);
    updateChildList();
}
      這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。

      GraphicsLayer類的成員函式addChild首先呼叫成員函式addChildInternal將引數childLayer描述的一個Graphics Layer作為當前正在處理的Graphics Layer的子Graphics Layer,如下所示:

void GraphicsLayer::addChildInternal(GraphicsLayer* childLayer)
{
    ......

    childLayer->setParent(this);
    m_children.append(childLayer);

    ......
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。

       這一步執行完成後,Graphics Layer之間就建立了父子關係。回到GraphicsLayer類的成員函式addChild中,它接下來還會呼叫另外一個成員函式updateChildList,用來在CC Layer之間建立父子關係,從而形CC Layer Tree。

       GraphicsLayer類的成員函式updateChildList的實現如下所示:

void GraphicsLayer::updateChildList()
{
    WebLayer* childHost = m_layer->layer();
    ......

    for (size_t i = 0; i < m_children.size(); ++i)
        childHost->addChild(m_children[i]->platformLayer());

    ......
}
      這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。

      從前面的分析可以知道,GraphicsLayer類的成員變數m_layer指向的是一個WebContentLayerImpl物件,呼叫這個WebContentLayerImpl物件的成員函式layer獲得的是一個WebLayerImpl物件,如下所示:

blink::WebLayer* WebContentLayerImpl::layer() {
  return layer_.get();
}
      這個函式定義在檔案external/chromium_org/content/renderer/compositor_bindings/web_content_layer_impl.cc中。

      從前面的分析可以知道,WebContentLayerImpl類的成員變數layer_指向的是一個WebLayerImpl物件,因此WebContentLayerImpl類的成員函式layer返回的是一個WebLayerImpl物件。

      回到GraphicsLayer類的成員函式updateChildList中,它接下來呼叫GraphicsLayer類的成員函式platformLayer獲得當前正在處理的Graphics Layer的所有子Graphics Layer對應的WebLayerImpl物件,如下所示:

WebLayer* GraphicsLayer::platformLayer() const
{
    return m_layer->layer();
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp中。

       這些子Graphics Layer對應的WebLayerImpl物件也就是通過呼叫它們的成員變數m_layer指向的WebContentLayerImpl物件的成員函式layer獲得的。

       再回到GraphicsLayer類的成員函式updateChildList中,獲得當前正在處理的Graphics Layer對應的WebLayerImpl物件,以及其所有的子Graphics Layer對應的WebLayerImpl物件之後,就可以通過呼叫WebLayerImpl類的成員函式addChild在它們之間也建立父子關係,如下所示:

void WebLayerImpl::addChild(WebLayer* child) {
  layer_->AddChild(static_cast<WebLayerImpl*>(child)->layer());
}
       這個函式定義在檔案external/chromium_org/content/renderer/compositor_bindings/web_layer_impl.cc中。

       從前面的分析可以知道,WebLayerImpl類的成員變數layer_指向的是一個PictrueLayer物件,因此WebLayerImpl類的成員函式addChild所做的事情就是在兩個PictrueLayer物件之間建立父子關係,這是通過呼叫PictrueLayer類的成員函式AddChild實現的。

       PictrueLayer類的成員函式AddChild是父類Layer繼承下來的,它的實現如下所示:

void Layer::AddChild(scoped_refptr<Layer> child) {
  InsertChild(child, children_.size());
}
       這個函式定義在檔案external/chromium_org/cc/layers/layer.cc中。

       Layer類的成員函式AddChild將引數child描述的Pictrue Layer設定為當前正在處理的Picture Layer的子Picture Layer,這是通過呼叫Layer類的成員函式InsertChild實現的,如下所示:

void Layer::InsertChild(scoped_refptr<Layer> child, size_t index) {
  DCHECK(IsPropertyChangeAllowed());
  child->RemoveFromParent();
  child->SetParent(this);
  child->stacking_order_changed_ = true;

  index = std::min(index, children_.size());
  children_.insert(children_.begin() + index, child);
  SetNeedsFullTreeSync();
}
      這個函式定義在檔案external/chromium_org/cc/layers/layer.cc中。

      Layer類的成員函式InsertChild所做的第一件事情是將當前正在處理的Picture Layer設定為引數child描述的Pictrue Layer的父Picture Layer,並且將引數child描述的Pictrue Layer儲存在當前正在處理的Picture Layer的子Picture Layer列表中。

      Layer類的成員函式InsertChild所做的第二件事情是呼叫另外一個成員函式SetNeedsFullTreeSync發出一個通知,要在CC Layer Tree與CC Pending Layer Tree之間做一個Tree結構同步。

      Layer類的成員函式SetNeedsFullTreeSync的實現如下所示:

void Layer::SetNeedsFullTreeSync() {
  if (!layer_tree_host_)
    return;

  layer_tree_host_->SetNeedsFullTreeSync();
}
      這個函式定義在檔案external/chromium_org/cc/layers/layer.cc中。

      Layer類的成員變數layer_tree_host_指向的是一個LayerTreeHost物件,這個LayerTreeHost是用來管理CC Layer Tree的,後面我們再分析它的建立過程。Layer類的成員函式SetNeedsFullTreeSync所做的事情就是呼叫這個LayerTreeHost物件的成員函式SetNeedsFullTreeSync通知它CC Layer Tree結構發生了變化,需要將這個變化同步到CC Pending Layer Tree中去。

      LayerTreeHost類的成員函式SetNeedsFullTreeSync的實現如下所示:

void LayerTreeHost::SetNeedsFullTreeSync() {
  needs_full_tree_sync_ = true;
  SetNeedsCommit();
}
       這個函式定義在檔案external/chromium_org/cc/trees/layer_tree_host.cc中。

       LayerTreeHost類的成員函式SetNeedsFullTreeSync將成員變數needs_full_tree_sync_設定為true,以標記要在CC Layer Tree和CC Pending Layer Tree之間做一次結構同步,然後再呼叫另外一個成員函式SetNeedsCommit請求在前面Chromium網頁渲染機制簡要介紹和學習計劃一文中提到的排程器將CC Layer Tree同步到CC Pending Tree去。至於這個同步操作什麼時候會執行,就是由排程器根據其內部的狀態機決定了。這一點我們在後面的文章再分析。

       這一步執行完成之後,就可以在CC模組中得到一個Layer Tree,這個Layer Tree與WebKit中的Graphics Layer Tree在結構上是完全同步的,並且這個同步過程是由WebKit控制的。這個同步過程之所以要由WebKit控制,是因為CC Layer Tree是根據Graphics Layer Tree建立的,而Graphics Layer Tree又是由WebKit管理的。

       WebKit現在還需要做的另外一件重要的事情是告訴CC模組,哪一個Picture Layer是CC Layer Tree的根節點,這樣CC模組才可以對整個CC Layer Tree進行管理。很顯然,Graphics Layer Tree的根節點對應的Picture Layer,就是CC Layer Tree的根節點。因此,WebKit會在建立Graphics Layer Tree的根節點的時候,將該根節點對應的Picture Layer設定到CC模組中去,以便後者將其作為CC Layer Tree的根節點。

       Graphics Layer Tree的根節點是什麼時候建立的呢?從前面Chromium網頁載入過程簡要介紹和學習計劃這個系列的文章可以知道,Graphics Layer Tree的根節點對應於Render Layer Tree的根節點,Render Layer Tree的根節點又對應於Render Object Tree的根節點,因此我們就從Render Object Tree的根節點的建立過程開始,分析Graphics Layer Tree的根節點的建立過程。

       從前面Chromium網頁DOM Tree建立過程分析一文可以知道,Render Object Tree的根節點是在Document類的成員函式attach中建立的,如下所示:

void Document::attach(const AttachContext& context)
{
    ......

    m_renderView = new RenderView(this);
    ......

    m_renderView->setStyle(StyleResolver::styleForDocument(*this));

    ......
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/dom/Document.cpp中。

       Document類的成員函式attach首先建立了一個RenderView物件,儲存在成員變數m_renderView中。這個RenderView物件就是Render Object Tree的根節點。Document類的成員函式attach接下來還會呼叫RenderView類的成員函式setStyle給前面建立的RenderView物件設定CSS屬性。

       從前面Chromium網頁Render Layer Tree建立過程分析一文可以知道,在給Render Object Tree的節點設定CSS屬性的過程中,會建立相應的Render Layer。這一步發生在RenderLayerModelObject類的成員函式styleDidChange中,如下所示:

void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)  
{  
    ......  
  
    LayerType type = layerTypeRequired();  
    if (type != NoLayer) {  
        if (!layer() && layerCreationAllowedForSubtree()) {  
            ......  
  
            createLayer(type);  
            
            ......  
        }  
    } else if (layer() && layer()->parent()) {  
        ......  
  
        layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer  
  
        ......  
    }  
  
    if (layer()) {  
        ......  
  
        layer()->styleChanged(diff, oldStyle);  
    }  
  
    ......  
}  
      這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerModelObject.cpp中。

      RenderLayerModelObject類的成員函式styleDidChange的詳細分析可以參考Chromium網頁Render Layer Tree建立過程分析一文。其中,Render Layer的建立是通過呼叫RenderLayerModelObject類的成員函式createLayer實現的,並且創建出來的Render Layer的成員函式styleChanged會被呼叫,用來設定它的CSS屬性。

      在設定Render Layer Tree的根節點的CSS屬性的過程中,會觸發Graphics Layer Tree的根節點的建立,因此接下來我們繼續分析RenderLayer類的成員函式styleChanged的實現,如下所示:

void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
{
    ......

    m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle);

    ......
}
      這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayer.cpp中。

      RenderLayer類的成員變數m_stackingNode指向的是一個RenderLayerStackingNode物件。這個RenderLayerStackingNode物件描述的是一個Stacking Context。關於Stacking Context,可以參考前面Chromium網頁Graphics Layer Tree建立過程分析一文。RenderLayer類的成員函式styleChanged呼叫上述RenderLayerStackingNode物件的成員函式updateStackingNodesAfterStyleChange通知它所關聯的Render Layer的CSS屬性發生了變化,這樣它可能就需要更新自己的子元素。

      RenderLayerStackingNode類的成員函式updateStackingNodesAfterStyleChange的實現如下所示:

void RenderLayerStackingNode::updateStackingNodesAfterStyleChange(const RenderStyle* oldStyle)
{
    bool wasStackingContext = oldStyle ? !oldStyle->hasAutoZIndex() : false;
    int oldZIndex = oldStyle ? oldStyle->zIndex() : 0;

    bool isStackingContext = this->isStackingContext();
    if (isStackingContext == wasStackingContext && oldZIndex == zIndex())
        return;

    dirtyStackingContextZOrderLists();

    if (isStackingContext)
        dirtyZOrderLists();
    else
        clearZOrderLists();
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp中。

       RenderLayerStackingNode類的成員函式updateStackingNodesAfterStyleChange判斷當前正在處理的RenderLayerStackingNode物件關聯的Render Layer的CSS屬性變化,是否導致它從一個Stacking Context變為一個非Stacking Context,或者從一個非Stacking Context變為一個Stacking Context。

       在從非Stacking Context變為Stacking Context的情況下,RenderLayerStackingNode類的成員函式updateStackingNodesAfterStyleChange就會呼叫另外一個成員函式dirtyZOrderLists將Stacking Context標記為Dirty狀態,這樣以後在需要的時候就會根據該Stacking Context的子元素的z-index重新構建Graphics Layer Tree。

       RenderLayerStackingNode類的成員函式dirtyZOrderLists的實現如下所示:

void RenderLayerStackingNode::dirtyZOrderLists()
{
    ......

    if (m_posZOrderList)
        m_posZOrderList->clear();
    if (m_negZOrderList)
        m_negZOrderList->clear();
    m_zOrderListsDirty = true;

    if (!renderer()->documentBeingDestroyed())
        compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree);
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/RenderLayerStackingNode.cpp中。

       RenderLayerStackingNode類的成員函式dirtyZOrderLists首先是將用來儲存子元素的兩個列表清空。其中一個列表用來儲存z-index為正數的子元素,另一個列表用來儲存z-index為負數的子元素。這些子元素在各自的列表中均是按照從小到大的順序排列的。有了這個順序之後,Graphics Layer Tree就可以方便地按照z-index順序創建出來。

       RenderLayerStackingNode類的成員函式dirtyZOrderLists接下來將成員變數m_zOrderListsDirty的值設定為true,就將自己的狀態標記為Dirty,以後就會重新根據子元素的z-index值,將它們分別儲存在對應的列表中。

       RenderLayerStackingNode類的成員函式dirtyZOrderLists最後判斷當前載入的網頁有沒有被銷燬。如果沒有被銷燬,就會呼叫另外一個成員函式compositor,獲得一個RenderLayerCompositor物件。這個RenderLayerCompositor物件是用來管理當前載入的網頁的Graphics Layer Tree的。有了這個RenderLayerCompositor物件之後,就可以呼叫它的成員函式setNeedsCompositingUpdate,用來通知它需要重建Graphics Layer Tree。

       RenderLayerCompositor類的成員函式setNeedsCompositingUpdate的實現如下所示:

void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType updateType)
{
    ......
    if (!m_renderView.needsLayout())
        enableCompositingModeIfNeeded();

    m_pendingUpdateType = std::max(m_pendingUpdateType, updateType);
    ......
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。

       RenderLayerCompositor類的成員變數m_renderView描述的是一個RenderView物件。這個RenderView物件就是在前面分析的Document類的成員函式attach中建立的RenderView物件。RenderLayerCompositor類的成員函式setNeedsCompositingUpdate判斷它是否需要重新Layout。如果需要的話,就會呼叫另外一個成員函式enableCompositingModeIfNeeded將網頁的Render Layer Tree的根節點設定為一個Compositing Layer,也就是要為它建立一個Graphics Layer。

       在我們這個情景中,RenderLayerCompositor類的成員變數m_renderView描述的RenderView物件是剛剛建立的,這意味它需要執行一個Layout操作,因此接下來RenderLayerCompositor類的成員函式setNeedsCompositingUpdate會呼叫成員函式enableCompositingModeIfNeeded為Render Layer Tree的根節點建立一個Graphics Layer,作為Graphics Layer Tree的根節點。

       RenderLayerCompositor類的成員函式enableCompositingModeIfNeeded的實現如下所示:

void RenderLayerCompositor::enableCompositingModeIfNeeded()
{
    ......

    if (rootShouldAlwaysComposite()) {
        ......
        setCompositingModeEnabled(true);
    }
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。

       RenderLayerCompositor類的成員函式enableCompositingModeIfNeeded首先呼叫成員函式rootShouldAlwaysComposite判斷是否要為網頁Render Layer Tree的根節點建立一個Graphics Layer。如果需要的話,就呼叫另外一個成員函式setCompositingModeEnabled進行建立。

       RenderLayerCompositor類的成員函式rootShouldAlwaysComposite的實現如下所示:

bool RenderLayerCompositor::rootShouldAlwaysComposite() const
{
    if (!m_hasAcceleratedCompositing)
        return false;
    return m_renderView.frame()->isMainFrame() || m_compositingReasonFinder.requiresCompositingForScrollableFrame();
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。

       只有在採用硬體加速渲染網頁的情況下,才需要建立Graphics Layer。當RenderLayerCompositor類的成員變數m_hasAcceleratedCompositing的值等於true的時候,就表示描述網頁採用硬體加速渲染。因此,當RenderLayerCompositor類的成員變數m_hasAcceleratedCompositing的值等於false的時候,RenderLayerCompositor類的成員函式就返回一個false值給呼叫者,表示不需要為網頁Render Layer Tree的根節點建立Graphics Layer。

       在採用硬體加速渲染網頁的情況下,在兩種情況下,需要為Render Layer Tree的根節點建立Graphics Layer。第一種情況是當前網頁載入在Main Frame中。第二種情況是當前網頁不是載入在Main Frame,例如是通過iframe嵌入在Main Frame中,但是它是可滾動的。

       我們假設當前網頁是載入在Main Frame中的,因此RenderLayerCompositor類的成員函式rootShouldAlwaysComposite的返回值為true,這時候RenderLayerCompositor類的成員函式enableCompositingModeIfNeeded就會呼叫另外一個成員函式setCompositingModeEnabled為網頁Render Layer Tree的根節點建立Graphics Layer。

       RenderLayerCompositor類的成員函式setCompositingModeEnabled的實現如下所示:

void RenderLayerCompositor::setCompositingModeEnabled(bool enable)
{
    ......

    m_compositing = enable;

    ......

    if (m_compositing)
        ensureRootLayer();
    else
        destroyRootLayer();

    ......
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。

       從前面的呼叫過程可以知道,引數enable的值等於true,這時候RenderLayerCompositor類的成員函式setCompositingModeEnabled會呼叫另外一個成員函式ensureRootLayer建立Graphics Layer Tree的根節點。

       RenderLayerCompositor類的成員函式ensureRootLayer的實現如下所示:

void RenderLayerCompositor::ensureRootLayer()  
{  
    RootLayerAttachment expectedAttachment = m_renderView.frame()->isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame;
    ......  
  
    if (!m_rootContentLayer) {  
        m_rootContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this);  
        ......  
    }  
  
    if (!m_overflowControlsHostLayer) {  
        ......  
  
        // Create a layer to host the clipping layer and the overflow controls layers.  
        m_overflowControlsHostLayer = GraphicsLayer::create(graphicsLayerFactory(), this);  
  
        // Create a clipping layer if this is an iframe or settings require to clip.  
        m_containerLayer = GraphicsLayer::create(graphicsLayerFactory(), this);  
        ......  
  
        m_scrollLayer = GraphicsLayer::create(graphicsLayerFactory(), this);  
        ......  
        // Hook them up  
        m_overflowControlsHostLayer->addChild(m_containerLayer.get());  
        m_containerLayer->addChild(m_scrollLayer.get());  
        m_scrollLayer->addChild(m_rootContentLayer.get());  
  
        ......  
    }  
  
    ......  

    attachRootLayer(expectedAttachment);
}  

       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。

       RenderLayerCompositor類的成員函式ensureRootLayer的詳細分析可以參考前面Chromium網頁Graphics Layer Tree建立過程分析一文,現在我們關注的重點是它最後呼叫另外一個成員函式attachRootLayer將Graphics Layer Tree的根節點設定給WebKit的使用者,即Chromium的Content層。

       RenderLayerCompositor類的成員函式attachRootLayer的實現如下所示:

void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment)
{
    ......

    switch (attachment) {
        ......
        case RootLayerAttachedViaChromeClient: {
            LocalFrame& frame = m_renderView.frameView()->frame();
            Page* page = frame.page();
            if (!page)
                return;
            page->chrome().client().attachRootGraphicsLayer(rootGraphicsLayer());
            break;
        }
        ......
    }

    m_rootLayerAttachment = attachment;
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/core/rendering/compositing/RenderLayerCompositor.cpp中。

       從前面的呼叫過程可以知道,如果當前網頁是在Main Frame中載入的,那麼引數attachment的值就等於RootLayerAttachedViaChromeClient,這時候RenderLayerCompositor類的成員函式attachRootLayer與當前載入網頁關聯的一個ChromeClientImpl物件,並且呼叫這個ChromeClientImpl物件的成員函式attachRootGraphicsLayer將Graphics Layer Tree的根節點傳遞給它處理。Graphics Layer Tree的根節點可以通過呼叫RenderLayerCompositor類的成員函式rootGraphicsLayer獲得。

       ChromeClientImpl類的成員函式attachRootGraphicsLayer的實現如下所示:

void ChromeClientImpl::attachRootGraphicsLayer(GraphicsLayer* rootLayer)
{
    m_webView->setRootGraphicsLayer(rootLayer);
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/web/ChromeClientImpl.cpp中。

       ChromeClientImpl類的成員變數m_webView指向的是一個WebViewImpl物件。這個WebViewImpl物件的建立過程可以參考前面Chromium網頁Frame Tree建立過程分析一文。ChromeClientImpl類的成員函式attachRootGraphicsLayer所做的事情就是呼叫這個WebViewImpl物件的成員函式setRootGraphicsLayer,以便將Graphics Layer Tree的根節點傳遞給它處理。

       WebViewImpl類的成員函式setRootGraphicsLayer的實現如下所示:

void WebViewImpl::setRootGraphicsLayer(GraphicsLayer* layer)
{
    if (pinchVirtualViewportEnabled()) {
        PinchViewport& pinchViewport = page()->frameHost().pinchViewport();
        pinchViewport.attachToLayerTree(layer, graphicsLayerFactory());
        if (layer) {
            m_rootGraphicsLayer = pinchViewport.rootGraphicsLayer();
            m_rootLayer = pinchViewport.rootGraphicsLayer()->platformLayer();
            ......
        } 
        ......
    } else {
        m_rootGraphicsLayer = layer;
        m_rootLayer = layer ? layer->platformLayer() : 0;
        ......
    }

    setIsAcceleratedCompositingActive(layer);
    
    ......
}
       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/web/WebViewImpl.cpp中。

       如果瀏覽器設定了"enable-pinch-virtual-viewport"啟動選項,呼叫WebViewImpl類的成員函式pinchVirtualViewportEnabled得到的返回值就會為true。這時候網頁有兩個Viewport,一個稱為Inner Viewport,另一個稱為Outer Viewport。Outer Viewport有兩個特性。第一個特性是它的大小不跟隨頁面進行縮放,第二個特性是fixed positioned元素的位置是根據它來計算的。這種體驗的特點是fixed positioned元素的位置不會隨頁面的縮放發生變化。為實現這種體驗,需要在Graphics Layer Tree中增加一些Graphics Layer。這些Graphics Layer通過一個PinchViewport管理。這時候Graphics Layer Tree的根節點就不再是引數layer描述的Graphics Layer,而是PinchViewport額外建立的一個Graphics Layer。關於Pinch Virtual Viewport特性的更多資訊,可以參考官方文件:Layer-based Solution for Pinch Zoom / Fixed Position

       為簡單起見,我們假設沒有設定"enable-pinch-virtual-viewport"啟動選項,這時候WebViewImpl類的成員函式setRootGraphicsLayer會將引數layer指向的一個Graphics Layer,也就是Graphics Layer Tree的根節點,儲存在成員變數m_rootGraphicsLayer中,並且呼叫它的成員函式platformLayer獲得與它關聯的一個WebLayerImpl物件,儲存在另外一個成員變數m_rootLayer中。

       再接下來,WebViewImpl類的成員函式setRootGraphicsLayer呼叫另外一個成員函式setIsAcceleratedCompositingActive啟用網頁的硬體加速渲染,它的實現如下所示:

void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
{
    ......

    if (!active) {
        m_isAcceleratedCompositingActive = false;
        ......
    } else if (m_layerTreeView) {
        m_isAcceleratedCompositingActive = true;
        ......
    } else {
        ......

        m_client->initializeLayerTreeView();
        m_layerTreeView = m_client->layerTreeView();
        if (m_layerTreeView) {
            m_layerTreeView->setRootLayer(*m_rootLayer);
            ......
        }

        ......

        m_isAcceleratedCompositingActive = true;

        ......
    }

    ......
}

       這個函式定義在檔案external/chromium_org/third_party/WebKit/Source/web/WebViewImpl.cpp中。

       從前面的呼叫過程可以知道,引數active的值是等於true的,WebViewImpl類的成員變數m_isAcceleratedCompositingActive的值將被設定為引數active的值,用來表示網頁是否已經啟用網頁硬體加速渲染。

       WebViewImpl類還有兩個重要的成員變數m_client和m_layerTreeView。其中,成員變數m_client的初始化過程可以參考前面Chromium網頁Frame Tree建立過程分析一文,它指向的是一個在Chromium的Content層建立的RenderViewImpl物件。

      另外一個成員變數m_layerTreeView是一個型別為WebLayerTreeView指標,它的值開始的時候是等於NULL的。WebViewImpl類的成員函式setIsAcceleratedCompositingActive被呼叫的時候,如果引數active的值是等於true,並且成員變數m_layerTreeView的值也等於NULL,那麼WebKit就會先請求使用者,也就是Chromium的Content層,初始化CC Layer Tree。這是通過呼叫成員變數m_client指向的一個RenderViewImpl物件的成員函式initializeLayerTreeView實現的。Layer Tree View初始化完成之後,WebViewImpl類再將成員變數m_rootLayer描述的WebLayerImpl物件關聯的Picture Layer設定為CC Layer Tree的根節點。

       接下來我們先分析RenderViewImpl類的成員函式initializeLayerTreeView初始化CC Layer Tree的過程,然後再分析設定CC Layer Tree根節點的過程。

       RenderViewImpl類的成員函式initializeLayerTreeView的實現如下所示:

void RenderViewImpl::initializeLayerTreeView() {
  RenderWidget::initializeLayerTreeView();
  ......
}
       這個函式定義在檔案external/chromium_org/content/renderer/render_view_impl.cc中。

       RenderViewImpl類的成員函式initializeLayerTreeView主要是呼叫父類RenderWidget的成員函式initializeLayerTreeView初始化一個CC Layer Tree,如下所示:

void RenderWidget::initializeLayerTreeView() {
  compositor_ = RenderWidgetCompositor::Create(
      this, is_threaded_compositing_enabled_);
  ......
  if (init_complete_)
    StartCompositor();
}
       這個函式定義在檔案external/chromium_org/content/renderer/render_widget.cc中。

       RenderWidget類的成員函式initializeLayerTreeView首先是呼叫RenderWidgetCompositor類的靜態成員函式Create建立一個RenderWidgetCompositor物件,並且儲存在成員變數compositor_中。在建立這個RenderWidgetCompositor物件期間,也會伴隨著建立一個CC Layer Tree。

       RenderWidget類有一個成員變數init_complete_,當它的值等於true的時候,表示Browser程序已經為當前正在載入的網頁初始化好Render View,這時候RenderWidget類的成員函式initializeLayerTreeView就會呼叫另外一個成員函式StartCompositor啟用前面Chromium網頁載入過程簡要介紹和學習計劃一文中提到的排程器,表示它可以開始進行排程工作了。

       接下來我們先分析RenderWidget類的成員變數init_complete_被設定為true的過程。從前面Chromium網頁Frame Tree建立過程分析一文可以知道,當Browser程序為在Render程序中載入的網頁建立了一個Render View之後,會向Render程序傳送一個型別為ViewMsg_New的訊息。這個IPC訊息被RenderThreadImpl類的成員函式OnCreateNewView處理。在處理期間,會建立一個RenderViewImpl物件,並且呼叫它的成員函式Initialize對其進行初始化,如下所示:

void RenderViewImpl::Initialize(RenderViewImplParams* params) {  
  ......  
  
  main_render_frame_.reset(RenderFrameImpl::Create(  
      this, params->main_frame_routing_id));  
  ......  
  
  WebLocalFrame* web_frame = WebLocalFrame::create(main_render_frame_.get());  
  main_render_frame_->SetWebFrame(web_frame);  
  ......  
  
  webwidget_ = WebView::create(this);  
  ......  

  // If this is a popup, we must wait for the CreatingNew_ACK message before
  // completing initialization.  Otherwise, we can finish it now.
  if (opener_id_ == MSG_ROUTING_NONE) {
    ......
    CompleteInit();
  }
  
  webview()->setMainFrame(main_render_frame_->GetWebFrame());  
    
  ......  
}
       這個函式定義在檔案external/chromium_org/content/renderer/render_view_impl.cc中。

       RenderViewImpl類的成員函式Initialize的詳細分析可以參考前面Chromium網頁Frame Tree建立過程分析一文。這裡我們看到,當RenderViewImpl類的成員變數opener_id_的值等於MSG_ROUTING_NONE的時候,另外一個成員函式CompleteInit就會被呼叫。RenderViewImpl類的成員變數opener_id_什麼時候會等於MSG_ROUTING_NONE呢?如果正在載入的網頁不是在一個Popup Window顯示時,它的值就會等於MSG_ROUTING_NONE,否則它的值等於將它Popup出來的網頁的Routing ID。從程式碼註釋我們還可以看到,如果當前載入的網頁是在一個Popup Window顯示時,RenderViewImpl類的成員函式CompleteInit將會延遲到Render程序接收到Broswer傳送另外一個型別為ViewMsg_CreatingNew_ACK的IPC訊息時才會被呼叫。

       我們假設正在載入的網頁不是一個Popup Window顯示,這時候RenderViewImpl類的成員函式CompleteInit就會被呼叫。RenderViewImpl類的成員函式CompleteInit是從父類RenderWidget繼承下來的,它的實現如下所示:

void RenderWidget::CompleteInit() {
  ......

  init_complete_ = true;

  if (compositor_)
    StartCompositor();

  ......
}
       這個函式定義在檔案external/chromium_org/content/renderer/render_widget.cc中。

       從這裡就可以看到,RenderWidget類的成員變數init_complete_將會被設定為true,並且在成員變數compositor_的值不等於NULL的情況下,會呼叫前面提到的成員函式StartCompositor啟用前面Chromium網頁載入過程簡要介紹和學習計劃一文中提到的排程器。

       回到前面分析的RenderWidget類的成員函式initializeLayerTreeView中,我們假設正在載入的網頁不是在一個Popup Window顯示,因此當RenderWidget類的成員函式initializeLayerTreeView被呼叫時,Browser程序已經為正在載入的網頁初始化好了Render View,這意味著此時RenderWidget類的成員變數init_complete_已經被設定為true,於是RenderWidget類的成員函式initializeLayerTreeView就會先呼叫RenderWidgetCompositor類的靜態成員函式Create建立一個RenderWidgetCompositor物件,然後再呼叫另外一個成員函式StartCompositor啟用前面Chromium網頁載入過程簡要介紹和學習計劃一文中提到的排程器。接下來我們就先分析RenderWidgetCompositor類的靜態成員函式Create的實現,在接下來一篇文章中再分析RenderWidget類的成員函式StartCompositor啟用排程器的過程。

       RenderWidgetCompositor類的靜態成員函式Create的實現如下所示:

scoped_ptr<RenderWidgetCompositor> RenderWidgetCompositor::Create(
    RenderWidget* widget,
    bool threaded) {
  scoped_ptr<RenderWidgetCompositor> compositor(
      new RenderWidgetCompositor(widget, threaded));

  CommandLine* cmd = CommandLine::ForCurrentProcess();

  cc::LayerTreeSettings settings;
  ......

  settings.initial_debug_state.show_debug_borders =
      cmd->HasSwitch(cc::switches::kShowCompositedLayerBorders);
  settings.initial_debug_state.show_fps_counter =
      cmd->HasSwitch(cc::switches::kShowFPSCounter);
  settings.initial_debug_state.show_layer_animation_bounds_rects =
      cmd->HasSwitch(cc::switches::kShowLayerAnimationBounds);
  settings.initial_debug_state.show_paint_rects =
      cmd->HasSwitch(switches::kShowPaintRects);
  settings.initial_debug_state.show_property_changed_rects =
      cmd->HasSwitch(cc::switches::kShowPropertyChangedRects);
  settings.initial_debug_state.show_surface_damage_rects =
      cmd->HasSwitch(cc::switches::kShowSurfaceDamageRects);
  settings.initial_debug_state.show_screen_space_rects =
      cmd->HasSwitch(cc::switches::kShowScreenSpaceRects);
  settings.initial_debug_state.show_replica_screen_space_rects =
      cmd->HasSwitch(cc::switches::kShowReplicaScreenSpaceRects);
  settings.initial_debug_state.show_occluding_rects =
      cmd->HasSwitch(cc::switches::kShowOccludingRects);
  settings.initial_debug_state.show_non_occluding_rects =
      cmd->HasSwitch(cc::switches::kShowNonOccludingRects);
  ......

  compositor->Initialize(settings);

  return compositor.Pass();
}
       這個函式定義在檔案external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。

       RenderWidgetCompositor類的靜態成員函式Create首先建立一個RenderWidgetCompositor物件,接著根據Render程序的啟動選項初始化一個LayerTreeSettings物件,最後以這個LayerTreeSettings物件為引數,對前面建立的RenderWidgetCompositor物件進行初始化,這是通過呼叫RenderWidgetCompositor類的成員函式Initialize實現的。

       接下來我們先分析RenderWidgetCompositor物件的建立過程,也就是RenderWidgetCompositor類的建構函式的實現,接下來再分析RenderWidgetCompositor物件的初始化過程,也就是RenderWidgetCompositor類的成員函式Initialize的實現。

       RenderWidgetCompositor類的建構函式的實現如下所示:

RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget* widget,
                                               bool threaded)
    : threaded_(threaded),
      ......,
      widget_(widget) {
}
      這個函式定義在檔案external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。

      RenderWidgetCompositor類的建構函式主要是將引數widget指向的RenderViewImpl物件儲存在成員變數widget_中,並且將引數threaded的值儲存在成員變數threaded_中。引數threaded用來描述Render程序是否要採用執行緒化渲染,也就是是否需要建立一個Compositor執行緒來專門執行渲染相關的工作。

      從前面的呼叫過程可以知道,引數threaded是從RenderWidget類的成員函式initializeLayerTreeView中傳遞過來的,它的值等於RenderWidget類的成員變數is_threaded_compositing_enabled_的值。RenderWidget類的成員變數is_threaded_compositing_enabled_是在建構函式初始化的,如下所示:

RenderWidget::RenderWidget(blink::WebPopupType popup_type,
                           const blink::WebScreenInfo& screen_info,
                           bool swapped_out,
                           bool hidden,
                           bool never_visible)
    : ...... {
  ......
  is_threaded_compositing_enabled_ =
      CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kEnableThreadedCompositing);
}
      這個函式定義在檔案external/chromium_org/content/renderer/render_widget.cc中。

      這意味著當Render程序設定了“enable-threaded-compositing”啟動選項時,Render程序就會採用執行緒化渲染機制。我們接下來以及以後的文章只考慮執行緒化渲染機制這種情況。

      回到RenderWidgetCompositor類的建構函式中,這意味著它的成員變數threaded_會被設定為true。

      接下來我們繼續分析RenderWidgetCompositor物件的初始化過程,也就是RenderWidgetCompositor類的成員函式Initialize的實現,如下所示:

void RenderWidgetCompositor::Initialize(cc::LayerTreeSettings settings) {
  scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy;
  RenderThreadImpl* render_thread = RenderThreadImpl::current();
  ......
  // render_thread may be NULL in tests.
  if (render_thread) {
    compositor_message_loop_proxy =
        render_thread->compositor_message_loop_proxy();
    ......
  }
  if (compositor_message_loop_proxy.get()) {
    layer_tree_host_ = cc::LayerTreeHost::CreateThreaded(
        this, shared_bitmap_manager, settings, compositor_message_loop_proxy);
  } else {
    layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(
        this, this, shared_bitmap_manager, settings);
  }
  ......
}
       這個函式定義在檔案external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。

       RenderWidgetCompositor類的成員函式Initialize首先呼叫RenderThreadImpl類的靜態成員函式current獲得一個RenderThreadImpl物件。這個RenderThreadImpl物件描述的實際上是Render程序的Render執行緒,也就是Main執行緒。這個Main執行緒是在Render程序啟動的時候建立的,是一定會存在的,具體可以參考Chromium的Render程序啟動過程分析一文。

       RenderWidgetCompositor類的成員函式Initialize接下來呼叫前面獲得的RenderThreadImpl物件的成員函式compositor_message_loop_proxy獲得Render程序的Compositor執行緒的訊息迴圈代理物件。當這個訊息迴圈代理物件存在時,就會呼叫cc::LayerTreeHost類的靜態成員函式CreateThreaded建立一個支援執行緒化渲染的LayerTreeHost物件,並且儲存在成員變數layer_tree_host_中。另一方面,如果Render程序中不存在Compositor執行緒,那麼RenderWidgetCompositor類的成員函式Initialize就會呼叫cc::LayerTreeHost類的靜態成員函式CreateSingleThreaded建立一個不支援執行緒化渲染的LayerTreeHost物件。在後一種情況下,所有的渲染操作都將在Render程序的Main執行緒中執行。

       接下來我們首先分析Render程序的Compositor執行緒的建立過程。前面提到,當Browser程序為Render程序中載入的網頁建立了一個Render View時,就會發送一個型別為ViewMsg_New的IPC訊息給Render程序。Render程序通過RenderThreadImpl類的成員函式OnCreateNewView接收和處理該訊息,如下所示:

void RenderThreadImpl::OnCreateNewView(const ViewMsg_New_Params& params) {  
  EnsureWebKitInitialized();  
  // When bringing in render_view, also bring in webkit's glue and jsbindings.  
  RenderViewImpl::Create(params.opener_route_id,  
                         params.window_was_created_with_opener,  
                         params.renderer_preferences,  
                         params.web_preferences,  
                         params.view_id,  
                         params.main_frame_routing_id,  
                         params.surface_id,  
                         params.session_storage_namespace_id,  
                         params.frame_name,  
                         false,  
                         params.swapped_out,  
                         params.proxy_routing_id,  
                         params.hidden,  
                         params.never_visible,  
                         params.next_page_id,  
                         params.screen_info,  
                         params.accessibility_mode);  
}  
       這個函式定義在檔案external/chromium_org/content/renderer/render_thread_impl.cc中。

       除了呼叫RenderViewImpl類的靜態成員函式Create建立一個RenderViewImpl物件,RenderThreadImpl類的成員函式OnCreateNewView還會呼叫另外一個成員函式EnsureWebKitInitialized確保WebKit已經初始化好。

       RenderThreadImpl類的成員函式EnsureWebKitInitialized的實現如下所示:

void RenderThreadImpl::EnsureWebKitInitialized() {
  if (webkit_platform_support_)
    return;

  webkit_platform_support_.reset(new RendererWebKitPlatformSupportImpl);
  blink::initialize(webkit_platform_support_.get());
  ......

  const CommandLine& command_line = *CommandLine::ForCurrentProcess();

  bool enable = command_line.HasSwitch(switches::kEnableThreadedCompositing);
  if (enable) {
    ......

    if (!compositor_message_loop_proxy_.get()) {
      compositor_thread_.reset(new base::Thread("Compositor"));
      compositor_thread_->Start();
      ......
      compositor_message_loop_proxy_ =
          compositor_thread_->message_loop_proxy();
      ......
    }

    ......
  }

  ......
}
      這個函式定義在檔案external/chromium_org/content/renderer/render_thread_impl.cc中。

      除了執行初始化WebKit的工作,RenderThreadImpl類的成員函式EnsureWebKitInitialized還做的另外一件重要事情是檢查Render程序是否設定了“enable-threaded-compositing”啟動選項。如果設定了,那麼就會建立和啟動一個Compositor執行緒,並且將這個Compositor執行緒的訊息迴圈代理物件儲存在成員變數compositor_message_loop_proxy_中。這樣當RenderThreadImpl類的成員函式compositor_message_loop_proxy被呼叫時,Compositor執行緒的訊息迴圈代理物件就會被返回給呼叫者,如下所示:

class CONTENT_EXPORT RenderThreadImpl : public RenderThread,
                                        public ChildThread,
                                        public GpuChannelHostFactory {
 public:
  ......

  scoped_refptr<base::MessageLoopProxy> compositor_message_loop_proxy() const {
    return compositor_message_loop_proxy_;
  }

  ......
};
      這個函式定義在檔案external/chromium_org/content/renderer/render_thread_impl.h中。

      有了這個訊息迴圈代理物件之後,就可以向Compositor執行緒傳送訊息請求其執行相應的操作了。

      回到RenderWidgetCompositor類的成員函式Initialize,它獲得了Compositor執行緒的訊息迴圈代理物件之後,接下來就呼叫cc::LayerTreeHost類的靜態成員函式CreateThreaded建立一個支援執行緒化渲染的LayerTreeHost物件,如下所示:

scoped_ptr<LayerTreeHost> LayerTreeHost::CreateThreaded(
    LayerTreeHostClient* client,
    SharedBitmapManager* manager,
    const LayerTreeSettings& settings,
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
  DCHECK(impl_task_runner);
  scoped_ptr<LayerTreeHost> layer_tree_host(
      new LayerTreeHost(client, manager, settings));
  layer_tree_host->InitializeThreaded(impl_task_runner);
  return layer_tree_host.Pass();
}
      這個函式定義在檔案external/chromium_org/cc/trees/layer_tree_host.cc中。

      LayerTreeHost類的靜態成員函式CreateThreaded首先建立了一個LayerTreeHost物件,如下所示:

LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client,
                             SharedBitmapManager* manager,
                             const LayerTreeSettings& settings)
    : ......,
      client_(client),
      ...... {
  ......
}
      這個函式定義在檔案external/chromium_org/cc/trees/layer_tree_host.cc中。

      從前面的呼叫過程可以知道,引數client指向的是一個RenderWidgetCompositor物件,這個RenderWidgetCompositor物件將會被儲存LayerTreeHost類的成員變數client_中。

      回到LayerTreeHost類的靜態成員函式CreateThreaded中,它建立了一個LayerTreeHost物件之後,接下來會呼叫它的成員函式InitializeThreaded對其進行初始化,如下所示:

void LayerTreeHost::InitializeThreaded(
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
  InitializeProxy(ThreadProxy::Create(this, impl_task_runner));
}
      這個函式定義在檔案external/chromium_org/cc/trees/layer_tree_host.cc中。

      從前面的呼叫過程可以知道,引數impl_task_runner描述的是Compositor執行緒的訊息迴圈,LayerTreeHost類的成員函式InitializeThreaded首先呼叫ThreadProxy類的靜態成員函式Create建立一個ThreadProxy物件,接著用這個ThreadProxy物件初始化當前正在處理的LayerTreeHost物件,這是通過呼叫LayerTreeHost類的成員函式IntializeProxy實現的。

      接下來我們先分析ThreadProxy類的靜態成員函式Create建立ThreadProxy物件的過程,接著再分析LayerTreeHost類的成員函式IntializeProxy初始化LayerTreeHost物件的過程。

      ThreadProxy類的靜態成員函式Create的實現如下所示:

scoped_ptr<Proxy> ThreadProxy::Create(
    LayerTreeHost* layer_tree_host,
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
  return make_scoped_ptr(new ThreadProxy(layer_tree_host, impl_task_runner))
      .PassAs<Proxy>();
}
      這個函式定義在檔案external/chromium_org/cc/trees/thread_proxy.cc中。

      從這裡可以看到,ThreadProxy類的靜態成員函式Create建立了一個ThreadProxy物件返回給呼叫者。

      ThreadProxy物件的建立過程,即ThreadProxy類的建構函式的實現,如下所示:

ThreadProxy::ThreadProxy(
    LayerTreeHost* layer_tree_host,
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
    : Proxy(impl_task_runner),
      ...... {
  ......
}
      這個函式定義在檔案external/chromium_org/cc/trees/thread_proxy.cc中。

      ThreadProxy類的建構函式主要是呼叫了父類Proxy的建構函式執行初始化工作,如下所示:

Proxy::Proxy(scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
    : main_task_runner_(base::MessageLoopProxy::current()),
      ......
      impl_task_runner_(impl_task_runner),
      ...... {
  ......
}
       這個函式定義在檔案external/chromium_org/cc/trees/proxy.cc中。

       從前面的分析可以知道,引數impl_task_runner描述的是Compositor執行緒的訊息迴圈,它將被儲存在Proxy類的成員變數impl_task_runner_中。此外,Proxy類的建構函式還會通過呼叫MessageLoopProxy類的靜態成員函式current獲得當前執行緒的訊息迴圈,並且儲存在成員變數main_task_runner_。當前執行緒即為Render程序的Main執行緒,因此Proxy類的成員變數main_task_runner_描述的Main執行緒的訊息迴圈。       

       初始化好Proxy類的成員變數main_task_runner_和impl_task_runner_之後,以後就可以通過呼叫Proxy類的成員函式MainThreadTaskRunner和ImplThreadTaskRunner獲得它們描述的執行緒的訊息迴圈,如下所示:

base::SingleThreadTaskRunner* Proxy::MainThreadTaskRunner() const {
  return main_task_runner_.get();
}

......

base::SingleThreadTaskRunner* Proxy::ImplThreadTaskRunner() const {
  return impl_task_runner_.get();
}
       這兩個函式定義在檔案external/chromium_org/cc/trees/proxy.cc中。      

       回到LayerTreeHost類的成員函式InitializeThreaded中,它建立了一個ThreadProxy物件之後,接下來就會呼叫另外一個成員函式InitializeProxy啟動前面建立的ThreadProxy物件,如下所示:

void LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) {
  ......

  proxy_ = proxy.Pass();
  proxy_->Start();
}
       這個函式定義在檔案external/chromium_org/cc/trees/layer_tree_host.cc中。

       LayerTreeHost類的成員函式InitializeProxy首先將引數proxy描述的一個ThreadProxy物件儲存在成員變數proxy_中,接著再呼叫上述ThreadProxy物件的成員函式Start對它進行啟動,如下所示:

void ThreadProxy::Start() {
  ......

  CompletionEvent completion;
  Proxy::ImplThreadTaskRunner()->PostTask(
      FROM_HERE,
      base::Bind(&ThreadProxy::InitializeImplOnImplThread,
                 base::Unretained(this),
                 &completion));
  completion.Wait();

  main_thread_weak_ptr_ = main().weak_factory.GetWeakPtr();

  main().started = true;
}
       這個函式定義在檔案external/chromium_org/cc/trees/thread_proxy.cc中。

       ThreadProxy類的成員函式Start主要是向Compositor執行緒的訊息佇列傳送了一個Task,並且等待這個Task完成。這個Task綁定了ThreadProxy類的成員函式InitializeImplOnImplThread,因此接下來ThreadProxy類的成員函式InitializeImplOnImplThread就會在Compositor執行緒中執行,如下所示:

void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
  ......
  impl().layer_tree_host_impl =
      layer_tree_host()->CreateLayerTreeHostImpl(this);

  SchedulerSettings scheduler_settings(layer_tree_host()->settings());
  impl().scheduler = Scheduler::Create(this,
                                       scheduler_settings,
                                       impl().layer_tree_host_id,
                                       ImplThreadTaskRunner());
  ......

  impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
  completion->Signal();
}
      這個函式定義在檔案external/chromium_org/cc/trees/thread_proxy.cc中。

      ThreadProxy類的成員函式InitializeImplOnImplThread主要是做了三件事情。

      第一件事情是呼叫前面建立的LayerTreeHost物件的成員函式CreateLayerTreeHostImpl函式建立了一個LayerTreeHostImpl物件,並且儲存在內部的一個CompositorThreadOnly物件的成員變數layer_tree_host_impl中。前面建立的LayerTreeHost物件可以通過呼叫成員函式layer_tree_host獲得。內部的CompositorThreadOnly物件可以通過呼叫成員函式impl