学习资料:链接
学习进度
- 20210518,学习最高优先级
- 2021.06.11,已完成对html、css、javascript学习,预计耗时2天时间学习本资料
- 2021.06.11晚,熟悉html css js语法后,更加理解视频的内容
Content
chrome安全模型,很关键的一个步骤,渲染在sandboxed process中
Blink:Rendering engine
web content
- HTML(Hyper-Text Markup Language)
- CSS(Cascading Style Sheets)
- JavaScript:和Rendering打交道
- images
- 不依赖于额外的库,这是web流行很重要的原因之一
DOM stage
目前市场上的图形库:Opengl,DirectX,Vulcan
渲染的目标
- 将HTML CSS JS正确地翻译到OpenGL calls去画像素
- 通过中间数据,实现快速的实时渲染。Intermediate data strucures let chrome update the rendering more efficiently
HTML Parse
- 对于HTML的文本内容,解析成一颗Tree——Document Object Model (DOM)
- DOM two duty
- 浏览器内部实现的代表结构
- 暴露API给JS
- V8 JS 引擎,暴露DOM AIPs给js,通过C++包装最后提供使用
- DOM two duty
- 解析过程如果碰到<script>就会停止HTML解析,因为js可能会修改DOM Tree结构
- 一个Document可能有多个DOM
- 因为存在customeElement,所以会有多个DOM。每个cutsomElement又有一个ShadowTree,有slot插槽,用于内嵌markup标签
style stage
允许用户通过属性,定义渲染方式
style可以修改某个指定的节点Node,也可以影响该以该节点为根的子树
style的定义可能会有冲突,这里面会有复杂的优先级判定。这也是style engine's job
CSS文本,被解析成一个object model
- 解析成StyleRule,包含SlectorList以及Property mappings
- CSS的底层实现,和py,.cc,.json有密不可分的关系
现在我们来看看解析style后,我们如何应用到DOM上
- 对于每一个DOM NODE先序遍历,都产生了一个ComputedStyle,计算属性值。F12→Element→Computed
- 通过 style engine(Blink)处理的
layout stage (LayOut Engine:NG)
简单来说,style values作为input到layout,layout通过各种算法进行布局
创建Layout Tree,计算好几何数据,绘制的顺序
- 我们可以认为每一个元素占领了content里面一个矩形区域。因此layout(布局)的工作,就是为了处理这些矩形坐标关系
- 使用了一个库叫做HarfBuzz,根据字体的长宽这些参数(Style属性的生成),计算出它们应该放在哪个位置,字体间距调整等等
- Layout会维护Scroll相关的数据。 DOM Root Node就是一个很典型的scrollable,相当于浏览器可上下拖动。CSS使得任何Node/Element都是scrollable
Layout Tree的节点和DOM节点基本上是一一对应,每个Layout TreeNode都实现了LayOut算法进行布局。每一个LayOutNode都是一个LayOut Object
- 一些特例,例如display:none的情况下,就没有LayOut Node
Compositing Update stage(输入分层,类似ps一样有多个图层)
在layout之后,paint之前
将页面分成多个图层,每个图层都有对应的display item list
Prepaint stage
创建Property tree
paint stage
在已有layout处理结果的情况下,在paint list里记录了所有的pain operationd
paint使用的是stacking顺序而非DOM顺序,例如z-index越大,反而会越靠后渲染
以上是main线程做的事情,输出paintOperationItemList
以下是compositor thread(Impl thread),输出最后的光栅化结果给GPU PROCESS
Divide tiles
将layer broken to tiles
Raster stage(光栅化)
光栅化将paintOperationItemList转变成bitmap 【RGBA】 和 GPUMemory
光栅化也在处理<img>标签的图片,对图片资源进行解码,然后通过光栅化的手段转换成像素点的rgba
Chrome光栅化使用的库,叫Skia Graphics library,简称SGL,以第三方插件(The Thrid Party)的形式在chrome中使用
- skia因为在render process中,是sandbox,因此不能直接进行system calls。需要通过GPU Process发起真正的OpenGL调用
CompositorFrame Buffer是渲染进程的结果,最后交给gpu process
GPU stage(GPU Process)
最后的光栅化结果从Render Process传送给GPU Process的skia图形库去处理。GPU有更强大的处理能力,以及更加安全的进行渲染
- 有另一种方式,skia图形库的光栅化在GPU上进行。直接 paintOperationItemList into gpu process,and run skia on gpu
在windows下,通过ANGLE,将OpenGL转化为DirectX
Optimization(渲染是动态的,走完所有stage是昂贵的,因此我们要做优化)
优化
- 如果每一帧都要把所有的stage跑一遍,那可能消耗太大了,因此要做按需update。需要改的地方重新渲染,不需要改动的地方reused复用
- chromium团队提出类似photoshop来解决卡顿(jank):enter:compositing
- layer的渲染是独立的,每个layer单独进行光栅化,将layer划分成若干个tiles,tile就变成了光栅化的更小单元
- compositor有一个tile manager去处理合并tile,在viewport的tile,优先光栅化。所有tile光栅化完毕之后,compositor thread开始draw quad,最后交给gpu process
- 例如wobble摇晃功能,只光栅化一次,之后直接在GPU移动bitmap on gpu
- 对于each layer,有一个property tree,最早是和layer耦合在一起。 近期chrome已经解耦,为了compositing architecture更加的flexible。有点像享元模式,节省了内存
- 单独使用一个impl线程去进程图层合成
- 当我们进行缩放,移动操作时,impl线程会监听用户的input,让main thread 继续执行 javascript code。如果其发现不能解决,还是会交给main thread执行
- layer的渲染是独立的,每个layer单独进行光栅化,将layer划分成若干个tiles,tile就变成了光栅化的更小单元
为了防止draw没完成,又来了一个commit,有一个临时的copy版本,pending tree供使用
display compositor 合并多个frame来自多个surface。简单来说,它可以处理多个render process output and 调用OpenGL calls
总结
web content → render → pixel
一些补充知识
现代浏览器是多进程架构
- 浏览器进程
- 缓存进程
- 网络进程
- 渲染器进程
- GPU进程
- 插件进程
为什么是多进程而不是多线程?
- 多进程安全,不会因为一个页面卡死,所有页面都卡死
- 有一些进程是沙箱环境,例如插件进程,防止恶意程序搞破坏
- 本质上还是内存换安全和鲁棒