zoukankan      html  css  js  c++  java
  • 理解WebKit和Chromium: WebKit布局 (Layout)

    转载请注明原文地址:http://blog.csdn.net/milado_nju/article/details/7854312

    # WebKit布局(layout)基础

    ## 概述

    一个网页从文本信息到最后的渲染结果,要经过很多复杂的过程,前面介绍过DOM树、Render树的创建,也阐述了页面如果被渲染的,其实,这两者中间还有一个非常重要的步骤――布局计算,这是因为在渲染每个元素之前,渲染引擎必须知道它的位置大小等布局信息,我们把计算这些信息的过程称之为布局。

    布局根据其计算的范围大致可以分为两类,第一类是对整个Render树进行的计算,第二类是对Render树中某个子树的计算,常见于文本元素或者是overflow:auto块的计算,这种情况一般是其子树布局的改变不会影响其周围元素的布局,因而不需要重新计算更大范围内的布局。

    按照惯例,为了便于表述,首先我们来看一个能够帮助理解问题的例子。这个例子不复杂,其重点是包含两个div元素,其中id为adiv的元素是类型为aclass元素的父亲。CSS样式设置了类型aclass的样式属性值。


    ## 箱子(box)模型

    先介绍箱子模型。CSS布局计算是基于箱子模型来进行的,其基本构成是一个矩形区域,包含了外边距(margin),内边距(padding),边框(border)和内容(content),也就是说每个元素的布局都是按照箱子模型来排布的,通过设置这些属性,达到特定的布局效果。如下图所示,最外层的虚线以内就是一个box模型的实例,这个实例表示的就是一个元素布局表示。


    这个图相信大家都看过,这里简单介绍一下。箱子最边缘部分分别是四个方向上的外边距(TM, RM, BM, LM),可以设置不同的大小,其次往内是四个方向上的边框(TB, RB, BB, LB),再次是四个方向上的内边距(TP, RP, BP, LB),最后是中间的内容。下面结合实例来解释,给人以直观印象,便于深入了解。下图就是本章开始时候介绍的示例在浏览器中的显示结果,最外边的矩形框就是ID为‘adiv’的div元素的显示区域,其内部就是对于属于’.aclass’的类型的div元素的box模型实例。旁边的标注表明了box模型的各个属性值,读者可以跟上面的箱子模型进行对照理解。


    例子中,文字被设置为‘A B C… T’,其表示的是内容区域,之所以设置成这样,是为了让布局随时可以换行,便于读者更清晰地看到内边距和内容区域。同样地,建议读者修改本章例子的各个参数,亲身体验这些设置带来的布局变化。

    介绍了箱子模型后,箱子内部的位置和大小可以被确定了,那么箱子本身的位置和大小是如何确定的?这就需要“包含块”的帮助了。

    ##Containing block(包含块)

    当需要计算元素的箱子的位置和大小的时候,需要计算它和另外一个矩形区域的相对位置,这个矩形区域称为该元素的包含块,箱子模型就是在包含块内计算和确定其一系列的属性值的,包含块的具体定义如下:

    1)      根元素的包含块称为初始包含块,通常它的大小就是可视区域(viewport)的大小。

    2)      对于其他位置属性设置为’static’或者’relative’元素,它的包含块就是的最近的祖先的箱子模型中的内容区域(content)。

    3)      如果元素的位置属性为’fixed’,其脱离文档,固定在可视区域的某个特定位置。

    4)      如果元素的位置属性为’absolute’,其包含块由最近的包含属性’absolute’, ‘relative’或者’fixed’的祖先决定,具体规则如下:

    a)        如果其是一个inline元素,那么元素的包含块是包含该祖先的第一个和最后一个inline盒子的内边距的区域。

    b)        否则,则是由该祖先的内边距所包围的区域。

    这个复杂的定义读起来比较让人头痛,webkit中简单理解起来就是:

    Render节点的包含块是该节点的负责决定该节点的祖先节点对应的块区域。根节点RenderView表示的就是”初始包含块”,其初始大小始终是可视区域的大小。

    结合实例来讲,类型为’aclass’的div元素的包含块就是父亲的内容区域,其箱子模型就是在该内容区域上进行计算生成得来的。

    ## 布局计算

    布局计算的相关信息都保存在RenderStyle对象中,如之前介绍,该对象属于Render节点。 RenderStyle没有什么特别之处,就是包含各个样式的属性值。同时,Render节点也包含一个位数组,该数组会保存一些用来表示是否需要重新计算布局等信息。

    下面看看如果计算布局的。其主要由RenderObject中的layout方法来完成:

    首先,layout函数会判断Render节点是否需要重新计算,通常这通过检查位数组中的相应标记位,子女是否需要计算布局等来确定。一般来说,初始显示,可视区域变化,样式值变化(例如动画,JavaScript操作样式值)等都会需要重新计算布局。

    其次,它会遍历其每一个子女节点,依次计算它们的布局。

    再次,对于每一个元素来说,它会实现自己的layout方法,根据特定的算法来计算该类型元素的布局。如果页面元素定义了其自己的宽高,那么webkit按照其定义的宽高来确定其大小,而对于象文本节点这样的Inline元素则需要结合其字体大小及文字的多少等来确定其对应的宽高。如果页面元素所确定的宽高超过了布局容器包含块所能提供的宽高,同时其overflow 属性为visible 或auto,则会提供滚动条来保证可以显示其所有内容。除非定义了页面元素的宽高,一般说来页面元素的宽高是在布局的时候通过相关计算得出来的。

    ## 布局测试(layouttests)

    渲染引擎要处理各式各样、越来越复杂的网页,这需要Layout测试来保证它的质量。

    Layout测试可以说是WebKit中最重要并且最著名的测试了。其基本测试工作方式是,预先准备很多很多的简单网页和期望的渲染结果,然后根据WebKit编译出来的DumpRenderTree(DRT)来测试网页,把得到的结果和期望的结果进行对比,以检查WebKit引擎的对网页排版布局等的正确性。每个WebKit的移植都会提供一个DumpRenderTree,通查由于移植的差异性,它们的期望结果也不一样,所以通常每个移植都有自己特殊的期望结果。

    每个测试都会有一个或者多个期望结果,一般地,期望结果是一些文本结果,但是,对一些复杂的测试,单纯的文本不能够满足需求,因为测试渲染结果可能需要比较布局,字体,图片等等,所以这时候期望结果其实是一幅图片(还有其他类型),这个图片其实就是网页应该渲染的结果。不幸的是,由于字体,平台的样式等差异性(例如Qt,GTK等就不一样),相同的网页渲染出的结果可能不一样,所以,你可以看到布局测试对不同的移植会有不同的期望结果。

    一般来讲,当开发者提交新的补丁时候,需要先进行布局测试,只有当该测试通过,才有可能被WebKit所接受。如果你提交的是解决了一个新问题,那么,建议你提交一个新的测试用例来保证代码的正确性。 

    ## 源文件目录

    third_party/WebKit/Source/WebCore/rendering/style

      渲染所需要的样式的支持类,其依赖于CSS解析器及其结果 

    ## 参考文献

    1.      http://www.webkit.org/projects/layout/index.html

    2.      http://www.w3.org/TR/CSS21/box.html#box-dimensions

    3.      http://www.webkit.org/blog/1452/layout-tests-theory/

    4.      http://www.webkit.org/blog/1456/layout-tests-practice/

    By yongsheng@chromium.org

  • 相关阅读:
    第四天 PYTHON 函数
    第四天 PYTHON 字符串格式化
    第四天 PYTHON 集合
    Linux使用sshfs挂载远程目录到本地
    linux通过安装包安装nginx和jdk
    使用ajax提交form表单,包括ajax文件上传
    Linux下mysql出错:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
    数据库连接池
    一台机器上安装两个tomcat
    mysql优化
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6313864.html
Copyright © 2011-2022 走看看