Webkit二:RenderTree 创建
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 创建的更多相关文章
- SQLite 入门教程(二)创建、修改、删除表 (转)
转于 SQLite 入门教程(二)创建.修改.删除表 一.数据库定义语言 DDL 在关系型数据库中,数据库中的表 Table.视图 View.索引 Index.关系 Relationship 和触发器 ...
- Ubuntu下Django初体验(二)——创建工程及应用
一.工程目录详解 创建工程后得到如下目录: 1. manage.py 管理项目.创建数据库.启动服务器等.测试等. 查看子命令: python manage.py 启动服务器: python mana ...
- VSTO之旅系列(二):创建Excel解决方案
原文:VSTO之旅系列(二):创建Excel解决方案 本专题概要 引言 创建VSTO项目 Excel对象模型 创建Excel外接程序 创建Excel文档级自定义项 小结 一.引言 也许很多朋友都没有听 ...
- BitAdminCore框架应用篇:(二)创建一个简单的增删改查模块
NET Core应用框架之BitAdminCore框架应用篇系列 框架演示:http://bit.bitdao.cn 框架源码:https://github.com/chenyinxin/cookie ...
- InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移
系列目录 InterSystems Ensemble学习笔记(一) Ensemble介绍及安装InterSystems Ensemble学习笔记(二) Ensemble创建镜像, 实现自动故障转移 一 ...
- 微信小程序从零开始开发步骤(二)创建小程序页面
上一章注册完小程序,添加新建的项目,大致的准备开发已经完成,本章要分享的是 要创建一个简单的页面了,创建小程序页面的具体几个步骤: 1. 在pages 中添加一个目录 选中page,右击鼠标,从硬盘打 ...
- Qt DLL总结【二】-创建及调用QT的 DLL(三篇)good
目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...
- 从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板
标题:从零开始实现ASP.NET Core MVC的插件式开发(二) - 如何创建项目模板 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p/11155 ...
- ML-Agents(二)创建一个学习环境
ML-Agents(二)创建一个学习环境 一.前言 上一节我们讲了如何配置ML-Agents环境,这一节我们创建一个示例,主要利用Reinforcement Learning(强化学习). 如上图,本 ...
- u-boot 移植(二)创建新平台的板级支持
u-boot 移植(二)创建新平台的板级支持 soc:s3c2440 board:jz2440 uboot:u-boot-2016.11 toolchain:gcc-linaro-7.4.1-2019 ...
随机推荐
- DB2 Catalog浅析&学习笔记
原文地址:http://king123654789.iteye.com/blog/1296492 Catalog 是远程连接部署在服务器端的DB2数据库的命令 [本文涉及到的命令] >db2 c ...
- java 时间戳与date转换
1.时间戳转换为date long sjc=1442633777; SimpleDateFormat t = new SimpleDateFormat("yyyyMMddHHmmss&quo ...
- python:print含有中文的list
Python 的 List 如果有中文的话, 会印出 \xe4\xb8... 等等的编码(如下所示), 要如何印出中文呢? >>> a = ['中文', 'ab']>>& ...
- google jib容器打包工具
简介 Jib 是 Google 开发的可以直接构建 Java 应用的 Docker 和 OCI 镜像的类库,以 Maven 和 Gradle 插件形式提供. 通过 Jib,Java 开发者可以使用他们 ...
- css3 手机端翻屏切换效果
原理是基于css3的 1.景深:perspective:100px; 2.中心点:transform-origin:center center 0; 3.transform-style:preserv ...
- linux shmget shmctl
shmgetint shmget(key_t key, size_t size, int flag);key: 标识符的规则size:共享存储段的字节数flag:读写的权限返回值:成功返回共享存储的i ...
- HDU 2767:Proving Equivalences(强连通)
题意: 一个有向图,问最少加几条边,能让它强连通 方法: 1:tarjan 缩点 2:采用如下构造法: 缩点后的图找到所有头结点和尾结点,那么,可以这么构造:把所有的尾结点连一条边到头结点,就必然可以 ...
- mysql 新增用户并授权
grant all privileges on *.* to 'root'@‘%’ identified by '123456'; *.* 表示所有资源. 刷新权限 flush privileges;
- LeetCode OJ--Merge Sorted Array *
http://oj.leetcode.com/problems/merge-sorted-array/ 两个有序数组A和B的归并排序,将结果存到A中.因为已知两数组长度且A的数组足够大,所以倒着处理, ...
- ELK之收集haproxy日志
由于HAProxy的运行信息不写入日志文件,但它依赖于标准的系统日志协议将日志发送到远程服务器(通常位于同一系统上),所以需要借助rsyslog来收集haproxy的日志.haproxy代理nginx ...