WebKit,爲了佈局,忙併美麗

如果沒有1440年以後活字印刷術的大規模普及,或許就不會有文藝復興運動,更不會有後來的啓蒙運動。如果沒有這兩個運動的開展,或許就不會有世界範圍的工業化。

在活字印刷術出現以前,每出版一本書,都必須先刻制一套模版,稱爲雕版,每套雕版上的每一個字,都是手工雕刻的。不僅製作雕版費時費力,而且有了錯誤不容易更改。活字印刷術的進步在於,可以預先批量生產各種樣式和大小的字體,稱爲活字。需要出版某一本書籍時,先製作該書的頁面模版,模版做好以後,只需要把這些活字擺放在模版上即可。如果出現錯誤,只需要調換某些活字,既省時又省力。如果某本書的模版不需要長期保存,還可以把模版中擺放的活字拆解下來,在印刷其它圖書時用,節約成本。

活字印刷術沒有解決的問題,1.圖像的印刷。起初不能印刷筆觸豐富,層次複雜的圖像,一直到1796年,石板印刷術(lithography)出現以後,才能印刷表現手段豐富的圖像。2. 靈活的佈局排版。紙張大小不同,佈局排版也不同,佈局變了,需要重新擺放活字,而且有時候還需要改變字體和大小。

靈活的佈局排版對於紙質書籍來說,或許並不太重要,但是對於電腦瀏覽器來說,卻必須實現完全的自動化。否則,每當用戶改變瀏覽器窗口的大小的時候,頁面內容就不能正確顯示。對於手機瀏覽器來說,佈局排版的自動化尤其重要,因爲不同手機的屏幕不一致,而且屏幕分辨率也不同。

但是即便是瀏覽器,也沒有擺脫傳統的排版方式。所謂傳統的排版方式,基本是橫平豎直的,單一的鳥瞰視角。

[轉載]新時代新潮流WebOS <wbr>【21】WebKit,爲了佈局,忙併美麗

Figure 1. Incunabulum, the end of 15'th century
Courtesyhttp://www.citrinitas.com/history_of_viscom/images/printing/venice-1505.jpg

[轉載]新時代新潮流WebOS <wbr>【21】WebKit,爲了佈局,忙併美麗

Figure 2. City of Words, by Vito Acconi, 1999
Courtesyhttp://upload.wikimedia.org/wikipedia/en/6/63/%27City_of_Words%27%2C_lithograph_by_Vito_Acconci%2C_1999.jpg

Figure 1中顯示的是1490年代的書籍,不難看出,現代書報中廣泛使用的雙列,邊注,頁碼,首字母大寫等等,都是繼承了500多年以前的做法。而CSS規範,囊括了所有這些頁面設計的要素。

在當今信息爆炸的形勢下,如何安排頁面的佈局排版,在有限的頁面面積內,承載更多內容,突出讀者關注的內容,增強頁面設計的視覺美感,成爲不可迴避的問題。例如,手機購物的UI設計,既要包含商品簡介,又要包含用戶意見反饋,還要包含實物照片,以及各個不同商場的標價等等。完美的頁面設計,不僅要求簡練而清晰,而且也不能遺漏相關內容,實在是一件困難的事情。可以說,手機購物之所以不普及,與手機購物的UI設計笨拙而醜陋是相關的。

要巧妙地 設計手機應用的UI設計,終極而言,需要突破傳統的單一鳥瞰視角的方式,Figure 2就是這方面的嘗試。Webkit能不能做到這一點?原理上是可以做到的,但是必須修改源代碼。但是在改造以前,我們還是先踏踏實實研究一下,Webkit的佈局排版的內部機制是什麼。只有充分了解對方之長,纔有可能改進對方之短。

讀解Webkit排版佈局與繪製的具體實現以前,首先需要明確的是,Webkit把排版佈局(layout),與繪製(paint),分開處理。

Layout負責確定RenderTree中,每個葉子和中間節點的位置。每個節點在屏幕上的顯示,都呈長方形格局。所謂位置,指的是這個長方形左上角起始座標(X,Y),以及長方形的寬度和高度。每個中間節點的長方形,裏面嵌套着若干小長方形,對應這個中間節點的後代節點等等。

在Layout過程結束以後,Webkit啓動 Paint過程,負責把RenderTree中各個葉子節點,在相應的位置繪製出來。Webkit 把具體繪製的工作,交給第三方圖形工具庫(GraphicsLibrary)去完成。常用的第三方圖形工具庫包括QT,GTK+,Wx,Skia,Cairo等等。

打個比方,圖形工具庫相當於活字,以及繪製圖像的石板(lithography),它們負責paint。而從嚴格意義上來說,Webkit的主要工作是layout,也就是排版佈局,相當於版面模版。

關於圖形庫,臺灣的開源高手,黃敬羣(Jim Huang / jserv),寫過一篇介紹Google Skia圖形庫的文章(http://blog.linux.org.tw/~jserv/archives/002095.html)。文中談到,

Google爲了搭建Android平臺,於2005年8月併購了Android公司。同年11月份,Google還收購了Skia公司。2007年11月,Google發佈Android,並公開部分源代碼。當人們熱衷於探究Android DalvikVM的奧祕的時候,忽略了Skia的意義。

2008年9月,Google發佈了以改良的Webkit爲核心的Chrome PC瀏覽器。當人們熱衷於探究V8JavaScript引擎等等功能模塊時,再次忽略了Skia的意義。

Skia是一個2D圖形工具庫,該產品的特色在於,能夠在手機等等移動設備中,以較低的內存和CPU消耗,呈現高品質的2D圖形。

Skia 的創辦人,Mike Reed,是圖形技術方面的頂尖人物。Mike早年任職於Apple,參與QuickDrawGX項目,處理字型和圖像顯示。後來他跳槽到OpenWave,開發手機瀏覽器。在OpenWave工作期間,與BenoitSchillings合作,在50-300KB的內存空間內,提供圖層之間alphablended方式的預覽,以及全功能向量矩陣轉換等等,真可謂螺絲殼裏做道場。後來BenoitSchillings離開OpenWave,去Trolltech任職CTO。Trolltech的主打產品是大名鼎鼎的QT。再後來Trolltech被Nokia併購,Benoit隨之加入Nokia。Benoit Schillings離開OpenWave不久,MikeReed也離開了OpenWave,去創建Skia公司。


[轉載]新時代新潮流WebOS <wbr>【21】WebKit,爲了佈局,忙併美麗
Figure 3. Layout implementation in Webkit
Courtesyhttp://www.flickr.com/photos/87209438%40N00/3609632247/sizes/l/

[轉載]新時代新潮流WebOS <wbr>【21】WebKit,爲了佈局,忙併美麗
Figure 4. Paint implementation in Webkit
Courtesyhttp://www.flickr.com/photos/87209438%40N00/3609632249/sizes/l/


Figure 3 和 Figure 4,分別顯示了Webkit執行排版佈局(layout),以及繪製(paint)的兩個過程。仔細查看這兩張sequencediagrams,會發現以下特點,

1. Layout 和 Paint這兩個過程完全分開。開始執行Paint過程以前,必然預先執行過Layout,否則圖形庫就不知道在哪裏寫字以及顯示圖像。但是這並不意味着,Layout執行結束後,隨即就立刻執行Paint。實際上,Layout執行結束後,觸發一個事件,這個事件啓動Paint過程。但是Paint過程也可以被其它事件觸發,譬如屏幕內容的切換,以及把隱藏的瀏覽器窗口復原等等。

2. Layout涵蓋了所有CSS規定的佈局要素。包括頁面邊緣與內容之間的空白,文字對插入圖像的避讓(floating),單列與多列,上下層覆蓋(z-index)等等。

3. 圖像,視頻播放器插件,Applet等等,在 Layout 被稱作 Replaced Render Object。這些Replaced元素的寬度和高度可以由CSS規定。如果CSS沒有規定,就解析這些元素的數據流,譬如一個JPG照片的metadata裏,規定了這幅照片原件的寬度和高度。如果元素自己也沒有規定寬度高度,就使用Webkit提供的缺省值。

4.文字的寬度根據頁面的排版來確定。譬如一頁中包含多列文字,則每列文字寬度相等。每列文字的寬度,乘以列數,加上列與列之間的夾縫,加上頁面邊緣空白等等,應當等於頁面總的寬度。假設頁面總的寬度已知,邊緣空白,和列與列之間的夾縫的寬度也已知,就可以反推文字的寬度。

5. RenderTree中每個節點在屏幕上的顯示,都呈長方形格局。前面第3點和第4點,描述了寬度的確定。而高度的確定,取決於這個中間節點的所有後代節點的高度的總和。對於 Replaced元素來說,它的高度相對比較容易確定,而文字段落的高度,需要根據字數,字型,以及字體大小計算得出。

6. 在 Layout 過程中,反覆出現以 Repaint 爲開頭的子過程,例如repaintAfterLayoutIfNeed
ed()。這些子過程的意義在於,當確定了某個節點的高度和寬度以後,需要對其前輩節點,和左右兄弟節點的位置,做適當調整。嚴格意義上來講,這不是repaint,而是relayout。

7. 相對於 Layout 過程,Paint過程的邏輯要簡單得多。Paint的過程,大致按照深度優先的順序,遍歷整棵RenderTree。也就是說,從最左邊的葉子節點開始,從左向右逐個繪製RenderTree所有可以顯示的葉子節點。所謂“可以顯示的葉子節點”,是因爲CSS中可以規定,不顯示某些葉子。


反覆研究以上Layout和Paint的過程,我們有以下看法。

1. Layout是一個計算量很繁重的過程。之所以繁重,主要體現在估算完每個RenderTree節點的寬度尤其是高度以後,需要相應調整這個節點的前輩節點以及左鄰右舍兄弟節點的位置。對於文字段落而言,它的高度有賴於字數,字體和大小,所以估算不容易準確。

有沒有可能把Layout 過程,與第一遍 Paint 過程合二爲一?只要遍歷一次RenderTree的所有葉子節點,繪製圖像並碼字。Paint過程結束後,各個葉子節點對應的長方形的起始位置的(X,Y)座標,以及寬度和高度都自然迎刃而解。然後再由葉子節點開始,逐步確定RenderTree中,各個中間節點的起始位置和寬度高度。這樣做的好處是,可以大大降低Layout 過程的成本。

2. Layout 過程假設每個RenderTree 的節點都對應一個長方形屏幕區域。受限於這個規定,類似於Figure2的效果,就顯示不出來。有沒有可能取消這個限制?SVG不僅提供了強大的繪圖能力,而且也提供了強大的排版佈局能力。能不能把CSS當着SVG格式的一個子集來看待?

發佈了3 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章