preface

Learning resources from Geek Time – Teacher Li Bing “Browser working principle and Practice”. Next, let’s check in every day

  • Day 01 Chrome architecture: Why 4 processes with only 1 page open?
  • Day 02 TCP: How to ensure that a page file can be delivered to the browser in its entirety?
  • Day 03 HTTP Request Flow: Why do many sites open quickly the second time?
  • Day 04 Navigation flow: What happens between entering the URL and presenting the page?
  • Day 05 Rendering Flow: How do HTML, CSS, and JavaScript become pages?

In the previous article, from entering URL to displaying what happens on the page, relevant content contained in the rendering process has been recorded. In the course of learning Li Bing here, I hope to further refine the learning and sorting.

Once the navigation is committed, the rendering phase begins, as described in the previous article. We have written HTML, CSS, JavaScript and other files, through the browser rendering module processing, the final output as pixels on the screen.

Due to the complexity of the rendering mechanism, the rendering module is divided into many sub-stages in the execution process, which is called the process flowRendering line, the general process is shown in the figure below:

According to the chronological order of rendering, the pipeline can be divided into the following sub-stages: DOM tree building, style calculation, layout stage, layering, drawing, chunking, rasterization, and composition.

During each phase, the following three points need to be focused:

  • At the beginning each sub-stage has its input;
  • Then each sub-stage has its own process;
  • Eventually each sub-stage generates output.

Build a DOM tree

Why build a DOM tree? This is because HTML cannot be understood and used directly by browsers, so you need to transform the HTML into a structure that browsers can understand — a DOM tree.

Here we also need a brief introduction to what is a tree structure. For a more intuitive understanding, you can refer to the following tree structure I draw:

As can be seen from the figure, the tree structure is very similar to the “tree” in our real life. Each point is called a node, and the connected nodes are called parent-child nodes. Trees are often used in browsers, for example in the rendering process we will describe below.

Let’s take a look at the DOM tree construction process. You can refer to the following figure:

As you can see from the figure, the input for building a DOM tree is a very simple HTML file, which is then parsed by an HTML parser and finally outputs the DOM as a tree structure.

To get a more intuitive view of the DOM tree, you can open Chrome’s Developer Tools, select the “Console” TAB to open the Console, type “Document” in the Console, and press Enter. You should see a complete DOM tree structure, as shown below:

The DOCUMENT in the DOM visualization is the DOM structure. As you can see, DOM is almost identical to HTML content, but unlike HTML, DOM is an in-memory tree structure that can be queried or modified using JavaScript. Then below to see how to use JavaScript to modify the content of the DOM, in the console input: the document. The getElementsByTagName (” p “) [0]. The innerText = “black”

What this line of code does is take the first one

Modify the content of the label to black. You can refer to the following figure for the specific execution result:

Modifying the DOM through JavaScript as you can see from the diagram, a section of modification is performed before the first one

After the JavaScript code of the tag, the content of the first P node of the DOM is successfully modified, along with the content of the page.

Ok, so now that we have generated the DOM tree, we still don’t know the style of the DOM node. To get the DOM node to have the correct style, we need to do style calculation.

Recalculate Style

The purpose of style calculation is to calculate the specific style of each element in the DOM node, which can be roughly divided into three steps.

1. Convert CSS to a structure that browsers can understand

So what are the main sources of CSS styles? You can start by looking at the following image:

Just like HTML files, browsers don’t understand the CSS styles of plain text directly, so when the rendering engine receives CSS text, it performs a conversion operation to convert the CSS text into a structure that browsers can understand :styleSheets.

To understand, you can look at the structure in the Chrome console. Just type Document. styleSheets in the console and you’ll see the structure like this:

As you can see from the figure, the stylesheet contains many styles, including styles from all three sources. Of course, the structure of the stylesheet is not the focus of our discussion today, but you need to know that the rendering engine converts all the CSS text retrieved into styleSheets, and that this structure has both query and modification capabilities, which will provide the basis for future stylesheet operations.

2. Transform property values in the stylesheet to standardize them

Now that we’ve converted the existing CSS text into a structure that browsers can understand, it’s time to standardize the property values.

To understand what attribute value normalization is, you can look at CSS text like this:

body { font-size: 2em }
p {color:blue; } span {display: none}
div {font-weight: bold}
div  p {color:green; } div {color:red; }
Copy the code

As you can see in the CSS text above, there are many attribute values, such as 2em, Blue and bold. These values are not easily understood by the rendering engine, so you need to convert all values into standardized computed values that the rendering engine can easily understand. This process is called attribute value standardization.

So what are the normalized attribute values?

As you can see, 2em is resolved to 32px, red is resolved to RGB (255,0,0), bold is resolved to 700…

3. Calculate the specific style of each node in the DOM tree

Now that the style properties have been standardized, you need to calculate the style properties for each node in the DOM tree. How?

This is where CSS inheritance and cascading rules come in.

The first is CSS inheritance. CSS inheritance is when each DOM node contains the style of its parent node. While this may seem a bit abstract, let’s see how a stylesheet like this is applied to a DOM node using a concrete example.

body { font-size: 20px }
p {color:blue; } span {display: none} div {font-weight: bold; color:red} div p {color:green; }Copy the code

The final effect of the stylesheet applied to the DOM node is shown below:

As you can see from the figure, all child nodes inherit the parent node style. For example, if the font-size property of the body node is 20, then all nodes below the body node will have a font-size of 20.

To deepen your understanding of CSS inheritance, you can open Chrome’s Developer Tools, select the first “Element” TAB, and then select the “Style” sub-tab. You will see the following screen:

This interface displays a wealth of information, which can be roughly described as follows.

  • First, you can select the style of the element you want to view (located in area 2 of the diagram) and click on the element in the first area of the diagram to view the style of the element in the area below. For example, the element we chose here is the tag, located in html.body.div. This path right over here.
  • Second, you can view the specific source information for the style from the ** style source (located in area 3 of the figure) ** to see whether it comes from the style file or the UserAgent style sheet. A special mention is made of the UserAgent style, which is a set of default styles provided by the browser. If you do not provide any styles, the UserAgent style is used by default.
  • Finally, you can look at the process of style inheritance in areas 2 and 3.

These are some of the CSS inherited features, style calculation process, according to the DOM node inheritance relationship to reasonably calculate the node style.

The second rule in style calculation is style cascade. Cascading is a fundamental feature of CSS. It is an algorithm that defines how to combine property values from multiple sources. It is at the heart of CSS, which is highlighted by its full name, cascading style sheets. About the specific rules of cascading here will not do too much introduction, online information is also very much, you can search for learning.

In short, the purpose of the style calculation stage is to calculate the specific style of each element in the DOM node. In the calculation process, two rules of CSS inheritance and cascading need to be observed. The final output of this phase is the style of each DOM node, stored in the ComputedStyle structure.

The layout phase

Now, we have the DOM tree and the styles of the elements in the DOM tree, but that’s not enough to display the page because we don’t yet know the geometry of the DOM elements. The next step is to figure out the geometry of the visible elements in the DOM tree, a process we call layout.

Chrome performs two tasks in the layout phase: creating a layout tree and calculating the layout.

1. Create a layout tree

You may have noticed that the DOM tree also contains many invisible elements, such as the head tag and elements that use the display: None attribute. So, before displaying, we also build an additional layout tree with only visible elements.

Let’s look at the layout tree construction process with the following figure:

As you can see from the figure above, all invisible nodes in the DOM tree are not included in the layout tree.

To build the layout tree, the browser basically does the following:

  • Iterate through all visible nodes in the DOM tree and add these nodes to the layout tree;
  • Invisible nodes are ignored by the layout tree, such as everything under the head tag, or the body.p.pan element, which is not included in the layout tree because its attribute contains dispaly: None.

2. Layout calculation

layered

For complex effects such as complex 3D transformations, scrolling, and z-indexing, the rendering engine will need to create a LayerTree for each node. If you are familiar with Photoshop, you will easily understand the concept of layers, which are added together to form the final page image.

The browser page is actually divided into many layers, which are superimposed to create the final page.

In general, not every node in the layout tree contains a layer, and if a node has no corresponding layer, then the node is subordinate to the layer of the parent node. If the SPAN tags in the image above do not have their own layer, they are subordinate to their parent layer. Eventually, however, each node is directly or indirectly subordinate to a layer.

So what criteria does the rendering engine need to meet to create a new layer for a particular node? Generally, elements that satisfy either of the following two points can be promoted to a separate layer.

First, elements with cascading context attributes are promoted to separate layers.

A page is a two-dimensional plane, but a cascading context gives a three-dimensional concept to HTML elements that are distributed along the Z-axis perpendicular to the two-dimensional plane in terms of their attribute priorities. You can use the following image to get a feel for it:

As you can see from the figure, elements with explicitly positioned attributes, elements with transparent attributes defined, elements with CSS filters, and so on, all have cascading context attributes.

Secondly, the places that need to be clipped will also be created as layers.

Layer to draw

After building the layer tree, the rendering engine will render each layer in the tree, so how does the rendering engine render layers?

Imagine if you were given a piece of paper and told to color the background blue, then draw a red circle in the middle, and then a green triangle on top of that circle. How would you do that?

Normally, you would break your drawing operation into three steps:

  1. Draw a blue background;
  2. Draw a red circle in the middle;
  3. Draw a green triangle on the circle.

The rendering engine implements layer drawing in a similar way, breaking a layer’s drawing into smaller instructions, which are then sequentially assembled into a list of instructions to draw, as shown below:

As can be seen from the figure, the instructions in the draw list are actually very simple. They are asked to perform a simple drawing operation, such as drawing a pink rectangle or a black line. Drawing an element usually requires several drawing instructions, because each element’s background, foreground, and borders require separate instructions to draw. So in the layer drawing phase, the output is these lists to draw.

You can also open the Layers TAB of the Developer Tools and select the Document layer to actually experience drawing a list, as shown in the following image:

In this figure, area 1 is the drawing list of Document, and dragging the progress bar in area 2 can reproduce the drawing process of the list.

Raster operation

A draw list is simply a list of draw orders and draw instructions that are actually done by the compositing thread in the rendering engine. You can see the relationship between the render main thread and the composition thread in the following image:

As shown in the figure above, when the drawing list of layers is ready, the main thread will draw the listsubmit(commit) to the composite thread, so how does the composite thread work next?

Usually a page may be large, but the user can only see part of it. We call the part of the page that the user can see the viewport.

The compositing thread will divide the layer into tiles, which are usually 256×256 or 512×512, as shown below:

The composition thread then prioritizes bitmap generation based on the blocks near the viewport, and the actual bitmap generation is performed by rasterization. Rasterization refers to the transformation of a map block into a bitmap. The graph block is the smallest unit for rasterization. The renderer maintains a rasterized thread pool, where all rasterization is performed, as shown below:

Composition and display

Once all the tiles have been rasterized, the composition thread generates a command to draw the tiles — “DrawQuad” — and submits the command to the browser process.

The browser process has a component called viz that receives DrawQuad commands from the compositing thread, draws its page contents into memory, and displays them on the screen.

At this point, through this series of stages, the HTML, CSS, JavaScript, etc., written by the browser will display a beautiful page.

Rendering assembly line summary

Combined with the above image, a complete rendering process can be summarized as follows:

  1. The renderer transforms the HTML content into a readable DOM tree structure.
  2. The rendering engine translates CSS styleSheets into styleSheets that browsers can understand, calculating the style of DOM nodes.
  3. Create a layout tree and calculate the layout information for the elements.
  4. Layer the layout tree and generate a hierarchical tree.
  5. Generate a draw list for each layer and submit it to the composition thread.
  6. The composite thread divides the layer into blocks and converts the blocks into bitmaps in the rasterized thread pool. 7. The composite thread sends the DrawQuad command to the browser process.
  7. The browser process generates the page from the DrawQuad message and displays it on the monitor.