浏览器渲染引擎学习总结
生活随笔
收集整理的這篇文章主要介紹了
浏览器渲染引擎学习总结
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
簡(jiǎn)單介紹瀏覽器渲染引擎情況
? ?很多人就只會(huì)用瀏覽器,不知道瀏覽器的工作原理或者說(shuō)瀏覽器最核心的東西,瀏覽器的內(nèi)核是最核
心的東西,也叫做渲染引擎,那這個(gè)東西到底是干嘛的呢,下面本教程就為大家好好介紹一下:
l 主流瀏覽器內(nèi)核介紹
主流瀏覽器內(nèi)核分類:瀏覽器內(nèi)核種類繁多,商用的加上非商業(yè)的免費(fèi)內(nèi)核,大約有10款以上甚至
更多,不過(guò)通常比較常見(jiàn)的大約只有以下4種,下面就簡(jiǎn)單介紹一下。
(1)Trident
Trident(又稱為MSHTML),是微軟的Windows搭載的網(wǎng)頁(yè)瀏覽器——Internet?
Explorer瀏覽器使用的內(nèi)核(俗稱IE內(nèi)核),該內(nèi)核程序在1997年的IE?
4中首次被采用,之后不斷地加入新的技術(shù)并隨著新版本的IE發(fā)布。Trident實(shí)際上是一款開(kāi)放的內(nèi)核,
Trident引擎被設(shè)計(jì)成一個(gè)軟件組件(模塊),使得其他軟件開(kāi)發(fā)人員很容易將網(wǎng)頁(yè)瀏覽功能加到他們自行
開(kāi)發(fā)的應(yīng)用程序里,其接口內(nèi)核設(shè)計(jì)相當(dāng)成熟,因此才涌現(xiàn)出許多采用IE內(nèi)核而非IE的瀏覽器(如
Maxthon、軟媒的閃游瀏覽器、騰訊的TT、GreenBrowser等),但是Trident只能用于Windows平臺(tái)。
由于IE本身的“壟斷性”而使得Trident內(nèi)核在很長(zhǎng)時(shí)間內(nèi)都是一家獨(dú)大,微軟也在相當(dāng)長(zhǎng)一段時(shí)間
內(nèi)都沒(méi)有更新Trident內(nèi)核,這就導(dǎo)致了兩個(gè)后果——一是Trident內(nèi)核曾經(jīng)幾乎與W3C標(biāo)準(zhǔn)脫節(jié);二是
Trident內(nèi)核的大量Bug等安全性問(wèn)題沒(méi)有得到及時(shí)解決。目前,微軟對(duì)Trident排版引擎做了重大變動(dòng),
除了加入新的技術(shù)之外,還增加了對(duì)網(wǎng)頁(yè)標(biāo)準(zhǔn)的支持。盡管這些變動(dòng)已經(jīng)在相當(dāng)大的程度上落后了其他
的排版引擎,如Gecko、WebCore、KHTML及Presto。
(2)Gecko
Gecko是開(kāi)放源代碼、以C++編寫(xiě)的網(wǎng)頁(yè)排版引擎,目前被Mozilla家族網(wǎng)頁(yè)瀏覽器以及Netscape?
6以后版本瀏覽器所使用。這款軟件原本是由網(wǎng)景通訊公司開(kāi)發(fā)的,現(xiàn)在則由Mozilla基金會(huì)維護(hù)。由于
Gecko的特點(diǎn)是代碼完全公開(kāi),因此,其可開(kāi)發(fā)程度很高,全世界的程序員都可以為其編寫(xiě)代碼,增加功
能。因?yàn)檫@是個(gè)開(kāi)源內(nèi)核,因此受到許多人的青睞,采用Gecko內(nèi)核的瀏覽器也很多,這也是Gecko內(nèi)核
雖然年輕但市場(chǎng)占有率能夠迅速提高的重要原因。
Gecko排版引擎提供了一個(gè)豐富的程序界面以供與互聯(lián)網(wǎng)相關(guān)的應(yīng)用程序使用,例如網(wǎng)頁(yè)瀏覽器、
HTML編輯器、客戶端/服務(wù)器等。雖然最初的主要對(duì)象是Mozilla的衍生產(chǎn)品,如Netscape和Mozilla?
Firefox,但是現(xiàn)在已有很多其他軟件利用這個(gè)排版引擎。此外Gecko也是一個(gè)跨平臺(tái)內(nèi)核,可以在
Windows、BSD、Linux和Mac OS X中使用。 ?
========
瀏覽器是怎樣工作的:渲染引擎,HTML解析(連載二)
渲染引擎渲染引擎的職責(zé)是……渲染,也就是把請(qǐng)求的內(nèi)容顯示到瀏覽器屏幕上。
默認(rèn)情況下渲染引擎可以顯示HTML,XML文檔以及圖片。 通過(guò)插件(瀏覽器擴(kuò)展)它可以顯示其它類型
文檔。比如使用PDF viewer插件顯示PDF文件。我們會(huì)在一個(gè)專門(mén)的章節(jié)討論插件與擴(kuò)展。在這一節(jié)我們
將專注渲染引擎的主要用途——顯示用CSS格式化的HTML與圖片。
各種渲染引擎
我們提到的Firefox, Safari兩種瀏覽器構(gòu)建于兩種渲染引擎之上:Firefox使用Gecko —— Mozilla自
家的渲染引擎;Safari 和 Chrome 都使用 Webkit。
Webkit 是一個(gè)開(kāi)源的渲染引擎,它源自Linux平臺(tái)上的一個(gè)引擎,經(jīng)過(guò)Apple公司的修改可以支持Mac與
Windows平臺(tái)。更多信息可以參考: http://webkit.org/ 。
主要流程
渲染引擎開(kāi)始于從網(wǎng)絡(luò)層獲取請(qǐng)求內(nèi)容,一般是不超過(guò)8K的數(shù)據(jù)塊。接下來(lái)就是渲染引擎的基本工作流
程:
圖 2:渲染引擎的基本工作流程(解析HTML構(gòu)建DOM樹(shù),渲染樹(shù)構(gòu)建,渲染樹(shù)布局,繪制渲染樹(shù)
)。
渲染引擎會(huì)解析HTML文檔并把標(biāo)簽轉(zhuǎn)換成內(nèi)容樹(shù)中的DOM節(jié)點(diǎn)。它會(huì)解析style元素和外部文件中
的樣式數(shù)據(jù)。樣式數(shù)據(jù)和HTML中的顯示控制將共同用來(lái)創(chuàng)建另一棵樹(shù)——渲染樹(shù)。
渲染樹(shù)包含帶有顏色,尺寸等顯示屬性的矩形。這些矩形的順序與顯示順序一致。
渲染樹(shù)構(gòu)建完成后就是”布局“處理,也就是確定每個(gè)節(jié)點(diǎn)在屏幕上的確切顯示位置。 下一個(gè)步驟是?
繪制 —— 遍歷渲染樹(shù)并用UI后端層將每一個(gè)節(jié)點(diǎn)繪制出來(lái)。
一定要理解這是一個(gè)緩慢的過(guò)程,為了更好的用戶體驗(yàn),渲染引擎會(huì)嘗試盡快的把內(nèi)容顯示出來(lái)。它不
會(huì)等到所有HTML都被解析完才創(chuàng)建并布局渲染樹(shù)。它會(huì) 在處理后續(xù)內(nèi)容的同時(shí)把處理過(guò)的局部?jī)?nèi)容
先展示出來(lái)。
主要流程示例
圖 3:Webkit主要流程
圖 4:Mozilla的Gecko渲染引擎主要流程(3.6)
從圖3和圖4中可以看出,盡管Webkit與Gecko使用略微不同的術(shù)語(yǔ),這個(gè)過(guò)程還是基本相同的。
Gecko 里把格式化好的可視元素稱做“幀樹(shù)”(Frame tree)。每個(gè)元素就是一個(gè)幀(frame)。?
Webkit 則使用”渲染樹(shù)”這個(gè)術(shù)語(yǔ),渲染樹(shù)由”渲染對(duì)象”組成。Webkit 里使用”layout”表示元素
的布局,Gecko則稱為”Reflow”。Webkit使用”Attachment”來(lái)連接DOM節(jié)點(diǎn)與可視化信息以構(gòu)建渲染
樹(shù)。一個(gè)非語(yǔ)義上的小差別是Gecko在HTML與DOM樹(shù)之間有一個(gè)附加的層 ,稱作”content sink
”,是創(chuàng)建DOM對(duì)象的工廠。我們會(huì)討論流程中的每一部分。
解析
因?yàn)榻馕鍪卿秩疽嬷幸粋€(gè)很重要的處理,我們會(huì)講的略深入一些。讓我們從一個(gè)小的解析介紹開(kāi)始。
解析一個(gè)文檔意味著把它翻譯成有意義的結(jié)構(gòu)以供代碼使用。解析的結(jié)果通常是一個(gè)表征文檔的由節(jié)點(diǎn)
組成的樹(shù),稱為解析樹(shù)或句法樹(shù)。
示例——解析表達(dá)式”2 + 3 – 1″可以返回下面的樹(shù):
圖 5:數(shù)學(xué)表達(dá)式樹(shù)節(jié)點(diǎn)
語(yǔ)法
解析是基于文檔所遵循的語(yǔ)法規(guī)則——書(shū)寫(xiě)所用的語(yǔ)言或格式——來(lái)進(jìn)行的。每一種可以解析的格式必
須由確定的語(yǔ)法與詞匯組成。這被稱之為上下文無(wú)關(guān)語(yǔ)法。 人類語(yǔ)言并非此種語(yǔ)言,所以不能用常規(guī)的
解析技術(shù)來(lái)解析。
解析器——詞法分析器組合
解析器有兩個(gè)處理過(guò)程——詞法分析與句法分析。
詞法分析負(fù)責(zé)把輸入切分成符號(hào)序列,符號(hào)是語(yǔ)言的詞匯——由該語(yǔ)言所有合法的單詞組成。
句法分析是對(duì)該語(yǔ)言句法法則的應(yīng)用。
解析器通常把工作分給兩個(gè)組件——分詞程序負(fù)責(zé)把輸入切分成合法符號(hào)序列,解析程序負(fù)責(zé)按照句法
規(guī)則分析文檔結(jié)構(gòu)和構(gòu)建句法樹(shù)。詞法分析器知道如何過(guò)濾像空格,換行之類的無(wú)關(guān)字符。
圖 6:從源文檔到解析樹(shù)(文檔,詞法分析,句法分析,解析樹(shù))。
解析過(guò)程是交互式的。解析器通常會(huì)從詞法分析器獲取新符號(hào)并嘗試匹配句法規(guī)則。如果匹配成功,就
在句法樹(shù)上創(chuàng)建相應(yīng)的節(jié)點(diǎn),并繼續(xù)從詞法分析器獲取下一個(gè)符號(hào)。如果沒(méi)有匹配的規(guī)則,解析器會(huì)內(nèi)
部保存這個(gè)符號(hào),并繼續(xù)從詞法分析器獲取符號(hào),直到內(nèi)部保存的所有符號(hào)能夠成功匹配一個(gè)規(guī)則。如
果最終無(wú)法匹配,解析器會(huì)拋出異常。這意味著文檔無(wú)效,含有句法錯(cuò)誤。
轉(zhuǎn)換
多數(shù)情況下解析樹(shù)并非最終結(jié)果。解析經(jīng)常是為了從輸入文檔轉(zhuǎn)換成另外一種格式。比如編譯器要把源
碼編譯成機(jī)器碼,會(huì)首先解析成解析樹(shù),再把解析樹(shù)轉(zhuǎn)換成機(jī)器碼。
圖 7:編譯過(guò)程(源碼,解析,解析樹(shù),轉(zhuǎn)換,機(jī)器碼)。
解析示例
在圖5中我們構(gòu)建了一個(gè)數(shù)學(xué)表達(dá)式解析樹(shù)。讓我們來(lái)試著定義一個(gè)簡(jiǎn)單的數(shù)學(xué)語(yǔ)言并看看解析是如何進(jìn)
行的。
詞匯:我們的語(yǔ)言可以包含整數(shù),加號(hào)和減號(hào)。
句法:
句法塊由表達(dá)式,術(shù)語(yǔ)及操作符組成。
我們的語(yǔ)言可以包含任意數(shù)量表達(dá)式。
表達(dá)式定義為術(shù)語(yǔ)緊跟著操作符,再跟另外一個(gè)術(shù)語(yǔ)。
操作符是加號(hào)或減號(hào)。
術(shù)語(yǔ)可以是整數(shù)或表達(dá)式。
讓我們分析輸入”2 + 3 – 1″。
第一個(gè)符合規(guī)則的子字符串是”2″,根據(jù)規(guī)則#5它是一個(gè)術(shù)語(yǔ)。第二個(gè)匹配是”2 + 3″,符合第二條
規(guī)則——一個(gè)術(shù)語(yǔ)緊跟一個(gè)操作符再跟另外一個(gè)術(shù)語(yǔ)。下一個(gè)匹配出現(xiàn)在輸入結(jié)束時(shí)。”2 + 3 – 1″
是一個(gè)表達(dá)式,因?yàn)槲覀円阎?+3”是一個(gè)術(shù)語(yǔ),所以符合第二條規(guī)則。 “2 + + “不會(huì)匹配任何規(guī)
則,所以是無(wú)效的輸入。
詞法與句法的合法性定義
詞匯通常用正則表達(dá)式來(lái)表示。
比如我們的語(yǔ)言可以定義為:
INTEGER :0|[1-9][0-9]*
PLUS : +
MINUS: -
如你所見(jiàn),整型是由正則表達(dá)式定義的。
句法常用BNF格式定義,我們的語(yǔ)言被定義為:
expression := ?term ?operation ?term
operation := ?PLUS | MINUS
term := INTEGER | expression
我們說(shuō)過(guò)常規(guī)解析器只能解析上下文無(wú)關(guān)語(yǔ)法的語(yǔ)言。這種語(yǔ)言的一個(gè)直覺(jué)的定義是它的句法可以用BNF
完整的表達(dá)。其規(guī)范定義請(qǐng)參考 http://en.wikipedia.org/wiki/Context-free_grammar
解析器的類型
解析器有兩種基本類型——自上而下解析器和自下而上解析器。主觀上可以認(rèn)為自上而下的解析器從上
層句法結(jié)構(gòu)開(kāi)始嘗試匹配句法;自下而上的則從輸入開(kāi)始,慢慢轉(zhuǎn)換成句法規(guī)則,從底層規(guī)則開(kāi)始,直
到上層規(guī)則全部匹配。
讓我們看看這兩種解析器將怎樣解析我們的例子:
自上而下解析器從上層規(guī)則開(kāi)始,它會(huì)把”2 + 3″定義為表達(dá)式,然后定義”2 + 3 – 1″為表達(dá)式(
定義表達(dá)式的過(guò)程中也會(huì)匹配其它規(guī)則,但起點(diǎn)是最高級(jí)別規(guī)則)。
自下而上的解析器會(huì)掃描輸入,直到有匹配的規(guī)則,它會(huì)把輸入替換成規(guī)則。這樣一直到輸入結(jié)束。部
分匹配的規(guī)則會(huì)放入解析堆棧。
Stack Input
2 + 3 – 1
term + 3 – 1
term operation 3 – 1
expression – 1
expression operation 1
expression
這種自下而上的解析器叫作移位歸約解析器,因?yàn)檩斎氡幌蛴乙苿?dòng)(想象一下一個(gè)指針從指向輸入開(kāi)始逐
漸向右移動(dòng)) 并逐漸歸約到句法樹(shù)。
自動(dòng)創(chuàng)建解析器
有一些工具可以為你創(chuàng)建解析器,它們通常稱為解析器生成器。你只需要提供語(yǔ)法——詞匯與句法規(guī)則
——它就能生成一個(gè)可以工作的解析器。創(chuàng)建解析器需要對(duì)解析器有深入的了解,并且手動(dòng)創(chuàng)建一個(gè)優(yōu)
化的解析器并不容易,所以解析器生成工具很有用。
Webkit使用兩款知名的解析器生成工具:Flex用于創(chuàng)建詞法分析器,Bison用于創(chuàng)建解析器 (你也許會(huì)看
到它們以Lex和Yacc的名字存在)。Flex的輸入文件是符號(hào)的正則表達(dá)式定義,Bison的輸入文件是BNF
格式的句法定義。
HTML解析器
HTML解析器的工作是解析HTML標(biāo)記到解析樹(shù)。
HTML語(yǔ)法定義
HTML的詞匯與句法定義在w3c組織創(chuàng)建的規(guī)范中。當(dāng)前版本是HTML4,HTML5的工作正在進(jìn)行中。
不是上下文無(wú)關(guān)語(yǔ)法
在對(duì)解析器的介紹中看到,語(yǔ)法可以用類似BNF的格式規(guī)范地定義。不幸的是所有常規(guī)解析器的討論
都不適用于HTML(我提及它們并不是為了娛樂(lè),它們可以用于解析CSS和JavaScript)。HTML無(wú)法用
解析器所需的上下文無(wú)關(guān)的語(yǔ)法來(lái)定義。過(guò)去HTML格式規(guī)范由DTD (Document Type Definition)來(lái)定義
,但它不是一個(gè)上下文無(wú)關(guān)語(yǔ)法。
HTML與XML相當(dāng)接近。XML有許多可用的解析器。HTML還有一個(gè)XML變種叫XHTML,那么它們主要區(qū)別在哪
里呢?區(qū)別在于HTML應(yīng)用更加”寬容”,它容許你漏掉一些開(kāi)始或結(jié)束標(biāo)簽等。它整個(gè)是一個(gè)“軟”句
法,不像XML那樣嚴(yán)格死板。 總的來(lái)說(shuō)這一看似細(xì)微的差別造成了兩個(gè)不同的世界。一方面這使得HTML
很流行,因?yàn)樗菽愕腻e(cuò)誤,使網(wǎng)頁(yè)作者的生活變得輕松。另一方面,它使編寫(xiě)語(yǔ)法格式變得困難。
所以綜合來(lái)說(shuō),HTML解析并不簡(jiǎn)單,現(xiàn)成的上下文相關(guān)解析器搞不定,XML解析器也不行。
HTML DTD
HTML的定義使用DTD文件。這種格式用來(lái)定義SGML族語(yǔ)言,它包含對(duì)所有允許的元素的定義,包括它們的
屬性和層級(jí)關(guān)系。如我們前面所說(shuō),HTML DTD構(gòu)不成上下文無(wú)關(guān)語(yǔ)法。
DTD有幾種不同類型。嚴(yán)格模式完全尊守規(guī)范,但其它模式為了向前兼容可能包含對(duì)早期瀏覽器所用標(biāo)簽
的支持。當(dāng)前的嚴(yán)格模式DTD:http://www.w3.org/TR/html4/strict.dtd
DOM
解析器輸出的樹(shù)是由DOM元素和屬性節(jié)點(diǎn)組成的。DOM的全稱為:Document Object Model。它是HT
ML文檔的對(duì)象化描述,也是HTML元素與外界(如Javascript)的接口。
DOM與標(biāo)簽幾乎有著一一對(duì)應(yīng)的關(guān)系,如下面的標(biāo)簽
<html>
<body>
<p>
Hello World
</p>
<div> <img src="example.png"/></div>
</body>
</html>
會(huì)被轉(zhuǎn)換成如的DOM樹(shù):
Figure 8: DOM tree of the example markup
?
與HTML一樣,DOM規(guī)范也由w3c組織制訂。參考:http://www.w3.org/DOM/DOMTR. 這是一個(gè)操作文檔的通
用規(guī)范。有一個(gè)專門(mén)的模塊定義HTML特有元素: http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-
20030109/idl-definitions.html.
當(dāng)我們說(shuō)樹(shù)中包含DOM節(jié)點(diǎn)時(shí),意思就是這個(gè)樹(shù)是由實(shí)現(xiàn)了DOM接口的元素組成。這些實(shí)現(xiàn)包含了
其它一些瀏覽器內(nèi)部所需的屬性。
解析算法
如我們前面看到的,HTML無(wú)法使用自上而下或自下而上的解析器來(lái)解析。
理由如下:
語(yǔ)言的寬容特點(diǎn)
瀏覽器需要對(duì)無(wú)效HTML提供容錯(cuò)性的事實(shí)。
解析過(guò)程的反復(fù)。通常解析過(guò)程中源碼不會(huì)變化。但在HTML中,script標(biāo)簽包含”document.write”時(shí)
可以添加內(nèi)容,即解析過(guò)程實(shí)際上還會(huì)改變?cè)创a。
瀏覽器創(chuàng)建了自己的解析器來(lái)解析HTML文檔。
HTML5規(guī)范里對(duì)解析算法有具體的說(shuō)明,解析由兩部分組成:分詞與構(gòu)建樹(shù)。
分詞屬于詞法分析部分,它把輸入解析成符號(hào)序列。在HTML中符號(hào)就是開(kāi)始標(biāo)簽,結(jié)束標(biāo)簽,屬性名稱
和屬生值。
分詞器識(shí)別這些符號(hào)并將其送入樹(shù)構(gòu)建者,然后繼續(xù)分析處理下一個(gè)符號(hào),直到輸入結(jié)束。
圖 6: HTML解析流程 (源自HTML5規(guī)范)
?
分詞算法
算法的輸出是HTML符號(hào)。算法可以用狀態(tài)機(jī)來(lái)描述。 每一個(gè)狀態(tài)從輸入流中消費(fèi)一個(gè)或多個(gè)字符,并根
據(jù)它們更新下一狀態(tài)。決策受當(dāng)前符號(hào)狀態(tài)和樹(shù)的構(gòu)建狀態(tài)影響。這意味著同樣的字符可能會(huì)產(chǎn)生不同
的結(jié)果,取決于當(dāng)前的狀態(tài)。算法太復(fù)雜,我們用一個(gè)例子來(lái)看看它的原理。
基礎(chǔ)示例,分析下面的標(biāo)簽:
<html>
<body>
Hello world
</body>
</html>
初始狀態(tài)是”Data state”,當(dāng)遇到”<“時(shí)狀態(tài)改為“Tag open state”。吃掉”a-z”字符組成的符
號(hào)后產(chǎn)生了”Start tag token”,狀態(tài)變更為“Tag name state”。我們一直保持此狀態(tài),直到遇到”
>”。每個(gè)字符都被追加到新的符號(hào)名上。在我們的例子中,解出的符號(hào)就是”html”。
當(dāng)碰到”>”時(shí),當(dāng)前符號(hào)完成,狀態(tài)改回“Data state”。”<body>”標(biāo)簽將會(huì)以同樣的方式處理。現(xiàn)
在”html”與”body”標(biāo)簽都完成了,我們回到“Data state”狀態(tài)。吃掉”H”(”Hello world”第
一個(gè)字母)時(shí)會(huì)產(chǎn)生一個(gè)字符符號(hào),直到碰到”</body>”的”<“符號(hào),我們就完成了一個(gè)字符符
號(hào)”Hello world”。
現(xiàn)在我們回到“Tag open state”狀態(tài)。吃掉下一個(gè)輸入”/”時(shí)會(huì)產(chǎn)生一個(gè)”end tag token”并變更
為“Tag name state”狀態(tài)。同樣,此狀態(tài)保持到我們碰到”>”時(shí)。這時(shí)新標(biāo)簽符號(hào)完成,我們又回到
“Data state”。同樣”</html>”也會(huì)被這樣處理。
圖 9: 示例輸入源的分詞處理
?
樹(shù)的構(gòu)建算法
當(dāng)解析器被創(chuàng)建時(shí),文檔對(duì)象也被創(chuàng)建了。在樹(shù)的構(gòu)建過(guò)程中DOM樹(shù)的根節(jié)點(diǎn)(Documen)將被修改,元
素被添加到上面去。每個(gè)分詞器完成的節(jié)點(diǎn)都會(huì)被樹(shù)構(gòu)建器處理。規(guī)范中定義了每一個(gè)符號(hào)與哪個(gè)DOM對(duì)
象相關(guān)。除了把元素添加到DOM樹(shù)外,它還會(huì)被添加到一個(gè)開(kāi)放元素堆棧。這個(gè)堆棧用于糾正嵌套錯(cuò)誤和
標(biāo)簽未關(guān)閉錯(cuò)誤。這個(gè)算法也用狀態(tài)機(jī)描述,它的狀態(tài)叫做”insertion modes”。
讓我們看看下面輸入的樹(shù)構(gòu)建過(guò)程:
<html>
<body>
Hello world
</body>
</html>
樹(shù)的構(gòu)建過(guò)程中,輸入就是分詞過(guò)程中得到的符號(hào)序列。第一個(gè)模式叫“initial mode”。接收 html?
符號(hào)后會(huì)變成“before html”模式并重新處理此模式中的符號(hào)。這會(huì)創(chuàng)建一個(gè)HTMLHtmlElement元素并
追加到根文檔節(jié)點(diǎn)。
然后狀態(tài)改變?yōu)椤癰efore head”。我們收到”body”時(shí),會(huì)隱式創(chuàng)建一個(gè)HTMLHeadElement,盡管我們
沒(méi)有這個(gè)標(biāo)簽,它也會(huì)被創(chuàng)建并添加到樹(shù)中。
現(xiàn)在我們進(jìn)入“in head”模式,然后是“after head”,Body會(huì)被重新處理,創(chuàng)建HTMLBodyElement元
素并插入,然后進(jìn)入“in body”模式。
字符符號(hào)”Hello world”收到后會(huì)創(chuàng)建一個(gè)”Text”節(jié)點(diǎn),所有字符都被一一追加到上面。
收到body結(jié)束標(biāo)簽后進(jìn)入 “after body” 模式,收到html結(jié)束標(biāo)簽后進(jìn)入“after after body”模式
。所有符號(hào)處理完后將終止解析。
圖 10: 示例HTML樹(shù)的構(gòu)建
解析結(jié)束后的動(dòng)作
在這一階段瀏覽器會(huì)把文檔標(biāo)記為交互模式,并開(kāi)始解析deferred模式的script。”deferred”意味著
腳本應(yīng)該在文檔解析完成后執(zhí)行。腳本處理完成后將進(jìn)入”complete”狀態(tài),”load”事件發(fā)生。
HTML5規(guī)范中包含了完整的算法: http://www.w3.org/TR/html5/syntax.html#html-parser
瀏覽器的容錯(cuò)
你永遠(yuǎn)不會(huì)看到HTML頁(yè)面語(yǔ)法錯(cuò)誤。瀏覽器會(huì)修正錯(cuò)誤并繼續(xù)。看看下面的例子:
<html>
? <mytag>
? </mytag>
? <div>
? <p>
? </div>
? Really lousy HTML
? </p>
</html>
我一定違背了幾百萬(wàn)條規(guī)則(”my tag”是非法標(biāo)簽,”p”與”div”元素嵌套錯(cuò)誤等等),但瀏覽器
仍然正確地顯示,沒(méi)有任何抱怨。所以很多解析器代碼在修正這些HTML作者的錯(cuò)誤。
瀏覽器的錯(cuò)誤處理相當(dāng)統(tǒng)一,驚人的是這并不是當(dāng)前HTML規(guī)范的一部分,就像書(shū)簽、前進(jìn)、后退,只是
多年以來(lái)在瀏覽器中開(kāi)發(fā)出來(lái)的。有些無(wú)效的HTML結(jié)構(gòu)出現(xiàn)在許多網(wǎng)站,瀏覽器會(huì)嘗試用和其它各種瀏
覽器一致的方式修復(fù)這些錯(cuò)誤。
HTML5規(guī)范中應(yīng)這一需求定義了一些東西,Webkit在它的HTML解析器類開(kāi)頭的注釋中很好的做了摘要:
解析器分析輸入符號(hào)生成文檔,并構(gòu)建文檔樹(shù)。如果文檔格式良好,解析工作會(huì)很簡(jiǎn)單。
不幸的是,我們要處理很多格式不良的HTML文檔,解析器需要寬容這些錯(cuò)誤。
我們至少需要照顧下列錯(cuò)誤:
1. 元素必需被插入在正確的位置。未關(guān)閉的標(biāo)簽應(yīng)該一一關(guān)閉,直到可以添加新元素。
2. 不允許直接添加元素。用戶可能會(huì)漏掉一些標(biāo)簽,比如:HTML HEAD BODY TBODY TR TD LI(我遺漏
了什么?)。
3. 在inline元素里添加block元素時(shí),應(yīng)關(guān)閉所有inline元素,再添加block元素。
4. 如果以上不起作用,關(guān)閉所有元素,直到可以添加,或者忽略此標(biāo)簽。
讓我們來(lái)看一些Webkit容錯(cuò)的例子:
使用</br>代替<br>
有些站點(diǎn)使用</br>而不是<br>。為了更好的與IE和Firefox兼容,Webkit將其視為<br>。代碼如下:
if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
? ? ?reportError(MalformedBRError);
? ? ?t->beginTag = true;
}
注意,這里的錯(cuò)誤處理是內(nèi)部的,并不會(huì)顯示給用戶。
迷失的表格
像下面的例子這樣,一個(gè)表格包含在另外一個(gè)表格的內(nèi)容中,但不是在外部表格的單元格里:
<table>
<table>
<tr><td>inner table</td></tr>
? ? ? ? ?</table>
<tr><td>outer table</td></tr>
</table>
Webkit會(huì)改變層級(jí)關(guān)系,把它們處理成兩個(gè)相臨的表格:
<table>
<tr><td>outer table</td></tr>
</table>
<table>
<tr><td>inner table</td></tr>
?</table>
代碼:
if (m_inStrayTableContent && localName == tableTag)
? ? ? ? popBlock(tableTag);
Webkit用一個(gè)堆棧保存當(dāng)前元素,它會(huì)把里面的表格彈出到外部表格堆棧,使它們成為兄弟表格。
元素嵌套
為防止一表單的嵌套,第二個(gè)表單會(huì)被忽略。代碼:
if (!m_currentFormElement) {
? ? ? ? m_currentFormElement = new HTMLFormElement(formTag, ? ?m_document);
}
過(guò)深的元素層級(jí)
注釋不言自喻:
www.liceo.edu.mx是一個(gè)層級(jí)過(guò)深的典型,它用大量的<b>嵌套到1500個(gè)標(biāo)簽的深度。我們只允許同一標(biāo)
簽連續(xù)出現(xiàn)20次,超過(guò)的話,所有此標(biāo)簽都會(huì)被忽略。
bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{
unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
? ? ? ? ?i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
? ? ?curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}
錯(cuò)誤的html或body結(jié)束標(biāo)簽位置
注釋仍然很明了:
支持真正的錯(cuò)誤html
我們永遠(yuǎn)不關(guān)閉tag,因?yàn)橛行┯薮赖木W(wǎng)頁(yè)在文檔真正結(jié)束之前就關(guān)閉了它。
讓我們用end()來(lái)關(guān)閉標(biāo)簽。
if (t->tagName == htmlTag || t->tagName == bodyTag )
? ? ? ? return;
所以網(wǎng)頁(yè)作者們小心了,除非你想寫(xiě)一個(gè)Webkit容錯(cuò)的示例代碼,否則請(qǐng)按正確格式書(shū)寫(xiě)HTML。
========
了解瀏覽器如何工作—渲染引擎
從基礎(chǔ)架構(gòu)上我們也可以看到瀏覽器的重頭戲其實(shí)在于渲染引擎(又稱排版引擎),很多頁(yè)面兼容性問(wèn)題的根源可以說(shuō)也皆來(lái)源于此。好了,那我們深入到渲染引擎內(nèi)部仔細(xì)看一下吧。
從基礎(chǔ)架構(gòu)上我們也可以看到瀏覽器的重頭戲其實(shí)在于渲染引擎(又稱排版引擎),很多頁(yè)面兼容性問(wèn)題
的根源可以說(shuō)也皆來(lái)源于此。360瀏覽器HTML5跑分再高(http://html5test.com/),UI與交互再怎么不
一樣,內(nèi)核還是一樣的。好了,那我們深入到渲染引擎內(nèi)部仔細(xì)看一下吧。
渲染引擎(the rendering engine)簡(jiǎn)述
渲染引擎的職責(zé),正如字面上的意思就是負(fù)責(zé)從服務(wù)器端返回的HTML,XML,或者IMAGES等資源的渲染工
作并顯示給最終用戶。通過(guò)瀏覽器 插件(plug-in or browser extension)技術(shù),它也能顯示一些其他
文檔格式的資源,如PDF,后期的文章會(huì)針對(duì)這種技術(shù)進(jìn)行一下說(shuō)明,本章重點(diǎn)描述渲染引擎的首要功能
,即通 過(guò)渲染引擎顯示出經(jīng)過(guò)CSS樣式化的HTML和圖片結(jié)果。
前面已經(jīng)介紹過(guò),firefox,chrome,safari 包括了兩種渲染引擎,火狐瀏覽器使用gecko,safari跟
chrome(后來(lái)opera跟進(jìn))使用webkit. Webkit是一個(gè)開(kāi)源的渲染引擎,起初只能用于linux平臺(tái),后來(lái)
蘋(píng)果公司apple對(duì)其源代碼進(jìn)行了擴(kuò)展改造,使其能運(yùn)行與mac跟windows 平臺(tái),后起之秀chrome對(duì)其有
進(jìn)行了一些列擴(kuò)充與推廣,使其越來(lái)越成為標(biāo)準(zhǔn)流行的渲染網(wǎng)頁(yè)引擎,webkit詳細(xì)介紹可參見(jiàn)?
http://webkit.org/。
基本渲染過(guò)程
用戶請(qǐng)求的資源通過(guò)瀏覽器的網(wǎng)絡(luò)層到達(dá)渲染引擎后,渲染工作開(kāi)始。每次渲染文檔通常不會(huì)超過(guò)8K的
數(shù)據(jù)塊,其中基礎(chǔ)的渲染過(guò)程如下圖所示: ? ? ?
渲染引擎首先解析HTML文檔,轉(zhuǎn)換為一棵DOM樹(shù),此為第一步。接下來(lái)不管是內(nèi)聯(lián)式,外聯(lián)式還是嵌入式
引入的CSS樣式也會(huì)被解析,渲染出另 外一棵用于渲染DOM樹(shù)的樹(shù)-渲染樹(shù)(render tree) ,渲染樹(shù)包含
帶有顏色,尺寸等顯示屬性的矩形,這些矩形的順序與顯示順序一致。然后就是對(duì)渲染樹(shù)的每個(gè)節(jié)點(diǎn)進(jìn)
行布局處理,確定其在屏幕上的顯示位置。最后 就是遍歷渲染樹(shù)并用上一章提到的UI后端層將每一個(gè)
節(jié)點(diǎn)繪制出來(lái)。
以上步驟是一個(gè)漸進(jìn)的過(guò)程,為了提高用戶體驗(yàn),渲染引擎試圖盡可能快的把結(jié)果顯示給最終用戶。它
不會(huì)等到所有HTML都被解析完才創(chuàng)建并布局渲染樹(shù)。它會(huì)在從網(wǎng)絡(luò)層獲取文檔內(nèi)容的同時(shí)把已經(jīng)接
收到的局部?jī)?nèi)容先展示出來(lái)。
不同渲染引擎具體不同的渲染流程
上面只是介紹了渲染引擎一般的處理流程,針對(duì)不同的渲染引擎具體步驟可能有所不同,就拿常見(jiàn)的
webkit跟gecko來(lái)說(shuō)吧。
首先是webkit的詳細(xì)渲染流程:
火狐等瀏覽器的gecko渲染流程:
從上面兩幅圖可以看出,盡管兩者使用了不同的“專業(yè)術(shù)語(yǔ)”,但是從圖上可以看出,兩者的渲染過(guò)程
可謂大同小異,正是于此,我們可以再把具體的過(guò)程統(tǒng)一分離出來(lái),接下來(lái)的四章會(huì)根據(jù)四個(gè)主要渲染
過(guò)程進(jìn)行一下較為細(xì)致的說(shuō)明。
原文鏈接:http://www.cnblogs.com/luluping/archive/2013/04/05/3000461.html
========
各種瀏覽器的頁(yè)面渲染引擎簡(jiǎn)介
Trident頁(yè)面渲染引擎
Trident(又稱為MSHTML),是微軟的視窗操作系統(tǒng)(Windows)搭載的網(wǎng)頁(yè)瀏覽器—Internet Explorer
的頁(yè)面渲染引擎的名稱,
它的第一個(gè)版本誕生于1997年10月Internet Explorer第四版中,IE7做了的重大的變動(dòng),除了加入新的
技術(shù)之外,
并增加對(duì)網(wǎng)頁(yè)標(biāo)準(zhǔn)的支持,目前是互聯(lián)網(wǎng)上最流行的排版引擎。
使用Trident頁(yè)面渲染引擎的瀏覽器有
· Internet Explorer(IE)
· 傲游
· 世界之窗瀏覽器
· Avant
· 騰訊TT
· Netscape 8
· NetCaptor
· Sleipnir
· GOSURF
· GreenBrowser
· KKman
Gecko頁(yè)面渲染引擎
Gecko是套開(kāi)放源代碼的、以C++編寫(xiě)的頁(yè)面渲染引擎。Gecko是跨平臺(tái)的,
能在Microsoft Windows、Linux和Mac OS X等主要操作系統(tǒng)上運(yùn)行。
它是最流行的頁(yè)面渲染引擎之一,其流行程度僅次于Trident。
使用Gecko頁(yè)面渲染引擎的瀏覽器有
· Fennec
· Firefox
· 網(wǎng)景(6至9)
· SeaMonkey
· Camino
· Flock
· Galeon
· K-Meleon
· Minimo
· Mozilla
· Sleipnir
· Songbird
· XeroBank
KHTML頁(yè)面渲染引擎或WebKit框架
KHTML,是HTML頁(yè)面渲染引擎之一,由KDE所開(kāi)發(fā)。KHTML擁有速度快捷的優(yōu)點(diǎn),
但對(duì)錯(cuò)誤語(yǔ)法的容忍度則比Mozilla產(chǎn)品所使用的Gecko引擎小。蘋(píng)果電腦于2002年采納了KHTML,
作為開(kāi)發(fā)Safari瀏覽器之用。WebCore及WebKit引擎均是KHTML的衍生產(chǎn)品;
WebKit是 Mac OS X v10.3及以上版本所包含的軟件框架,WebKit是Mac OS X的Safari網(wǎng)頁(yè)瀏覽器的基礎(chǔ)
。
使用KHTML頁(yè)面渲染引擎的瀏覽器有
· Safari
· Konqueror
· Epiphany
· Google Chrome
· iCab
· OmniWeb
· Midori
· Shiira
Presto頁(yè)面渲染引擎
Presto是一個(gè)由Opera Software開(kāi)發(fā)的瀏覽器頁(yè)面渲染引擎,應(yīng)用于Opera 7.0~9.60版,
它取代了舊版Opera中所使用的Elektra頁(yè)面渲染引擎,包括加入動(dòng)態(tài)功能,
例如網(wǎng)頁(yè)或其部分可隨著DOM及Script語(yǔ)法的事件而重新排版。
使用Presto頁(yè)面渲染引擎的瀏覽器有
· Opera
· 任天堂DS瀏覽器
Java軟件平臺(tái)
Java,是一種可以撰寫(xiě)跨平臺(tái)應(yīng)用軟件的面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言,
Java 編程語(yǔ)言的風(fēng)格十分接近C++語(yǔ)言。微軟推出的.NET平臺(tái)以及模仿Java的C#語(yǔ)言正是與之競(jìng)爭(zhēng)下的
產(chǎn)物。
使用Java平臺(tái)的瀏覽器有
· HotJava
· Opera Mini
· UCWEB
Tasman頁(yè)面渲染引擎
Tasman,是微軟的Internet Explorer for Mac瀏覽器所使用的頁(yè)面渲染引擎,
也是為嘗試支援W3C所制定的網(wǎng)頁(yè)標(biāo)準(zhǔn)而設(shè)計(jì)的。在Mac版的Microsoft Office 2004中,
電子郵件客戶端Microsoft Entourage使用的就是Tasman頁(yè)面渲染引擎。
使用Tasman頁(yè)面渲染引擎的瀏覽器有
· Internet Explorer for Mac
· MSN for Mac OS X
文本界面
就是一些純文字式的網(wǎng)頁(yè)瀏覽器,在LINUX系統(tǒng)中比較常見(jiàn)。
使用文本界面的瀏覽器有
· Lynx
· Links
· w3m
手持設(shè)備或嵌入式系統(tǒng)
· Internet Explorer Mobile
· Minimo
· Opera Mobile
· PSP瀏覽器
其它頁(yè)面渲染引擎
· Amaya
· Dillo
· Mosaic
========
總結(jié)
以上是生活随笔為你收集整理的浏览器渲染引擎学习总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: dNet项目数据访问层代码总结
- 下一篇: 不同浏览器前端调试查看返回页面的json