前面介紹了 Render 樹,RenderLayer,還有RenderObject,可能對這些概念仍是有點模糊,這裏再補充下。chrome
當瀏覽器經過網絡或者本地文件系統加載一個 HTML 文件,並對它進行解析完畢後,內核就會生成它最重要的數據結構 - DOM 樹。canvas
DOM 樹上每個節點都對應着網頁裏面的每個元素,而且網頁也能夠經過 JavaScript 操做這棵 DOM 樹,動態改變它的結構。可是 DOM 樹自己並不能直接用於排版和渲染,內核還會生成另一棵樹 - Render 樹,Render 樹上的每個節點 - RenderObject,跟 DOM 樹上的節點幾乎是一一對應的,當一個可見的 DOM 節點被添加到 DOM 樹上時,內核就會爲它生成對應的 RenderOject 添加到 Render 樹上。瀏覽器
Render 樹是瀏覽器排版引擎的主要做業對象,排版引擎根據 DOM 樹和 CSS 樣式表的樣式定義,按照預約的排版規則肯定了 Render 樹最後的結構,包括其中每個 RenderObject 的大小和位置,而一棵通過排版的 Render 樹,則是瀏覽器渲染引擎的主要輸入,讀者能夠認爲,Render 樹是銜接瀏覽器排版引擎和渲染引擎之間的橋樑,它是排版引擎的輸出,渲染引擎的輸入。網絡
不過瀏覽器渲染引擎並非直接使用 Render 樹進行繪製,爲了方便處理 Positioning(定位),Clipping(裁剪),Overflow-scroll(頁內滾動),CSS Transform/Opacity/Animation/Filter,Mask or Reflection,Z-indexing(Z排序)等,瀏覽器須要生成另一棵樹 – Layer 樹。數據結構
渲染引擎會爲一些特定的 RenderObject 生成對應的 RenderLayer,而這些特定的 RenderObject 跟對應的 RenderLayer 就是直屬的關係,相應的,它們的子節點若是沒有對應的 RenderLayer,就從屬於父節點的 RenderLayer。最終,每個 RenderObject 都會直接或者間接地從屬於一個 RenderLayer。ide
RenderObject 生成 RenderLayer 的條件,來自 GPU Accelerated Compositing in Chrome性能
- It’s the root object for the page
- It has explicit CSS position properties (relative, absolute or a transform)
- It is transparent
- Has overflow, an alpha mask or reflection
- Has a CSS filter
- Corresponds to canvas element that has a 3D (WebGL) context or an accelerated 2D context
- Corresponds to a video element
瀏覽器渲染引擎遍歷 Layer 樹,訪問每個 RenderLayer,再遍歷從屬於這個 RenderLayer 的 RenderObject,將每個 RenderObject 繪製出來。讀者能夠認爲,Layer 樹決定了網頁繪製的層次順序,而從屬於 RenderLayer 的 RenderObject 決定了這個 Layer 的內容,全部的 RenderLayer 和 RenderObject 一塊兒就決定了網頁在屏幕上最終呈現出來的內容。ui
軟件渲染模式下,瀏覽器繪製 RenderLayer 和 RenderObject 的順序,來自 GPU Accelerated Compositing in Chromethis
In the software path, the page is rendered by sequentially painting all the RenderLayers, from back to front. The RenderLayer hierarchy is traversed recursively starting from the root and the bulk of the work is done in RenderLayer::paintLayer() which performs the following basic steps (the list of steps is simplified here for clarity):spa
- Determines whether the layer intersects the damage rect for an early out.
- Recursively paints the layers below this one by calling paintLayer() for the layers in the negZOrderList.
- Asks RenderObjects associated with this RenderLayer to paint themselves.
- This is done by recursing down the RenderObject tree starting with the RenderObject which created the layer. Traversal stops whenever a RenderObject associated with a different RenderLayer is found.
- Recursively paints the layers above this one by calling paintLayer() for the layers in the posZOrderList.
In this mode RenderObjects paint themselves into the destination bitmap by issuing draw calls into a single shared GraphicsContext (implemented in Chrome via Skia).