Property Trees & DispalyItem

版权声明:本文为CSDN博主「tornmy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tornmy/article/details/82593718

tornmy 2018-09-10 21:53:11 407 收藏 2
分类专栏: chromium
版权
//src/third_party/blink/renderer/core/paint/README.md

Property Tree:

DisplayItem:

什么是property tree:
Paint properties define characteristics of how a paint chunk should be drawn,
such as the transform it should be drawn with. To enable efficient updates,
a chunk’s paint properties are described hierarchically. For instance, each
chunk is associated with a transform node, whose matrix should be multiplied by
its ancestor transform nodes in order to compute the final transformation matrix
to the screen.

Transform Tree

Each paint chunk is associated with a transform node,
which defines the coordinate space in which the content should be painted.

Each transform node has:

1 a 4×4 TransformationMatrix
2
a 3-dimensional transform origin, which defines the origin relative to which
the transformation matrix should be applied (e.g. a rotation applied with some
transform origin will rotate the plane about that point)
3 a pointer to the parent node, which defines the coordinate space relative to
which the above should be interpreted
4
a boolean indicating whether the transform should be projected into the plane
of its parent (i.e., whether the total transform inherited from its parent
should be flattened before this node’s transform is applied and propagated to
children)
5* an integer rendering context ID; content whose transform nodes share a
rendering context ID should sort together

The parent node pointers link the transform nodes in a hierarchy (the transform
tree
), which defines how the transform for any painted content can be
determined.

其中1、2、4、5已统一用State结构体封装。父节点指针继承自PaintPropertyNode,通过parent节点连接成Tree。

Clip Tree

Clips

Each paint chunk is associated with a clip node,
which defines the raster region that will be applied on the canvas when
the chunk is rastered.

Each clip node has:

  • A float rect with (optionally) rounded corner radius.

  • An associated transform node, which the clip rect is based on.

The raster region defined by a node is the rounded rect transformed to the
root space, intersects with the raster region defined by its parent clip node
(if not root).

Effect Tree

Effects

Each paint chunk is associated with an effect node,
which defines the effect (opacity, transfer mode, filter, mask, etc.) that
should be applied to the content before or as it is composited into the content
below.

Each effect node has:

  • a floating-point opacity (from 0 to 1, inclusive)
  • a pointer to the parent node, which will be applied to the result of this
    effect before or as it is composited into its parent in the effect tree

The paret node pointers link the effect nodes in a hierarchy (the effect
tree
), which defines the dependencies between rasterization of different
contents.

One can imagine each effect node as corresponding roughly to a bitmap that is
drawn before being composited into another bitmap, though for implementation
reasons this may not be how it is actually implemented.

Scroll Tree

Scrolling

Each paint chunk is associated with a scroll node
which defines information about how a subtree scrolls so threads other than the
main thread can perform scrolling. Scroll information includes:

  • Which directions, if any, are scrollable by the user.

  • A reference to a transform node which contains
    a 2d scroll offset.

  • The extent that can be scrolled. For example, an overflow clip of size 7×9
    with scrolling contents of size 7×13 can scroll 4px vertically and none
    horizontally.

To ensure geometry operations are simple and only deal with transforms, the
scroll offset is stored as a 2d transform in the transform tree.

blink为什么需要输出property tree:抽象出property tree可以

how a subtree scrolls so threads other than the
main thread can perform scrolling
也许在一定程度上可以提高renderer进程的效率

blink property trees在Layout Tree进行prepaint时构造,(paint时则会产生Displayitem list和创建Graphics Layer Tree)。

具体调用栈为

void PrePaintTreeWalk::Walk(const LayoutObject& object) {

WalkInternal(object, context());

for (const LayoutObject child = object.SlowFirstChild(); child;
child = child->NextSibling()) {
if (child->IsLayoutMultiColumnSpannerPlaceholder()) {
child->GetMutableForPainting().ClearPaintFlags();
continue;
}
Walk(
child);
}

}
void PrePaintTreeWalk::WalkInternal(const LayoutObject& object,
PrePaintTreeWalkContext& context) {
PaintInvalidatorContext& paint_invalidator_context =
context.paint_invalidator_context;

base::Optional

FragmentPaintPropertyTreeBuilder(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& full_context,
PaintPropertyTreeBuilderFragmentContext& context,
FragmentData& fragment_data)
: object_(object),
full_context_(full_context),
context_(context),
fragment_data_(fragment_data),
properties_(fragment_data.PaintProperties()) {}

fragment_data = &object_.GetMutableForPainting().FirstFragment();
Each PaintLayer‘s LayoutObject has one or more FragmentData objects (see
below for more on fragments). Every FragmentData has an
ObjectPaintProperties object if any property nodes are induced by itDuring paint, each display item will be associated with a property
tree state.

其中,核心函数为

void FragmentPaintPropertyTreeBuilder::UpdateForSelf() {

if (properties_) {
UpdateTransform();
UpdateClipPathClip(false);
UpdateEffect();
UpdateLinkHighlightEffect();
UpdateClipPathClip(true); // Special pass for SPv1 composited clip-path.

UpdateCssClip();
UpdateFilter();
UpdateOverflowControlsClip();
}
UpdateLocalBorderBoxContext();
}
通过下面的宏(不用虚函数方式是为了提高效率吗)可以统一对所有Property Trees进行创建

#define ADD_NODE(type, function, variable) \
const type##PaintPropertyNode function() const { return variable.get(); } \
UpdateResult Update##function(const type##PaintPropertyNode& parent, \
type##PaintPropertyNode::State&& state) { \
auto result = Update(variable, parent, std::move(state)); \
DCHECK(!is_immutable_ || result.Unchanged()) \
<< “Value changed while immutable. New state:\n” \
<<
variable; \
return result; \
}
对于Transform Tree 调用

static scoped_refptr

static scoped_refptr

static scoped_refptr

static scoped_refptr

回到PrePaintTreeWalk::Walk

void PrePaintTreeWalk::Walk(LocalFrameView& frame_view) {

// ancestor_overflow_paint_layer does not cross frame boundaries.

context().ancestor_overflow_paint_layer = nullptr;
if (context().tree_builder_context) {
PaintPropertyTreeBuilder::SetupContextForFrame(
frame_view, *context().tree_builder_context);
}

Walk(*view);

}
通过PaintPropertyTreeBuilder::SetupContextForFrame调用

PaintPropertyTreeBuilderFragmentContext::
PaintPropertyTreeBuilderFragmentContext()
: current_effect(&EffectPaintPropertyNode::Root()) {
current.clip = absolute_position.clip = fixed_position.clip =
&ClipPaintPropertyNode::Root();
current.transform = absolute_position.transform = fixed_position.transform =
&TransformPaintPropertyNode::Root();
current.scroll = absolute_position.scroll = fixed_position.scroll =
&ScrollPaintPropertyNode::Root();
}
也就是在这里为4个Property Tree设置了root,以后都可以通过XXXPaintPropertyNode::Root()的方式访问对应的root,

其创建的方式也比较fancy,root定义了一个静态变量,用lambda创建,以Transform Tree的root为例

const TransformPaintPropertyNode& TransformPaintPropertyNode::Root() {
DEFINE_STATIC_REF(
TransformPaintPropertyNode, root,
base::AdoptRef(new TransformPaintPropertyNode(
nullptr,
State{TransformationMatrix(), FloatPoint3D(), false,
BackfaceVisibility::kVisible, 0, CompositingReason::kNone,
CompositorElementId(), &ScrollPaintPropertyNode::Root()},
true / is_parent_alias /)));
return *root;
}

#define DEFINE_STATIC_REF(type, name, arguments) \
static type* name = [](scoped_refptr

void PaintArtifactCompositor::Update(
scoped_refptr

然后就进一步收集DisplayItemList,它是DisplayItem的集合。

什么是DisplayItem:

Display items

A display item is the smallest unit of a display list in Blink. Each display
item is identified by an ID consisting of:

  • an opaque pointer to the display item client that produced it
  • a type (from the DisplayItem::Type enum)
    class PLATFORM_EXPORT DisplayItem {
    DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();

public:

// Ids are for matching new DisplayItems with existing DisplayItems.

struct Id {

const DisplayItemClient& client;
const Type type;
const unsigned fragment;
};
Id GetId() const { return Id(*client_, GetType(), fragment_); }

const DisplayItemClient* client_;
FloatRect visual_rect_;
float outset_for_raster_effects_;

static_assert(kTypeLast < (1 << 8), “DisplayItem::Type should fit in 8 bits”);
unsigned type_ : 8;
unsigned derived_size_ : 8; // size of the actual derived class
unsigned fragment_ : 14;
unsigned is_cacheable_ : 1;
unsigned is_tombstone_ : 1;
};
DisplayItemList间接继承自ContiguousContainerBase,具有成员Vector

A Quick Overview of Chrome’s Rendering Path

举个栗子,如下的网页

Hello World

Property Trees & DispalyItem

将产生如下的DisplayItemList,包含3个DispalyItems:

从client_包含了对LayoutObject的关联,可以看出其对应的内容,第一个对应与Layout的根节点,另一个对应于InlineTextBox,还有一个对应于LayoutImage。

从这里看,Displayitem的绘制指令,其实只包含LayoutObject的位置和大小信息,也就是还需要结合property trees。

Displayitem的创建过程如下

其中不同的LayoutObject会有不同入口的函数,比如Graphicslayer对应于ViewPainter::PaintBoxDecorationBackground,inlineText对应于InlineTextBoxPainter::Paint,而LayoutImage对应于ImagePainter::PaintReplaced,等等。相同的是它们都会在栈上创建base::DrawingRecorder,在离开对应函数时,调用DrawingRecorder的析构函数,从而创建DisplayItem并Append到DisplayItemList上,而new_display_item_list_为PaintController的成员,是控制整个paint流程的。如下:

template

void PaintController::ProcessNewItem(DisplayItem& display_item) {
if (IsSkippingCache() && usage_ == kMultiplePaints)
display_item.Client().Invalidate(PaintInvalidationReason::kUncacheable);

new_paint_chunks_.IncrementDisplayItemIndex(display_item);
auto& last_chunk = new_paint_chunks_.LastChunk();

last_chunk.outset_for_raster_effects =
std::max(last_chunk.outset_for_raster_effects,
display_item.OutsetForRasterEffects());

}
}
具体通过如下合并相同DisplayItem

bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) {
bool item_forces_new_chunk = item.IsForeignLayer() || item.IsScrollHitTest();
if (item_forces_new_chunk)
force_new_chunk_ = true;

size_t new_chunk_begin_index;
if (chunks_.IsEmpty()) {
new_chunk_begin_index = 0;
} else {
auto& last_chunk = LastChunk();
if (!force_new_chunk_ && current_properties_ == last_chunk.properties) {
// Continue the current chunk.

last_chunk.end_index++;
// We don’t create a new chunk when UpdateCurrentPaintChunkProperties()
// just changed |next_chunk_id_| but not |current_properties_|. Clear
// |next_chunk_id_| which has been ignored.

next_chunk_id_ = base::nullopt;
return false;
}
new_chunk_begin_index = last_chunk.end_index;
}

chunks_.emplace_back(new_chunk_begin_index, new_chunk_begin_index + 1,
next_chunk_id_ ? *next_chunk_id_ : item.GetId(),
current_properties_);
next_chunk_id_ = base::nullopt;

// When forcing a new chunk, we still need to force new chunk for the next
// display item. Otherwise reset force_new_chunk_ to false.

if (!item_forces_new_chunk)
force_new_chunk_ = false;

return true;
}
可以看出,PaintChunk(仅仅是Displayitem的Id(*client_, GetType(), fragment_),而不是Displalyitem本身; )在PaintChunker中线性存贮,而这一步合并不是全局的,而是每次新产生的DisplayItem和之前的PaintChunk的PropertyTreeState形同则合并到统一PaintChunk,即增加该PaintChunk的end_index,否则新加一个PaintChunk。(这一步只是粗略的合并,之后还有进一步合并,还是说此处有进一步优化的可能呢?)

而最终产生的DisplayItemList和PaintChunk会被打包成PaintArtifact,方便调用,当然它也是PaintControl的成员。

void PaintController::CommitNewDisplayItems() {

// The new list will not be appended to again so we can release unused memory.

new_display_item_list_.ShrinkToFit();

current_paint_artifact_ =
PaintArtifact::Create(std::move(new_display_item_list_),
new_paint_chunks_.ReleasePaintChunks());

}
Chromium之后会使用slimming paint v2,所以我们关注RuntimeEnabledFeatures::SlimmingPaintV2Enabled()的流程,打开此特性(可以使用的特性的名字在//src/third_party/blink/renderer/platform/runtime_enabled_features.json5的data中查询)。并在开启chrome时添加如下参数:

chrome –enable-blink-features=SlimmingPaintV2
而CC使用的displayitem的结构和blink使用的displayitem结构也不完全相同,所以会把PaintChunk转换成CC需要的格式,

scoped_refptr

class CC_PAINT_EXPORT DisplayItemList
: public base::RefCountedThreadSafe

最终转换好的DisplayItemList存储在ContentLayerClientImpl中,其存储于PaintArtifactCompositor,其存储于LocalFrameView。
————————————————

Original: https://www.cnblogs.com/bigben0123/p/14992048.html
Author: Bigben
Title: Property Trees & DispalyItem

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551280/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 二十一、XML

    二十一、XML 21.1 XML介绍 21.1.1 一个问题引入 XML 思考:前面的反射可以加载配置文件里的信息,获取类的字节码对象从而动态创建对象和调用方法,但是如果需要创建多…

    技术杂谈 2023年7月11日
    076
  • 实战模拟│企业微信机器人实时报错预警

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    技术杂谈 2023年7月11日
    077
  • node glob 文件查找

    glob https://www.npmjs.com/package/glob Original: https://www.cnblogs.com/mengfangui/p/158…

    技术杂谈 2023年5月31日
    079
  • 需求项目迭代思考-by k

    博客园 :当前访问的博文已被密码保护 请输入阅读密码: Original: https://www.cnblogs.com/shoshana-kong/p/16498659.htm…

    技术杂谈 2023年6月1日
    0104
  • JAVA基础学习第二天!

    精华笔记: 1.变量:存数的 -声明:—————在银行开了个帐户 -初始化:———&…

    技术杂谈 2023年7月11日
    060
  • 葫芦侠:一键签到云函数 超详细教程

    前言 此代码搬运吾爱破解@fuxi ,而我做这个博客就是记录一些可以使用函数签到的教程,不喜勿喷 教程 1、腾讯云函数地址:https://cloud.tencent.com/lo…

    技术杂谈 2023年6月21日
    0105
  • lambda表达式常用01

    1、 优化线程代码 以前我们使用线程可能是这么使用的: 使用lambda: 再次进行优化写法: 2.Arrays.sort 排序优化 在代码中,我们会使用Arrays.sort对数…

    技术杂谈 2023年7月24日
    081
  • C++中函数的参数加了&和const的作用

    例如下面这段代码 fun(int* in, const std::string& str) { } 不加引用的话,str则被复制一份,函数中对str的操作实质上是对其复制品…

    技术杂谈 2023年7月24日
    067
  • 专业品质的3月TOGAF认证线上公开课

    IT帮出品课程,以专业赢得客户的认可。 01 讲师有话说 2020年01月线下公开课 10人小班2020年02月线上公开课 33人大班阿里企业内训 如果你想报名我们的这个课程,可以…

    技术杂谈 2023年5月31日
    0114
  • Node安装与卸载命令汇总

    nvm(MAC管理node版本) 安装最新稳定版node: nvm install stable 安装指定版本: nvm install <version></v…

    技术杂谈 2023年6月21日
    083
  • PHP8.1.10手动安装教程及报错解决梳理

    安装php版本8.1.10:https://www.php.net/distributions/php-8.1.10.tar.gz 易错步骤梳理: 1、安装的版本是php8,因此教…

    技术杂谈 2023年7月11日
    082
  • python2.6.6安装Image模块

    python2.6.6安装Image模块1、下载Image模块源码地址:http://www.pythonware.com/products/pil/index.htm2、加压文件…

    技术杂谈 2023年7月11日
    084
  • SQL语句复习整理

    SQL语句SQL 是用于访问和处理数据库的标准的计算机语言,SQL 指结构化查询语言 可以把 SQL 分为两个部分:数据操作语言 (DML) 和 数据定义语言 (DDL)。 SQL…

    技术杂谈 2023年6月21日
    0114
  • JAVA基本类型和包装类型

    JAVA基本类型和包装类型 前言 Java语言中的数据类型分为基本数据类型和引用类型,而我们进行Java开发的时候都听说过基本数据类型和包装类型,今天我们就来详细聊一聊Java中的…

    技术杂谈 2023年6月21日
    090
  • FTP文件服务的安装与部署

    FTP(文件传输协议)概念 FTP基于C/S模式,FTP客户端与服务器端有两种传输模式,分别是FTP主动模式、FTP被动模式,主被动模式均是以FTP服务器端为参照。企业实际环境中,…

    技术杂谈 2023年7月11日
    085
  • CentOs安装Nginx

    安装 gcc pcre pcre-devel zlib OpenSSL 安装 安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需…

    技术杂谈 2023年7月10日
    075
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球