Mozilla's Layout Engine
Wednesday, July 12, 2006, 16:00 PDT
Some bits taken from 2002 tech talks on gecko (waterson) and style system (dbaron)
Layout
- where things go on the screen / paper
- between content and view+gfx
- also interacts with images, plugins, etc.
Layout (and neighbors)
- single threaded
- most operations run to completion off main event loop
Layout (and neighbors)
Layout (and neighbors)
Layout (and neighbors)
Input (concepts)
- content tree
- images, plugins, etc.
Input: Content tree
<doc>
<title>A few quotes</title>
<para class="emph">
Franklin said that <quote>"A penny
saved is a penny earned."</quote>
</para>
<para>
FDR said <quote>"We have nothing to
fear but <span class="emph">fear
itself.</span>"</quote>
</para>
</doc>
Input: Content tree
| doc | |
| ↙ | ↓ | ↘ | |
title | | para class="emph" | | para |
| ↓ | | ↓ |
| quote | | quote |
| ↓ |
| span class="emph" |
Input: Content Tree APIs
- nsIContent, nsINode, etc. (internal; preferred)
- nsIDOM* (frozen)
Output (concepts)
- Calls to 2-D graphics API
- translate, save, restore, fill rect, draw text, draw image, etc.
- See vlad's talk
- Mapping from coordinates back to content nodes (e.g., for event handling)
- APIs for computed style and element positions
Parts of Layout
- Style data computation
- Frame construction
- Reflow
- Painting (and event handling)
- Glue to hold things together
- Other things on frame classes: selection, accessibility, etc.
Sources of style data
- nsIStyleSheet; nsIStyleRuleProcessor
- nsIStyleRule
- examples of implementations (CSS, mapped attributes)
- selector matching done up-front
Style context
- The internal API for computed style data
- style structs
- lazily computed data
- immutable
- shared among siblings
Rule tree
Rules:
/* rule 1 */ doc { display: block; text-indent: 1em; }
/* rule 2 */ title { display: block; font-size: 3em; }
/* rule 3 */ para { display: block; }
/* rule 4 */ [class="emph"] { font-style: italic; }
|
Rule tree:
| A: null | |
| ↙ | ↓ | | ↓ | ↘ | |
B: 1 | | C: 2 | | D: 3 | | E: 4 |
| ↓ | |
| F: 4 | |
|
Style context tree:
| doc: B | |
| ↙ | ↓ | ↘ | |
title: C | | para: F class="emph" | | para: D |
| ↓ | | ↓ |
| quote: A | | quote: A |
| ↓ |
| span: E class="emph" |
|
Frames
- Bad name: CSS "box", "rendering object"
- nsIFrame interface
- internal
- XUL: nsIBox, nsIBoxLayout
- tree structure, using linked lists of children
Examples of frame classes
- nsBlockFrame
- nsInlineFrame
- nsTableRowFrame
- nsViewportFrame
- nsGfxScrollFrame
- nsBoxFrame, nsLeafBoxFrame
- nsSVGOuterSVGFrame
- many more
Frame construction
- nsCSSFrameConstructor.cpp
- Also has some frame initialization code that could be refactored
- Based on element name or style data
- Recursive, but need not start at top
- Most often done in response to nsIDocumentObserver notifications
- frame->content pointers, content->frame hashtable
Continuations
- line breaking
- page breaking
- bidirectional text
Continuations
<p>text <span>with
line</span> breaks</p> |
text with
line breaks |
<Block>text <Inline(1)>with</Inline(1)>
<Inline(2)>line</Inline(2)> breaks</Block> |
Continuations
(diagram from continuation model)
Root Root
| / | \
A A1 A2 A3
/ \ / | | |
B C B C1 C2 C3
| /|\ | | | \ |
D E F G D E F G1 G2
Generated content
(Differences between frame and content trees, #1.)
<p>World</p> |
p:before { display: inline; content: url(icon.png) "Hello"; } |
|
| Block(p) | |
| ↓ | ↘ | |
| Inline(p:before) | | Text "World" |
| ↙ | ↓ | |
Image | | Text "Hello" | |
|
XBL
(Differences between frame and content trees, #2.)
- XBL interleaves "anonymous" content with content tree
- Frame tree matches the "flattened" (interleaved) content tree
- XTF similar
Floats and absolute positioning
(Differences between frame and content trees, #3.)
- floats and absolutely positioned elements (and some others) are "out of flow"
- placed at a different place in the frame tree than they are in the content tree
- a placeholder frame is placed where they would have been with a pointer
- The frame manager has a hashtable for the reverse (out of flow -> placeholder) mapping
- multiple child lists
- float ends up in additional child list of its containing block
Floats and absolute positioning
(Differences between frame and content trees, #3.)
<p>This is a document with <span>some
markup and a floating <img align="left"
src="icon.png"> image</span> in it.</p> |
This is a document with some
markup and a floating image in it. Blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah.
|
Extra frames
(Differences between frame and content trees, #4.)
- table
- table cell
- scroll frame
- viewport
Extra frames
(Differences between frame and content trees, #4.)
table |
↓ |
tbody |
↓ |
tr |
↓ |
td |
↓ |
"Cell" |
|
TableOuter(table) |
↓ |
Table(table) |
↓ |
TableRowGroup(tbody) |
↓ |
TableRow(tr) |
↓ |
TableCell(td) |
↓ |
Block(td) |
↓ |
"Cell" |
|
Reflow
- Computing coordinates (top, left, width, height) for frames
- top and left relative to parent
- Recursive, starting from top of tree or reflow roots
- frames that are also boxes use Layout instead
- box->block glue in in nsFrame::DoLayout, GetPrefSize, etc.
- block->box glue in nsBoxFrame::Reflow, nsLeafBoxFrame::Reflow
- usually off the main event loop
Intrinsic sizes
- boxes have GetMinSize, GetPrefSize, GetMaxSize
- non-boxes will have GetMinWidth, GetPrefWidth
Reflow
- nsHTMLReflowState is input
- nsHTMLReflowMetrics is output
- caller of Reflow responsible for setting the rect to the size in the reflow metrics
- Designed for traditional-style layout (wdiths input, heights output)
Breaking
- lines, columns, pages
- Breaking done by propagating break-before or break-after status out of reflow
- Caller responsible for creating next-in-flow and propagating status
Intrinsic widths (future)
- nsIFrame::GetPrefWidth and GetMinWidth
- Separate methods for inline layout
Incremental layout (future)
- bits: is dirty, has dirty children
- intrinsic widths can be marked as dirty too (and are, up & down)
Box Layout
- Parent sizes box first, then calls Layout
- much of the work done by an nsIBoxLayout object (sprocket, stack/deck)
- grid, tree more complicated
Painting
- BuildDisplayList method builds a display list for the frames in a
clip rect or at a point
- we then paint the items in the list from bottom-most-needed to
top
- views mostly vestigial
- usually off the main event loop
Painting: BuildDisplayList
- Recursive, starting from root
- will soon cross parent/child presentations, if it doesn't already
- Only adds items that are in the clip rect / at the event's point
- Single recursive call to build lists for a multi-pass algorithm
- Various display items added to display list, for painting things like
- Read CSS2.1 Appendix E for requirements
Invalidation
- Reflow invalidates regions that need to be repainted
- We don't have a good sense of what the rules are, and they'll hopefully change soon
- maximum containing rectangle or each rectangle separately?
Painting
- Display list optimized to avoid painting things underneath fully opaque things, etc.
- Paint bottom-to-top, using 2-D graphics API
Event handling
- point ← frame mapping must use paint order
- so we use the same display list
Reasons to optimize dynamic changes
- Incremental page loading
- Small changes should take smaller amounts of time (DOM manipulation,
editing)
- resizing
Dynamic changes: content changes
- document observer notifications trigger frame destruction/construction
- incremental reflow
- repaint invalidated region
Dynamic changes: attribute and event state changes
document .getElementById("ok-button") .removeAttribute("disabled");
- Changes to :hover, :checked, :link (vs. :visited)
- Style system makes a somewhat (not very) conservative approximation for whether something might have changed
- Worth doing as much work as selector matching since it's not the whole subtree
- If a change, processed as a style change
Dynamic changes: style changes
document .getElementById("foo") .style .color = "green";
- style changes caused by attribute or event state changes
- rerun rule matching on subtree
- recursively compare data in old and new style contexts
- hints (applying to subtree): frame reconstruction, reflow, repaint, etc.