关于前端:浏览器之渲染引擎WebKit

10次阅读

共计 3837 个字符,预计需要花费 10 分钟才能阅读完成。

前言

一探浏览器幕后的《三俩事》上一篇的介绍让大家对浏览器的组成有了个含糊的意识:

  1. 浏览器是什么?
  2. 浏览器 (chromium) 根本架构
  3. 浏览器次要组件
  4. 浏览器内核是什么?
  5. JavaScript(js)引擎
  6. 渲染引擎

明天呢做渲染模块 (WebKit) 开展学习探讨。

首先作为程序介绍来说。我应该具体介绍实现一个浏览器应该蕴含哪些内容 (介绍一下chromium 实现蕴含了哪些内容)。然而思考在 前端 话题的介绍。只做简略的列举不做具体展开讨论; 有趣味能够自行上来学习。

其次按大家耳熟能详的水平来说的话我应该着重讨论一下 JS 引擎(V8 event-loop 相干); 然而本节内容还是想先介绍讨论一下 渲染引擎 (WebKit)。不为别的我就是喜爱玩~ 因为我写这个系列的受众还是偏差前端, 所以波及到须要代码染指解说的局部这边采取JavaScript 来实现。

渲染引擎

画架构图画习惯了, 不要在意俊俏的细节 – -.
由上图能够失去渲染引擎外部解析执行大略过程的信息:

  1. 当拜访页面的时候会进行网络申请 (network) 去获取页面的内容; 当如果命中缓存 (cache) 就会从存储 (memory) 上间接读取。
  2. HTMLParser 进行 html 解析通过特定标识进行分块。可解析为 CSS DOM JS 几个模块。
  3. CSSParser 进行 css 也是解析。
  4. DOMParser 进行 DOM 构造解析。(构建过程中发现是 JS 局部执行 5, 如果是资源进行异步申请. 不会妨碍解析)。
  5. JavaScript 局部丢给 JS 引擎进行解析。(如果有操作 DOM/CSS 局部会影响之前的解析, 同时会妨碍解析)。
  6. 通过上文解析内容构建 RenderTree。
  7. 解析实现通过 renderTree 进行布局和绘制。
  8. 将最终图像显示在屏幕上。

上面对于上文所提局部进行展开讨论一下 flow me~ gogogo!


Parser 解析

下面 Parser 的字眼是不是太多了。咱们失去一个信息解析是渲染引擎中十分重要的一个环节,所以首先须要介绍一下解析.

解析文档是指将文档转化成为有意义的构造,也就是可让代码了解和应用的构造。解析失去的后果通常是代表了文档构造的节点树,它称作解析树或者语法树。

解析是以文档所遵循的语法规定(编写文档所用的语言或格局)为根底的。比方说 HTML 解析那么是在 HTML4/ 5 的标准上进行的。所有能够解析的格局都必须对应确定的语法(由词汇和语法规定形成)。

解析过程通常是分成两个子过程:词法剖析和语法分析
词法剖析 是将输出内容宰割成大量标记的过程。(进行切分可辨认大量标记的词段)语法分析 是利用语言的语法规定的过程(到底这段语言是要做什么工作)。

HTMLParser

HTML 解析器的工作是将 HTML 标记解析成解析树。

HTML 语法定义:
HTML 的词汇和语法在 W3C 组织创立的标准中进行了定义。

DOM
解析器的输入“解析树”是由 DOM 元素和属性节点形成的树结构。DOM 是文档对象模型 (Document Object Model) 的缩写。它是 HTML 文档的对象示意,同时也是内部内容 (例如 JavaScript) 与 HTML 元素之间的接口。
解析树的根节点是 Document 对象。

DOM 解析 code 示意(不能运行的) 首先要理解解析过程肯定是迭代过程:

// 剖析标记 <> 和属性的正则表达式
    var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[\w-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/,
        endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/,
        attr = /([-A-Za-z0-9_]+)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g;
    function ParserHTML(html){
         // 接管参数 html
        while(html){

            // 匹配正文内容
            if(html.indexOf("<!--") == 0){//}
            // 匹配开始标签
            if (html.indexOf("<") == 0) {match = html.match(startTag);

                if (match) {html = html.substring(match[0].length); // 匹配截取
                  // 持续迭代
                }
           }
           if(html.indexOf("</") == 0){// 匹配完结标签操作}

        }
    }
    // 输入示意构造
    {
        element:"",
        parentNode:{},
        childrenNode:{},
        content:"",
        ....
    }
    // 我之前写的找不到了 --, 大家能够试着去实现一下。有问题随时沟通 本示例正则可用。

CSSParser

CSS 解析同 HTML 不同中央是上下文无关的语法; 可通过很多解析器做解析。
词法语法(词汇)是针对各个标记用正则表达式定义的:

  • comment \/\*[^*]*\*+([^/*][^*]*\*+)*\/
  • num [0-9]+|[0-9]*"."[0-9]+
  • nonascii [\200-\377]
  • nmstart [_a-z]|{nonascii}|{escape}
  • nmchar [_a-z0-9-]|{nonascii}|{escape}
  • name {nmchar}+
  • ident {nmstart}{nmchar}*
  • 通过 CSS 语法文件主动创立解析器, 会创立自下而上的移位归约解析器。会将 CSS 文件解析成 StyleSheet 对象,且每个对象都蕴含 CSS 规定。CSS 规定对象则蕴含选择器和申明对象,以及其余与 CSS 语法对应的对象。如下:

RenderTree

在 DOM 树构建的同时,浏览器还会构建另一个树结构:渲染树。这是由可视化元素依照其显示程序而组成的树,也是文档的可视化示意。它的作用是让您依照正确的程序绘制内容。

WebKits RenderObject 类是所有渲染树的基类,其定义如下:

class RenderObject{virtual void layout();  // 布局
  virtual void paint(PaintInfo);  // 绘制
  virtual void rect repaintRect(); // 从新绘制 Rect
  Node* node;  // DOM 节点
  RenderStyle* style;  // 计算 render style
  RenderLayer* containgLayer; //render layer 
}
渲染树和 DOM 树的关系

渲染树是和 DOM 元素绝对应的,但并非一一对应。非可视化的 DOM 元素不会插入渲染树中,例如“head”元素。如果元素的 display 属性值为“none”,那么也不会显示在渲染树中(然而 visibility 属性值为“hidden”的元素仍会显示)。

对于多渲染树的例子是格局有效的 HTML。依据 CSS 标准,inline 元素只能蕴含 block 元素或 inline 元素中的一种。如果呈现了混合内容,则应创立匿名的 block 渲染树,以包裹 inline 元素。

有一些渲染对象对应于 DOM 节点,但在树中所在的地位与 DOM 节点不同。浮动定位和相对定位的元素就是这样,它们处于失常的流程之外,搁置在树中的其余中央,并映射到真正的框架,而放在原位的是占位框架。

布局

创立实现渲染树时,并不蕴含地位和大小信息。计算这些值的过程称为布局或重排。

HTML 采纳基于流的布局模型,这意味着大多数状况下只有一次遍历就能计算出几何信息。处于流中靠后地位元素通常不会影响靠前地位元素的几何特色,因而布局能够按从左至右、从上至下的程序遍历文档。然而也有例外情况,比方 HTML 表格的计算就须要不止一次的遍历 (3.5)。

坐标系是绝对于根框架而建设的,应用的是上坐标和左坐标。

布局是一个递归的过程。它从根渲染树(对应于 HTML 文档的 <html> 元素)开始,而后递归遍历局部或所有的框架层次结构,为每一个须要计算的渲染树计算几何信息。

根渲染树的地位左上角 是 0,0,(跟 canvas2D 坐标规定统一) 其尺寸为视口(也就是浏览器窗口的可见区域)。
所有的渲染树都有一个 layout 或者 reflow 办法,每一个渲染树将会调用其须要进行布局的子代的 layout 办法。

绘制

在绘制阶段,零碎会遍历渲染树,并调用渲染树的 paint 办法,将渲染树的内容显示在屏幕上。绘制工作是应用用户界面根底组件实现的。

绘制的程序其实就是元素进入堆栈款式上下文的程序; 从后向前。块渲染树的堆栈程序如下:

  1. 背景色彩
  2. 背景图片
  3. 边框
  4. 子代
  5. 轮廓

绘制实现可参考canvas(canvas 肯定要学的啊 时刻关注一些前沿的动作), 理解根底图元绘制办法与过程。例如绘制line(须要坐标 根底图元构造等等):

图片起源

最初

间隔上一篇文章的生存日记: 20210521 那天呢照样开心(朋友圈仍旧不沉闷)。20210522 呢不开心。20210523 也就是明天总的来说过得去 并没有学习。(劳逸结合 哈哈)

而后呢因为最近有人总微信我编程范式到底抉择哪种好一点呢? 我当初用的更多是什么编程范式呢? 本人写代码保护起来好艰难怎么办呢?… (做了很久的解答, 应该记录下来提供给大家)下期 JS 引擎之前 我会把编程范式做一个简略介绍供大家参考 小小插曲(预计今天)。

加油!有问题请大家随时留言, 看到肯定会回复的。对于上篇补架构图 … 好吧是我鸽了 我看也没人催.. 懒得画了

相干参考

  1. CSS 的词法和语法
  2. 解决模型
  3. WebCore Rendering
  4. WebKit 官网
  5. WebKit 介绍
  6. canvas 相干
正文完
 0