出處:http://www.cnblogs.com/jyli/archive/2010/01/31/1660355.html
作者:李嘉昱
研究Webkit內(nèi)核已經(jīng)有一段時(shí)間了,在這期間我花了很多時(shí)間去研讀webkit代碼,并在網(wǎng)上查閱了不少的資料。在這之后,我開(kāi)始嘗試對(duì)Webkit內(nèi)核進(jìn)行剪裁,以便得到自己所需的部分。
俗語(yǔ)有言,“獨(dú)學(xué)而無(wú)友 則孤陋而寡聞”,遂本著交流的態(tài)度拿出來(lái)與大家分享之,順便回顧一下自己這段時(shí)間以來(lái)走過(guò)的路。到目前,本人雖不能說(shuō)是精 通Webkit內(nèi)核 ,但也總算是在Webkit內(nèi)核中游歷過(guò)了一番,并獲得了不少Webkit內(nèi)核代碼的直接經(jīng)驗(yàn)。
在此,我將以Webkit內(nèi)核代碼為基礎(chǔ),詳細(xì)介紹Webkit內(nèi)核的組成以及其各個(gè)模塊的功能和實(shí)現(xiàn)。文章寫(xiě)到哪算哪,有了新的認(rèn)識(shí)也會(huì)更新,補(bǔ)充。
什么是Webkit
Wekbit是一個(gè)開(kāi)源的Web瀏覽器引擎,也就是瀏覽器的內(nèi)核。Apple的Safari, Google的Chrome, Nokia S60平臺(tái)的默認(rèn)瀏覽器,Apple手機(jī)的默認(rèn)瀏覽器,Android手機(jī)的默認(rèn)瀏覽器均采用的Webkit作為器瀏覽器內(nèi)核。Webkit的采用程度由 此可見(jiàn)一斑,理所當(dāng)然的成為了當(dāng)今主流的三大瀏覽器內(nèi)核之一。另外兩個(gè)分別是Gecko和Trident,大名鼎鼎的Firefox便是使用的Gecko 內(nèi)核,而微軟的IE系列則使用的是Trident內(nèi)核。雖然目前市場(chǎng)上IE內(nèi)核瀏覽器仍然占據(jù)大多數(shù)市場(chǎng)份額,但其他內(nèi)核瀏覽器也大有后來(lái)居上之勢(shì)。其 中,Webkit作為一款優(yōu)秀的瀏覽器內(nèi)核,它眾多優(yōu)秀的特性引起業(yè)內(nèi)的的廣泛關(guān)注。尤其是近來(lái),google的加入更是讓W(xué)ebkit有所升溫,從 Goole Chrome瀏覽器, Goole Anroid手機(jī)操作系統(tǒng)內(nèi)置瀏覽器均采用Webkit作為內(nèi)核, 近來(lái)推出的Chrome OS更是讓人期待。從實(shí)現(xiàn)角度來(lái)講,據(jù)說(shuō)其比Gecko代碼更為整潔清晰,我目前還沒(méi)研究過(guò)Gecko的代碼,所以還無(wú)從比較。
Wekbit做了什么?
作為瀏覽器的內(nèi)核,Webkit做了哪些工作?為了了解這些,先讓我們來(lái)看下一個(gè)Web瀏覽器究竟做了什么。我們可以從輸入輸出的角度來(lái)看一個(gè) Web瀏覽器為我們做了哪些工作。先看一個(gè)簡(jiǎn)單的例子,Web瀏覽器的輸入是一個(gè)HTML文檔,輸出則是一個(gè)我們用眼睛所看到的一個(gè)Web頁(yè)面, 就普通用戶(hù)而言它的輸入和輸出就是這么簡(jiǎn)單,如下圖所示。
那么Webkit的輸入和輸出又是什么呢?如果能明白這個(gè),那我們就能很清楚的知道Webkit到底是做什么的了。不過(guò)現(xiàn)在要說(shuō)清楚這個(gè)還有點(diǎn)困 難,因?yàn)閃ebkit的輸出就要復(fù)雜些了,因?yàn)樗妮敵霰緛?lái)就非直接面向用戶(hù),現(xiàn)在簡(jiǎn)單點(diǎn)來(lái)說(shuō),Webkit的輸入是web 文檔,輸出是一些看不見(jiàn)的模型,瀏覽器上層借助于這些模型來(lái)繪制出我們所看到的實(shí)際頁(yè)面。后面適當(dāng)?shù)臅r(shí)候會(huì)更具體的探討這些模型。
Wekbit組成
Webkit實(shí)際上包含三大部分,至少?gòu)拇a結(jié)構(gòu)上來(lái)說(shuō)是這樣的,當(dāng)然,如果細(xì)分的話(huà)還能夠劃分出更多的模塊。如下圖所示
其中,WebCore是Webkit的核心部分,它實(shí)現(xiàn)了對(duì)文檔的模型化,包括了CSS, DOM, Render等的實(shí)現(xiàn), JavaSript Core顯然是對(duì)JavaSript支持的實(shí)現(xiàn)。而橘黃色標(biāo)注的Webkit部分包含了很多不同平臺(tái)對(duì)Webkit封裝的實(shí)現(xiàn),即抽象出了與瀏覽器所能直 接對(duì)應(yīng)的一些概念的實(shí)現(xiàn),如,WebView,WebPage, WebFrame等。這三部分共同構(gòu)成了Webkit, 在源碼中,它們分別對(duì)應(yīng)這個(gè)這三個(gè)目錄, 即Webkit三大部分為WebCore, JavaSript Core,Webkit。
應(yīng)用程序如何利用Webkit的
從下圖可以看出,利用Webkit的應(yīng)用程序的位置處于Webkit模塊之上,應(yīng)用程序并不直接和WebCore以及JavaScript Core來(lái)打交道,也不需要和它們打交道,而是同我前面提到過(guò)的Webkit模塊來(lái)交互,從而屏蔽了WebCore和JavaSript Core部分。Webkit模塊實(shí)際上抽象出了大多數(shù)應(yīng)用程序所需要的那一部分,這里所說(shuō)的大多數(shù)應(yīng)用程序其實(shí)就是指的瀏覽器, 對(duì)于實(shí)現(xiàn)一個(gè)瀏覽器而言,Webkit模塊所提供的接口已經(jīng)足夠。不過(guò)對(duì)于某些應(yīng)用,可能得對(duì)其實(shí)施一定的改造,但是話(huà)又說(shuō)回來(lái),Webkit本來(lái)就是被設(shè)計(jì)成為Browser的內(nèi)核而被實(shí)現(xiàn)的。
看到這里,也就是說(shuō)如果我們要想利用Webkit來(lái)實(shí)現(xiàn)一個(gè)功能完善Browser或其他類(lèi)瀏覽器應(yīng)用程序的話(huà),你只需要了解Webkit模塊部分 就足夠了,更確切的說(shuō)只需要了解它所提供的接口就夠了。事實(shí)上,大多數(shù)平臺(tái),如果采用了Webkit內(nèi)核作為瀏覽器內(nèi)核組件的話(huà),所提供的對(duì)應(yīng)文檔部分都 是關(guān)于Webkit模塊所提供的接口的描述。很多平臺(tái)都提供了Browser組件,其使用方法就像是其他可視組件一樣,在應(yīng)用程序中應(yīng)用起來(lái)非常方便。比 如,某平臺(tái)提供了叫做WebView的可視化組件,我們就可以通過(guò)如下幾行代碼來(lái)展示一個(gè)網(wǎng)頁(yè), 使用的代碼僅僅三行。
WebView *view = new WebView();
view->load(Url("http://www.google.cn"));
view->show();
以Webkit作為瀏覽器組件的平臺(tái)有不少,包括Symbian S60, Android, Qt, GTK等等,前不久看到消息,好像Black Berry也準(zhǔn)備在自家的手機(jī)上使用Webkit了。
CSS在Webkit中的實(shí)現(xiàn)屬于相對(duì)獨(dú)立的一個(gè)模塊,注意這里說(shuō)的是相對(duì)。
CSS在Webkit中的作用自然是不言而喻的,在Web早期,文檔的結(jié)構(gòu)和樣式還未分離的那個(gè)時(shí)代,HTML擔(dān)負(fù)了文檔的結(jié)構(gòu)和樣式這兩個(gè)雙重任 務(wù),即HTML既負(fù)責(zé)文檔的結(jié)構(gòu),同時(shí)文檔的樣式也通過(guò)HTML中通過(guò)標(biāo)簽的屬性來(lái)指定??上攵?,在那個(gè)時(shí)候HMTL頁(yè)面的開(kāi)發(fā)和使用比起現(xiàn)在而言是多 么的不便。
不過(guò)仔細(xì)想想,這恐怕與當(dāng)時(shí)的技術(shù)發(fā)展程度有著很大大關(guān),首先,那個(gè)時(shí)候互聯(lián)網(wǎng)遠(yuǎn)不像現(xiàn)在這樣普及,另外,網(wǎng)頁(yè)也遠(yuǎn)不如現(xiàn)在這樣復(fù)雜,不像現(xiàn)在, 可以說(shuō),世界上信息的主要傳播方式是以網(wǎng)頁(yè)形式出現(xiàn)的,沒(méi)數(shù)據(jù)說(shuō)明,但我覺(jué)得至少趨勢(shì)是這樣的。 就這樣,互聯(lián)網(wǎng)在不斷的前進(jìn)之中,直到后來(lái)CSS的出現(xiàn),大大的改進(jìn)了Web的開(kāi)發(fā)模式,從此,文檔的結(jié)構(gòu)和樣式被清晰的一分為二。HTML主要負(fù)責(zé)文檔 的結(jié)構(gòu),而CSS則擔(dān)負(fù)著文檔的樣式指定。
關(guān)于CSS的介紹網(wǎng)上已經(jīng)有很多了,在這里將主要從Webkit實(shí)現(xiàn)的角度對(duì)其進(jìn)行介紹。
CSS是什么
CSS是Cascading Style Sheets的縮寫(xiě),按照官方定義,它可以被認(rèn)為是一個(gè)樣式表語(yǔ)言,它允許用戶(hù)通過(guò)它來(lái)為結(jié)構(gòu)化文檔(HTML文檔)指定樣式。通過(guò)使用CSS用戶(hù)可以將文檔的內(nèi)容和樣式分離,從而簡(jiǎn)化Web頁(yè)面的開(kāi)發(fā)和維護(hù)。
既然說(shuō)它是一個(gè)樣式表語(yǔ)言,那么它就有相應(yīng)的語(yǔ)法規(guī)則,規(guī)定了如何如何來(lái)書(shū)寫(xiě)一個(gè)樣式表,讓其作用與文檔內(nèi)容達(dá)到書(shū)寫(xiě)者想要的外觀。CSS的語(yǔ)法規(guī) 則是比較簡(jiǎn)單的, 自頂向下的來(lái)看,一個(gè)級(jí)聯(lián)樣式表(CSS)是由一系列的規(guī)則(rule)組成的, 每一條規(guī)則又是由一個(gè)選擇器(selector)和若干條聲明(Declearation)組成的。每條聲明(Declearation)又是一個(gè)鍵值 對(duì),由屬性(property)和值(value)來(lái)組成,如下圖所示。
原圖片出處:http://dabrook.org/cc/Basic-Anatomy-of-a-CSS-Rule.png
從這里可以看到,語(yǔ)法是很簡(jiǎn)單的,使用起來(lái)也確實(shí)很簡(jiǎn)單。注意,我在這里只是說(shuō)使用簡(jiǎn)單,就跟鉛筆一樣,誰(shuí)都會(huì)用,鉛筆的使用當(dāng)然是簡(jiǎn)單的不能再簡(jiǎn) 單了,但是就是這樣普通的工具,在專(zhuān)業(yè)人士和普通人的手里所能創(chuàng)造出的東西是截然不同的。所以我想說(shuō)的是,你能很快的學(xué)會(huì)如何使用CSS并不代表你編織出 漂亮的網(wǎng)頁(yè),它只是一個(gè)工具,能發(fā)揮到什么程度還得看人。
轉(zhuǎn)回來(lái),從其簡(jiǎn)單的語(yǔ)法來(lái)看,似乎是只要簡(jiǎn)單的將其轉(zhuǎn)化為對(duì)應(yīng)的程序設(shè)計(jì)模型即可,但實(shí)際中,CSS的實(shí)現(xiàn)還是比較復(fù)雜的,其復(fù)雜性就在于,CSS 本身的復(fù)雜程度,它定義了一系列的規(guī)則來(lái)決定為哪些元素來(lái)指定樣式,以及樣式的繼承關(guān)系,哪些是繼承的,哪些是非繼承的,以及作用于同一個(gè)元素的多個(gè)樣式 的疊加,還有就是它對(duì)所有能指定的樣式都有完整的對(duì)應(yīng)的屬性集。所以從實(shí)現(xiàn)的角度來(lái)看,一個(gè)完整的,兼容于標(biāo)準(zhǔn)的CSS實(shí)現(xiàn),需要顧及到的東西還是很多 的。
CSS實(shí)現(xiàn)模型
webkit css部分的實(shí)現(xiàn)代碼為于目錄webcore/css中,算是webkit中一個(gè)相對(duì)獨(dú)立的模塊,下面類(lèi)圖是我為了更好的了解css實(shí)現(xiàn)所作,大致勾勒出了CSS的內(nèi)部實(shí)現(xiàn)。
用戶(hù)所書(shū)寫(xiě)的css文檔,最終會(huì)轉(zhuǎn)化為webkit內(nèi)部的模型表示,這里有幾個(gè)比較重要的類(lèi)。
(待續(xù)...)
CSS默認(rèn)樣式表
從Webkit CSS的實(shí)現(xiàn)可以看到,即使你不指定任何樣式表,實(shí)際上當(dāng)CSS模塊運(yùn)作起來(lái)的時(shí)候,它都會(huì)載入幾張默認(rèn)的樣式表,要知道,在 CSSStyleSelector的構(gòu)造函數(shù)中,總是會(huì)調(diào)用loadDefaultStyle()這個(gè)函數(shù),其作用就是載入默認(rèn)的樣式表。
這些默認(rèn)的樣式表包含了一些HTML元素的最基本的樣式信息。相信在使用css的用戶(hù)中,大多數(shù)人都不會(huì)在對(duì)<div>指定樣式的時(shí)候 會(huì)為其添加一條display:block吧,是啊,幾乎所有使用css html的人都知道div是一個(gè)塊級(jí)元素,所以沒(méi)人會(huì)多此一舉,但是通過(guò)了解其CSS模塊的具體實(shí)現(xiàn),我們可以知道,這些個(gè)默認(rèn)的樣式表其實(shí)就已經(jīng)為我們 指定了一系列我們認(rèn)為的想當(dāng)然的規(guī)則。
這四個(gè)默認(rèn)樣式表是
額,從名字上大致也能夠了解1, 2了吧,它們不是以文件形式存儲(chǔ),而是在CSS中以字符數(shù)組的形式出現(xiàn),也就是說(shuō)作為數(shù)據(jù)編到代碼里面去了,應(yīng)該是考慮到每次都要使用默認(rèn)樣式表而為了減少I(mǎi)/O造成的性能損失。
為了說(shuō)明我前面所說(shuō)的,這些默認(rèn)樣式表描述的都是些個(gè)關(guān)于HTML元素的最基本的信息,還是來(lái)看個(gè)例子吧,
比如說(shuō)html4UserAgentStyleSheet,從名字上可以看到,這張應(yīng)該就是傳說(shuō)中的瀏覽器默認(rèn)樣式表了??纯炊加行┥栋?,這里只截取個(gè)片段。
1 html {
2 display: block
3 }
4
5 head {
6 display: none
7 }
8
9 meta {
10 display: none
11 }
12
13 title {
14 display: none
15 }
16
17 link {
18 display: none
19 }
20
21 style {
22 display: none
23 }
24
25 script {
26 display: none
27 }
28
29 body {
30 display: block;
31 margin: 8px
32 }
33
34 p {
35 display: block;
36 margin: 1.0__qem 0px
37 }
38
39 div {
40 display: block
41 }
42
43 layer {
44 display: block
45 }
從上面可以看出,真就是些最基本的屬性的指定,如果沒(méi)有這些默認(rèn)值指定的話(huà),用戶(hù)還得自行添加這些規(guī)則,那會(huì)很麻煩。
其他幾張表在此不作分析。
CSS解析
CSS使用的時(shí)候,只需要將按照其語(yǔ)法規(guī)范,書(shū)寫(xiě)一個(gè)規(guī)則集合,然后保存為一個(gè).css文件,在html中引用即可,當(dāng)然這里使用的是外部樣式表的方式,只是使用CSS的一種方式,在這里我不打算討論CSS的幾種使用方式,所以都按外部的來(lái)。
那么這種按照語(yǔ)法規(guī)則書(shū)寫(xiě)的CSS樣式表式如何轉(zhuǎn)換為Webkit內(nèi)部的CSS模型的呢,這自然需要通過(guò)詞法語(yǔ)法分析。在這里,Webkit使用了 自動(dòng)代碼生成工具生成了相應(yīng)的代碼,也就是說(shuō)詞法分析和語(yǔ)法分析這部分代碼是自動(dòng)生成的,但它們不夠完整,然后我們需要自己寫(xiě)一些配合性的代碼才能讓真?zhèn)€ CSS模塊工作起來(lái),說(shuō)的再白一些,就是需要我們自己是寫(xiě)一些函數(shù)讓那些個(gè)自動(dòng)生成的代碼來(lái)Call Back,用過(guò)其他各類(lèi)解析器的朋友們應(yīng)該很熟悉這個(gè)吧。如果誰(shuí)對(duì)這部分代碼有興趣,可以研究一下。我倒是曾經(jīng)為找一個(gè)跨平臺(tái)的bug調(diào)過(guò)這部分代碼,結(jié) 構(gòu)還是蠻簡(jiǎn)單的,代碼看起來(lái)稍多了些。入口是yylex和yyparse,有興趣可以自己看看。
那么Webkit中實(shí)現(xiàn)的這些個(gè)Call Back們?cè)谀睦锬??就在CSSParser中了,顯然,刨去生成的代碼不說(shuō),需要手工完成的CSS解析代碼部分就是這個(gè)了。CSS的一些解析功能的入口 也在此處,它們會(huì)調(diào)用lex,parse等生成代碼。相對(duì)的,生成代碼中需要的Call Back也需要在這里實(shí)現(xiàn)。
舉例來(lái)說(shuō),現(xiàn)在可以來(lái)看一個(gè)較大單位的回調(diào)函數(shù)的實(shí)現(xiàn),createStyleRule(),該函數(shù)將在一般性的規(guī)則需要被建立的時(shí)候調(diào)用。
1 CSSRule* CSSParser::createStyleRule(CSSSelector* selector)
2 {
3 CSSStyleRule* rule = 0;
4 if (selector) {
5 rule = new CSSStyleRule(styleElement);
6 m_parsedStyleObjects.append(rule);
7 rule->setSelector(sinkFloatingSelector(selector));
8 rule->setDeclaration(new CSSMutableStyleDeclaration(rule, parsedProperties, numParsedProperties));
9 }
10 clearProperties();
11 return rule;
12 }
從該函數(shù)的實(shí)現(xiàn)可以很清楚的看到,解析器達(dá)到某條件需要?jiǎng)?chuàng)建一個(gè)CSSStyleRule的時(shí)候?qū)⒄{(diào)用該函數(shù),該函數(shù)的功能是創(chuàng)建一個(gè) CSSStyleRule,并將其添加已解析的樣式對(duì)象列表m_parsedStyleObjects中去,這里的對(duì)象就是指的Rule。那么如此一來(lái), 經(jīng)過(guò)這樣一番解析后,作為輸入的樣式表中的所有Style Rule將被轉(zhuǎn)化為Webkit 的內(nèi)部模型對(duì)象CSSStyleRule對(duì)象,存儲(chǔ)在m_parsedStyleObjects中,它是一個(gè)Vector。
像這樣的函數(shù)還有createCharsetRule,createImportRule,createMediaRule等等,它們的作用大體上和createStyleRule類(lèi)似,都是為創(chuàng)建Rule而準(zhǔn)備的,只不過(guò)是不同類(lèi)型的Rule。
了解了上面這些,大體上能夠就能夠了解CSS解析式怎么運(yùn)作的。但是我們解析所要的結(jié)果是什么?通過(guò)調(diào)用CSSStyleSheet的 parseString函數(shù),上CSS解析過(guò)程將啟動(dòng),解析完一遍后,所有的Rule都將存儲(chǔ)在對(duì)應(yīng)的CSSStyleSheet對(duì)象中。但是這個(gè)時(shí)候的 規(guī)則依然是不易于處理的,需要將之轉(zhuǎn)換為CSSRuleSet,CSSRuleSet提供了一個(gè)addRulesFromSheet方法,能將 CSSStyleSheet中的rule轉(zhuǎn)換為CSSRuleSet中的rule,這樣所有的純樣式規(guī)則都會(huì)放存儲(chǔ)在對(duì)應(yīng)的集合當(dāng)中,這種集合的抽象就是 CSSRuleSet。以后就可以基于這些個(gè)CSSRuleSet來(lái)決定每個(gè)頁(yè)面中的元素的樣式了,后面會(huì)有介紹。
(...)
CSS如何作用于Render Tree
所謂的作用于Render Tree其實(shí)是指基于上面的解析成果來(lái)為相應(yīng)的Render Object來(lái)指定特定的樣式,這個(gè)樣式的抽象就是RenderStyle(關(guān)于Render Tree可參見(jiàn)我的其他文章)。
(...)
版權(quán)所有 2008-2028 保留所有權(quán)利
ICP備案號(hào):冀ICP備09005044號(hào)-1
技術(shù)支持:邢臺(tái)永翔科技開(kāi)發(fā)有限公司
冀公網(wǎng)安備 13050002000749號(hào)