Paint Layer Tree 创建

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

 目前Render Layer已经更新为Paint Layer, 其最终通过PaintLayer::InsertOnlyThisLayerAfterStyleChange创建,其函数调用关系如下,通过之前创建Layout Object Tree的LayoutTreeBuilderForElement::CreateLayoutObject调入:

LayoutTreeBuilderForElement::CreateLayoutObject实现如下:

DISABLE_CFI_PERF
void LayoutTreeBuilderForElement::CreateLayoutObject() {
  ...
  LayoutObject* new_layout_object = node_->CreateLayoutObject(style);
  ...
  new_layout_object->SetStyle(
      &style);  // SetStyle() can depend on LayoutObject() already being set
  ...
}
                                                                                

其调用SetStyle设置LayoutObject的CSS属性:

DISABLE_CFI_PERF
void LayoutObject::SetStyle(scoped_refptr<ComputedStyle> style) {
  DCHECK(style);
  if (style_ == style)
    return;
  StyleDifference diff;
  ...
  diff = AdjustStyleDifference(diff);
  StyleWillChange(diff, *style);
  scoped_refptr<ComputedStyle> old_style = std::move(style_);
  SetStyleInternal(std::move(style));
  ...
  StyleDidChange(diff, old_style.get());
  ...
}

其中style_ type is ComputedStyle, describe the CSS attribute of this layout object. And it calculte the CSS difference between current and previous one, and calling SetStyleInternal to store new CSS into style_.  Then calling LayoutBlockFlow::StyleDidChange. LayoutBlockFlow类是间接地从LayoutObject类继承下来的,并且重写了成员函数StyleDidChange。因此,接下来RenderBlockFlow类的成员函数StyleDidChange就会被调用。在调用的过程中,就会检查是否需要创建一个Paint Layer。LayoutBlockFlow类的成员函数StyleDidChange的实现如下所示:

void LayoutBlock::StyleDidChange(StyleDifference diff,
                                 const ComputedStyle* old_style) {
  LayoutBox::StyleDidChange(diff, old_style);
  ...
}

void LayoutBlock::StyleDidChange(StyleDifference diff,
                                 const ComputedStyle* old_style) {
  LayoutBox::StyleDidChange(diff, old_style);
  ...
}

void LayoutBox::StyleDidChange(StyleDifference diff,
                               const ComputedStyle* old_style) {
  ...
  LayoutBoxModelObject::StyleDidChange(diff, old_style);
  ...
}

并且一步步回调基类的StyleDidChange,直到LayoutBoxModelObject::StyleDidChange:

DISABLE_CFI_PERF
void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
                                          const ComputedStyle* old_style) {
  ...
  PaintLayerType type = LayerTypeRequired();
  if (type != kNoPaintLayer) {
    if (!Layer()) {
      ...
      CreateLayerAfterStyleChange();
    }
  } else if (Layer() && Layer()->Parent()) {
    ...
    Layer()->RemoveOnlyThisLayerAfterStyleChange(old_style);
    ...
  }
  ...
  if (Layer()) {
    Layer()->StyleDidChange(diff, old_style);
    ...
  }
  ...
}

LayoutBoxModelObject::StyleDidChange首先调用成员函数layerTypeRequired判断是否需要为当前正在处理的LayoutObject创建一个Paint Layer。

PaintLayerType LayoutBox::LayerTypeRequired() const {
  // hasAutoZIndex only returns true if the element is positioned or a flex-item
  // since position:static elements that are not flex-items get their z-index
  // coerced to auto.
  if (IsPositioned() || CreatesGroup() || HasTransformRelatedProperty() ||
      HasHiddenBackface() || HasReflection() || Style()->SpecifiesColumns() ||
      Style()->IsStackingContext() ||
      Style()->ShouldCompositeForCurrentAnimations() ||
      IsEffectiveRootScroller())
    return kNormalPaintLayer;

  if (HasOverflowClip())
    return kOverflowClipPaintLayer;

  return kNoPaintLayer;
}

 一个Render Object的CSS属性如果具有以下10种情况之一,那么就需要为它创建一个Render Layer:

       1. IsPositioned:position属性值不等于默认值static;

       2. CreatesGroup:设置有透明度(transparent)、遮罩(mask)、滤镜(filter)或者混合模式(mix-blend-mode);

       3. HasTransformRelatedProperty:设置有2D或者3D转换(matrix、translate、scale、rotate、skew、perspective);

       4. HasHiddenBackface:隐藏背面(backface-visibility: hidden);

       5. HasReflection:设置有倒影(box-reflect);

       6. SpecifiesColumns:设置有列宽和列数(columns: column-width column-count);

       7. IsStackingContext:z-index属性值不等于默认值auto,即指定了z-index值;

       8. ShouldCompositeForCurrentAnimations:指定了不透明度(opacity)、变换(transform)或者滤镜(filter)动画;

       9. IsEffectiveRootScroller: src/third_party/blink/renderer/core/page/scrolling/README.md

       10. HasOverflowClip:剪切溢出内容(overflow:hidden)。

      其中,前9种情况创建的Paint Layer的类型为NormalLayer,第10种情况创建的Paint Layer的类型为OverflowClipLayer。这两种类型的Paint Layer在本质上并没有区别,将一个Paint Layer的类型设置为OverflowClipLayer只为Bookkeeping目的,即在需要的时候可以在Paint Layer Tree中找到一个类型为OverflowClipLayer的Paint Layer做相应的处理。

      如果需要创建,那么LayoutBoxModelObject类的成员函数LayerTypeRequired的返回值就不等于NoLayer。在这种情况下,LayerBoxModelObject类的成员函数就会调用成员函数Layer检查当前正在处理的LayoutObject是否已经关联有一个Paint Layer了。如果已经关联有,那么调用RenderLayerModelObject类的成员函数Layer的返回值就不等于NULL。这时候就不需要为当前正在处理的LayoutObject创建一个Paint Layer。如果还没有关联,那么调用CreateLayerAfterStyleChange()创建一个新的Paint Layer,如下:

void LayoutBoxModelObject::CreateLayerAfterStyleChange() {
  ...
  // create current Paint Layer
  GetMutableForPainting().FirstFragment().SetLayer(
      std::make_unique<PaintLayer>(*this));
  SetHasLayer(true);
  // insert into Paint Layer Tree
  Layer()->InsertOnlyThisLayerAfterStyleChange();
  SetNeedsPaintPropertyUpdate();
}

其调用GetMutableForPainting().FirstFragment().SetLayer(std::make_unique<PaintLayer>(*this))创建最终的Piant Layer,调用Layer()->InsertOnlyThisLayerAfterStyleChange()插入Paint Layer Tree。

void PaintLayer::InsertOnlyThisLayerAfterStyleChange() {
  if (!parent_ && GetLayoutObject().Parent()) {
    // We need to connect ourselves when our layoutObject() has a parent.
    // Find our enclosingLayer and add ourselves.
    PaintLayer* parent_layer = GetLayoutObject().Parent()->EnclosingLayer();
    DCHECK(parent_layer);
    PaintLayer* before_child = GetLayoutObject().Parent()->FindNextLayer(
        parent_layer, &GetLayoutObject());
    parent_layer->AddChild(this, before_child);
  }

  // Remove all descendant layers from the hierarchy and add them to the new
  // position.
  for (LayoutObject* curr = GetLayoutObject().SlowFirstChild(); curr;
       curr = curr->NextSibling())
    curr->MoveLayers(parent_, this);

  ...
}

前面提到,RenderLayer类的成员变量parent_等于NULL的时候,表示当前正在处理的Paint Layer还未插入到网页的Paint Layer Tree中,这时候才有可能需要将其插入到网页的Paint Layer Tree中去。这里说有可能,是因为还需要满足另外一个条件,就是当前正在处理的Paint Layer所关联的LayoutObject已经插入到网页的Layout Object Tree中,也就是该LayoutObject具有父节点。

       RenderLayer类的成员函数insertOnlyThisLayer按照以下三个步骤将一个Render Layer插入到网页的Render Layer Tree中去:

       1. 找到要插入的Paint Layer关联的LayoutObject的父节点所对应的Paint Layer。这里找到的Paint Layer就作为要插入的Paint Layer的父Paint Layer,调用EnclosingLayer

 RenderObject类的成员函数EnclosingLayer的实现如下所示,

PaintLayer* LayoutObject::EnclosingLayer() const {
  for (const LayoutObject* current = this; current;
       current = current->Parent()) {
    if (current->HasLayer())
      return ToLayoutBoxModelObject(current)->Layer();
  }
  // TODO(crbug.com/365897): we should get rid of detached layout subtrees, at
  // which point this code should not be reached.
  return nullptr;
}

       2. 找到要插入的Paint Layer在父Paint Layer的Child List中的位置before_child,调用FindNextLayer

PaintLayer* LayoutObject::FindNextLayer(PaintLayer* parent_layer,
                                        LayoutObject* start_point,
                                        bool check_parent) {
  ...
  // Step 1: If our layer is a child of the desired parent, then return our layer.
  PaintLayer* our_layer =
      HasLayer() ? ToLayoutBoxModelObject(this)->Layer() : nullptr;
  if (our_layer && our_layer->Parent() == parent_layer)
    return our_layer;

  // Step 2: If we don't have a layer, or our layer is the desired parent, then
  // descend into our siblings trying to find the next layer whose parent is the
  // desired parent.
  if (!our_layer || our_layer == parent_layer) {
    for (LayoutObject* curr = start_point ? start_point->NextSibling()
                                          : SlowFirstChild();
         curr; curr = curr->NextSibling()) {
      PaintLayer* next_layer =
          curr->FindNextLayer(parent_layer, nullptr, false);
      if (next_layer)
        return next_layer;
    }
  }

  // Step 3: If our layer is the desired parent layer, then we're finished. We
  // didn't find anything.
  if (parent_layer == our_layer)
    return nullptr;

  // Step 4: If |checkParent| is set, climb up to our parent and check its
  // siblings that follow us to see if we can locate a layer.
  if (check_parent && Parent())
    return Parent()->FindNextLayer(parent_layer, this, true);

  return nullptr;
}

       3. 将要插入的Paint Layer设置为父Paint Layer的Child,一个Render Layer的子Paint Layer以链表方式进行组织。Paint Layer类的成员函数AddChild将参数child描述的子Render Layer插入在参数before_child描述的子Paint Layer的前面。如果没有指定before_child,那么参数child描述的子Paint Layer就会插入在链表的最后。另一方面,如果指定的before_child就是保存在链表的第一个位置,那么参数child描述的子Paint Layer就会取代它保存在链表的第一个位置。调用AddChild 

void PaintLayer::AddChild(PaintLayer* child, PaintLayer* before_child) {
  PaintLayer* prev_sibling =
      before_child ? before_child->PreviousSibling() : LastChild();
  if (prev_sibling) {
    child->SetPreviousSibling(prev_sibling);
    prev_sibling->SetNextSibling(child);
    DCHECK(prev_sibling != child);
  } else {
    SetFirstChild(child);
  }

  if (before_child) {
    before_child->SetPreviousSibling(child);
    child->SetNextSibling(before_child);
    DCHECK(before_child != child);
  } else {
    SetLastChild(child);
  }

  child->parent_ = this;
  ...
}

       回到LayoutBoxModelObject::StyleDidChange,

如果前面LayoutBoxModelObject::LayerTypeRequired的返回值等于NoLayer,并且当前正在处理的LayoutObject关联有Paint Layer,以及这个Paint Layer位于Paint Layer Tree中有父节点,那么就需要将这个Paint Layer从Paint Layer Tree中删除(),这是通过调用RemoveOnlyThisLayerAfterStyleChange实现:  (之前创建的PaintLayer现在不需要了,所以CSS是动态可变的吗)

DISABLE_CFI_PERF
void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
                                          const ComputedStyle* old_style) {
  ...
  } else if (Layer() && Layer()->Parent()) {
    ...
    Layer()->RemoveOnlyThisLayerAfterStyleChange(old_style);
    ...
  }
  ...
  if (Layer()) {
    Layer()->StyleDidChange(diff, old_style);
    ...
  }
  ...
}

       最后,如果当前正在处理的LayoutObject关联的Paint Layerc存在(可能新创建的,或者本来就已经关联了),那么RenderLayerModelObject类的成员函数StyleDidChange还会通知这个Paint Layer,它所关联的LayoutObject的CSS属性发生了变化,这是通过调用RenderLayer类的成员函数styleChanged实现的。RenderLayer类的成员函数styleChanged在调用期间,会判断是否需要为当前正在处理的Render Layer创建一个Graphics Layer。创建出来的Graphics Layer就会形成图1所示的Graphics Layer Tree。在接下来一篇文章中,我们再详细分析Graphics Layer Tree的创建过程。

猜你喜欢

转载自blog.csdn.net/tornmy/article/details/81737603
今日推荐