Layer Tree 绘制

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

网页绘图表面创建完成之后,调度器就会请求绘制CC Layer Tree,这样网页在加载完成之后就能快速显示出来。通过CC Layer Tree可以依次找到Graphics Layer Tree、Paint Layer Tree和Layout Object Tree,就可以执行具体的绘制工作了。

crRendererMain线程实际上并没有对CC Layer Tree执行真正的绘制,它只是将每一个Layer的绘制命令收集起来。这些绘制命令在对网页分块进行光栅化时才会被执行,也就是PREPARE_TILES中执行。

       CC Layer Tree中的每一个Layer都是按照分块进行绘制的。每一个分块的绘制命令都收集在一个SkPicture中。这个SkPicture就类似于Android应用程序UI硬件加速渲染过程形成的Display List。Layer分块并不是简单的区域划分。简单的区域划分在网页缩放过程中会有问题。Layer划分成相互重叠的区域。重叠的区域多大才合适的呢?这与网页的最小缩放因子有关。假设网页最小可以缩小原来的1/16,那么重叠的区域就至少需要15个点。

       当调度器调用SchedulerStateMachine类的成员函数NextAction询问状态机下一步要执行的操作时,SchedulerStateMachine类的成员函数NextAction会调用另外一个成员函数ShouldSendBeginMainFrame。当SchedulerStateMachine类的成员函数ShouldSendBeginMainFrame返回值等于true的时候,状态机就会提示调度器接下来需要执行SEND_BEGIN_MAIN_FRAME操作,也就是对CC Layer Tree进行绘制。

SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
  ...
  if (ShouldSendBeginMainFrame())
    return Action::SEND_BEGIN_MAIN_FRAME;
  ...
}

 状态从BeginMainFrameState::IDLE转变成BeginMainFrameState::SENT

void SchedulerStateMachine::WillSendBeginMainFrame() {
  ...
  begin_main_frame_state_ = BeginMainFrameState::SENT;
  needs_begin_main_frame_ = false;
  did_send_begin_main_frame_for_current_frame_ = true;
  last_frame_number_begin_main_frame_sent_ = current_frame_number_;
}
void ProxyImpl::ScheduledActionSendBeginMainFrame(
    const viz::BeginFrameArgs& args) {
  ...
  std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
      new BeginMainFrameAndCommitState);
  ...
  MainThreadTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&ProxyMain::BeginMainFrame, proxy_main_weak_ptr_,
                     base::Passed(&begin_main_frame_state)));
  host_impl_->DidSendBeginMainFrame();
  devtools_instrumentation::DidRequestMainThreadFrame(layer_tree_host_id_);
}

向crRendererMain线程的消息队列发送一个Task,这个Task绑定的函数是ProxyMain::BeginMainFrame。因此,接下来会转入crRendererMain线程

void ProxyMain::BeginMainFrame(
    std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
  ...

  if (!layer_tree_host_->IsVisible()) {
    ...
    ImplThreadTaskRunner()->PostTask(
        FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl,
                                  base::Unretained(proxy_impl_.get()),
                                  CommitEarlyOutReason::ABORTED_NOT_VISIBLE,
                                  begin_main_frame_start_time,
                                  base::Passed(&empty_swap_promises)));
    return;
  }

  layer_tree_host_->ApplyScrollAndScale(
      begin_main_frame_state->scroll_info.get());

  layer_tree_host_->WillBeginMainFrame();

  layer_tree_host_->BeginMainFrame(begin_main_frame_state->begin_frame_args);

  layer_tree_host_->AnimateLayers(
      begin_main_frame_state->begin_frame_args.frame_time);

  if (begin_main_frame_state->evicted_ui_resources)
    layer_tree_host_->GetUIResourceManager()->RecreateUIResources();

  layer_tree_host_->RequestMainFrameUpdate(
      skip_paint_and_commit ? LayerTreeHost::VisualStateUpdate::kPrePaint
                            : LayerTreeHost::VisualStateUpdate::kAll);

  ...

  if (skip_paint_and_commit) {
    ...
    ImplThreadTaskRunner()->PostTask(
        FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl,
                                  base::Unretained(proxy_impl_.get()),
                                  CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT,
                                  begin_main_frame_start_time,
                                  base::Passed(&empty_swap_promises)));
    ...
    return;
  }

  // If UI resources were evicted on the impl thread, we need a commit.
  if (begin_main_frame_state->evicted_ui_resources)
    final_pipeline_stage_ = COMMIT_PIPELINE_STAGE;

  current_pipeline_stage_ = UPDATE_LAYERS_PIPELINE_STAGE;
  bool should_update_layers =
      final_pipeline_stage_ >= UPDATE_LAYERS_PIPELINE_STAGE;

  ...
  bool updated = should_update_layers && layer_tree_host_->UpdateLayers();

  // If updating the layers resulted in a content update, we need a commit.
  if (updated)
    final_pipeline_stage_ = COMMIT_PIPELINE_STAGE;

  layer_tree_host_->WillCommit();
  devtools_instrumentation::ScopedCommitTrace commit_task(
      layer_tree_host_->GetId());

  current_pipeline_stage_ = COMMIT_PIPELINE_STAGE;
  if (final_pipeline_stage_ < COMMIT_PIPELINE_STAGE) {
    ...
    ImplThreadTaskRunner()->PostTask(
        FROM_HERE, base::BindOnce(&ProxyImpl::BeginMainFrameAbortedOnImpl,
                                  base::Unretained(proxy_impl_.get()),
                                  CommitEarlyOutReason::FINISHED_NO_UPDATES,
                                  begin_main_frame_start_time,
                                  base::Passed(&swap_promises)));
    ...
    return;
  }
  ...
  {
    ...
    ImplThreadTaskRunner()->PostTask(
        FROM_HERE,
        base::BindOnce(&ProxyImpl::NotifyReadyToCommitOnImpl,
                       base::Unretained(proxy_impl_.get()), &completion,
                       layer_tree_host_, begin_main_frame_start_time,
                       hold_commit_for_activation));
    completion.Wait();
  }
  ...
}

BeginMainFrame主要是做三件事情:


       1. 计算CC Layer Tree的布局。这是通过调用LayerTreeHost类的成员函数BeginMainFrame实现的。


       2. 计算CC Layer Tree的动画。使用网址:https://www.jianshu.com/p/7da4895b3693进行动画渲染调试
当网页的DOM Tree中的某一个Element需要创建动画时,调用Animation::create为其创建一个动画,运行在CrBrowserMain进程,如下所示:

scoped_refptr<Animation> Animation::CreateImplInstance() const {
  return Animation::Create(id());
}

 更新网页的Graphics Layer Tree的时候,就会将DOM Tree中的动画注册到CC模块中去,接着又会调用DocumentAnimations::UpdateAnimations执行网页的DOM Tree中的动画。

扫描二维码关注公众号,回复: 3072803 查看本文章

void PaintLayerCompositor::UpdateIfNeededRecursiveInternal(
    DocumentLifecycle::LifecycleState target_state,
    CompositingReasonsStats& compositing_reasons_stats) {
  ...
  if (!layout_view_.GetDocument().Printing() ||
      RuntimeEnabledFeatures::PrintBrowserEnabled()) {
    ...
    if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled()) {
      base::Optional<CompositorElementIdSet> composited_element_ids;
      DocumentAnimations::UpdateAnimations(layout_view_.GetDocument(),
                                           DocumentLifecycle::kCompositingClean,
                                           composited_element_ids);
    }
    ...
}



void DocumentAnimations::UpdateAnimations(
    Document& document,
    DocumentLifecycle::LifecycleState required_lifecycle_state,
    base::Optional<CompositorElementIdSet>& composited_element_ids) {
  if (document.GetPendingAnimations().Update(composited_element_ids)) {
    DCHECK(document.View());
    document.View()->ScheduleAnimation();
  }
  ...
}

LocalFrameView::ScheduleAnimation调度执行这些动画 。PendingAnimations::Update将动画是注册到CC模块

bool PendingAnimations::Update(
    const base::Optional<CompositorElementIdSet>& composited_element_ids,
    bool start_on_compositor) {
  ...
  for (auto& animation : animations) {
    bool had_compositor_animation =
        animation->HasActiveAnimationsOnCompositor();
    // Animations with a start time do not participate in compositor start-time
    // grouping.
    if (animation->PreCommit(animation->startTime() ? 1 : compositor_group,
                             composited_element_ids, start_on_compositor)) {
      if (animation->HasActiveAnimationsOnCompositor() &&
          !had_compositor_animation) {
        started_synchronized_on_compositor = true;
      }

      if (animation->Playing() && !animation->startTime() &&
          animation->TimelineInternal() &&
          animation->TimelineInternal()->IsActive()) {
        waiting_for_start_time.push_back(animation.Get());
      }
    } else {
      deferred.push_back(animation);
    }
  }

  ...
}

 其中的Animation::PreCommit如下:

bool Animation::PreCommit(
    int compositor_group,
    const base::Optional<CompositorElementIdSet>& composited_element_ids,
    bool start_on_compositor) {
  ...
  if (should_start) {
    compositor_group_ = compositor_group;
    if (start_on_compositor) {
      ...
      if (failure_code.Ok()) {
        CreateCompositorAnimation();
        StartAnimationOnCompositor(composited_element_ids);
        compositor_state_ = std::make_unique<CompositorState>(*this);
      ...
  }

  return true;
}

最终调用CompositorAnimations::StartAnimationOnCompositor执行该动画。 

void CompositorAnimations::StartAnimationOnCompositor(
    const Element& element,
    ...,
    const EffectModel& effect,
    ...) {
  ...
  GetAnimationOnCompositor(timing, group, start_time, time_offset,
                           keyframe_effect, keyframe_models,
                           animation_playback_rate);
  for (auto& compositor_keyframe_model : keyframe_models) {
    int id = compositor_keyframe_model->Id();
    compositor_animation.AddKeyframeModel(std::move(compositor_keyframe_model));
    started_keyframe_model_ids.push_back(id);
  }
}

其中compositor_annimation类型为CompositorAnimation,具有类型为cc::SingleKeyframeEffectAnimation的成员变量animation_ 。

 参数element描述的是要执行动画的一个Element。这个Element对应的是网页的DOM Tree中的一个节点。通过调用CompositorAnimations类的成员函数toRenderBoxModelObject可以获得它在网页的Render Layer Tree中对应的节点,也就是一个RenderLayer对象。

       参数effect描述了上述Element要执行的动画,每一个动画会被重新封装成一个WebAnimation对象。这是通过调用CompositorAnimationsImpl类的静态成员函数CompositorAnimations::GetAnimationOnCompositor实现的,如下所示:

void CompositorAnimations::GetAnimationOnCompositor(
    const Timing& timing,
    ...,
    const KeyframeEffectModelBase& effect,
    Vector<std::unique_ptr<CompositorKeyframeModel>>& keyframe_models,
    double animation_playback_rate) {
  ...
  for (const auto& property : properties) {
    ...
    const PropertySpecificKeyframeVector& values =
        effect.GetPropertySpecificKeyframes(property);

    CompositorTargetProperty::Type target_property;
    std::unique_ptr<CompositorAnimationCurve> curve;
    switch (property.GetCSSProperty().PropertyID()) {
      ...
      case CSSPropertyTransform: {
        target_property = CompositorTargetProperty::TRANSFORM;
        std::unique_ptr<CompositorTransformAnimationCurve> transform_curve =
            CompositorTransformAnimationCurve::Create();
        AddKeyframesToCurve(*transform_curve, values);
        transform_curve->SetTimingFunction(*timing.timing_function);
        transform_curve->SetScaledDuration(scale);
        curve = std::move(transform_curve);
        break;
      }
      ...
    }
    std::unique_ptr<CompositorKeyframeModel> keyframe_model =
        CompositorKeyframeModel::Create(*curve, target_property, group, 0);

    ...
    keyframe_models.push_back(std::move(keyframe_model));
  }
}

每一个动画都封装成CompositorKeyframeModel,保存在compositor_animation中,接下来要把它们关联到Dom节点对应都Graphics Layer中,回到CompositorAnimations::StartAnimationOnCompositor,通过compositor_animation.AddKeyframeModel,最终将动画添加到keyframe_models_

void KeyframeEffect::AddKeyframeModel(
    std::unique_ptr<KeyframeModel> keyframe_model) {
  ...
  keyframe_models_.push_back(std::move(keyframe_model));
  ...
}

而这个对象keyframe_models_就是CCLayer计算Animation所使用到到对象,通过调用LayerTreeHost类的成员函数AnimateLayers实现的。

void LayerTreeHost::AnimateLayers(base::TimeTicks monotonic_time) {
  ...
  // slimming path and will do so in a follow up. (762717)
  if (IsUsingLayerLists())
    return;

  std::unique_ptr<MutatorEvents> events = mutator_host_->CreateEvents();

  if (mutator_host_->TickAnimations(monotonic_time,
                                    property_trees()->scroll_tree, true))
    mutator_host_->UpdateAnimationState(true, events.get());

  if (!events->IsEmpty())
    property_trees_.needs_rebuild = true;
}

mutator_host_负责管理动画,类型为AnimationHost. 

注册动画

void KeyframeEffect::Tick(base::TimeTicks monotonic_time) {
  DCHECK(has_bound_element_animations());
  if (!element_animations_->has_element_in_any_list())
    return;

  if (needs_to_start_keyframe_models_)
    StartKeyframeModels(monotonic_time);

  for (auto& keyframe_model : keyframe_models_) {
    TickKeyframeModel(monotonic_time, keyframe_model.get(),
                      element_animations_.get());
  }

  last_tick_time_ = monotonic_time;
  element_animations_->UpdateClientAnimationState();
}


void KeyframeEffect::TickKeyframeModel(base::TimeTicks monotonic_time,
                                       KeyframeModel* keyframe_model,
                                       AnimationTarget* target) {
  ...

  AnimationCurve* curve = keyframe_model->curve();
  base::TimeDelta trimmed =
      keyframe_model->TrimTimeToCurrentIteration(monotonic_time);

  switch (curve->Type()) {
    case AnimationCurve::TRANSFORM:
      target->NotifyClientTransformOperationsAnimated(
          curve->ToTransformAnimationCurve()->GetValue(trimmed),
          keyframe_model->target_property_id(), keyframe_model);
      break;
    ...
  }
}

由此Animation的绘制就从Dom关联到了CCLayer 。


       3. 绘制CC Layer Tree。

创建Layout Object Tree时有以下调用栈

从Document::UpdateStyleAndLayoutTree创建或更新Layout Object Tree,并在完成后通过LocalFrameView::UpdateLayout创建或更新Layout

void Document::UpdateStyleAndLayout() {
  ...
  UpdateStyleAndLayoutTree();
  ...

  if (frame_view && frame_view->NeedsLayout())
    frame_view->UpdateLayout();

  ...
}
void LocalFrameView::UpdateLayout() {
  // We should never layout a Document which is not in a LocalFrame.  
    ...
    // PreLayout is for what
    PerformPreLayoutTasks();
    ...
      bool in_subtree_layout = IsSubtreeLayout();
      ...
      PerformLayout(in_subtree_layout);
      ...
}
void LocalFrameView::PerformLayout(bool in_subtree_layout) {
  ...
  {
    ...
    if (in_subtree_layout) {
      // subtree
      ...
    } else {
      // whole tree
      if (HasOrthogonalWritingModeRoots())
        LayoutOrthogonalWritingModeRoots();
      GetLayoutView()->UpdateLayout();
    }
  }
  ...
}

经历如下调用栈,

其中主要的递归逻辑在

void LayoutBlockFlow::LayoutBlockChildren(bool relayout_children,
                                          SubtreeLayoutScope& layout_scope,
                                          LayoutUnit before_edge,
                                          LayoutUnit after_edge) {
  ...
  // first do all the Layout of children Layout Objects
  while (next) {
    LayoutBox* child = next;
    LayoutObject* next_sibling = child->NextSibling();
    CHECK(!next_sibling || next_sibling->IsBox());
    next = ToLayoutBox(next_sibling);
    ...

    // Lay out the child.
    LayoutBlockChild(*child, layout_info);
    layout_info.ClearIsAtFirstInFlowChild();
    last_normal_flow_child = child;
  }

  // Second do the layout for the current Layout Object
  // Now do the handling of the bottom of the block, adding in our bottom
  // border/padding and determining the correct collapsed bottom margin
  // information.
  HandleAfterSideOfBlock(last_normal_flow_child, before_edge, after_edge,
                         margin_info);
}

 这样得到了完整的Layout,然后可以开始绘制CCLayer,通过调用LayerTreeHost类的成员函数UpdateLayers实现的。

CC Layer Tree与Graphics Layer Tree中的节点是一一对应关系,并且Graphics Layer Tree的每一个Layer代表的都是一个图层。这个图层在硬件加速渲染条件下,就是一个FBO。但是到底要不要为Graphics Layer Tree中的Layer分配一个图层最终是由CC模块决定的。如果CC模块决定要为一个Graphics Layer分配一个图层,那么就会为它创建一个Render Surface。Render Surface才是真正表示一个图层。

       LayerTreeHostCommon类静态成员函数CalculateDrawProperties根据CC Layer Tree创建出来的Render Surface Tree虽然在结构上也是一个Tree,不过它的节点是以列表的形式储存的,也就是储存在本地变量render_surface_list_描述的一个RenderSurfaceList(std::vector<RenderSurfaceImpl*>)中。

(CrBrowserMain)

1.计算以参数root_layer指向的Layer对象为根节点的CC Layer Tree的每一个Layer的绘图属性。此外,LayerTreeHostCommon类静态成员函数CalculateDrawProperties还会根据上述CC Layer Tree创建一个Render Surface Tree。CC Layer Tree中的节点与Render Surface Tree中的节点是多对一的关系。也就是只有CC Layer Tree的某些节点在Render Surface Tree中才拥有Render Surface。

void CalculateDrawPropertiesInternal(
    LayerTreeHostCommon::CalcDrawPropsImplInputs* inputs,
    PropertyTreeOption property_tree_option) {
  inputs->render_surface_list->clear();

  const bool should_measure_property_tree_performance =
      property_tree_option == BUILD_PROPERTY_TREES;

  LayerImplList visible_layer_list;
  switch (property_tree_option) {
    case BUILD_PROPERTY_TREES: {
      if (should_measure_property_tree_performance) {
        TRACE_EVENT_BEGIN0(
            TRACE_DISABLED_BY_DEFAULT("cc.debug.cdp-perf"),
            "LayerTreeHostCommon::ComputeVisibleRectsWithPropertyTrees");
      }

      PropertyTreeBuilder::BuildPropertyTrees(
          inputs->root_layer, inputs->page_scale_layer,
          inputs->inner_viewport_scroll_layer,
          inputs->outer_viewport_scroll_layer,
          inputs->elastic_overscroll_application_layer,
          inputs->elastic_overscroll, inputs->page_scale_factor,
          inputs->device_scale_factor, gfx::Rect(inputs->device_viewport_size),
          inputs->device_transform, inputs->property_trees);
      draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
          inputs->root_layer, inputs->property_trees,
          inputs->can_adjust_raster_scales);

      inputs->property_trees->transform_tree
          .set_source_to_parent_updates_allowed(false);
      break;
    }
    ...
  }

  draw_property_utils::FindLayersThatNeedUpdates(
      inputs->root_layer->layer_tree_impl(), inputs->property_trees,
      &visible_layer_list);
  draw_property_utils::ComputeDrawPropertiesOfVisibleLayers(
      &visible_layer_list, inputs->property_trees);

  CalculateRenderSurfaceLayerList(
      inputs->root_layer->layer_tree_impl(), inputs->property_trees,
      inputs->render_surface_list, inputs->max_texture_size);

  ...
}

       有了上述RenderSurfaceLayerList(CrBrowserMain计算)之后,LayerTreeHost类的成员函数UpdateLayers再调用另外一个成员函数PaintLayerContents对保存在RenderSurfaceLayerList中的Render Surface进行绘制,实际上就是对CC Layer Tree进行绘制。

(CrRendererMain)

bool LayerTreeHost::UpdateLayers() {
  ...
  // LayerTreeHost::root_layer 获取cc layer的根节点。
  bool result = DoUpdateLayers(root_layer());
  ...

  return result;
}


bool LayerTreeHost::DoUpdateLayers(Layer* root_layer) {
  ...
  gfx::Transform identity_transform;
  LayerList update_layer_list;

  if (!IsUsingLayerLists()) {
    PropertyTreeBuilder::BuildPropertyTrees(
        root_layer, page_scale_layer, inner_viewport_scroll_layer(),
        outer_viewport_scroll_layer(), overscroll_elasticity_layer(),
        elastic_overscroll_, page_scale_factor_, device_scale_factor_,
        gfx::Rect(device_viewport_size_), identity_transform, &property_trees_);
    } else {
      ...
    }

    draw_property_utils::UpdatePropertyTrees(this, &property_trees_);
    draw_property_utils::FindLayersThatNeedUpdates(this, &property_trees_,
                                                   &update_layer_list);

  ...
  bool did_paint_content =
      PaintContent(update_layer_list, &painted_content_has_slow_paths,
                   &painted_content_has_non_aa_paint);

  ...

  return did_paint_content;
}


bool LayerTreeHost::PaintContent(const LayerList& update_layer_list,
                                 bool* content_has_slow_paths,
                                 bool* content_has_non_aa_paint) {
  base::AutoReset<bool> painting(&in_paint_layer_contents_, true);
  bool did_paint_content = false;
  for (const auto& layer : update_layer_list) {
    did_paint_content |= layer->Update();
    ...
  }
  return did_paint_content;
}

CC Layer Tree中的每一个Layer都是通过一个PictureLayer对象描述的。因此,接下来我们分析PictureLayer::Update的实现,如下所示:

bool PictureLayer::Update() {
  update_source_frame_number_ = layer_tree_host()->SourceFrameNumber();
  bool updated = Layer::Update();

  gfx::Size layer_size = bounds();

  recording_source_->SetBackgroundColor(SafeOpaqueBackgroundColor());
  recording_source_->SetRequiresClear(
      !contents_opaque() &&
      !picture_layer_inputs_.client->FillsBoundsCompletely());

  ...

  picture_layer_inputs_.recorded_viewport =
      picture_layer_inputs_.client->PaintableRegion();

  updated |= recording_source_->UpdateAndExpandInvalidation(
      &last_updated_invalidation_, layer_size,
      picture_layer_inputs_.recorded_viewport);

  if (updated) {
    picture_layer_inputs_.display_list =
        picture_layer_inputs_.client->PaintContentsToDisplayList(
            ContentLayerClient::PAINTING_BEHAVIOR_NORMAL);
    picture_layer_inputs_.painter_reported_memory_usage =
        picture_layer_inputs_.client->GetApproximateUnsharedMemoryUsage();
    recording_source_->UpdateDisplayItemList(
        picture_layer_inputs_.display_list,
        picture_layer_inputs_.painter_reported_memory_usage,
        layer_tree_host()->recording_scale_factor());

    SetNeedsPushProperties();
  } else {
    ...
  }
  return updated;
}

PictureLayer类的成员函数Update首先调用父类Layer的成员函数Update让其有机会对当前正在处理的Layer执行一些更新工作(实际上什么也没有做)。PictureLayer类有个重要的成员变量last_updated_invalidation_指向的是一个Region对象。这个Region对象描述的是当前正在处理的Layer的待重绘区域。PictureLayer类的成员函数Update在重绘这个区域之前,会先将它的值设置到另外一个成员变量pile_invalidation_中去,以表示Layer的当前重绘区域,同时也会将待重绘区域清空。

其中GraphicsLayer::PaintContentsToDisplayList创建DisplayItemList,存储了ccLayer的绘制指令

scoped_refptr<cc::DisplayItemList> GraphicsLayer::PaintContentsToDisplayList(
    PaintingControlSetting painting_control) {
  TRACE_EVENT0("blink,benchmark", "GraphicsLayer::PaintContents");

  PaintController& paint_controller = GetPaintController();
  paint_controller.SetDisplayItemConstructionIsDisabled(
      painting_control == DISPLAY_LIST_CONSTRUCTION_DISABLED);
  paint_controller.SetSubsequenceCachingIsDisabled(
      painting_control == SUBSEQUENCE_CACHING_DISABLED);

  if (painting_control == PARTIAL_INVALIDATION)
    client_.InvalidateTargetElementForTesting();

  // We also disable caching when Painting or Construction are disabled. In both
  // cases we would like to compare assuming the full cost of recording, not the
  // cost of re-using cached content.
  if (painting_control == DISPLAY_LIST_CACHING_DISABLED ||
      painting_control == DISPLAY_LIST_PAINTING_DISABLED ||
      painting_control == DISPLAY_LIST_CONSTRUCTION_DISABLED)
    paint_controller.InvalidateAll();

  GraphicsContext::DisabledMode disabled_mode =
      GraphicsContext::kNothingDisabled;
  if (painting_control == DISPLAY_LIST_PAINTING_DISABLED ||
      painting_control == DISPLAY_LIST_CONSTRUCTION_DISABLED)
    disabled_mode = GraphicsContext::kFullyDisabled;

  // Anything other than PAINTING_BEHAVIOR_NORMAL is for testing. In non-testing
  // scenarios, it is an error to call GraphicsLayer::Paint. Actual painting
  // occurs in LocalFrameView::PaintTree() which calls GraphicsLayer::Paint();
  // this method merely copies the painted output to the cc::DisplayItemList.
  if (painting_control != PAINTING_BEHAVIOR_NORMAL)
    Paint(nullptr, disabled_mode);

  auto display_list = base::MakeRefCounted<cc::DisplayItemList>();

  DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName();
  PaintChunksToCcLayer::ConvertInto(
      GetPaintController().PaintChunks(), layer_state_->state,
      gfx::Vector2dF(layer_state_->offset.X(), layer_state_->offset.Y()),
      VisualRectSubpixelOffset(),
      paint_controller.GetPaintArtifact().GetDisplayItemList(), *display_list);

  paint_controller.SetDisplayItemConstructionIsDisabled(false);
  paint_controller.SetSubsequenceCachingIsDisabled(false);

  display_list->Finalize();
  return display_list;
}

 回到ProxyMain::BeginMainFrame,

void ProxyMain::BeginMainFrame(
    std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
  ...

  layer_tree_host_->BeginMainFrame(begin_main_frame_state->begin_frame_args);

  layer_tree_host_->AnimateLayers(
      begin_main_frame_state->begin_frame_args.frame_time);

  layer_tree_host_->RequestMainFrameUpdate(
      skip_paint_and_commit ? LayerTreeHost::VisualStateUpdate::kPrePaint
                            : LayerTreeHost::VisualStateUpdate::kAll);
}

对Graphics Layer进行绘制,最终调用CompositedLayerMapping::PaintContents对Normal Layer, Squashe Layer和ScrollableArea采用不同方式分别绘制

void CompositedLayerMapping::PaintContents(
    const GraphicsLayer* graphics_layer,
    GraphicsContext& context,
    GraphicsLayerPaintingPhase graphics_layer_painting_phase,
    const IntRect& interest_rect) const {
  ...

  PaintLayerFlags paint_layer_flags = 0;
  ...
  if (graphics_layer == graphics_layer_.get() ||
      graphics_layer == foreground_layer_.get() ||
      graphics_layer == mask_layer_.get() ||
      graphics_layer == child_clipping_mask_layer_.get() ||
      graphics_layer == scrolling_contents_layer_.get() ||
      graphics_layer == decoration_outline_layer_.get() ||
      graphics_layer == ancestor_clipping_mask_layer_.get()) {
    ...
    DoPaintTask(paint_info, *graphics_layer, paint_layer_flags, context,
                interest_rect);
  } else if (graphics_layer == squashing_layer_.get()) {
    for (size_t i = 0; i < squashed_layers_.size(); ++i) {
      DoPaintTask(squashed_layers_[i], *graphics_layer, paint_layer_flags,
                  context, interest_rect);
    }
  } else if (IsScrollableAreaLayer(graphics_layer)) {
    PaintScrollableArea(graphics_layer, context, interest_rect);
  }
  ...
}

随后进入对Paint Layer Tree的绘制,如对于Normal调用DoPaintTask,

void CompositedLayerMapping::DoPaintTask(
    const GraphicsLayerPaintInfo& paint_info,
    const GraphicsLayer& graphics_layer,
    PaintLayerFlags paint_layer_flags,
    GraphicsContext& context,
    const IntRect& clip /* In the coords of rootLayer */) const {
  ...
  // Paint Layer owns Graphics Layer
  if (paint_info.paint_layer->GetCompositingState() !=
      kPaintsIntoGroupedBacking) {
    // FIXME: GraphicsLayers need a way to split for multicol.
    PaintLayerPaintingInfo painting_info(
        paint_info.paint_layer, LayoutRect(dirty_rect), kGlobalPaintNormalPhase,
        paint_info.paint_layer->SubpixelAccumulation());
    PaintLayerPainter(*paint_info.paint_layer)
        .PaintLayerContents(context, painting_info, paint_layer_flags);

    if (paint_info.paint_layer->ContainsDirtyOverlayScrollbars()) {
      PaintLayerPainter(*paint_info.paint_layer)
          .PaintLayerContents(
              context, painting_info,
              paint_layer_flags | kPaintLayerPaintingOverlayScrollbars);
    }
  } else {
    // Paint Layer don't own Graphics Layer
    PaintLayerPaintingInfo painting_info(
        paint_info.paint_layer, LayoutRect(dirty_rect), kGlobalPaintNormalPhase,
        paint_info.paint_layer->SubpixelAccumulation());
    PaintLayerPainter(*paint_info.paint_layer)
        .Paint(context, painting_info, paint_layer_flags);
  }
}

 参数paintInfo描述的GraphicsLayerPaintInfo对象的成员变量paint_layer描述的是当前要绘制的Paint Layer。当一个其拥有自己的Graphics Layer时,它会绘制自己的Backing Store中,否则的话,它与其它的Paint Layer一起绘制在别的Backing Store中。

       我们假设当前要绘制的拥有自己的Graphics Layer,这时候调用它的成员函数compositingState得到的返回值不等于PaintsIntoGroupedBacking,因此接下来CompositedLayerMapping类的成员函数doPaintTask就会调用PaintLayerPainter::PaintLayerContents实现如下所示:

PaintResult PaintLayerPainter::PaintLayerContents(
    GraphicsContext& context,
    const PaintLayerPaintingInfo& painting_info_arg,
    PaintLayerFlags paint_flags_arg) {
  ...

  PaintLayerFragments layer_fragments;

  if (should_paint_content || should_paint_self_outline ||
      is_painting_overlay_scrollbars) {
    ...

    paint_layer_for_fragments->CollectFragments(
        layer_fragments, local_painting_info.root_layer,
        &local_painting_info.paint_dirty_rect,
        kIgnorePlatformOverlayScrollbarSize, respect_overflow_clip,
        &offset_from_root, local_painting_info.sub_pixel_accumulation);

    ...

  bool selection_only =
      local_painting_info.GetGlobalPaintFlags() & kGlobalPaintSelectionOnly;

  {  // Begin block for the lifetime of any filter.
    size_t display_item_list_size_before_painting =
        context.GetPaintController().NewDisplayItemList().size();

    bool is_painting_root_layer = (&paint_layer_) == painting_info.root_layer;
    bool should_paint_background =
        should_paint_content && !selection_only &&
        (is_painting_composited_background ||
         (is_painting_root_layer &&
          !(paint_flags & kPaintLayerPaintingSkipRootBackground)));
    bool should_paint_neg_z_order_list =
        (is_painting_scrolling_content && is_painting_overflow_contents) ||
        (!is_painting_scrolling_content && is_painting_composited_background);
    bool should_paint_own_contents =
        is_painting_composited_foreground && should_paint_content;
    bool should_paint_normal_flow_and_pos_z_order_lists =
        is_painting_composited_foreground;
    bool should_paint_overlay_scrollbars = is_painting_overlay_scrollbars;

    base::Optional<ScopedPaintChunkProperties>
        subsequence_forced_chunk_properties;
    if (subsequence_recorder && paint_layer_.HasSelfPaintingLayerDescendant()) {
      ...
      subsequence_forced_chunk_properties.emplace(
          context.GetPaintController(),
          paint_layer_.GetLayoutObject()
              .FirstFragment()
              .LocalBorderBoxProperties(),
          paint_layer_, DisplayItem::kUninitializedType);
    }

    if (should_paint_background) {
      if (subsequence_forced_chunk_properties) {
        context.GetPaintController().ForceNewChunk(
            paint_layer_, DisplayItem::kLayerChunkBackground);
      }
      PaintBackgroundForFragments(layer_fragments, context,
                                  local_painting_info, paint_flags);
    }

    if (should_paint_neg_z_order_list) {
      if (subsequence_forced_chunk_properties) {
        context.GetPaintController().ForceNewChunk(
            paint_layer_, DisplayItem::kLayerChunkNegativeZOrderChildren);
      }
      if (PaintChildren(kNegativeZOrderChildren, context, painting_info,
                        paint_flags) == kMayBeClippedByPaintDirtyRect)
        result = kMayBeClippedByPaintDirtyRect;
    }

    if (should_paint_own_contents) {
      PaintForegroundForFragments(
          layer_fragments, context, local_painting_info, selection_only,
          !!subsequence_forced_chunk_properties, paint_flags);
    }

    if (should_paint_self_outline) {
      PaintSelfOutlineForFragments(layer_fragments, context,
                                   local_painting_info, paint_flags);
    }

    if (should_paint_normal_flow_and_pos_z_order_lists) {
      if (subsequence_forced_chunk_properties) {
        context.GetPaintController().ForceNewChunk(
            paint_layer_,
            DisplayItem::kLayerChunkNormalFlowAndPositiveZOrderChildren);
      }
      if (PaintChildren(kNormalFlowChildren | kPositiveZOrderChildren, context,
                        painting_info,
                        paint_flags) == kMayBeClippedByPaintDirtyRect)
        result = kMayBeClippedByPaintDirtyRect;
    }

    if (should_paint_overlay_scrollbars) {
      PaintOverflowControlsForFragments(layer_fragments, context,
                                        local_painting_info, paint_flags);
    }

    if (!is_painting_overlay_scrollbars && paint_layer_.PaintsWithFilters() &&
        display_item_list_size_before_painting ==
            context.GetPaintController().NewDisplayItemList().size()) {
      // If a layer with filters painted nothing, we need to issue a no-op
      // display item to ensure the filters won't be ignored.
      PaintEmptyContentForFilters(context);
    }
  }  // FilterPainter block

  bool should_paint_mask = is_painting_mask && should_paint_content &&
                           paint_layer_.GetLayoutObject().HasMask() &&
                           !selection_only;
  if (should_paint_mask) {
    PaintMaskForFragments(layer_fragments, context, local_painting_info,
                          paint_flags);
  } else if ...
  return result;
}

       收集到了要绘制的Fragment之后,大概就按照以下顺序绘制自己的内容:

       1. Background

       2. Z-index为负的子Paintr Layer

       3. Foreground

       4. Outline

       5. Z-index为0和正数的子Paint Layer 

       6. Scollbar 

       7. Mask

除了子Paint Layer Layer的内容是通过调用成员函数PaintChildren进行绘制的,其余的内容是通过调用成员函数PaintXXXForFragments进行绘制的。

继而进入Layout Object Tree的绘制。

void BlockPainter::PaintObject(const PaintInfo& paint_info,
                               const LayoutPoint& paint_offset) {
  ...
  // paint background
  if (ShouldPaintSelfBlockBackground(paint_phase)) {
   ...
      layout_block_.PaintBoxDecorationBackground(paint_info, paint_offset);
    ...
  }
  // paint mask
  if (paint_phase == PaintPhase::kMask &&
      layout_block_.Style()->Visibility() == EVisibility::kVisible) {
    layout_block_.PaintMask(paint_info, paint_offset);
    return;
  }
  // paint foreground
  if (paint_phase == PaintPhase::kForeground && paint_info.IsPrinting())
    ObjectPainter(layout_block_)
        .AddPDFURLRectIfNeeded(paint_info, paint_offset);
  
  // paint contents
  if (paint_phase != PaintPhase::kSelfOutlineOnly) {
    ...
    const PaintInfo& contents_paint_info =
        scrolled_paint_info ? *scrolled_paint_info : paint_info;

    if (layout_block_.IsLayoutBlockFlow()) {
      BlockFlowPainter block_flow_painter(ToLayoutBlockFlow(layout_block_));
      block_flow_painter.PaintContents(contents_paint_info, paint_offset);
      if (paint_phase == PaintPhase::kFloat ||
          paint_phase == PaintPhase::kSelection ||
          paint_phase == PaintPhase::kTextClip)
        block_flow_painter.PaintFloats(contents_paint_info);
    } else {
      PaintContents(contents_paint_info, paint_offset);
    }
  }
  // paint outline
  if (ShouldPaintSelfOutline(paint_phase))
    ObjectPainter(layout_block_).PaintOutline(paint_info, paint_offset);

  // If the caret's node's layout object's containing block is this block, and
  // the paint action is PaintPhaseForeground, then paint the caret.
  if (paint_phase == PaintPhase::kForeground &&
      layout_block_.ShouldPaintCarets())
    PaintCarets(paint_info, paint_offset);
}
void BlockPainter::PaintChildren(const PaintInfo& paint_info) {
  for (LayoutBox* child = layout_block_.FirstChildBox(); child;
       child = child->NextSiblingBox())
    PaintChild(*child, paint_info);
}


void BlockPainter::PaintChild(const LayoutBox& child,
                              const PaintInfo& paint_info) {
  if (!child.HasSelfPaintingLayer() && !child.IsFloating() &&
      !child.IsColumnSpanAll())
    child.Paint(paint_info);  // ----->   recursively call LayoutBlock::Paint
}

当子Layout Object不拥有自己的Paint Layer,并且它也没有设置Float属性的时候,就会递归调用LayoutBlock::Paint进行绘制,直到中间某个Layout Object的所有子Render Object都具有自己的Paint Layer为止,或者都设置了float属性。

       这样,一个Paint Layer的内容就绘制完成了。PaintResult PaintLayerPainter::PaintLayerContents除了绘制自身内容,还会绘制它的子Paint Layer的内容,

PaintResult PaintLayerPainter::PaintChildren(
    unsigned children_to_visit,
    GraphicsContext& context,
    const PaintLayerPaintingInfo& painting_info,
    PaintLayerFlags paint_flags) {
  ...
  PaintLayer* child = iterator.Next();
  if (!child)
    return result;

  for (; child; child = iterator.Next()) {
    // If this Layer should paint into its own backing or a grouped backing,
    // that will be done via CompositedLayerMapping::PaintContents() and
    // CompositedLayerMapping::DoPaintTask().
    if (child->PaintsIntoOwnOrGroupedBacking(
            painting_info.GetGlobalPaintFlags()))
      continue;

    if (child->IsReplacedNormalFlowStacking())
      continue;

    if (PaintLayerPainter(*child).Paint(context, painting_info, paint_flags) ==
        kMayBeClippedByPaintDirtyRect)
      result = kMayBeClippedByPaintDirtyRect;
  }

  return result;
}

这一步执行完成之后,回到前面分析的LayerTreeHost::UpdateLayers中,这时候网页的CC Layer Tree的内容就绘制完成了,不过仅仅是将绘制命令记录在一系列的Render Surface,也得到了Property Tree。 

然后返回到ProxyMain的成员函数BeginMainFrame中,这时候它就会向Compositor线程的消息队列发送一个Task。Compositor线程开始执行。期间,CrRendererMain线程进入等待状态。

void ProxyMain::BeginMainFrame(
    std::unique_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
  ...
  {
    ...
    ImplThreadTaskRunner()->PostTask(
        FROM_HERE,
        base::BindOnce(&ProxyImpl::NotifyReadyToCommitOnImpl,
                       base::Unretained(proxy_impl_.get()), &completion,
                       layer_tree_host_, begin_main_frame_start_time,
                       hold_commit_for_activation));
    completion.Wait();
  }
  ...
}
void ProxyImpl::NotifyReadyToCommitOnImpl(
    CompletionEvent* completion,
    LayerTreeHost* layer_tree_host,
    base::TimeTicks main_thread_start_time,
    bool hold_commit_for_activation) {
  ...
  scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);

  host_impl_->ReadyToCommit();
  ...
  scheduler_->NotifyReadyToCommit();
}

Scheduler::NotifyBeginMainFrameStarted把状态机改为BeginMainFrameState::STARTED,继续Scheduler::NotifyReadyToCommit中,它将状态机修改为READY_TO_COMMIT之后,再调用成员函数ProcessScheduledActions将刚刚绘制好的CC Layer Tree同步到一个新的CC Pending Layer Tree中去。

猜你喜欢

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