開發一款瀏覽器內核需要學習哪些方面的知識?

最近參加畢業設計,題目選的是《基於Linux平台的網頁瀏覽器設計與實現》。
想認真做一下,所以不準備直接用現成的開源瀏覽器內核(比如WebKit或者KHTML這些)來做套殼,而是打算自己用C/C++從零開始,裸的寫一個簡單的瀏覽器內核,也就是所謂的排版引擎或者網頁渲染引擎。考慮到自己的能力,目標暫定為能夠支持html1.0。
但是最近幾天在網上搜索了一下,國內似乎沒有相關的資料或者書籍。所以來知乎問問各位前輩,開發一款瀏覽器內核需要學習哪些方面的知識?或者在哪裡能夠找到相關資料?
不勝感激。
=====================================
20130123 1825 更新:
自己能想到的部分是解析html、CSS和JavaScript這些應該會涉及到編譯解釋方面的知識,其他的部分,比如涉及到網路的方面就不甚了解了。
希望大家原諒我這種算偷懶的行為吧~~


恭喜你選了一個好題目。你橫跨了網頁開發,網路,編譯原理,圖形,網頁開發等幾個方面。

網頁開發:你要知道inline與block有什麼不同,什麼是box model,ie是怎麼實現的,標準的是怎麼樣的。

網路方面:瀏覽器會使用URL,表單提交,下載,DNS等一系列知識,深一些的比如說在chrome下面輸入chrome://dns,看看什麼叫 prefetch DNS,淺一點至少要知道怎麼實現表單提交,表單提交分那些格式。在網路那一層要怎麼拼。

編譯原理:簡單的是狀態機,具體的是CSS的解析,Javascript的解析。其實光HTML,CSS的解析就夠做一個畢設的了,據一個簡單的例子,瀏覽器是邊下載邊解析,邊顯示的,這個地方就有不少的坑等著你,光拿一個開源的xml解析器可不行,html的解析中還有圖文混排等功能,整個地方又是無數的坑。 就不要說javascript的引擎了,龍書中寫的只是一小部分,裡面還牽涉到什麼JIT等一大堆東西。

圖形:硬體加速,你在chrome瀏覽器中地址欄中輸入 chrome://gpu ,裡面出現頻率最高的就是Hardware accelerated


如果你真要做,準備把所有的時間放在chromium與webkit兩個網站上吧,但是就算這樣,裡面有很多東西也不會說,比如說邊下載邊解析,這張東西在他們看來太簡單了,裡面根本就沒有文檔。URL的轉義也是。看標準是一回事,但是有些東西根本在RFC中不會說,比如說URL的長度,整個就沒有標準,但是通常瀏覽器都會是2048以上。

如邊疆所說,怎麼簡化怎麼來吧,比如說做個WAP1.0的瀏覽器,這個木有javascript,木有css,就是URL轉義,wap標籤顯示,表單的提交。


從整個瀏覽器的工作周期來看:

首先是聯網模塊
包括域名解析(這個可以忽略)、發起請求,連接線程的管理等(單線程請忽略)

然後是解析模塊
包括了html的解析、DOM樹的建立等。尤其是html的解析,會涉及到容錯方面的考慮,DOM樹要考慮各種場景下的效率(好吧畢業設計可以不考慮效率)

接下來是渲染模塊
根據你建立的DOM樹,按照網頁所描述的內容展示字體、色塊等,這個沒什麼好說的。

還有其他,比如網頁對象的管理、頁面事件的響應(那些OnClick什麼的,好吧我不知道這個是不是html1.0里的東西)插件管理(flash和java,好吧這些又不是你的畢設範圍了)

有了以上,差不多應該就是一個瀏覽器內核了。

插句嘴,
只有一個內核估計很難作為畢業設計展示,你還得搭配著寫一個簡易的瀏覽器外殼,所以這不是個小工程。

綜上,能用webkit寫寫也不是不可以,做個引擎不是那麼簡單的事。

發牢騷:
知乎都開始幫人做作業了,是在向百度知道靠攏么


我突然也想就這個問題做個解答,因為我畢設也做了這個東西。不過,做的很渣啊……基本功能都沒有實現啊……但是我卻發現這個東西非常有意思。

首先,毫無疑問,瀏覽器是個非常複雜的系統。但是任何複雜軟體系統都可以通過層層抽象來簡化設計,這個也就是我們平常熟悉的自頂向下的設計方式。

那麼我們首先就要對瀏覽器進行拆解。現在的瀏覽器都有一個叫做瀏覽器內核的關鍵部分(也稱作排版引擎),而這個部分相對於瀏覽器本身來說就是一個黑箱,提供介面,給出結果。另外對現代瀏覽器來說,書籤管理等功能則獨立於排版引擎而存在。那麼你在做的時候,重點也就在排版引擎。

那排版引擎主要做什麼功能呢?簡單講就是根據URL獲取資源的位元組流,然後根據位元組流和資源類型交給相關的解析器進行處理。這個時候需要考慮我們到底需要處理幾種資源,各種資源如何處理。所謂的資源處理就是將無結構的位元組流變成結構化數據。因為計算機能夠處理是結構化數據。拿到結構化數據,便可以根據結構化數據繼續處理。

那我們先看URL獲取的這個部分。你可以通過給內核模塊封裝一個調用介面,從瀏覽外殼傳遞URL字元串到內核介面,然後根據URI的相關標準(http://www.ietf.org/rfc/rfc3986.txt)來處理就好了。因為這裡面涉及各種協議,比如file協議,比如http/https協議,你可能還需要封裝一個自己的協議,用來獲取內核自帶的一些資源路徑,比如默認的404頁面。

處理好URI之後,你就可以根據URI的結構,交給相關網路模塊來處理。我在做的時候,直接扔給了libcurl。但是libcurl在iOS上面,不是最好的實現方法,這個時候你可以繼續抽象,提供統一的網路介面,對接操作系統提供的網路相關API。

網路模塊的主要任務就是抓取位元組流,抓取回來位元組流之後,這個時候你可以直接處理,但是很容易阻塞。所以你可以去實現一個緩存機制,把抓取到的位元組流緩存在本地,形成一個資源池。這個地方的實現我沒有具體研究過,原諒我直接使用了靜態變數來做……

你把資源抓回來了,你就需要看這個這個資源的類型,是圖像的,你可以放在那裡等著回頭用的之後直接調取,是HTML、CSS或者腳本文件,你可以首先判斷文件類型,這個一般根據網路請求的Header中的content-type來決定。

除了判定資源的類型以外,你還需要判斷文件的編碼格式,是UTF-8呢,還是GB2312呢?這個有多種方法,包括解析Meta標籤,或者採取《HTML5規範》中給出的演算法來進行判定。參考:
2 Common infrastructure
8 The HTML syntax

那麼你現在拿到HTML的源代碼了,又知道源代碼的編碼格式了,那就處理唄。不過為了更好的開發,一般會將HTML的編碼轉換成UTF-8,反正《HTML5規範》中是這麼寫的(我只是粗略的讀了,可能是我理解錯了?)。正如前面的答案給出的,HTML解析就是一個自動機模型,雖然是這麼說,但是寫起來還是很不容易的。《HTML5規範》中有詳細的演算法:8 The HTML syntax

貌似總共有大概232個判斷條件?反正我嘗試寫了一個之後,果斷放棄了,而是採用了 google/gumbo-parser · GitHub 。所以如果你感興趣HTML的解析,可以參考Google的實現,自己寫一個也是可以的,只不過要耐心點。Google Gumbo本身給你實現一個類似DOM Tree的數據結構,但是如果自己調用的話貌似有些問題,因為你需要首先清楚他們的數據結構。

補充點不相關的內容:如果你想看Google Gumbo的代碼,別去直接看代碼了,用doxygen,順便打開自動生成UML的功能,寫論文都靠它了。

DOM Tree是HTML的結構化依託的數據結構,HTML其實可以表示成多種數據結構,但是《HTML 5規範》中直接採用了DOM Tree,或許由於已經成為事實上的標準了。但是,我們都知道《HTML 5規範》並非W3C嫡出……(扯遠了)

生成DOM Tree,其實規範中也是有詳細演算法描述的,參見 8 The HTML syntax 。簡單描述就是採用一個棧結構。HTML的解析需要考慮各種不規範的情況……什麼嵌套結構有錯,標籤沒有正確閉合等等。好在規範都給出了演算法。

DOM Tree也是網頁的對外介面。CSS的樣式化,JavaScript對於HTML文件的操作都是操作DOM Tree。

至於CSS,看標準唄。Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification 標準中直接給出了CSS的語言描述,可以採用YACC/LEX直接生成。但是我卡在這裡了,後面的也就都沒有做,只是看了下如何實現的。

至於JavaScript,我都還不會寫JavaScript,就不涉及了。不過你可以調用V8嘛!

你獲取了DOM結構和CSS的結構,就可以根據CSS的規則,按照CSS的選擇器遍歷DOM Tree找到相關節點,然後把樣式信息寫過去。這個時候,CSS是有三層的,一層是瀏覽器給各類標籤定義的默認樣式,一般也是用CSS來描述的,一種是網頁作者提供的CSS樣式,一種是用戶定義的樣式。這個時候根據優先順序,融合這三種CSS,然後對DOM Tree進行樣式化。樣式話無非就是一個遍歷的過程而已。

經過樣式化之後,你會得到一個經過樣式話的DOM Tree,也就是各個DOM節點帶了這個節點的樣式信息。這個時候就開始進行布局計算了。布局計算,說白了就是從DOM Tree構建一個子樹,我們稱為Rendering Tree。Rendering Tree的各個節點都是將來要在屏幕上畫出來的,因此一般只涉及&&裡面的內容。這個就是渲染過程的開始部分了,所有隱藏的元素其實都是不會進入到Rendering Tree的,例如具有CSS的display:none屬性的,都是不會顯示的,自然也就無法進入Rendering Tree。對於渲染,可以去讀如下的五篇文章,講的非常好:
Rendering:
Very useful series of posts by Dave Hyatt:
WebCore Rendering I – The Basics
WebCore Rendering II – Blocks and Inlines
WebCore Rendering III – Layout Basics
WebCore Rendering IV – Absolute/Fixed and Relative Positioning
WebCore Rendering V – Floats
Render Layers and The Rendering paths – 「WebKit Rendering Basics」 section explains it very well.

拿到Rendering Tree之後,就是渲染了,這個時候就可以調用操作系統提供的各種API繪製文字、圖片和視頻等。各種Form空間就可以綁定到原生控制項。然後顯示出來。還記得剛開始翻WebKit代碼時,就看到貌似採用了一個NSScorllView作為畫布,進行繪製。

整個瀏覽器內核的工作原理也就是這些,說起來容易,寫起來,則需要各種考量。自己寫一個,不一定能寫出多少東西,但是整個研究過程,會學習到很多設計模式的精髓什麼的。雖然我的畢設混過去了,但是我準備再好好重構重寫這個內核,真的很有趣。(自立Flag)

你做的是瀏覽器內核,那麼最好的參考材料其實是W3C出的各種規範,各種RFC以及現有的瀏覽器內核的開源實現。印象最深的一句話就是RFC和具體實現其實是相輔相成,互相描述的。

另外,排版引擎的功能不止在這裡,寫iOS的時候,意識到其實窗口管理器喝各種UI本質上和HTML的排版是類似的,其本質也是利用各種數據結構來記錄處理各UI控制項之間的關係。

總之,計算機的各層抽象隱藏了很多細節,但是往往這些細節都是優美的,我們看到的往往是水面上的冰山。附上一些做畢設的時候的研究資料,供參考(原諒我直接從論文文獻拷貝出來了):

  1. Let"s build a browser engine! Part 1: Getting started.

  2. 朱永盛. WebKit 技術內幕 [M]. 北京 : 電子工業出版社, 2014.

  3. GARSIEL T, IRISH P. How Browsers Work: Behind the scenes of modern web

    browsers[EB/OL]. [2014-08-28].

    How Browsers Work: Behind the scenes of modern web browsers.


&

找不到資料是因為你不會找,找的方向不對,用的關鍵字不對,用的搜索引擎不對,以及用的語言不對。下面是我覺得有價值的資料:

  • How browsers work
  • The WebKit Open Source Project

另外注意現代瀏覽器渲染引擎結構早就不是為了 HTML 1.0 設計了,支持的語法不是簡單的 SGML,還要支持 CSS 和 JavaScript 等許多其他技術。所以你如果只想支持 HTML 1.0 的話現在的渲染引擎結構會過於複雜了,至於怎麼做簡化得自己摸著石頭過河。


HTML 1.0的話,基本還是沒有什麼難度的。

從前到後幾個點:
1、網路方面,HTTP是個基於文本的協議,TCP/IP 80埠走ASCII文本流,乾脆暫時不用支持編碼好了,隨便找個Socket的書讀讀,寫個控制台發GET啥的給伺服器看看返回啥很簡單。
2、然後是解析HTML,考慮到是HTML 1.0,暫時也不搞什麼容錯啥的,找個正則的庫,然後網上搜一下HTML正則,也就差不多了。當然如果喜歡可以自己寫Tokenizer。
3、HTML 1.0是沒有CSS、JS之類的東西的,所以排版的唯一問題是圖文混排文本加粗什麼的。
4、最後就是窗口呈現、選擇文本、地址欄、刷新停止按鈕,超鏈接點擊處理之類的東西了。


當然,我肯定不會告訴你.NET Framework囊括了所有這些基礎部件的(包括HTTP協議實現)。。。。


這些回答都不及格。不存在HTML 1.0,ietf的第一個版本就是2.0。
先根據你的地基需要學X或者GTK+之類的。還有就是數值計算和牛頓力學。


如果是真正的瀏覽器內核開發,那涵蓋的知識領域太多了,編譯原理、分散式計算、網路編程、圖形圖像等,很慚愧我其實是做外殼的專家... 自己編程練習的話,我覺得編譯原理還是很重要的


瀏覽器的工作原理:現代網路瀏覽器幕後揭秘

很不錯的文章,希望對你有所幫助


我覺得題主可以試一試,定義一個簡單的html文本(只支持&,&黑體,超鏈接&,圖片&,不支持css,frame,form,div等其他的tag),寫個支持的http協議的的簡單下載模塊(支持簡單的http頭, 簡單的容錯,估計500行代碼搞定,能下html文本和&tag中的圖片),寫個解析器(支持Dom,但只解析其中的幾個tag而已,估計1000行代碼內),繪製(我用的是objective-c,裡面有coreText這種庫,可以實現一些富文本繪製和圖文混排的排版效果,估計2000代碼搞定,其它語言不了解),把這三個模塊串列起來,能適應&黑體,超鏈接&,圖片&這幾個tag的任意排列和組合,然後慢慢增加一些tag的解析(折騰文本解析這個模塊),然後在解析dom的過程中交叉發起圖片的下載和繪製,使性能更好。。

&
text&text (文本圖片任意混排)
&


做一個畢業設計的話, 推薦看一下j2me lwuit 的html component. 代碼實現比較簡單, 符合你只想實現html 1.0 的要求。 你想用c/c++ 重新實現一遍也比較簡單, javascript 你想要實現一個效率不高的解釋器,不整JIT 什麼的沒那麼複雜。要知道有人在j2me 平台也實現了一個javascript 解釋器的,

Links:
Lwuit: Subversion
HTMLComponent
minijoe -

Minimal Javascript Object Environement for J2ME

不要嫌這個實現太簡單,太小兒科。 也是支持html4.0 和css 1.0的。 正因為簡單才比較好理解。 j2me 平台基本上沒什麼前途了, 但是因為它的memory 限制, 有些idea 和implementation 對其他平台還是有借鑒價值的。

學習編程最好的方法是Read the fxxking code。 但我的建議要從簡單直接的code 讀起, 一上來就整webkit, gecko, V8, TraceMonkey, 很難找到對自己直接有用的代碼, 對培養自信也沒好處。


花三個月看一下WebKit的代碼,又不是什麼難事。
然後你就知道這個坑有多大了。

Apple都不敢自己弄,拿了KHTML回來改。
Google也不敢自己弄,拿了WebKit回來改。
Opera自己弄了,然後扔了。
IE修修補補,終於決定扔了再寫一個。

祝你成功,其實能夠拿 gumbo 和 v8封裝出來一個支持 JS 操作 DOM 的解析引擎已經很不錯了,排版部分還是算了吧。。。


感覺題目太大,其實可以選一個有針對性點的問題呢?比如安全方面,像Google Chrome投入大量資源研發各種高性能的沙盒技術,可以看下源代碼目錄下就有好多個沙盒,其中就有將項目投給研究院的學生做畢業設計用;除了沙盒,它還投入大量資源研究腳本引擎,比如V8/Dart等。具體我也列不出來。但是不管是哪一個方面,你都會發現可以搜出大量的論文來。試試吧。

我所想表達的是,對於瀏覽器——未來的操作系統,是一極其複雜的系統,從細處著手研究也會是極具價值的工作。

當然對於整體而言,了解瀏覽器的工作方式也是很有趣的事兒。


現代瀏覽器甚至與操作系統同樣複雜


瀏覽器內核又可以分成兩部分:渲染引擎(layout engineer 或者 Rendering Engine)和 JS 引擎。它負責取得網頁的內容(HTML、XML、圖像等等)、整理訊息(例如加入 CSS 等),以及計算網頁的顯示方式,然後會輸出至顯示器或印表機。瀏覽器的內核的不同對於網頁的語法解釋會有不同,所以渲染的效果也不相同。所有網頁瀏覽器、電子郵件客戶端以及其它需要編輯、顯示網路內容的應用程序都需要內核。JS 引擎則是解析 Javascript 語言,執行 javascript 語言來實現網頁的動態效果。
最開始渲染引擎和 JS 引擎並沒有區分的很明確,後來 JS 引擎越來越獨立,內核就傾向於只指渲染引擎。有一個網頁標準計劃小組製作了一個 ACID 來測試引擎的兼容性和性能。內核的種類很多,如加上沒什麼人使用的非商業的免費內核,可能會有 10 多種,但是常見的瀏覽器內核可以分這四種:Trident、Gecko、Blink、Webkit。http://sep9.cn/h4k5we


考慮下基於文本的類links網頁遊覽器的設計實現吧,


http://www.tongda2000.com/gao/netbit/


推薦閱讀:

《神探夏洛克》里Sherlock使用Windows Vista操作系統和IE8瀏覽器,這符合Sherlock的性格嗎?
你覺得體驗比較好的瀏覽器是哪款?為什麼?
Webkit 瀏覽器前綴傷害了 web 技術的進步嗎?

TAG:網頁瀏覽器 | 瀏覽器內核 | 排版引擎瀏覽器 | 瀏覽器引擎 |