Graphics Layer Tree创建

站在老罗的肩膀上:https://blog.csdn.net/luoshengyang/article/details/50661553

Graphics Layer形成一个Graphics Layer Tree。Graphics Layer可看作是一个图形缓冲区,被若干Render Layer共用。本文接下来就分析Graphics Layer Tree的创建过程。

网页的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的这个特性,使得它可以成为一个观念上的原子类型绘制层(Atomic Conceptual Layer for Painting)。也就是说,只要我们定义好Stacking Context内部元素的绘制顺序,那么再根据拥有Stacking Context的元素的z-index属性值,那么就可以得到网页的所有元素的绘制顺序。

       我们可以通过图2所示的例子直观地理解Stacking Context的上述特性,如下所示:

  

图2 Stacking Context

 从图1可以看到,Graphics Layer Tree是根据Paint Layer Tree创建的。也就是说,Paint Layer与Graphics Layer存在对应关系,如下所示:

图3 Paint Layer Tree与Graphics Layer的关系

       原则上,Paint Layer Tree中的每一个Paint 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的特征。例如,如果一个Paint Layer关联的LayoutObject设置了3D Transform属性,那么就需要为该Paint Layer创建一个Composited Layer Mapping。

       Blink一共定义了54个Compositing Reason,如下所示:

#define FOR_EACH_COMPOSITING_REASON(V)                                        \
  /* Intrinsic reasons that can be known right away by the layer. */          \
  V(3DTransform)                                                              \
  ...                                                                         \
  V(InlineTransform)

// generate shift bits via enum
 enum {
#define V(name) kE##name,
    FOR_EACH_COMPOSITING_REASON(V)
#undef V
};

// shift for each compositing reason
#define V(name) k##name = UINT64_C(1) << kE##name,
    FOR_EACH_COMPOSITING_REASON(V)
#undef V

// need to squash
kComboSquashableReasons =
        kOverlap | kAssumedOverlap | kOverflowScrollingParent,

如果启用了Overlap Testing,那么Blink会根据上述的Stacking Context顺序计算每一个Paint Layer的后面是否有其它的Paint Layer与其重叠。如果有,并且与其重叠的Paint Layer有一个对应的Composited Layer Mapping,那么就会将位于上面的Paint Layer的Compositing Reason设置为kOverlap。

       如果没有启用Overlap Testing,那么WebKit会根据上述的Stacking Context顺序检查每一个Render Layer的后面是否有一个具有Composited Layer Mapping的Paint Layer。只要有,不管它们是否重叠,那么就会将位于上面的Paint Layer的Compositing Reason设置为kAssumedOverlap。

       最后,如果一个Paint Layer包含在一个具有overflow属性为"scroll"的Render Block中,并且该Layout Block所对应的Paint Layer具有Composited Layer Mapping,那么该Paint Layer的Compositing Reason就会被设置为kOverflowScrollingParent。

       Blink会将位于一个具有Composited Layer Mapping的Render Layer的上面的那些有着Squashable Reason的Paint 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中?考虑具有kOverlap和kAssumedOverlap的Render Layer,当它们需要重绘,或者它们下面的具有Composited Layer Mapping的Render Layer重绘时,都不可避免地对它们以及它们下面的具有Composited Layer Mapping的Paint Layer进行Compositing。这是由于它们相互之间存在重叠区域,只要其中一个发生变化,就会牵一发而动全身。类似地,当一个overflow属性为"scroll"的Layout Block滚动时,包含在该Layout Block内的Paint Layer在执行完成重绘操作之后,需要参与到Compositing操作去。

       Blink定义了两个函数,用来判断一个Paint 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 & ~CompositingReason::kComboSquashableReasons;
}

// 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 & CompositingReason::kComboSquashableReasons);
}

参数reasons描述的是一个Paint Layer的Compositing Reason,函数requiresCompositing判断该Paint Layer是否需要Compositing,也就是是否要为该Render Layer创建一个Composited Layer Mapping,而函数RequiresSquashing判断该Paint Layer需要Squashing,也就是绘制在一个Squashing Graphics Layer中。

      除了Compositing Paint Layer和Squashing Paint Layer,剩下的其它Paint Layer称为Non-Compositing Render Layer。这些Render Layer将会与离其最近的具有Composited Layer Mapping的父Paint Layer绘制同样的Graphics Layer中

      Blink是根据Graphics Layer Tree来绘制网页内容的。在绘制一个Graphics Layer的时候,除了绘制Graphics Layer本身所有的内容之外,还会在Paint Layer Tree中。找到与该Graphics Layer对应的Paint Layer,并且从该Paint Layer开始,将那些Non-Compositing类型的子Paint Layer也一起绘制,直到遇到一个具有Composited Layer Mapping的子Paint 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 Paint Layer,那么上述Graphics Layer Sub Tree还包含有一个Squashing Graphics Layer。不过这一部分Graphics Layer Sub Tree已经足于让我们理解Composited Layer Mapping的组成。

       在图5中,只有Main Layer是必须存在的,它用来绘制一个Paint 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规则排序的子Paint Layer对应的Composited Layer Mapping描述的Graphics Layer Sub Tree,它们均以父Paint Layer的Scrolling Container为父Graphics Layer。

      5. 如果一个Paint Layer是根Paint Layer,并且它的背景被设置为固定的,即网页的body标签的CSS属性background-attachment被设置为“fixed”,那么就会存在Background Layer。

       6. 当Negative z-order children存在时,就会存在Foreground Layer。从前面描述的Stacking Context规则可以知道,Negative z-order children对应的Graphics Layer Sub Tree先于当前Graphics Layer Sub Tree绘制。Negative z-order children对应的Graphics Layer Sub Tree在绘制的时候可能会设置了偏移位置。这些偏移位置不能影响后面的Normal flow children和Positive z-order children对应的Graphics Layer Sub Tree的绘制,因此就需要在中间插入一个Foreground Layer,用来抵消Negative z-order children对应的Graphics Layer Sub Tree设置的偏移位置。

       7. 如果一个Paint Layer的上面存在Squashing Paint Layer,那么就会存在Squashing Layer。

       了解了Composited Layer Mapping对应的Graphics Layer Sub Tree的结构之后,接下来我们就可以结合源码分析网页的Graphics Layer Tree的创建过程了。网页的Graphics Layer Tree的创建主要是分三步进行:

       1. 计算各个Paint Layer Tree中的Paint Layer的Compositing Reason;

       2. 为有需要的Paint Layer创建Composited Layer Mapping;

       3. 将各个Composited Layer Mapping描述Graphics Layer Sub Tree连接起来形成Graphics Layer Tree。

Graphic Layer通过GraphicLayerTreeBuilder::Rebuild创建,调用栈如下


  1. 创建Composited Layer Mapping   

  2. 创建Graphics Layer Sub Tree   

  3. 连接Graphics Layer Sub Tree​​​​​​


在Blink中,每一个正在加载的网页都关联有一个LocalFrameView对象,其关联自WebView,其关联自RenderView。从LocalFrameView::RunCompositingLifecyclePhase出发

bool LocalFrameView::RunCompositingLifecyclePhase(
    DocumentLifecycle::LifecycleState target_state) {
  ...
    if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
    ...
    layout_view->Compositor()->UpdateIfNeededRecursive(target_state);
  ...
}

*layout_view为一个LayoutView对象(间接继承自LayoutObject), 其含有类型为PaintLayerCompositor成员compositor_,调用UpdateIfNeededRecursive,

void PaintLayerCompositor::UpdateIfNeededRecursive(
    DocumentLifecycle::LifecycleState target_state) {
  CompositingReasonsStats compositing_reasons_stats;
  UpdateIfNeededRecursiveInternal(target_state, compositing_reasons_stats);
  ...  
}


void PaintLayerCompositor::UpdateIfNeededRecursiveInternal(
    DocumentLifecycle::LifecycleState target_state,
    CompositingReasonsStats& compositing_reasons_stats) {
  ...
  UpdateIfNeeded(target_state, compositing_reasons_stats);
  ...
}

最终调用PaintLayerCompositor::UpdateIfNeeded,实现如下

void PaintLayerCompositor::UpdateIfNeeded(
    DocumentLifecycle::LifecycleState target_state,
    CompositingReasonsStats& compositing_reasons_stats) {
  ...
  CompositingUpdateType update_type = pending_update_type_;
  pending_update_type_ = kCompositingUpdateNone;

  if (!HasAcceleratedCompositing()) {
    UpdateWithoutAcceleratedCompositing(update_type);
    Lifecycle().AdvanceTo(
        std::min(DocumentLifecycle::kCompositingClean, target_state));
    return;
  }

  if (update_type == kCompositingUpdateNone) {
    Lifecycle().AdvanceTo(
        std::min(DocumentLifecycle::kCompositingClean, target_state));
    return;
  }

  PaintLayer* update_root = RootLayer();
  Vector<PaintLayer*> layers_needing_paint_invalidation;

  if (update_type >= kCompositingUpdateAfterCompositingInputChange) {
    CompositingInputsUpdater(update_root, compositing_reason_finder_).Update();
    ...
    CompositingRequirementsUpdater(layout_view_, compositing_reason_finder_)
        .Update(update_root, compositing_reasons_stats);

    CompositingLayerAssigner layer_assigner(this);
    layer_assigner.Assign(update_root, layers_needing_paint_invalidation);

    ...

    if (layer_assigner.LayersChanged()) {
      update_type = std::max(update_type, kCompositingUpdateRebuildTree);
      ...
    }
    
  if (updater.NeedsRebuildTree())
    update_type = std::max(update_type, kCompositingUpdateRebuildTree);

  ...

  if (update_type >= kCompositingUpdateRebuildTree) {
    GraphicsLayerVector child_list;
    {
      TRACE_EVENT0("blink", "GraphicsLayerTreeBuilder::rebuild");
      GraphicsLayerTreeBuilder().Rebuild(*update_root, child_list);
    }

    if (!child_list.IsEmpty()) {
      CHECK(compositing_);
      if (GraphicsLayer* content_parent =
              ParentForContentLayers(current_parent)) {
        content_parent->SetChildren(child_list);
      }
    }
    ...
  }
...
}

首先需要创建Composited Layer Mapping


                                       创建Composited Layer Mapping   


      首先要对网页的Graphics Layer Tree需要进行更新,要求浏览器开启硬件加速合成。当调用PaintLayerCompositor类的成员函数HasAcceleratedCompositing得到的返回值等于true的时候,就表明浏览器开启了硬件加速合成。当PaintLayerCompositor类的成员变量pending_update_type_的值不等于CompositingUpdateNone的时候,就表明网页的Graphics Layer Tree需要进行更新。

 当pending_update_type_的值大于等于CompositingUpdateAfterCompositingInputChange的时候,表示Graphics Layer Tree的输入发生了变化,例如,Paint Layer Tree中的某一个Render Layer的内容发生了变化。在这种情况下,PaintLayerCompositor类的成员函数UpdateIfNeeded会构造一个CompositingInputsUpdater对象,并且调用成员函数Update从网页的Paint Layer Tree的根节点开始,递归计算每一个Paint Layer的Compositing Reason,主要就是根据各个Paint Layer包含的Layout Object的CSS属性来计算。

      计算好网页的Paint Layer Tree中的每一个Paint Layer的Compositing Reason之后,PaintLayerCompositor类的成员函数UpdateIfNeeded接着再构造一个CompositingLayerAssigner对象layer_assigner,并且调用它的成员函数Assign根据每一个Render Layer新的Compositing Reason决定是否需要为它创建一个新的Composited Layer Mapping或者删除它原来拥有的Composited Layer Mapping。如果有的Paint Layer原来是没有Composited Layer Mapping的,现在有了Composited Layer Mapping,或者原来有Composited Layer Mapping,现在没有了Composited Layer Mapping,那么本地变量layers_changed_的值就会被设置为true。这时候本地变量update_type的值会被更新为CompositingUpdateRebuildTree。

     在本地变量update_type的值不等于CompositingUpdateNone的情况下,PaintLayerCompositor类的成员函数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。这时候本地变量update_type的值也会被更新为CompositingUpdateRebuildTree。

       一旦本地变量updateType的值被更新为CompositingUpdateRebuildTree,或者它本来的值,也就是RenderLayerCompositor类的成员变量pending_update_type_的值,原本就等于CompositingUpdateRebuildTree,那么PaintLayerCompositor类的成员函数UpdateIfNeeded又会构造一个GraphicsLayerTreeBuilder对象,并且调用这个GraphicsLayerTreeBuilder对象的成员函数Rebuild从Paint Layer Tree的根节点开始,递归创建一个新的Graphics Layer Tree。

       注意,前面调用GraphicsLayerTreeBuilder类的成员函数Rebuild的时候,传递进去的第一个参数update_root是Paint Layer Tree的根节点,第二个参数child_list是一个输出参数,它里面保存的是Graphics Layer Tree的根节点的子节点。Graphics Layer Tree的根节点由PaintLayerCompositor类的成员函数RootGraphicsLayer指向的GraphicsLayer对象描述,因此当参数childList描述的Vector不为空时,它里面所保存的Graphics Layer都会被设置为PaintLayerCompositor类的成员函数RootGraphicsLayer指向的GraphicsLayer对象的子Graphics Layer。

       接下来我们主要分析CompositingLayerAssigner类的成员函数Assign、GraphicsLayerUpdater类的成员函数Update以及GraphicsLayerTreeBuilder类的成员函数Rebuild的实现,以及了解Graphics Layer Tree的创建过程。

       CompositingLayerAssigner类的成员函数Assign主要是为Paint Layer创建或者删除Composited Layer Mapping,它的实现如下所示:

void CompositingLayerAssigner::Assign(
    PaintLayer* update_root,
    Vector<PaintLayer*>& layers_needing_paint_invalidation) {
  ...
  SquashingState squashing_state;
  AssignLayersToBackingsInternal(update_root, squashing_state,
                                 layers_needing_paint_invalidation);
  ...
}
void CompositingLayerAssigner::AssignLayersToBackingsInternal(
    PaintLayer* layer,
    SquashingState& squashing_state,
    Vector<PaintLayer*>& layers_needing_paint_invalidation) {
    ...
    CompositingStateTransitionType composited_layer_update =
        ComputeCompositedLayerUpdate(layer);

    if (compositor_->AllocateOrClearCompositedLayerMapping(
            layer, composited_layer_update)) {
      ...
      layers_needing_paint_invalidation.push_back(layer);
      layers_changed_ = true;
      ...
    }

    ...
    // Add this layer to a squashing backing if needed.
    UpdateSquashingAssignment(layer, squashing_state, composited_layer_update,
                              layers_needing_paint_invalidation);
    const bool layer_is_squashed =
        composited_layer_update == kPutInSquashingLayer ||
        (composited_layer_update == kNoCompositingStateChange &&
         layer->GroupedMapping());
    if (layer_is_squashed) {
      squashing_state.next_squashed_layer_index++;
      IntRect layer_bounds = layer->ClippedAbsoluteBoundingBox();
      squashing_state.total_area_of_squashed_rects +=
          layer_bounds.Size().Area();
      squashing_state.bounding_rect.Unite(layer_bounds);
    }
  }

  if (layer->StackingDescendantNeedsCompositingLayerAssignment() &&
      layer->GetLayoutObject().StyleRef().IsStackingContext()) {
    PaintLayerStackingNodeIterator iterator(*layer->StackingNode(),
                                            kNegativeZOrderChildren);
    while (PaintLayer* child_node = iterator.Next()) {
      AssignLayersToBackingsInternal(child_node, squashing_state,
                                     layers_needing_paint_invalidation);
    }
  }

  // At this point, if the layer is to be separately composited, then its
  // backing becomes the most recent in paint-order.
  if (layer->NeedsCompositingLayerAssignment() &&
      layer->GetCompositingState() == kPaintsIntoOwnBacking) {
    DCHECK(!RequiresSquashing(layer->GetCompositingReasons()));
    squashing_state.UpdateSquashingStateForNewMapping(
        layer->GetCompositedLayerMapping(), layer->HasCompositedLayerMapping(),
        layers_needing_paint_invalidation);
  }

  if (layer->StackingNode() &&
      layer->StackingDescendantNeedsCompositingLayerAssignment()) {
    PaintLayerStackingNodeIterator iterator(
        *layer->StackingNode(), kNormalFlowChildren | kPositiveZOrderChildren);
    while (PaintLayer* curr_layer = iterator.Next()) {
      AssignLayersToBackingsInternal(curr_layer, squashing_state,
                                     layers_needing_paint_invalidation);
    }
  }
  ...
}

CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal首先调用成员函数ComputeCompositedLayerUpdate计算参数layer描述的Paint Layer的Compositing State Transition,如下所示:

CompositingStateTransitionType
CompositingLayerAssigner::ComputeCompositedLayerUpdate(PaintLayer* layer) {
  CompositingStateTransitionType update = kNoCompositingStateChange;
  if (NeedsOwnBacking(layer)) {
    if (!layer->HasCompositedLayerMapping()) {
      update = kAllocateOwnCompositedLayerMapping;
    }
  } else {
    if (layer->HasCompositedLayerMapping())
      update = kRemoveOwnCompositedLayerMapping;

    if (!layer->SubtreeIsInvisible() && compositor_->CanBeComposited(layer) &&
        RequiresSquashing(layer->GetCompositingReasons())) {
      // We can't compute at this time whether the squashing layer update is a
      // no-op, since that requires walking the paint layer tree.
      update = kPutInSquashingLayer;
    } else if (layer->GroupedMapping() || layer->LostGroupedMapping()) {
      update = kRemoveFromSquashingLayer;
    }
  }
  return update;
}

一个Paint 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,表示要将它绘制离其最近的一个Paint Layer的Composited Layer Mapping里面的一个Squashing Layer上。

       4. 它不需要Squashing,这时候Compositing State Transition设置为RemoveFromSquashingLayer,表示要将它从原来对应的Squashing Layer上删除。

       注意,后面2种Compositing State Transition,只有在CompositingLayerAssigner类的成员变量m_layerSquashingEnabled的值在等于true的时候才会进行设置。默认情况下,浏览器是开启Layer Squashing机制的,不过可以通过设置“disable-layer-squashing”选项进行关闭,或者通过设置“enable-layer-squashing”选项显式开启。

       判断一个Paint Layer是否需要Compositing,是通过调用CompositingLayerAssigner类的成员函数NeedsOwnBacking进行的,它的实现如下所示:

bool CompositingLayerAssigner::NeedsOwnBacking(const PaintLayer* layer) const {
  if (!compositor_->CanBeComposited(layer))
    return false;

  return RequiresCompositing(layer->GetCompositingReasons()) ||
         (compositor_->StaleInCompositingMode() && layer->IsRootLayer());
}

一个Paint Layer可以Compositing,需要满足以下4个条件:

       1. 浏览器开启硬件加速合成。

       2. Paint Layer本身有Compositing绘制的需求。

       3. Paint Layer描述的网页内容是可见的,也就是调用它的成员函数subtreeIsInvisible得到的返回值等于false。

       4. Paint Layer的内容不是渲染在一个LayoutFlowThread中

        如果可以Compositing,进一步判断该Render Layer是否真的需要进行Compositing。

       如果参数layer描述的Paint Layer满足以下3个条件之一,那么CompositingLayerAssigner类的成员函数NeedsOwnBacking就会认为它需要进行Compositing:

       1. Paint Layer的Compositing Reason表示它需要Compositing,这是通过调用前面提到的函数RequiresCompositing判断的。

       2. Render Layer的Compositing Reason表示它需要Squashing,但是浏览器禁用了“Layer Squashing”机制。当浏览器禁用“Layer Squashing”机制时,CompositingLayerAssigner类的成员变量m_layerSquashingEnabled会等于false。调用前面提到的函数requiresSquashing可以判断一个Render Layer是否需要Squashing。

       3. Paint Layer是Paint Layer Tree的根节点,并且Paint Layer Compositor处于Compositing模式中。除非设置了Paint Layer Tree的根节点无条件Compositing,否则的话,当在Paint Layer Tree根节点的子树中,没有任何Paint Layer需要Compositing时, Paint Layer Tree根节点也不需要Compositing,这时候Paint Layer Compositor就会被设置为非Compositing模式。判断一个Paint Layer是否是Paint Layer Tree的根节点,调用它的成员函数IsRootLayer即可,而判断一个Paint Layer Compositor是否处于Compositing模式,调用它的成员函数StaleInCompositingMode即可。

    回到CompositingLayerAssigner类的成员函数computeCompositedLayerUpdate中,当它调用结束后,再返回到CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal中,这时候CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal就知道了参数layer描述的Render Layer的Compositing State Transition Type。

       之后,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal接下来调用成员变量m_compositor描述的一个RenderLayerCompositor对象的成员函数allocateOrClearCompositedLayerMapping为其创建或者删除Composited Layer Mapping,如下所示:

bool PaintLayerCompositor::AllocateOrClearCompositedLayerMapping(
    PaintLayer* layer,
    const CompositingStateTransitionType composited_layer_update) {
  bool composited_layer_mapping_changed = false;
  ...
  switch (composited_layer_update) {
    case kAllocateOwnCompositedLayerMapping:
      ...

      layer->EnsureCompositedLayerMapping();
      composited_layer_mapping_changed = true;
      ...
      break;
    case kRemoveOwnCompositedLayerMapping:
    // PutInSquashingLayer means you might have to remove the composited layer
    // mapping first.
    case kPutInSquashingLayer:
      if (layer->HasCompositedLayerMapping()) {
        layer->ClearCompositedLayerMapping();
        composited_layer_mapping_changed = true;
      }

      break;
    case kRemoveFromSquashingLayer:
    case kNoCompositingStateChange:
      // Do nothing.
      break;
  }

  if (!composited_layer_mapping_changed)
    return false;
  ...
  return true;
}

 CompositingLayerAssigner类的成员函数UpdateSquashingAssignment的实现如下所示:

void CompositingLayerAssigner::UpdateSquashingAssignment(
    PaintLayer* layer,
    SquashingState& squashing_state,
    const CompositingStateTransitionType composited_layer_update,
    Vector<PaintLayer*>& layers_needing_paint_invalidation) {
  ...
  if (composited_layer_update == kPutInSquashingLayer) {
    ...
    bool changed_squashing_layer =
        squashing_state.most_recent_mapping->UpdateSquashingLayerAssignment(
            layer, squashing_state.next_squashed_layer_index);
    if (!changed_squashing_layer)
      return;
    ...
  } else if (composited_layer_update == kRemoveFromSquashingLayer) {
    if (layer->GroupedMapping()) {
      ...
      layer->SetGroupedMapping(
          nullptr, PaintLayer::kInvalidateLayerAndRemoveFromMapping);
    }
    ...
  }
}

       CompositingLayerAssigner类的成员函数UpdateSquashingAssignment也是根据Paint Layer的Compositing State Transition Type决定是否要将它绘制在一个Squashing Graphics Layer中,或者将它从一个Squashing Graphics Layer中删除。

       对于Compositing State Transition Type等于PutInSquashingLayer的Paint Layer,它将会绘制在一个Squashing Graphics Layer中。这个Squashing Graphics Layer保存在一个Composited Layer Mapping中。这个Composited Layer Mapping关联的Paint Layer处于要Squashing的Paint Layer的下面,并且前者离后者是最近的,记录在参数squashing_state描述的一个SquashingState对象的成员变量most_recent_mapping中。通过调用CompositedLayerMapping类的成员函数updateSquashingLayerAssignment可以将一个Paint Layer绘制在一个Composited Layer Mapping内部维护的一个Squashing Graphics Layer中。

       对于Compositing State Transition Type等于RemoveFromSquashingLayer的Paint Layer,如果它之前已经被设置绘制在一个Squashing Graphics Layer中,那么就需要将它从这个Squashing Graphics Layer中删除。如果一个Render Layer之前被设置绘制在一个Squashing Graphics Layer中,那么调用它的成员函数GroupedMapping就可以获得一个Grouped Mapping, 即CompositedLayerMapping指针,维护Paint Layer所绘制在的Squashing Graphics Layer。因此,要将一个Render Layer从一个Squashing Graphics Layer中删除,只要将它的Grouped Mapping指针设置为NULL即可。这是通过调用RenderLayer类的成员函数SetGroupedMapping实现的。

       再回到CompositingLayerAssigner::AssignLayersToBackingsInternal中,它接下来判断参数layer描述的Render Layer所关联的Render Object是否是一个Stacking Context。如果是的话,那么就递归调用AssignLayersToBackingsInternal遍历那些z-index为负数的子Render Object对应的Render Layer,确定是否需要为它们创建Composited Layer Mapping。

       到目前为止,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal就处理完成参数layer描述的Paint Layer,以及那些z-index为负数的子Paint Layer。这时候,参数layer描述的Paint Layer可能会作为那些z-index大于等于0的子Paint Layer的Grouped Mapping,因此在继续递归处理z-index大于等于0的子Paint Layer之前,CompositingLayerAssigner类需要将参数layer描述的Paint Layer对应的Composited Layer Mapping记录下来,前提是这个Paint Layer拥有Composited Layer Mapping。这是通过调用squashing_state.UpdateSquashingStateForNewMapping实现的,实际上就是记录在该SquashingState对象的成员变量most_recent_mapping中。这样就可以知道将其参数layer描述的Paint Layer绘制在哪一个Squashing Graphics Layer中。(所以这一步确定了一个squashing group的大小,只要有一个Paint Layer有Composited Layer Mapping, 其子Paint Layer 如果有需要,都会sqush到这个Paint Layer, 直到出现一个新的layer创建了Composited Layer Mapping,之后情况如前)

       最后,CompositingLayerAssigner类的成员函数assignLayersToBackingsInternal就递归调用自己处理那些z-index大于等于0的子Paint Layer。递归调用完成之后,整个Paint Layer Tree就处理完毕了。这时候哪些Paint Layer具有Composited Layer Mapping就可以确定了。

       前面分析PaintLayerCompositor类的成员函数AllocateOrClearCompositedLayerMapping时提到,调用PaintLayer类的成员函数EnsureCompositedLayerMapping可以为一个Paint Layer创建一个Composited Layer Mapping,接下来我们就继续分析这个函数的实现,以便了解Composited Layer Mapping的创建过程。如下:

void PaintLayer::EnsureCompositedLayerMapping() {
  if (rare_data_ && rare_data_->composited_layer_mapping)
    return;
  // std::make_unique will call the construct function
  EnsureRareData().composited_layer_mapping =
      std::make_unique<CompositedLayerMapping>(*this);
  rare_data_->composited_layer_mapping->SetNeedsGraphicsLayerUpdate(
      kGraphicsLayerUpdateSubtree);

  if (PaintLayerResourceInfo* resource_info = ResourceInfo())
    resource_info->InvalidateFilterChain();
}


CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
    : owning_layer_(layer),
      ...
      background_paints_onto_graphics_layer_(false),
      draws_background_onto_content_layer_(false) {
  ...
  // ensure there must be Main Layer
  CreatePrimaryGraphicsLayer();
  ..
}

Composited Layer Mapping中的其它Graphics Layer也是通过调用成员函数CreateGraphicsLayer创建的。

void CompositedLayerMapping::CreatePrimaryGraphicsLayer() {
  graphics_layer_ =
      CreateGraphicsLayer(owning_layer_.GetCompositingReasons(),
                          owning_layer_.GetSquashingDisallowedReasons());
  ...
}


std::unique_ptr<GraphicsLayer> CompositedLayerMapping::CreateGraphicsLayer(
    CompositingReasons reasons,
    SquashingDisallowedReasons squashing_disallowed_reasons) {
  std::unique_ptr<GraphicsLayer> graphics_layer = GraphicsLayer::Create(*this);
...
}


std::unique_ptr<GraphicsLayer> GraphicsLayer::Create(
    GraphicsLayerClient& client) {
  return base::WrapUnique(new GraphicsLayer(client));
}


// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
// Note that std::unique_ptr<T> has very different semantics from
// std::unique_ptr<T[]>: do not use this helper for array allocations.
template <typename T>
std::unique_ptr<T> WrapUnique(T* ptr) {
  return std::unique_ptr<T>(ptr);
}

这一步执行完成后,一个Composited Layer Mapping及其内部的Main Graphics Layer就创建完成了。

前面分析CompositingLayerAssigner类的成员函数UpdateSquashingAssignment时提到,调用CompositedLayerMapping类的成员函数UpdateSquashingLayerAssignment可以将一个Paint Layer绘制在其内部维护的一个Squashing Graphics Layer中。CompositedLayerMapping类的成员函数updateSquashingLayerAssignment的实现如下所示:

bool CompositedLayerMapping::UpdateSquashingLayerAssignment(
    PaintLayer* squashed_layer,
    size_t next_squashed_layer_index) {
  GraphicsLayerPaintInfo paint_info;
  paint_info.paint_layer = squashed_layer;
   
  if (next_squashed_layer_index < squashed_layers_.size()) {
    if (paint_info.paint_layer ==
        squashed_layers_[next_squashed_layer_index].paint_layer)
      return false;

    ...
    InvalidateLayerIfNoPrecedingEntry(next_squashed_layer_index);

    squashed_layers_.insert(next_squashed_layer_index, paint_info);
  } else {
    ...
    squashed_layers_.push_back(paint_info);
  }
  squashed_layer->SetGroupedMapping(
      this, PaintLayer::kInvalidateLayerAndRemoveFromMapping);

  return true;
}

这样创建Composited Layer Mapping完成,接下来调用GraphicsLayerUpdater类的成员函数Update为Composited Layer Mapping创建Graphics Layer Sub Tree。 


                                            创建Graphics Layer Sub Tree   


Graphics Layer Sub Tree 结构:

  // The hierarchy of layers that is maintained by the CompositedLayerMapping
  // looks like this:
  //
  //  + ancestor_clipping_layer_ [OPTIONAL]
  //    + graphics_layer_
  //      + child_transform_layer_ [OPTIONAL]
  //      | + child_containment_layer_ [OPTIONAL]
  //      |   <-OR->
  //      |   (scrolling_layer_ + scrolling_contents_layer_) [OPTIONAL]
  //      + overflow_controls_ancestor_clipping_layer_ [OPTIONAL]
  //      | + overflow_controls_host_layer_ [OPTIONAL]
  //      |   + layer_for_vertical_scrollbar_ [OPTIONAL]
  //      |   + layer_for_vertical_scrollbar_ [OPTIONAL]
  //      |   + layer_for_scroll_corner_ [OPTIONAL]
  //      + decoration_outline_layer_ [OPTIONAL]
  // The overflow controls may need to be repositioned in the graphics layer
  // tree by the RLC to ensure that they stack above scrolling content.
  //
  // We need an ancestor clipping layer if our clipping ancestor is not our
  // ancestor in the clipping tree. Here's what that might look like.
  //
  // Let A = the clipping ancestor,
  //     B = the clip descendant, and
  //     SC = the stacking context that is the ancestor of A and B in the
  //          stacking tree.
  //
  // SC
  //  + A = graphics_layer_
  //  |  + child_containment_layer_
  //  |     + ...
  //  ...
  //  |
  //  + B = ancestor_clipping_layer_ [+]
  //     + graphics_layer_
  //        + ...
  //
  // In this case B is clipped by another layer that doesn't happen to be its
  // ancestor: A.  So we create an ancestor clipping layer for B, [+], which
  // ensures that B is clipped as if it had been A's descendant.
  // In addition, the ancestor_clipping_layer_ will have an associated
  // mask layer if the ancestor, A, has a border radius that requires a
  // rounded corner clip rect. The mask is not part of the layer tree; rather
  // it is attached to the ancestor_clipping_layer_ itself.
  //
  //
  //
  // 
  // If ancestor_clipping_layer_ is present:
  //
  // ancestor_clipping_layer_
  //   + graphics_layer_
  //   + squashing_layer_
  //
  // If not:
  //
  // squashing_containment_layer_
  //   + graphics_layer_
  //   + squashing_layer_
  //
  // Stacking children of a squashed layer receive graphics layers that are
  // parented to the compositd ancestor of the squashed layer (i.e. nearest
  // enclosing composited layer that is not
  // squashed).

GraphicsLayerUpdater::Updated调用GraphicsLayerUpdater::UpdateRecursive,实现如下所示:

void GraphicsLayerUpdater::Update(
    PaintLayer& layer,
    Vector<PaintLayer*>& layers_needing_paint_invalidation) {
  TRACE_EVENT0("blink", "GraphicsLayerUpdater::update");
  UpdateRecursive(layer, kDoNotForceUpdate, UpdateContext(),
                  layers_needing_paint_invalidation);
}
void GraphicsLayerUpdater::UpdateRecursive(
    PaintLayer& layer,
    UpdateType update_type,
    const UpdateContext& context,
    Vector<PaintLayer*>& layers_needing_paint_invalidation) {
  if (layer.HasCompositedLayerMapping()) {
    CompositedLayerMapping* mapping = layer.GetCompositedLayerMapping();

    if (update_type == kForceUpdate || mapping->NeedsGraphicsLayerUpdate()) {
      ...
      if (mapping->UpdateGraphicsLayerConfiguration(compositing_container)) {
        needs_rebuild_tree_ = true;
        ...
      }
      ...
  }

  UpdateContext child_context(context, layer);
  for (PaintLayer* child = layer.FirstChild(); child;
       child = child->NextSibling()) {
    UpdateRecursive(*child, update_type, child_context,
                    layers_needing_paint_invalidation);
  }
}

从前面的调用过程可以知道,参数layer描述的Paint Layer是Paint 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(
    const PaintLayer* compositing_container) {
  ...
  bool layer_config_changed = false;

  if (UpdateForegroundLayer(
          compositor->NeedsContentsCompositingLayer(&owning_layer_)))
    layer_config_changed = true;
  ...
  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
    ...
    if (UpdateClippingLayers(needs_ancestor_clip, needs_ancestor_clipping_mask,
                             needs_descendants_clipping_layer))
      layer_config_changed = true;
  }

  if (UpdateScrollingLayers(owning_layer_.NeedsCompositedScrolling()))
    layer_config_changed = true;
  ...
  if (UpdateDecorationOutlineLayer(needs_decoration_outline_layer))
    layer_config_changed = true;

  if (UpdateOverflowControlsLayers(
          RequiresHorizontalScrollbarLayer(), RequiresVerticalScrollbarLayer(),
          RequiresScrollCornerLayer(), needs_ancestor_clip))
    layer_config_changed = true;

  bool has_perspective = style.HasPerspective();
  bool needs_child_transform_layer = has_perspective && layout_object.IsBox();
  if (UpdateChildTransformLayer(needs_child_transform_layer))
    layer_config_changed = true;

  if (UpdateSquashingLayers(!squashed_layers_.IsEmpty()))
    layer_config_changed = true;

  ...

  if (layer_config_changed)
    UpdateInternalHierarchy();

  ...

  return layer_config_changed;
}

CompositedLayerMapping类的成员函数UpdateGraphicsLayerConfiguration依次检查它内部维护的Background Layer、Foreground Layer、Clip Layer、Scrolling Layer、DecorateionOutLine Layer, OverflowControls 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 needs_squashing_layers) {
  bool layers_changed = false;

  if (needs_squashing_layers) {
    if (!squashing_layer_) {
      squashing_layer_ =
          CreateGraphicsLayer(CompositingReason::kLayerForSquashingContents);
      squashing_layer_->SetDrawsContent(true);
      layers_changed = true;
    }

    if (ancestor_clipping_layer_) {
      if (squashing_containment_layer_) {
        squashing_containment_layer_->RemoveFromParent();
        squashing_containment_layer_ = nullptr;
        layers_changed = true;
      }
    } else {
      if (!squashing_containment_layer_) {
        squashing_containment_layer_ =
            CreateGraphicsLayer(CompositingReason::kLayerForSquashingContainer);
        squashing_containment_layer_->SetShouldFlattenTransform(false);
        layers_changed = true;
      }
    }
  } else {
    if (squashing_layer_) {
      squashing_layer_->RemoveFromParent();
      squashing_layer_ = nullptr;
      layers_changed = true;
    }
    if (squashing_containment_layer_) {
      squashing_containment_layer_->RemoveFromParent();
      squashing_containment_layer_ = nullptr;
      layers_changed = true;
    }
  }

  return layers_changed;
}

从前面的调用过程可以知道,当CompositedLayerMapping类的成员变量squashed_layers_描述的Vector不等于空时,这里的参数needs_squashing_layer的值就会等于true,表示需要对CompositedLayerMapping类内部维护的Squashing Layer进行更新。更新过程如下所示:
      1. 如果Squashing Layer还没有创建,那么就会调用我们前面分析过的CompositedLayerMapping类的成员函数CreateGraphicsLayer进行创建,并且保存在成员变量squashing_layer_中。
         2. CompositedLayerMapping类的成员变量ancestor_clipping_layer描述的是图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类的成员变量squashed_layers描述的Vector等于空时,参数NeedsSquashingLayers的值就会等于false,表示CompositedLayerMapping类不需要在内部维护一个Squashing Layer。这时候如果存在Squashing Layer,那么就需要将它从Graphics Layer Sub Tree中移除。如果Squashing Containment Layer也存在,那么也要将它一起从Graphics Layer Sub Tree中移除。这是因为Squashing Containment Layer本来就是为Squashing Layer创建的,现在既然Squashing Layer不需要了,那么它自然也不再需要了。
       回到CompositedLayerMapping类的成员函数updateGraphicsLayerConfiguration中,接下来我们继续分析它调用另外一个成员函数UpdateInternalHierarchy更新内部维护的Graphics Layer Sub Tree的过程,如下所示:

void CompositedLayerMapping::UpdateInternalHierarchy() {
  // m_foregroundLayer has to be inserted in the correct order with child
  // layers, so it's not inserted here.
  if (ancestor_clipping_layer_)
    ancestor_clipping_layer_->RemoveAllChildren();

  graphics_layer_->RemoveFromParent();

  if (ancestor_clipping_layer_)
    ancestor_clipping_layer_->AddChild(graphics_layer_.get());

  // Layer to which children should be attached as we build the hierarchy.
  GraphicsLayer* bottom_layer = graphics_layer_.get();
  auto update_bottom_layer = [&bottom_layer](GraphicsLayer* layer) {
    if (layer) {
      bottom_layer->AddChild(layer);
      bottom_layer = layer;
    }
  };

  update_bottom_layer(child_transform_layer_.get());
  update_bottom_layer(child_containment_layer_.get());
  update_bottom_layer(scrolling_layer_.get());

  // Now constructing the subtree for the overflow controls.
  bottom_layer = graphics_layer_.get();
  // TODO(pdr): Ensure painting uses the correct GraphicsLayer when root layer
  // scrolls is enabled.  crbug.com/638719
  if (is_main_frame_layout_view_layer_ &&
      !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
    bottom_layer = GetLayoutObject()
                       .GetFrame()
                       ->GetPage()
                       ->GetVisualViewport()
                       .ContainerLayer();
  }
  update_bottom_layer(overflow_controls_ancestor_clipping_layer_.get());
  update_bottom_layer(overflow_controls_host_layer_.get());
  if (layer_for_horizontal_scrollbar_) {
    overflow_controls_host_layer_->AddChild(
        layer_for_horizontal_scrollbar_.get());
  }
  if (layer_for_vertical_scrollbar_) {
    overflow_controls_host_layer_->AddChild(
        layer_for_vertical_scrollbar_.get());
  }
  if (layer_for_scroll_corner_)
    overflow_controls_host_layer_->AddChild(layer_for_scroll_corner_.get());

  // Now add the DecorationOutlineLayer as a subtree to GraphicsLayer
  if (decoration_outline_layer_.get())
    graphics_layer_->AddChild(decoration_outline_layer_.get());

  // The squashing containment layer, if it exists, becomes a no-op parent.
  if (squashing_layer_) {
    DCHECK((ancestor_clipping_layer_ && !squashing_containment_layer_) ||
           (!ancestor_clipping_layer_ && squashing_containment_layer_));

    if (squashing_containment_layer_) {
      squashing_containment_layer_->RemoveAllChildren();
      squashing_containment_layer_->AddChild(graphics_layer_.get());
      squashing_containment_layer_->AddChild(squashing_layer_.get());
    } else {
      // The ancestor clipping layer is already set up and has m_graphicsLayer
      // under it.
      ancestor_clipping_layer_->AddChild(squashing_layer_.get());
    }
  }
}

从这里我们就可以看到,通过调用GraphicsLayer类的成员函数AddChild,就可以将一个Graphics Layer作为另外一个Graphics Layer的子Graphics Layer,这样就可以形成一个Graphics Layer Sub Tree。CompositedLayerMapping类的成员函数updateInternalHierarchy构建出来的Graphics Layer Sub Tree大致就如图5所示。
       CompositedLayerMapping类内部维护的Graphics Layer Sub Tree,除了前面描述的Clip Layer和Squashing Containment Layer不能并存之外,另外两个Layer,即Child Containment Layer和Child Tranform Layer,也是不能并存的。这些Graphics Layer的具体作用,以及什么在情况下会存在,可以通过阅读CompositedLayerMapping类的代码获悉,这里就不再展开描述。
     还有一点需要注意的是,CompositedLayerMapping类内部维护的Background Layer和Foreground Layer也是属于CompositedLayerMapping类描述的Graphics Layer Sub Tree的一部分,但是它们不是由CompositedLayerMapping类的成员函数UpdateInternalHierarchy插入到Graphics Layer Sub Tree中去的。等到将Graphics Layer Sub Tree连接在一起形成整个Graphics Layer Tree的时候,它们才会插入到各自的Graphics Layer Sub Tree中去,因为处理它们需要更多的信息。


                                       连接Graphics Layer Sub Tree


      由于各个Graphics Layer 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 (squashing_containment_layer_)
    return squashing_containment_layer_.get();

  if (ancestor_clipping_layer_)
    return ancestor_clipping_layer_.get();

  return graphics_layer_.get();
}

从这里可以看到,如果存在Squashing Containment Layer,那么它就会作为父Graphics Layer Sub Tree的子Graphics Layer。

另一方面,如果不存在Squashing Containment Layer,那么

如果存在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。
返回另外一个Graphics Layer作为父Graphics Layer Sub Tree的子Graphics Layer。

CompositedLayerMapping类的成员函数ParentForSublayers的实现如下所示:

GraphicsLayer* CompositedLayerMapping::ParentForSublayers() const {
  if (scrolling_contents_layer_)
    return scrolling_contents_layer_.get();

  if (child_containment_layer_)
    return child_containment_layer_.get();

  if (child_transform_layer_)
    return child_transform_layer_.get();

  return graphics_layer_.get();
}

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,其调用RebuildRecursive,实现如下所示: 

void GraphicsLayerTreeBuilder::RebuildRecursive(
    PaintLayer& layer,
    GraphicsLayerVector& child_layers,
    PendingOverflowControlReparents& pending_reparents) {
  ...
  const bool has_composited_layer_mapping = layer.HasCompositedLayerMapping();
  CompositedLayerMapping* current_composited_layer_mapping =
      layer.GetCompositedLayerMapping();

  ...
  GraphicsLayerVector this_layer_children;
  GraphicsLayerVector* layer_vector_for_children =
      has_composited_layer_mapping ? &this_layer_children : &child_layers;

  PendingOverflowControlReparents this_pending_reparents_children;
  PendingOverflowControlReparents* pending_reparents_for_children =
      has_composited_layer_mapping ? &this_pending_reparents_children
                                   : &pending_reparents;

  if (style.IsStackingContext()) {
    PaintLayerStackingNodeIterator iterator(*layer.StackingNode(),
                                            kNegativeZOrderChildren);
    while (PaintLayer* child_layer = iterator.Next()) {
      RebuildRecursive(*child_layer, *layer_vector_for_children,
                       *pending_reparents_for_children);
    }

    // If a negative z-order child is compositing, we get a foreground layer
    // which needs to get parented.
    if (has_composited_layer_mapping &&
        current_composited_layer_mapping->ForegroundLayer()) {
      layer_vector_for_children->push_back(
          current_composited_layer_mapping->ForegroundLayer());
    }
  }

  if (layer.StackingNode()) {
    PaintLayerStackingNodeIterator iterator(
        *layer.StackingNode(), kNormalFlowChildren | kPositiveZOrderChildren);
    while (PaintLayer* child_layer = iterator.Next()) {
      RebuildRecursive(*child_layer, *layer_vector_for_children,
                       *pending_reparents_for_children);
    }
  }

  if (has_composited_layer_mapping) {
    // part 4
    bool parented = false;
    if (layer.GetLayoutObject().IsLayoutEmbeddedContent()) {
      parented = PaintLayerCompositor::AttachFrameContentLayersToIframeLayer(
          ToLayoutEmbeddedContent(layer.GetLayoutObject()));
    }
    size_t offset = 0;
    Vector<PendingPair> pending;
    for (auto& item : *pending_reparents_for_children)
      pending.push_back(std::make_pair(item.key, item.value));
    pending_reparents_for_children->clear();

    std::sort(pending.begin(), pending.end(),
              [](const PendingPair& a, const PendingPair& b) {
                return a.second < b.second;
              });
    for (auto& item : pending) {
      this_layer_children.insert(item.second + offset,
                                 item.first->GetCompositedLayerMapping()
                                     ->DetachLayerForOverflowControls());
      offset++;
    }
    if (!parented)
      current_composited_layer_mapping->SetSublayers(this_layer_children);
    // part 5
    if (ShouldAppendLayer(layer)) {
      child_layers.push_back(
          current_composited_layer_mapping->ChildForSuperlayers());
    }
  }
  ...
}

从前面的调用过程可以知道,参数layer描述的是网页Paint Layer Tree的根节点,另外一个参数ChildLayersOfEnclosingLayer是一个输出参数,用来保存参数layer描述的Paint Layer的子Paint Layer的Child For Super Layers,也就是前面描述的一个Composited Layer Mapping中作为父Graphics Layer Sub Tree的子Graphics Layer。
       GraphicsLayerTreeBuilder根据Stacking Context顺序从Paint Layer Tree的根节点开始,不断地递归调用自己,不过只会处理那些具有Composited Layer Mapping的Paint Layer。对于那些不具有Composited Layer Mapping的Render Layer,仅仅是用作跳板找到具有Composited Layer Mapping的Paint Layer。这一点容易理解,因为只有具有Composited Layer Mapping的Render Layer才对应的Graphics Layer。
       GraphicsLayerTreeBuilder类的成员函数RebuildRecursive处理具有Composited Layer Mapping的Render Layer的过程如下所示:
       1. 收集z-index为负数的子Render Layer的Child For Super Layers,并且保存在本地变量layerChildren描述的一个Vector中。
       2. 如果正在处理的Render Layer具有z-index为负数的子Paint Layer,那么根据前面的分析可以知道,正在处理的Paint Layer的Composited Layer Mapping内部有一个Foreground Layer。这个Foreground Layer也会保存在本地变量child_layer描述的一个Vector中,并且是位于那些z-index为负数的子Paint Layer的Child For Super Layers之后。这就是为什么Foreground Layer不是由CompositedLayerMapping类的成员函数UpdateInternalHierarchy直接插入到Graphics Layer Sub Tree去的原因,因为CompositedLayerMapping类不知道一个Paint Layer有哪些z-index为负数的子Paint Layer。
       3. 收集z-index为0和正数的子Paint Layer的Child For Super Layers,并且保存在本地变量child_layer描述的一个Vector中。
       4. 经过前面三个收集操作,当前正在处理的Paint Layer的Foreground Layer,以及它所有的子Paint Layer的Child For Super Layers,就都保存在了本地变量child_layer描述的一个Vector中。这时候只要找到当前正在处理的Paint Layer的Parent For Sub Layers,再将前者作为后者的Children,就可以将具有父子关系的Graphics Layer Sub Tree连接起来。从前面的分析可以知道,当前正在处理的Paint Layer的Parent For Sub Layers,可以通过调用它的Composited Layer Mapping的成员函数ParentForSublayers获得。它的执行有一个前提条件,就是本地变量parented的值为false。这是什么意思呢?当一个Render Layer的宿主Render Object对应的HTML Element是一个frame/iframe或者embed标签时,该Render Object是从RenderPart类继承下来的,称为Render Part。Render Part可能会具有自己的Render Layer Compositor,这可以通过调用RenderLayerCompositor类的静态成员函数parentFrameContentLayers进行判断。如果一个Render Part具有自己的Render Layer Compositor,那么它的子Render Object就由这个Render Layer Compositor进行具体的绘制,绘制好之后再交给Render Part的父Render Object对应的Render Layer Compositor进行合成。因此,在这种情况下,Render Part的子Render Object所对应的Graphics Layer就不会插入在Render Part的父Render Object所对应的Graphics Layer Tree中。从另外一个角度理解就是,每一个Render Layer Compositor都有一个Graphics Layer Tree,而一个Graphics Layer不能同时位于两个Graphics Layer Tree中。
       5. 当前正在处理的Paint Layer的Child For Super Layers,要保存在参数ChildLayersOfEnclosingLayer描述的Vector中,以便作为其父Paint Layer的Parent For Sub Layers的Children。它的执行也有一个前提条件,就是当前正在处理的Render Layer对应的Graphcis Layer需要插入Graphics Layer Tree的时候才会执行,这可以通过调用函数ShouldAppendLayer进行判断,如下所示:

static bool ShouldAppendLayer(const PaintLayer& layer) {
  Node* node = layer.GetLayoutObject().GetNode();
  if (node && IsHTMLVideoElement(*node)) {
    HTMLVideoElement* element = ToHTMLVideoElement(node);
    if (element->IsFullscreen() && element->UsesOverlayFullscreenVideo())
      return false;
  }
  return true;
}

当一个Paint Layer的宿主Layout Object对应的HTML Element是一个audio或者video标签时,并且它们是全屏播放、以及浏览器允许全屏播放时,那么它对应的Graphcis Layer就不需要插入Graphics Layer Tree中去,因为毕竟就只有它是需要渲染的,其他的网页内容都是不可见的。
       至此网页的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。
 

猜你喜欢

转载自blog.csdn.net/tornmy/article/details/81453831