Skip to content

Getting started with layout

Corey Farwell edited this page Aug 10, 2015 · 5 revisions

Getting started with the layout code

There are a number of ways to help out with the layout code:

  1. Find a layout bug in a web page, and create a github issue with a minimal test case.

    This is very useful as it can be a time consuming process (see section below for a guide on creating minimal test cases). Once the test case is created, you could identify where in the layout code the bug occurs and fix it (or ask for help on IRC).

  2. Fix existing bugs.

    Search the github issues list for layout bugs, and find some that also have the E-easy tag applied:

  3. Add a new feature.

    Most of the remaining layout features are large in scope, so it's difficult to start out with a brand new feature. If there is a particular layout feature you want to implement, it's best to discuss in IRC first.

Creating a minimal test case for a layout bug:

Creating minimal test cases can be time consuming, but following these steps generally works:

  • Find a page that displays correctly in Firefox but has layout bugs in Servo.
  • Use the File: "Save Page As..." menu command in Firefox to save the page locally. Select the "Web page, complete" option in the Save dialog so images and stylesheets are included. (Firefox Nightly users: this will only work in a non-e10s window.)
  • Confirm the locally saved version still displays fine in FF but not Servo.
  • Open the FF developer tools, and go to the Inspector tab.
  • Delete some nodes, re-save the web page and confirm that it is still working in FF but not Servo.
  • If you break the page in FF, you can ctrl-z to undo your element changes.
  • Try to remove script elements, and style elements from the header section first, as they tend to be large and fairly easy to remove the majority of them.
  • Keep deleting nodes and testing the bug still occurs, until you have a minimal case.
  • Once you get to a small page saved locally that reproduces the problem, (optionally) open it in a text editor and simplify further.
  • Start debugging the test case in servo and/or open an issue on the github tracker with the minimal test case.

For an example of a minimal repro test - see https://github.com/servo/servo/issues/4945

Some tips for debugging layout:

Enable some or all of the following command line flags when debugging layout:

  • -y 1 Disable parallel layout.
  • -t 1 Disable parallel painting.
  • -i Forces non-incremental layout. This can be useful to test if a layout bug is related to incremental layout.
  • -Z bubble-widths Makes the bubble widths pass run separately, which can make it simpler to see what is going on.
  • -Z dump-flow-tree Will dump the flow tree.
  • -Z dump-display-list Dumps the display list (with geometric information).
  • -Z relayout-event Prints information when there is a reflow event.

High level overview of the layout code:

The layout code is responsible for using the input DOM nodes + CSS styles to build the Flow Tree, which is then used to build the Display List. The resulting display list is handed off to the paint tasks to do the actual drawing.

  • Look for the handle_reflow function in layout_task.rs - this is the entry point to doing a layout reflow.
  • Enable the node.dump() call near the start of the function to print to the console what the incoming DOM tree looks like.
  • Set the -Z dump-flow-tree command line option to print the resulting flow tree.

Major parts of handle_reflow:

  • traverse_dom_preorder - Traverse the DOM and do CSS selector matching + build the flow tree.
  • solve_constraints - Perform layout to determine where every box is on the page. This does several flow tree traversals.
    • BubbleISizes (bottom-up) — computes intrinsic inline-sizes (minimum and preferred) from children. See http://dbaron.org/css/intrinsic/
    • AssignISizes (top-down) — computes actual inline-sizes from parent inline-sizes.
    • AssignBSizesAndStoreOverflow (bottom-up) — computes actual block-sizes (for example, by performing word wrapping) and sends
  • build_display_list_for_reflow (top-down and bottom-up) - Build a display list consisting of a tree stacking contexts containing drawing commands. This data structure is then sent to the paint tasks.
    • Computation of stacking-context-relative positions (top-down)—computes the exact position of every item on the page.
    • Display list building (bottom-up)—builds drawing commands for every fragment on the page.

Terminology:

advance The inline distance between one glyph and the next.

Azure, Moz2D The 2D vector painting library that Servo uses for all content and that Gecko uses for some content. Moz2D can use Direct2D, Skia, Cairo, and Core Graphics as backends, in both CPU and GPU-accelerated modes.

block formatting context See https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context

computed values/computed style A data structure that stores the actual CSS property values that the engine calculated for each DOM node. These are computed from the DOM and the CSS style sheets during style recalculation.

display list A set of drawing commands sent to the painting task to be painted in parallel. Display lists are generated out-of-order and then shuffled into the proper paint order per CSS 2.1 Appendix E.

display list optimization An optimization pass that runs over display lists before they're painted and throws out display items that aren't visible (because they're entirely outside the tile or because they're covered up by another display item).

flow A container of fragments that forms the units over which parallel layout occurs. Generally speaking, every flow can be laid out in parallel. (Exceptions include flows impacted by floats and block formatting contexts.) Block flows are in 1:1 mapping with their fragments, since blocks can be laid out in parallel, while inline flows are in 1:N mapping with their fragments, since inlines in the same paragraph cannot be laid out in parallel.

fragment A box on the page. May have borders, padding, margins, and content. Examples of fragments include text fragments and image fragments.

generic fragment A fragment with no replaced content (for example, a regular old div).

glyph run One shaped word within a larger text run. Text runs are divided into glyph runs so that we can cache the shaped words individually; as words are frequently repeated on pages, this saves a lot of time.

HarfBuzz The library that Servo uses for shaping.

inline-size, block-size The abstract notion of width and the abstract notion of height, respectively. Because of writing modes, inline-size may actually be either width or height depending on whether the writing direction is horizontal or vertical, and likewise with block-size.

layer A hardware backing store for a stacking context (i.e. a set of GPU textures). A stacking context with a layer can be animated and transformed purely on the compositor, without having to rebuild display lists. Not all stacking contexts have layers.

overflow area A rectangle that encompasses all the paint inside a particular fragment or flow.

reflow The combination of style recalculation, layout, and display list construction.

shaping The process of converting a Unicode string in a particular font to a series of glyphs and advances.

stacking context See: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context In Servo, stacking contexts contain display lists.

style recalculation A pass that determines the computed values that apply to each DOM node.

text run A shaped string of glyphs in one font. Text runs are divided into glyph runs.

Clone this wiki locally