1. 程式人生 > >理解WebKit和Chromium: Chromium WebView和Chrome瀏覽器渲染機制

理解WebKit和Chromium: Chromium WebView和Chrome瀏覽器渲染機制

轉載請註明原文地址:http://blog.csdn.net/milado_nju

## 資料對比

前面介紹過Chromium WebView的時候,說過有關ChromiumWebView同Chrome瀏覽器有很多不同之處,下面以Chromium Content Shell來對比來描述Chromium WebView,這是因為Chrome瀏覽器的渲染機制等同Content Shell是類似的,不過Chrome瀏覽器上層程式碼是源的,所以筆者使用自己編譯的Content Shell來分析。

在仔細介紹Chromium WebView之前,先看一組效能方面的資料,是有關於Chromium WebView和Chromium Content Shell的對比。雖然版本有些舊,並且現在的變化很快,但是這一版本依舊能夠說明一些問題。

下面的效能資料是在Android4.4系統上測試基於Chromium30的WebView和ChromiumContent Shell。所使用的測試的兩個Benchmark一個是測試CSS3D效能,另外一個是測試Canvas 2D效能。效能指標主要是包括FPS和記憶體兩個方面,如下圖所示。

效能方面,目前Content Shell較ChromiumWebView有不錯的表現,在CSS3D和Canvas 2D上都有出色的表現,其中FishIETank出現的特別大的差異主要是因為Chromium 30上硬體加速的Canvas2D技術還沒有支援。在記憶體方面,Chromium WebView使用更少的記憶體,這個主要源於它的程序模型,它沒有使用多程序架構。


## Content Shell的渲染方式

下面詳細描述Content Shell的渲染方式。圖中有多個執行緒,其中標註橙色的是在Browser程序中,標註另外顏色的是Renderer程序。在Renderer執行緒中,主要是渲染樹和合成樹,同時有個合成器執行緒,根據之前章節的描述,它負責合成網頁的各個層。在Android系統上,Chromium中的GPU工作變成一個執行緒,工作在Browser程序中,具體功能之前介紹過。

在Browser程序中,還有一個瀏覽器測的合成器執行緒,它的主要工作是將Renderer程序中合成結果和瀏覽器介面的一些內容合成起來,輸出到SurfaceView物件。因為Android上SurfaceView的特性,所以可以為它建立單獨的EGLContext,合成器執行緒可以結果繪製到該SurfaceView物件中顯示出來。

在這一過程中,Chromium並不需要UI執行緒的參與,所有的工作都是在其它執行緒來完成的,所以UI執行緒不會被阻塞。不過,因為Android系統上的動畫、變換等並能作用於SurfaceView物件,所以瀏覽器沒有關係,但是用來嵌入其它UI介面,可能不能滿足開發者的需求。具體的過程如下圖所示。


這種情況下,就需要能夠嵌入使用者介面的一種機制,那就是Chromium WebView。

## Chromium WebView

Chromium WebView同之前的基於AndroidWebKit的所提供的功能類似,那就是它也能夠提供一個View,並嵌入到其它UI介面中,跟其它沒有view沒有什麼不同,只不過是用來渲染網頁,下圖描述Chromium WebView如何將網頁內容繪製到使用者UI介面中。

  

因為Chromium WebView沒有多程序架構,所以圖中所有執行緒都工作在主程序中。首先看渲染執行緒,它也不再工作在Renderer程序。同Content Shell類似,它也是包括渲染樹和合成樹。GPU執行緒也是類似的功能。不同之處在於同步的合成器,將網頁的合成器放在主執行緒中來工作,這裡主要的問題在於,需要繪製網頁內容到UI中的時候需要在UI執行緒。

在Android系統中,如果使用者介面設定的渲染方式硬體加速渲染方式,那麼Android會使用內部HwUI機制。該機制會為每個Activity的內部View(ViewRootImpl類)構建一個HardwareRenderer,該物件能夠建立EGLSurface和EGLContext,並將繪圖動作轉變成OpenGLES的操作。當繪製介面內容的時候,會充值當前EGLContext為自己建立的,逐次呼叫每個View的繪圖操作。當繪製到WebView物件的時候,它會呼叫同步合成器將網頁的結果繪製到當前的FBO中。下圖是Android系統如何呼叫WebView的繪圖網頁內容的過程。


上圖中上面三個階段是Android繪圖系統中的呼叫,下面兩個是WebView的呼叫過程。在繪製介面的過程,會出現多個階段,每個階段的操作可能還不一樣,所以讀者能夠看到圖中Functor::operator函數出現state引數。

如果是軟體渲染模式,那麼問題變得更簡單一些。在Renderer執行緒中,只需要渲染樹,當呼叫WebView::onDraw(Canvas canvas)的時候,將網頁的內容直接繪製在該Canvas物件上。在新版本上,因為使用UberCompositor等機制,所以合成器也能夠直接輸出到一個Bitmap物件上。

## PictureLayer層等處理

除了總體上的繪製機制存在明顯的不同之外,兩者還存在對某些層的繪製方法不一致的地方。這裡的主要原因在於Chromium WebView能夠使用系統內部的函式,而作為App的Content Shell缺不行。主要針對於那些常見的層,也就是基本文字圖片等層PictureLayer,如下圖所示。


左側是Content Shell所使用的機制,右側是Chromium WebView所使用的機制。因為跨程序的原因,Chromium使用共享記憶體將SkPicture繪製的內容(CPU記憶體中儲存)通過共享記憶體傳到Browser程序,並上傳到GPU的紋理物件。右側則是使用“gralloc”函式來分配”graphic buffer”,SkPicture直接將網頁的一層繪製到該緩衝區物件上。

相信隨著時間的推移,ChromiumWebView會越來越接近Content Shell,不過如果Android圖形系統不改變,那麼在某些方面Chromium WebView仍然不會趕上Content Shell的效能,特別是將網頁的結果合成部分必須在UI執行緒來進行,必然會阻礙UI執行緒對使用者事件等的響應。