RenderObject 作为所有Render 树节点的基类,完全类似与DOM树中的Node基类,它是构成Render 树的基础,作用非比寻常,其中包含了构成Render 树所可能涉及到的一些基本属性及方法,内容相当多,其主要数据成员及方法分别如下:

其中成员m_parent、m_previous、m_next为构建Render 树设置好关联基础;m_Node 则为DOM 树中对应的节点;m_style 成员则描述该节点对应的各种CSS基本属性数据,下面会单独介绍;至于其他的诸如m_positioned、m_isText、m_inline、m_floating、m_replaced等则描述其特性,就像CSS标准对不同元素的属性分类定义一样,从字面上我们就可以上一节WebKit 网页布局实现之基本概念及标准篇中可以找到它们这么定义的踪影。成员m_needsPositionedMovementLayout 、m_normalChildNeedsLayout 、m_posChildNeedsLayout 、m_needsLayout 等主要用来描述该RenderObject 是否确实需要重新布局;当 一个新的RenderObject 对象插入到Render 树的时候,它会设置其m_needsLayout 属性为true,同时会根据该 RenderObject对象在祖先RenderObject 看来是一个positioned( 拥有positiong:absolute 或fixed 属 性)状态的孩子,如是则将相应祖先RenderObject 对象的属性m_posChildNeedsLayout 设置为true;如果是一个in-flow(positon:static 或relative)状态的孩子,则将相应祖先RenderObject对象的属性m_normalChildNeedsLayout设置为true;

其中很多方法如paint()、layout()等是虚拟的,不同的子类可以重载它;其中方法container() 、containingBlock()、paint()、layout()很值得大家深入研究;总的说来RenderObject 基类定义一些通用属性、方法,以便维护、布局、渲染Render 树。

1.RenderObject创建过程

2.RenderObject继承关系

2 子类RenderBox

RenderBox 代表描述CSS 标准中的Box Model,它继承自RenderObject,其主要重载了部分继承而来的方法。

3.子类RenderContainer
RenderContainer 类用来描述可以拥有子RenderObject 成员的容器类,它继承自RenderBox。其主要重载了RenderObject 提供的维护Render 树新增、删除树节点等方面的方法

4.子类RenderFlow
RenderFlow 主要用来描述CSS 标准中提到的能进行inline-flow、block-flow 相关处理的Render 树结点,它继承自RenderContainer;其主要方法包括在flow的过程中创建、关联匿名
对象等

5.子类RenderBlock

RenderBlock 代表CSS 标准中的block-level 元素,它继承自RenderFlow它维护了一组由它定位的positioned 树节点,以及有关overflow 方面的设置。其主要重载了RenderObject 继承下来的layout、paint等方法。因为html中的body、div、p等标签对应RenderBlock 类对象,其在Render 树具有非常重要的地位,其layout、paint 等方法的实现,往往是WebKit 整个布局、渲染处理的发起中心,内容比较多并且复杂,以后有机会详解。

6.子类RenderInline

RenderInline 代表inline-level 元素, 其继承自RenderFlow,主要重载了RenderObject 关于inline-flow 方面处理的方法,提供了splitFlow、splitInlines等处理自动换行的方法。

7.子类RenderText

RenderText 代表对html 中Text node 对应的Render 树节点,它直接继承自RenderObject它提供关于处理文字方面如显示文字、行高计算、整个Text node对应的宽度等;它没有重载layout 方法,因为它自身的定位往往由

RenderBlock、RenderInline 父对象来处理;

8.子类RenderImage
RenderImage 代表html 中img 标签对应的树节点,它继承自RenderBox。其主要提供关于图片显示、大小设置等方面的处理,其中paintReplaced 方法将其图片显示出来;

9.子类RenderView
RenderView对应整个html文档对象的树节点,可看成是Render树的根,它继承自RenderBlock其中m_frameview 成员对应整个文档对应的FrameView,而m_widgets 则包括了该文档可能包含的plugin 插件等对应的Render

树节点。RenderView 对象作为Render 树的根,它往往随着Document 对象的创建而创建,它的layout、paint 方法的发起往往是整颗Render树布局、渲染处理的开始。其中也包含了对选择处理

10.子类RenderButton
RenderButton代表html中input标签type为button时对应的Render 树节点,它直接继承自RenderFlexibleBox。RenderFlexibleBox代表能按居中、左对齐、右对齐等水平或垂直方向布局子节点的树节点

其中m_buttonText为button上的文字对应的树节点,而m_inner为添加m_buttonText 时创建的匿名对象,以便于居中等处理等。这成员的创建来自于方法updateFromElement;

这 些css属性通过CSSStyleSelector::applyProperty方法来设定其成员m_RenderStyle 对应的值, 其中包含m_style->setAppearance(PushButtonAppearance)。尤其值得关注,其初步决定了button是如何画出来的

11.子类RenderTextControl
RenderTextControl 代表html 中input 标签type 为text 或textarea标签对应的Render 树节点,它直接继承自RenderBlock;其中成员m_multiLine 以描述是textarea 或text input;m_innerText 为其中包括的文字对应的树节点;当作搜索按钮时m_cancelButton/m_resultsButton 为对应的树节点;这些成员的创建来自于方法updateFromElement;

12.子类RenderListBox
RenderListBox代表html中select标签对应的Render树节点,它直接继承自RenderBlock;

13.子类RenderTheme
RenderTheme 在html 标签中没有对应的页面元素,其作用主要用于如何渲染按钮、输入框、列表框等,其实现往往有一定平台相关性。RenderTheme 往往提供一个接口,不同的图形库对其中不同的方法如paintbutton、paintcheckbox、painttextfield等进行了实现;其 中 paint 方法则根据appearance 属性的不同以分别调用不同的paintxxx 方法,

14. 子 类 RenderTable 、 RenderTableRow 、 RenderTableCol 、RenderTableCell

RenderTable 主要通过addChild 方法来维护对RenderTableCell、RenderTableCol、RenderTableRow等对象的管理.RenderTableRow 通过方法layout 和paint 方法来布局管理RenderTableCell对象。这一组子类主要实现人们熟知的表格布局,

15.子类RenderFrame
RenderFrame代表html中标签frame对应的Render 树节点其中属性m_widget、m_view 代表frame 对应的widget 及frameview,通过其中setwidget 方法来设置m_widget 属性,m_view属性则在对象创建的时候设置为当前document对应的frameview。其中html 中的embed/object 插件标签对应的Render 树节点为RenderPartObject对象。

3.渲染对象(RenderObjects)与渲染图层(RenderLayers)

每个渲染对象(RenderObject)都有其对应的渲染图层(RenderLayer),或者是直接关联,或者是通过其根对象(其根级RenderObject)间接关联。

一般来讲,拥有相同坐标空间(如受控于相同的CSS变换)的渲染对象会属于同一个渲染图层。渲染图层可以保证渲染对象在重叠、半透明等情况时,能以正确层叠次序进行绘制。
RenderBoxModelObject::requiresLayer()中定义了一些为渲染对象创建新渲染图层的前提条件,如:

* 渲染对象是页面的根对象;
 * 渲染对象有独立的CSS定位属性(相对、绝对、变换);
 * 渲染对象是透明的;
 * 覆盖有透明(Alpha)蒙版或者反射层;
 * 有CSS效果滤镜;
 * 该渲染对象对应于<canvas>标签指定的WebGL或者2D加速图形元素;
 * 该渲染对象对应于<video>标签元素;

注意渲染对象与渲染图层间不存在一对一关系,一个渲染对象,要么对应于专为它创建的的渲染图层,要么对应于其某级根对象的渲染图层。

渲染图层(RenderLayers)也是以树形结构来组织的,根部的图层即对应渲染树(Render Tree)中根部的渲染对象。
每个渲染图层(RenderLayer)同时存储在两个基于不同深度值方向(Z-Order)的列表中:正向深度列表posZOrderList,以及负向深度列表negZOrderList。

用WebGL技术的canvas元素。每个合成层都有一个RenderLayerBacking,RenderLayerBacking负责管理RenderLayer所需要的所有后端存储,因为后端存储可能需要多个存储空间。在WebKit中,存储空间使用类GraphicsLayer来表示。

下图就是WebKit构建的从RenderLayer树到RenderLayBacking树,再到GraphicsLayer树,并给出这些硬件加速基础设施的对应关系。在RenderLayer树中的第四个节点没有创建RenderLayerBacking对象,因为不符合上面的创建条件,而对于每个RenderLayerBacking对象,它也至少需要一个GraphicsLayer对象,当然也可能需要多个,图中的RenderLayerBacking分别需要2个,1个或者4个GraphicsLayer对象,这些对象分别表示什么呢?

为什么一个RenderLayerBacking对象需要这么多层呢?原因有很多,例如是需要将滚动条独立开来称为一个层,需要前景层、背景层等,需要两个容器层来表示RenderLayer对应的Z坐标为正数的子女和Z坐标负数的子女,将可能需要滚动的内容建立新层,还有剪裁层和反射层

4. 三个树结构

可以说,渲染过程中,有三个树形结构各司其职:

* DOM树(DOM Tree),持有构成页面的所有的数据节点对象;
 * 渲染对象树(RenderObject Tree),持有与可显示节点(Node)一对一的渲染对象,每个渲染对象知道如何绘制与其对应的节点;

* 渲染图层树(RenderLayer Tree),基于渲染对象树构建的层级树,每个渲染图层对应一至多个渲染对象;

5. 软件渲染过程

WebKit在渲染页面时,从根节点开始遍历渲染图层树(RenderLayer Tree),直至叶子节点,在页面渲染的实现上,WebKit包含两种方式:
软件渲染和硬件加速渲染,而软件渲染是最基本的方式。

软件渲染过程,整个页面中的每个渲染图层按照深度从后向前的顺序依次被绘制,渲染图层的主要绘制工作都是在RenderLayer::paintLayer()中完成,其中大概包含如下步骤:

a. 判断图层边界是否与刷新矩形有交叉;
 b. 通过调用图层的paintLayer()方法,屏幕深度上从前向后,递归绘制negZOrderList列表中位于该图层后面的图层;
 c. 让该图层相关联的所有渲染对象(RenderObject)完成各自的绘制;
 d. 渲染对象(RenderObject)的绘制过程,从那个创建该图层的对象开始,向渲染对象树(RenderObject Tree)末端遍历,
    直至遇到一个不属于当前渲染图层(RenderLayer)的渲染对象(RenderObject)而结束;
 e. 通过调用图层的paintLayer()方法,屏幕深度上从后向前,递归绘制posZOrderList列表中位于该图层前面的图层。
 
在这种渲染方式下,渲染对象通过对绘图环境(GraphicsContext,Chrome中的Skia库)执行一系列绘图操作,将自己的内容绘制在内存位图上。

绘图环境本身并不关心图层的概念,但是在绘制半透明图层时有一点需要注意:半透明图层在开始绘制渲染对象时,会调用GraphicsContext::beginTransparencyLayer(),
在Skia库的实现中,这个调用会使得后续的所有绘制都在独立的位图上进行,以至于当该图层相对应的所有对象渲染完成时(此时endTransparencyLayer()方法被调用),
这些独立位图能够与基础图像(或者称背景图像)进行合成(进行必要的Alpha混合,以实现半透明效果)。

6. 将WebKit渲染结果显示在屏幕上

当所有的渲染图层(RenderLayers)将内容绘制到内存位图上之后,还需要将内存位图呈现在屏幕上。在Chrome系统中,渲染器进程会将渲染好的内存位图放入共享内存中,
然后通过IPC消息通知浏览器进程进行界面更新,浏览器进程收到IPC通知后,使用操作系统API,将内存位图绘制到指定窗口(标签对应的网页视图)上。

Webkit二:RenderTree 创建的更多相关文章

  1. SQLite 入门教程(二)创建、修改、删除表 (转)

    转于 SQLite 入门教程(二)创建.修改.删除表 一.数据库定义语言 DDL 在关系型数据库中,数据库中的表 Table.视图 View.索引 Index.关系 Relationship 和触发器 ...

  2. Ubuntu下Django初体验(二)——创建工程及应用

    一.工程目录详解 创建工程后得到如下目录: 1. manage.py 管理项目.创建数据库.启动服务器等.测试等. 查看子命令: python manage.py 启动服务器: python mana ...

  3. VSTO之旅系列(二):创建Excel解决方案

    原文:VSTO之旅系列(二):创建Excel解决方案 本专题概要 引言 创建VSTO项目 Excel对象模型 创建Excel外接程序 创建Excel文档级自定义项 小结 一.引言 也许很多朋友都没有听 ...

  4. BitAdminCore框架应用篇:(二)创建一个简单的增删改查模块

    NET Core应用框架之BitAdminCore框架应用篇系列 框架演示:http://bit.bitdao.cn 框架源码:https://github.com/chenyinxin/cookie ...

  5. InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移

    系列目录 InterSystems Ensemble学习笔记(一) Ensemble介绍及安装InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移 一 ...

  6. 微信小程序从零开始开发步骤(二)创建小程序页面

    上一章注册完小程序,添加新建的项目,大致的准备开发已经完成,本章要分享的是 要创建一个简单的页面了,创建小程序页面的具体几个步骤: 1. 在pages 中添加一个目录 选中page,右击鼠标,从硬盘打 ...

  7. Qt DLL总结【二】-创建及调用QT的 DLL(三篇)good

    目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...

  8. 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板

    标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...

  9. ML-Agents(二)创建一个学习环境

    ML-Agents(二)创建一个学习环境 一.前言 上一节我们讲了如何配置ML-Agents环境,这一节我们创建一个示例,主要利用Reinforcement Learning(强化学习). 如上图,本 ...

  10. u-boot 移植(二)创建新平台的板级支持

    u-boot 移植(二)创建新平台的板级支持 soc:s3c2440 board:jz2440 uboot:u-boot-2016.11 toolchain:gcc-linaro-7.4.1-2019 ...

随机推荐

  1. P2730 魔板 Magic Squares (搜索)

    题目链接 Solution 这道题,我是用 \(map\) 做的. 具体实现,我们用一个 \(string\) 类型表示任意一种情况. 可以知道,排列最多只有 \(8!\) 个. 然后就是直接的广搜了 ...

  2. idea报错could not autowired .但是可以正常运行

    转 http://www.cnblogs.com/softidea/p/5763285.html 解决办法: File-->Project Setting-->Facets-->Sp ...

  3. HDU 2594 kmp算法变形

    Simpsons’ Hidden Talents Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

  4. APUE 学习笔记(六) 进程控制

    1. fork 创建新进程 fork创建的新进程称为子进程,fork函数调用一次,返回两次. 两次返回的唯一区别就是子进程的返回值是0,而父进程的返回值是新子进程的进程ID 在fork之后是父进程先执 ...

  5. poj 4001 To Miss Our Children Time

    To Miss Our Children Time Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Jav ...

  6. configure: error: C++ preprocessor "/lib/cpp" fails sanity check

    configure: error: C++ preprocessor "/lib/cpp" fails sanity check 参考链接: error: C++ preproce ...

  7. 开发使用mysql的一些必备知识点整理(三)高级

    简介 实体与实体之间有3种对应关系,这些关系也需要存储下来 在开发中需要对存储的数据进行一些处理,用到内置的一些函数 视图用于完成查询语句的封装 事务可以保证复杂的增删改操作有效 关系 创建成绩表sc ...

  8. java通过代码控制线程状态,解决线程不安全的问题。

    写两个类,Input,output 两个都是使用同步代码块的方式实现线程间的同步 input类,是为变量赋值 output类,是打印变量 由于线程争夺cpu造成数据的不匹配 通过,设立一个 flag ...

  9. Linux 性能优化解析

    前情概述 进程调度 老板 cpu 任劳任怨的打工仔 线程 工作在做什么 可运行队列 拥有的工作清单 上下文切换 和老板沟通以便得到老板的想法并及时调整自己的工作 中断 部分工作做完以后还需要及时向老板 ...

  10. Network | Public-key cryptography

    公开密钥加密public-key cryptography,也称为非对称(密钥)加密. 非对称密钥,是指一对加密密钥与解密密钥,这两个密钥是数学相关,用某用户密钥加密后所得的信息,只能用该用户的解密密 ...