用來輸入URI的地址欄css
· 前進、後退按鈕html
· 書籤選項html5
· 用於刷新及暫停當前加載文檔的刷新、暫停按鈕node
· 用於到達主頁的主頁按鈕web
瀏覽器的主要組件包括:算法
1. 用戶界面 -- 包括地址欄、後腿/前進按鈕、書籤目錄等,也就是你所看到的除了用來顯示你鎖清秋頁面的主窗口以外的其餘部分chrome
2. 瀏覽器引擎- 用來查詢及操做渲染引擎的接口後端
3. 渲染引擎 - 用來顯示請求的年日用 (例如若是請求內容爲html 它負責解析html 及css,並將解析後的結果顯示出來)瀏覽器
4.網絡 - 用來完成網絡調用,例如http請求,他具備平臺無關的接口,能夠在不一樣平臺上工做緩存
5. UI後端 - 用來繪製相似組合選擇框及對話框等基本組件,具備不特定於某個平臺的通用接口,底層使用操做系統的用戶接口
6.JS解釋器- 用來解釋執行js 代碼
7. 數據存儲- 屬於持久層,瀏覽器須要在硬盤中保存類型cookie 的各類數據,html5定義了web database 技術,這是一種輕量級完整的客戶端存儲技術。
1、渲染引擎
須要注意的是,不一樣於大部分瀏覽器,chrom 爲每一個tab 分配了各自的渲染引擎實例,每一個tab 就是獨立的進程。
渲染引擎的職責是渲染,即在瀏覽器窗口中顯示所請求的內容。
默認狀況下,渲染引擎能夠顯示html、xml 文檔及圖片,它也能夠藉助插件(一種瀏覽器擴展)顯示其餘類數據,例如使用PDF閱讀器插件,能夠顯示PDF格式,這裏只討論渲染引擎最主要的用途--- 顯示應用了css 以後的html 及圖片
渲染引擎首先經過網絡得到所請求文檔的內容,一般以8K 分塊的方式完成。
下面是渲染引擎在取得內容以後的基本流程
解析html 以構建dom 樹 -> 構建render 樹 -> 佈局render樹 -> 繪製render 樹
渲染引擎開始解析html,並將標籤轉化爲內容樹中的dom節點。接着,它解析外部css 文件及style 標籤中的樣式信息。這些樣式信息以及html中的可見性指令將被用來構建另外一個棵樹 ---- render 樹。
render 樹由一些包含有顏色和大小等屬性的矩形組成,他們被將按照正確的順序顯示到屏幕上
render 樹構建好了以後,將會執行佈局過程,它將肯定要每一個節點在屏幕上的確切座標。在下一步就是繪製,即遍歷render 樹,並使用UI 後端層繪製每一個節點。
值得注意的是,這個過程是逐步完成的,爲了更好的用戶體驗,渲染引擎將會盡量早的將內容呈現到屏幕上,並不會等到全部的html都解析完成以後在去構建和佈局render 樹。 它是解析完一部份內容就顯示一部份內容,同事可能還在經過網絡下載其他內容。
2、解析
解析一個文檔也就是將其轉換爲具備必定意義的結構(編碼能夠理解和使用的東西) 。解析的結構一般是經過表達文檔結構的節點樹,稱爲解析樹或語法樹。
HTML解析器的工做是將html 標識解析爲解析樹。
解析樹,是有DOM 元素及屬性節點組成的。DOM是文檔對象模型的縮寫,它是html 文檔對象標識,做爲html 元素的外部接口供js 等調用。
DOM和標籤基本是一一對應的關係,例如,以下的標籤:
<html> <body> <p> Hello DOM </p> <div><img src=」example.png」 /></div> </body> </html>
將會被轉換爲DOM樹:
這裏所謂的樹包含了DOM節點是說樹是由實現了DOM 接口的元素構建而成的,瀏覽器使用已被瀏覽器內容使用的其餘屬性的具體實現。解析算法
正如前面章節中討論的,html 不能被通常的自頂向下或者向上的解析器所解析
緣由是:
1. 這門語言自己的寬鬆特性
2.瀏覽器對一些常見的非法的html 有容錯機制
3. 解析過程每每是反覆的,一般源碼不會在解析過程當中發生改變,但在html 中,腳本標籤包含的"document.write" 可能添加標籤,這說明在解析過程當中實際上修改了輸入
不能使用正確解析技術,瀏覽器爲html 定製了專屬的解析器。
html解析流程
基本示例——符號化下面的html:
<html>
<body>
Hello world
</body>
</html>
初始狀態爲「Data State」,當遇到「<」字符,狀態變爲「Tag open state」,讀取一個a-z的字符將產生一個開始標籤符號,狀態相應變爲「Tag name state」,一直保持這個狀態直到讀取到「>」,每一個字符都附加到這個符號名上,例子中建立的是一個html符號。
當讀取到「>」,當前的符號就完成了,此時,狀態回到「Data state」,「<body>」重複這一處理過程。到這裏,html和body標籤都識別出來了。如今,回到「Data state」,讀取「Hello world」中的字符「H」將建立並識別出一個字符符號,這裏會爲「Hello world」中的每一個字符生成一個字符符號。
這樣直到遇到「</body>」中的「<」。如今,又回到了「Tag open state」,讀取下一個字符「/」將建立一個閉合標籤符號,而且狀態轉移到「Tag name state」,仍是保持這一狀態,直到遇到「>」。而後,產生一個新的標籤符號並回到「Data state」。後面的「</html>」將和「</body>」同樣處理。
樹的建立過程
來看一下示例中樹的建立過程:
<html>
<body>
Hello world
</body>
</html>
構建樹這一階段的輸入是符號識別階段生成的符號序列。
首先是「initial mode」,接收到html符號後將轉換爲「before html」模式,在這個模式中對這個符號進行再處理。此時,建立了一個HTMLHtmlElement元素,並將其附加到根Document對象上。
狀態此時變爲「before head」,接收到body符號時,即便這裏沒有head符號,也將自動建立一個HTMLHeadElement元素並附加到樹上。
如今,轉到「in head」模式,而後是「after head」。到這裏,body符號會被再次處理,將建立一個HTMLBodyElement並插入到樹中,同時,轉移到「in body」模式。
而後,接收到字符串「Hello world」的字符符號,第一個字符將致使建立並插入一個text節點,其餘字符將附加到該節點。
接收到body結束符號時,轉移到「after body」模式,接着接收到html結束符號,這個符號意味着轉移到了「after after body」模式,當接收到文件結束符時,整個解析過程結束。
html樹的構建過程
在這個階段,瀏覽器將文檔標記爲可交互的,並開始解析處於延時模式中的腳本——這些腳本在文檔解析後執行。
文檔狀態將被設置爲完成,同時觸發一個load事件。
詳見 http://www.aiuxian.com/article/p-1832762.html
三 、腳本解析 Parsing scripts
RenderObject是Webkit的渲染對象基類,它的定義以下:
class RenderObject{
virtual void layout();
virtual void paint(PaintInfo);
virtual void rect repaintRect();
Node* node; //the DOM node
RenderStyle* style; // the computed style
RenderLayer* containgLayer; //the containing z-index layer
}
每一個渲染對象用一個和該節點的css盒模型相對應的矩形區域來表示,正如css2所描述的那樣,它包含諸如寬、高和位置之類的幾何信息。盒模型的類型受該節點相關的display樣式屬性的影響(參考樣式計算章節)。下面的webkit代碼說明了如何根據display屬性決定某個節點建立何種類型的渲染對象。
webkit代碼說明了如何根據display屬性決定某個節點建立何種類型的渲染對象。
RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
{
Document* doc = node->document();
RenderArena* arena = doc->renderArena();
...
RenderObject* o = 0;
switch (style->display()) {
case NONE:
break;
case INLINE:
o = new (arena) RenderInline(node);
break;
case BLOCK:
o = new (arena) RenderBlock(node);
break;
case INLINE_BLOCK:
o = new (arena) RenderBlock(node);
break;
case LIST_ITEM:
o = new (arena) RenderListItem(node);
break;
...
}
return o;
}
元素的類型也須要考慮,例如,表單控件和表格帶有特殊的框架。
layout通常有下面這幾個部分:
1. 父渲染對象決定它本身的寬度
2. 父渲染對象讀取chilidren,並:
Firefox使用一個「state」對象(nsHTMLReflowState)作爲參數去佈局(firefox稱爲reflow),state包含parent的寬度及其餘內容。1. 放置child渲染對象(設置它的x和y)
2. 在須要時(它們當前爲dirty或是處於全局layout或者其餘緣由)調用child渲染對象的layout,這將計算child的高度
3. parent渲染對象使用child渲染對象的累積高度,以及margin和padding的高度來設置本身的高度-這將被parent渲染對象的parent使用
4. 將dirty標識設置爲false
渲染對象的寬度使用容器的寬度、渲染對象樣式中的寬度及margin、border進行計算。例如,下面這個div的寬度:
<div style="width:30%"/>
webkit中寬度的計算過程是(RenderBox類的calcWidth方法):
· 容器的寬度是容器的可用寬度和0中的最大值,這裏的可用寬度爲:contentWidth= clientWidth() - paddingLeft() - paddingRight(),clientWidth 和 clientHeight 表明一個對象內部的不包括border和滑動條的大小
· 元素的寬度指樣式屬性width的值,它能夠經過計算容器的百分比獲得一個絕對值
· 加上水平方向上的border和padding
到這裏是最佳寬度的計算過程,如今計算寬度的最大值和最小值,若是最佳寬度大於最大寬度則使用最大寬度,若是小於最小寬度則使用最小寬度。最後緩存這個值,當須要layout 但寬度未改變時使用。
當一個渲染對象在佈局過程當中須要折行時,則暫停並告訴它的parent它須要折行,parent將建立額外的渲染對象並調用它們的layout。
繪製階段,遍歷渲染樹並調用渲染對象的paint方法將它們的內容顯示在屏幕上,繪製使用UI基礎組件,這在UI的章節有更多的介紹。
和佈局同樣,繪製也能夠是全局的-繪製完整的樹-或增量的。在增量的繪製過程當中,一些渲染對象以不影響整棵樹的方式改變,改變的渲染對象使其在屏幕上的矩形區域失效,這將致使操做系統將其看做dirty區域,併產生一個paint事件,操做系統很巧妙的處理這個過程,並將多個區域合併爲一個。Chrome中,這個過程更復雜些,由於渲染對象在不一樣的進程中,而不是在主進程中。Chrome在必定程度上模擬操做系統的行爲,表現爲監聽事件並派發消息給渲染根,在樹中查找到相關的渲染對象,重繪這個對象(每每還包括它的children)。
css2定義了繪製過程的順序。這個就是元素壓入堆棧的順序,這個順序影響着繪製,堆棧從後向前進行繪製。
重繪前,webkit將舊的矩形保存爲位圖,而後只繪製新舊矩形的差集。
瀏覽器老是試着以最小的動做響應一個變化,因此一個元素顏色的變化將只致使該元素的重繪,元素位置的變化將大體元素的佈局和重繪,添加一個Dom節點,也會大體這個元素的佈局和重繪。一些主要的變化,好比增長html元素的字號,將會致使緩存失效,從而引發整數的佈局和重繪。
while (!mExiting)
NS_ProcessNextEvent(thread);
CSS盒模型
全部的元素都有一個display屬性,用來決定它們生成box的類型,例如:
block-生成塊狀box
inline-生成一個或多個行內box
none-不生成box
默認的是inline,但瀏覽器樣式表設置了其餘默認值,例如,div元素默認爲block。
這裏有三種策略:
1. normal-對象根據它在文檔的中位置定位,這意味着它在渲染樹和在Dom樹中位置一致,並根據它的盒模型和大小進行佈局
2. float-對象先像普通流同樣佈局,而後儘量的向左或是向右移動
3. absolute-對象在渲染樹中的位置和Dom樹中位置無關
static和relative是normal,absolute和fixed屬於absolute。
在static定位中,不定義位置而使用默認的位置。其餘策略中,做者指定位置——top、bottom、left、right。
Box佈局的方式由這幾項決定:box的類型、box的大小、定位策略及擴展信息(好比圖片大小和屏幕尺寸)。
Block box:構成一個塊,即在瀏覽器窗口上有本身的矩形
Inline box:並無本身的塊狀區域,但包含在一個塊狀區域內
block一個挨着一個垂直格式化,inline則在水平方向上格式化。
Inline盒模型放置在行內或是line box中,每行至少和最高的box同樣高,當box以baseline對齊時——即一個元素的底部和另外一個box上除底部之外的某點對齊,行高能夠比最高的box高。當容器寬度不夠時,行內元素將被放到多行中,這在一個p元素中常常發生。
相對定位——先按照通常的定位,而後按所要求的差值移動。
一個浮動的box移動到一行的最左邊或是最右邊,其他的box圍繞在它周圍。下面這段html:
<p>
<img style="float:right" src="images/image.gif" width="100" height="100">Lorem ipsum dolor sit amet, consectetuer...
</p>
將顯示爲:
這種狀況下的佈局徹底不顧普通的文檔流,元素不屬於文檔流的一部分,大小取決於容器。Fixed時,容器爲viewport(可視區域)。
圖17:fixed
注意-fixed即便在文檔流滾動時也不會移動。
這個由CSS屬性中的z-index指定,表示盒模型的第三個大小,即在z軸上的位置。Box分發到堆棧中(稱爲堆棧上下文),每一個堆棧中靠後的元素將被較早繪製,棧頂靠前的元素離用戶最近,當發生交疊時,將隱藏靠後的元素。堆棧根據z-index屬性排序,擁有z-index屬性的box造成了一個局部堆棧,viewport有外部堆棧,例如:
<STYLE type="text/css"> div {position: absolute;left: 2in;top: 2in;} </STYLE> <P> <DIV style="z-index: 3;background-color:red; width: 1in; height: 1in; "></DIV> <DIV style="z-index: 1;background-color:green;width: 2in; height: 2in;"> </DIV> </p>
結果是:
雖然綠色div排在紅色div後面,可能在正常流中也已經被繪製在後面,但z-index有更高優先級,因此在根box的堆棧中更靠前。