Webkit內核探究【2】——Webkit CSS實現

注:【轉載請註明文章來源、保持原樣】css

出處:http://www.cnblogs.com/jyli/archive/2010/01/31/1660364.html
做者:李嘉昱html

CSS在Webkit中的實現屬於相對獨立的一個模塊,注意這裏說的是相對。web

CSS在Webkit中的做用天然是不言而喻的,在Web早期,文檔的結構和樣式還未分離的那個時代,HTML擔負了文檔的結構和樣式這兩個雙重任 務,即HTML既負責文檔的結構,同時文檔的樣式也經過HTML中經過標籤的屬性來指定。可想而知,在那個時候HMTL頁面的開發和使用比起如今而言是多 麼的不便。數組

不過仔細想一想,這恐怕與當時的技術發展程度有着很大大關,首先,那個時候互聯網遠不像如今這樣普及,另外,網頁也遠不如如今這樣複雜,不像如今, 能夠說,世界上信息的主要傳播方式是以網頁形式出現的,沒數聽說明,但我以爲至少趨勢是這樣的。 就這樣,互聯網在不斷的前進之中,直到後來CSS的出現,大大的改進了Web的開發模式,今後,文檔的結構和樣式被清晰的一分爲二。HTML主要負責文檔 的結構,而CSS則擔負着文檔的樣式指定。瀏覽器

關於CSS的介紹網上已經有不少了,在這裏將主要從Webkit實現的角度對其進行介紹。app

CSS是什麼 svg

 


CSS是Cascading Style Sheets的縮寫,按照官方定義,它能夠被認爲是一個樣式表語言,它容許用戶經過它來爲結構化文檔(HTML文檔)指定樣式。經過使用CSS用戶能夠將文檔的內容和樣式分離,從而簡化Web頁面的開發和維護。函數

既然說它是一個樣式表語言,那麼它就有相應的語法規則,規定了如何如何來書寫一個樣式表,讓其做用與文檔內容達到書寫者想要的外觀。CSS的語法規 則是比較簡單的, 自頂向下的來看,一個級聯樣式表(CSS)是由一系列的規則(rule)組成的, 每一條規則又是由一個選擇器(selector)和若干條聲明(Declearation)組成的。每條聲明(Declearation)又是一個鍵值 對,由屬性(property)和值(value)來組成,以下圖所示。工具

 

原圖片出處:http://dabrook.org/cc/Basic-Anatomy-of-a-CSS-Rule.png性能

從這裏能夠看到,語法是很簡單的,使用起來也確實很簡單。注意,我在這裏只是說使用簡單,就跟鉛筆同樣,誰都會用,鉛筆的使用固然是簡單的不能再簡 單了,可是就是這樣普通的工具,在專業人士和普通人的手裏所能創造出的東西是大相徑庭的。因此我想說的是,你能很快的學會如何使用CSS並不表明你編織出 漂亮的網頁,它只是一個工具,能發揮到什麼程度還得看人。

轉回來,從其簡單的語法來看,彷佛是隻要簡單的將其轉化爲對應的程序設計模型便可,但實際中,CSS的實現仍是比較複雜的,其複雜性就在於,CSS 自己的複雜程度,它定義了一系列的規則來決定爲哪些元素來指定樣式,以及樣式的繼承關係,哪些是繼承的,哪些是非繼承的,以及做用於同一個元素的多個樣式 的疊加,還有就是它對全部能指定的樣式都有完整的對應的屬性集。因此從實現的角度來看,一個完整的,兼容於標準的CSS實現,須要顧及到的東西仍是不少 的。

CSS實現模型


webkit css部分的實現代碼爲於目錄webcore/css中,算是webkit中一個相對獨立的模塊,下面類圖是我爲了更好的瞭解css實現所做,大體勾勒出了CSS的內部實現。

用戶所書寫的css文檔,最終會轉化爲webkit內部的模型表示,這裏有幾個比較重要的類。

(待續...)

CSS默認樣式表


從Webkit CSS的實現能夠看到,即便你不指定任何樣式表,實際上當CSS模塊運做起來的時候,它都會載入幾張默認的樣式表,要知道,在 CSSStyleSelector的構造函數中,老是會調用loadDefaultStyle()這個函數,其做用就是載入默認的樣式表。

這些默認的樣式表包含了一些HTML元素的最基本的樣式信息。相信在使用css的用戶中,大多數人都不會在對<div>指定樣式的時候 會爲其添加一條display:block吧,是啊,幾乎全部使用css html的人都知道div是一個塊級元素,因此沒人會畫蛇添足,可是經過了解其CSS模塊的具體實現,咱們能夠知道,這些個默認的樣式表其實就已經爲咱們 指定了一系列咱們認爲的想固然的規則。

這四個默認樣式表是

  • html4UserAgentStyleSheet
  • quirksUserAgentStyleSheet
  • svgUserAgentStyleSheet
  • sourceUserAgentStyleSheet

額,從名字上大體也可以瞭解1, 2了吧,它們不是以文件形式存儲,而是在CSS中以字符數組的形式出現,也就是說做爲數據編到代碼裏面去了,應該是考慮到每次都要使用默認樣式表而爲了減小I/O形成的性能損失。

爲了說明我前面所說的,這些默認樣式表描述的都是些個關於HTML元素的最基本的信息,仍是來看個例子吧,

好比說html4UserAgentStyleSheet,從名字上能夠看到,這張應該就是傳說中的瀏覽器默認樣式表了。看看都有些啥吧,這裏只截取個片斷。

 

複製代碼
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   }
複製代碼

 

 

從上面能夠看出,真就是些最基本的屬性的指定,若是沒有這些默認值指定的話,用戶還得自行添加這些規則,那會很麻煩。

其餘幾張表在此不做分析。

CSS解析


CSS使用的時候,只須要將按照其語法規範,書寫一個規則集合,而後保存爲一個.css文件,在html中引用便可,固然這裏使用的是外部樣式表的方式,只是使用CSS的一種方式,在這裏我不打算討論CSS的幾種使用方式,因此都按外部的來。

那麼這種按照語法規則書寫的CSS樣式表式如何轉換爲Webkit內部的CSS模型的呢,這天然須要經過詞法語法分析。在這裏,Webkit使用了 自動代碼生成工具生成了相應的代碼,也就是說詞法分析和語法分析這部分代碼是自動生成的,但它們不夠完整,而後咱們須要本身寫一些配合性的代碼才能讓真個 CSS模塊工做起來,說的再白一些,就是須要咱們本身是寫一些函數讓那些個自動生成的代碼來Call Back,用過其餘各種解析器的朋友們應該很熟悉這個吧。若是誰對這部分代碼有興趣,能夠研究一下。我卻是曾經爲找一個跨平臺的bug調過這部分代碼,結 構仍是蠻簡單的,代碼看起來稍多了些。入口是yylex和yyparse,有興趣能夠本身看看。

那麼Webkit中實現的這些個Call Back們在哪裏呢?就在CSSParser中了,顯然,刨去生成的代碼不說,須要手工完成的CSS解析代碼部分就是這個了。CSS的一些解析功能的入口 也在此處,它們會調用lex,parse等生成代碼。相對的,生成代碼中須要的Call Back也須要在這裏實現。

舉例來講,如今能夠來看一個較大單位的回調函數的實現,createStyleRule(),該函數將在通常性的規則須要被創建的時候調用。

複製代碼
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 }
複製代碼

 

從該函數的實現能夠很清楚的看到,解析器達到某條件須要建立一個CSSStyleRule的時候將調用該函數,該函數的功能是建立一個 CSSStyleRule,並將其添加已解析的樣式對象列表m_parsedStyleObjects中去,這裏的對象就是指的Rule。那麼如此一來, 通過這樣一番解析後,做爲輸入的樣式表中的全部Style Rule將被轉化爲Webkit 的內部模型對象CSSStyleRule對象,存儲在m_parsedStyleObjects中,它是一個Vector。

像這樣的函數還有createCharsetRule,createImportRule,createMediaRule等等,它們的做用大致上和createStyleRule相似,都是爲建立Rule而準備的,只不過是不一樣類型的Rule。

瞭解了上面這些,大致上可以就可以瞭解CSS解析式怎麼運做的。可是咱們解析所要的結果是什麼?經過調用CSSStyleSheet的 parseString函數,上CSS解析過程將啓動,解析完一遍後,全部的Rule都將存儲在對應的CSSStyleSheet對象中。可是這個時候的 規則依然是不易於處理的,須要將之轉換爲CSSRuleSet,CSSRuleSet提供了一個addRulesFromSheet方法,能將 CSSStyleSheet中的rule轉換爲CSSRuleSet中的rule,這樣全部的純樣式規則都會放存儲在對應的集合當中,這種集合的抽象就是 CSSRuleSet。之後就能夠基於這些個CSSRuleSet來決定每一個頁面中的元素的樣式了,後面會有介紹。

(...)


CSS如何做用於Render Tree


所謂的做用於Render Tree實際上是指基於上面的解析成果來爲相應的Render Object來指定特定的樣式,這個樣式的抽象就是RenderStyle(關於Render Tree可參見個人其餘文章)。

(...)


(待續..)

相關文章
相關標籤/搜索