Browser under the macro perspective: 06 | rendering process (under): HTML, CSS and JavaScript, is how to become a page?

Preface: This article Description: See  description - the browser works with the practice directory

 

  In the last article , we introduced the rendering pipeline DOM production , style computing and layout of the three phases, then explain that today we render later pipeline stages.

 

  Here is briefly recap on the main content of the pre-holiday three stages: after the HTML page content to be submitted to the rendering engine, HTML rendering engine will first be resolved to the browser's DOM can be understood; then according to the CSS style sheet to calculate the DOM All style tree nodes; followed calculating the coordinate position of each geometric element, and saves the information in the layout tree.

 

  Stratified

  Now that we have the layout of the tree, and the specific location of each element of information is calculated, then, is it time to begin working to draw up page?

  The answer is still no.

  Because the page has many complex effects, such as some complex 3D transformation, page scrolling, or use the z-indexing make z-sorting, in order to more easily achieve these effects, the rendering engine also need to generate special view of a particular node layer, and generates a corresponding layer tree (LayerTree). If you are familiar with PS, I believe you will be very easy to understand the concept of layers, it is these layers superimposed together to form the final page image.

 

  To understand what is intuitively layers, you can open the "Developer Tools" Chrome, and select "Layers" tab, you can visualize stratification of the page, as shown below:

Page rendering engine to multi-layered schematic

 

  As can be seen from the figure, points to the page rendering engine many layers, these layers is superimposed in a certain order together to form the final page, you can refer to the following:

The final page shows Overlay

 

  现在你知道了浏览器的页面实际上被分成了很多图层,这些图层叠加后合成了最终的页面。下面我们再来看看这些图层和布局树节点之间的关系,如文中图所示:

布局树和图层树关系示意图

  通常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。如上图中的 span 标签没有专属图层,那么它们就从属于它们的父节点图层。但不管怎样,最终每个节点都会直接或者间接地从属于一个层。

 

  那么需要满足什么条件,渲染引擎才会为特定的节点创建新的层呢?通常满足下面两点中任意一点的元素就可以被提升为单独的一个图层。

 

  第一点,拥有图层上下文属性的元素会被提升为单独的一层。

 

  页面是个二维平面,但是层叠上下文能够让 HTML 元素具有三维概念,这些 HTML 元素按照自身属性的优先级分布在垂直于这个二维平面的 Z 轴上。你可以结合下图来直观感受下:

层叠上下文示意图

  从图中可以看出,明确定位属性的元素、定义透明属性的元素、使用 CSS 滤镜的元素等,都拥有层叠上下文属性。

 

  若你想要了解更多层叠上下文的知识,你可以参考这篇文章

 

  第二点,需要裁剪(clip)的地方也会被创建为图层。

 

  不过首先你需要了解什么是裁剪,结合下面的 HTML 代码:

<style>
    div {
        width: 200;
        height: 200;
        overflow: auto;
        background: gray;
    }
</style>

<body>
    <div>
        <p>所以元素有了层叠上下文的的属性或者需要被裁剪,那么就会被提升成为单独一层,你可以参考……</p>
        <p>从上图我们可以看到,document层上有A和B层,而B层之上又有两个图层。这些图层组织在一起也是一颗树状结构。</p>
        <p>图层树是基于布局树来创建的,为了找出哪些元素需要在哪些层中,渲染引擎会遍历布局树来创建层树(Update LayerTree)。</p>
    </div>
</body>

  在这里我们把 div 的大小限定为 200 * 200 像素,而 div 里面的文字内容比较多,文字所显示的区域肯定会超出 200 * 200 的面积,这时候就产生了裁剪,渲染引擎会把裁剪文字内容的一部分用于显示在 div 区域,下图是运行时的执行结果:

裁剪执行结果

  出现这种裁剪情况的时候,渲染引擎会为文字部分单独创建一个层,如果出现滚动条,滚动条也会被提升为单独的层。你可以参考下图:

被裁减的内容会出现在单独一层

  所以说,元素有了层叠上下文的属性或者需要被裁剪,满足这任意一点,就会被提升为单独一层。

 

图层绘制

  在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制,那么接下来我们看看渲染引擎是怎么实现图层绘制的?

 

  试想一下,如果给你一张纸,让你先把纸的背景涂成蓝色,然后在中间位置画一个红色的圆,最后再在圆上画个绿色三角形。你会怎么操作?

  通常,你会把你绘制操作分解为散步:

  1. 绘制蓝色背景;

  2. 在中间绘制一个红色的圆;

  3. 再在圆上绘制绿色三角形。

  渲染引擎实现图层的绘制与之类似,会把一个图层的绘制分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表,如下图所示:

绘制列表

  从图中可以看出,绘制列表中的指令其实非常简单,就是让其执行一个简单的绘制操作,比如绘制粉色矩形或者黑色的线等。而绘制一个元素通常需要好几条绘制指令,因为每个元素的背景、前景、边框都需要单独的指令去绘制。所以在图层绘制阶段,输出的内容就是这些带绘制列表。

 

  你也可以打开 “开发者工具” 的 “Layers” 标签,选择 “document” 层,来实际体验下绘制列表,如下图所示:

一个图层的绘制列表

  在该图中,区域 1 就是 document 的绘制列表,拖动区域 2 中的进度条可以重现绘制的绘制过程。

 

栅格化(raster)操作

  绘制列表只是用来记录绘制记录和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。你可以结合下图来看下渲染主线程和合成线程之间的关系:

渲染经常中的合成线程和主线程

  如上图所示,当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)结合成线程,那么接下来合成线程是怎么工作的呢?

 

  那么我们得先来看看什么是视口,你可以参考下图:

视口

  通常一个页面可能很大,但是用户只能看到其中的一部分,我们把用户可以看到的这个部分叫做 视口(viewport)。

  

  在有些情况下,有的图层可能很大,比如有的页面你使用滚动条要滚动好久才能滚动到底部,但是通过视口,用户只能看到页面的很小一部分,所以在这种情况下,要绘制出所有图层内容的话,就会产生太大的开销,而且也没有必要。

 

  基于这个原因,合成线程会将图层划分为图块(tile),这些图块的大小通常是 256 * 256 或者 512 * 512,如下图所示:

图层被划分为图块示意图

  然后合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的,运行方式如下图所示:

合成线程提交图块给栅格化线程池

 

Guess you like

Origin www.cnblogs.com/bala/p/12121590.html