Gecko:Overview: Difference between revisions

Jump to navigation Jump to search
31,312 bytes removed ,  27 May 2024
Move CSS, layout, and dynamic change handling to firefox source doc.
(→‎WebRender vs Layers: Add a note and bug link about the layers rendering path having been removed.)
(Move CSS, layout, and dynamic change handling to firefox source doc.)
 
Line 198: Line 198:
=== Style System ===
=== Style System ===


==== Quantum CSS (Stylo) ====
The style system section has been moved to https://firefox-source-docs.mozilla.org/layout/StyleSystemOverview.html
 
Starting with Firefox 57 and later, Gecko makes use of the parallel style system written in Rust that comes from Servo.  There's an [https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo/ overview] of this with graphics to help explain what's going on.  The [https://github.com/servo/servo/wiki/Layout-Overview Servo wiki] has some more details.
 
==== Gecko ====
 
The rest of the style section section describes the Gecko style system used in Firefox 56 and earlier.  Some bits may still apply, but it likely needs revising.
 
In order to display the content, Gecko needs to compute the styles
relevant to each DOM node.  It does this based on the model described in
the CSS specifications:  this model applies to style specified in CSS
(e.g. by a 'style' element, an 'xml-stylesheet' processing instruction
or a 'style' attribute),
style specified by presentation attributes, and the default style
specified by our own user agent style sheets.  There are two major
sets of data structures within the style system:
* first, data structures that represent sources of style data, such as CSS style sheets or data from stylistic HTML attributes
* second, data structures that represent computed style for a given DOM node.
These sets of data structures are mostly distinct (for example, they
store values in different ways).
 
The loading of CSS style sheets from the network is managed by the
[https://dxr.mozilla.org/mozilla-central/source/layout/style/Loader.h CSS loader];
they are then tokenized by the
[https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.h CSS scanner]
and parsed by the
[https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSParser.h CSS parser]. 
Those that are attached to the document also expose APIs to
script that are known as the CSS Object Model, or CSSOM.
 
The style sheets that apply to a document are managed by a class called
the [https://dxr.mozilla.org/mozilla-central/source/layout/style/nsStyleSet.h style set].
The style set interacts with the different types of
style sheets (representing CSS style sheets, presentational
attributes, and 'style' attributes) through two interfaces:
[http://dxr.mozilla.org/mozilla-central/source/layout/style/nsIStyleSheet.h nsIStyleSheet] for basic management of style sheets and
[http://dxr.mozilla.org/mozilla-central/source/layout/style/nsIStyleRuleProcessor.h nsIStyleRuleProcessor] for getting the style data out of them.  Usually
the same object implements both interfaces, except in the most important
case, CSS style sheets, where there is a single rule processor for all
of the CSS style sheets in each origin (user/UA/author) of the CSS cascade.
 
The computed style data for an element/frame are exposed to the rest of
Gecko through the class mozilla::ComputedStyle (previously called
nsStyleContext).  Rather than having a member variable for each
CSS property, it breaks up the properties into groups of related
properties called style structs.  These style structs obey the rule that
all of the properties in a single struct either inherit by default (what
the CSS specifications call "Inherited: yes" in the definition of
properties; we call these inherited structs) or all are not inherited by
default (we call these reset structs).  Separating the properties in
this way improves the ability to share the structs between similar
ComputedStyle objects and reduce the amount of memory needed to store
the style data. The ComputedStyle API exposes a method for getting each
struct, so you'll see code like
<code>sc->GetStyleText()->mTextAlign</code> for getting the value of the
text-align CSS property.  (Frames (see the Layout section below) also
have the same
GetStyle* methods, which just forward the call to the frame's
ComputedStyle.)
 
The ComputedStyles form a tree structure, in a shape somewhat like the
content tree (except that we coalesce identical sibling ComputedStyles
rather than keeping two of them around; if the parents have been
coalesced then this can apply recursively and coalasce cousins, etc.;
we do not coalesce parent/child ComputedStyles).
The parent of a ComputedStyle has the style data that the ComputedStyle
inherits from when CSS inheritance occurs.  This means that the parent
of the ComputedStyle for a DOM element is generally the ComputedStyle
for that DOM element's parent, since that's how CSS says inheritance
works.
 
The process of turning the style sheets into computed style data goes
through three main steps, the first two of which closely relate to the
[http://dxr.mozilla.org/mozilla-central/source/layout/style/nsIStyleRule.h nsIStyleRule] interface, which represents an immutable source of style
data, conceptually representing (and for CSS style rules, directly
storing) a set of property:value pairs.  (It is similar to the idea of a
CSS style rule, except that it is immutable; this immutability allows
for significant optimization.  When a CSS style rule is changed through
script, we create a new style rule.)
 
The first step of going from style sheets to computed style data is
finding the ordered sequence of style rules that apply to an element.
The order represents which rules override which other rules:  if two
rules have a value for the same property, the higher ranking one wins.
(Note that there's another difference from CSS style rules: declarations
with !important are represented using a separate style rule.)  This is
done by calling one of the nsIStyleRuleProcessor::RulesMatching methods.
The ordered sequence is stored in a
[http://en.wikipedia.org/wiki/Trie trie] called the rule tree:  the path
from the root of the rule tree to any (leaf or non-leaf) node in the
rule tree represents a sequence of rules, with the highest ranking
farthest from the root.  Each rule node (except for the root) has a
pointer to a rule, but since a rule may appear in many sequences, there
are sometimes many rule nodes pointing to the same rule.  Once we have
this list we create a ComputedStyle (or find an appropriate existing
sibling) with the correct parent pointer (for inheritance) and rule node
pointer (for the list of rules), and a few other pieces of information
(like the pseudo-element).
 
The second step of going from style sheets to computed style data is
getting the winning property:value pairs from the rules.  (This only
provides property:value pairs for some of the properties; the remaining
properties will fall back to inheritance or to their initial values
depending on whether the property is inherited by default.)  We do this
step (and the third) for each style struct, the first time it is needed.
This is done in nsRuleNode::WalkRuleTree, where we ask each style rule
to fill in its property:value pairs by calling its MapRuleInfoInto
function.  When called, the rule fills in only those pairs that haven't
been filled in already, since we're calling from the highest priority
rule to the lowest (since in many cases this allows us to stop before
going through the whole list, or to do partial computation that just
adds to data cached higher in the rule tree).
 
The third step of going from style sheets to computed style data (which
various caching optimizations allow us to skip in many cases) is
actually doing the computation; this generally means we transform the
style data into the data type described in the "Computed Value" line in
the property's definition in the CSS specifications.  This
transformation happens in functions called nsRuleNode::Compute*Data,
where the * in the middle represents the name of the style struct.  This
is where the transformation from the style sheet value storage format to
the computed value storage format happens.
 
Once we have the computed style data, we then store it:  if a style struct
in the computed style data doesn't
depend on inherited values or on data from other style structs, then we
can cache it in the rule tree (and then reuse it, without recomputing
it, for any ComputedStyles pointing to that rule node).  Otherwise, we
store it on the ComputedStyle (in which case it may be shared
with the ComputedStyle's descendant ComputedStyles).
This is where keeping inherited and
non-inherited properties separate is useful:  in the common case of
relatively few properties being specified, we can generally cache the
non-inherited structs in the rule tree, and we can generally share the
inherited structs up and down the ComputedStyle tree.
 
The ownership models in style sheet structures are a mix of reference
counted structures (for things accessible from script) and directly
owned structures.  ComputedStyles are reference counted, and own their
parents (from which they inherit), and rule nodes are garbage collected
with a simple mark and sweep collector (which often never needs to run).
 
* code: [http://dxr.mozilla.org/mozilla-central/source/layout/style/ layout/style/], where most files have useful one line descriptions at the top that show up in DXR
* Bugzilla: Style System (CSS)
* specifications
** [http://www.w3.org/TR/CSS21/ CSS 2.1]
** [http://www.w3.org/TR/css-2010/ CSS 2010, listing stable css3 modules]
** [http://dev.w3.org/csswg/ CSS WG editors drafts] (often more current, but sometimes more unstable than the drafts on the technical reports page)
** [http://dbaron.org/mozilla/visited-privacy Preventing attacks on a user's history through CSS :visited selectors]
* documentation
** [http://www-archive.mozilla.org/newlayout/doc/style-system.html style system documentation] (somewhat out of date)


=== Layout ===
=== Layout ===


Much of the layout code deals with operations on the frame tree (or
The layout section has been moved to https://firefox-source-docs.mozilla.org/layout/LayoutOverview.html
rendering tree).  In the frame tree, each node represents a rectangle
(or, for SVG, other shapes).  The frame tree has a shape similar to the
content tree, since many content nodes have one corresponding frame,
though it differs in a few ways, since some content nodes have more than
one frame or don't have any frames at all.  When elements are
display:none in CSS or undisplayed for certain other reasons, they won't
have any frames.  When elements are broken across lines or pages, they
have multiple frames; elements may also have multiple frames when
multiple frames nested inside each other are needed to display a single
element (for example, a table, a table cell, or many types of form
controls).
 
Each node in the frame tree is an instance of a class derived from
<code>nsIFrame</code>.  As with the content tree, there is a substantial
type hierarchy, but the type hierarchy is very different:  it includes
types like text frames, blocks and inlines, the various parts of tables,
flex and grid containers, and the various types of HTML form controls.
 
Frames are allocated within an arena owned by the PresShell.  Each
frame is owned by its parent; frames are not reference counted, and code
must not hold on to pointers to frames.  To mitigate potential security
bugs when pointers to destroyed frames, we use
[http://robert.ocallahan.org/2010/10/mitigating-dangling-pointer-bugs-using_15.html frame poisoning], which takes two parts.  When a frame is destroyed
other than at the end of life of the presentation, we fill its memory
with a pattern consisting of a repeated pointer to inaccessible memory,
and then put the memory on a per-frame-class freelist.  This means that
if code accesses the memory through a dangling pointer, it will either
crash quickly by dereferencing the poison pattern or it will find a
valid frame.
 
Like the content tree, frames must be accessed only from the UI thread.
 
The frame tree should not store any important data, i.e. any data that cannot
be recomputed on-the-fly.  While the frame tree does
usually persist while a page is being displayed, frames are often
destroyed and recreated in response to certain style changes, and in the
future we may do the same to reduce memory use for pages that are
currently inactive.  There were a number of cases where this rule was
violated in the past and we stored important data in the frame tree;
however, most (though not quite all) such cases are now fixed.
 
The rectangle represented by the frame is what CSS calls the element's
border box.  This is the outside edge of the border (or the inside edge
of the margin).  The margin lives outside the border; and the padding
lives inside the border.  In addition to nsIFrame::GetRect, we also have
the APIs nsIFrame::GetPaddingRect to get the padding box (the outside
edge of the padding, or inside edge of the border) and
nsIFrame::GetContentRect to get the content box (the outside edge of the
content, or inside edge of the padding).  These APIs may produce out of
date results when reflow is needed (or has not yet occurred).
 
In addition to tracking a rectangle, frames also track two overflow
areas: ink overflow and scrollable overflow.  These overflow areas
represent the union of the area needed by the frame and by all its
descendants.  The ink overflow is used for painting-related
optimizations:  it is a rectangle covering all of the area that might be
painted when the frame and all of its descendants paint.  The scrollable
overflow represents the area that the user should be able to scroll to
to see the frame and all of its descendants.  In some cases differences
between the frame's rect and its overflow happen because of descendants
that stick out of the frame; in other cases they occur because of some
characteristic of the frame itself.  The two overflow areas are
similar, but there are differences:  for example, margins are part of
scrollable overflow but not ink overflow, whereas text-shadows are
part of ink overflow but not scrollable overflow.
 
When frames are broken across lines, columns, or pages, we create
multiple frames representing the multiple rectangles of the element.
The first one is the primary frame, and the rest are its continuations
(which are more likely to be destroyed and recreated during reflow).
These frames are linked together as continuations: they have a
doubly-linked list that can be used to traverse the continuations using
nsIFrame::GetPrevContinuation and nsIFrame::GetNextContinuation.
(Currently continuations always have the same style data, though we may
at some point want to break that invariant.)
 
Continuations are sometimes siblings of each other (i.e.
nsIFrame::GetNextContinuation and nsIFrame::GetNextSibling might return
the same frame), and sometimes not.
For example, if a paragraph contains a span which contains a link, and
the link is split across lines, then the continuations of the span are
siblings (since they are both children of the paragraph), but the
continuations of the link are not siblings (since each continuation of
the link is descended from a different continuation of the span).
Traversing the entire frame tree does '''not''' require explicit traversal
of any frames' continuations-list, since all of the continuations are
descendants of the element containing the break.
 
We also use continuations for cases (most importantly, bidi reordering,
where left-to-right text and right-to-left text need to be separated
into different continuations since they may not form a contiguous
rectangle) where the continuations should not be rewrapped during
reflow:  we call these continuations fixed rather than fluid.
nsIFrame::GetNextInFlow and nsIFrame::GetPrevInFlow traverse only the
fluid continuations and do not cross fixed continuation boundaries.
 
If an inline frame has non-inline children, then we split the original
inline frame into parts. The original inline's children are
distributed into these parts like so: The children of the original
inline are grouped into runs of inline and non-inline, and runs of
inline get an inline parent, while runs of non-inline get an anonymous
block parent. We call this 'ib-splitting' or 'block-inside-inline splitting'.
This splitting proceeds recursively up the frame tree until all
non-inlines inside inlines are ancestors of a block frame with anonymous
block wrappers in between. This splitting maintains the relative order
between these child frames, and the relationship between the parts of a
split inline is maintained using an ib-sibling chain. It is important
to note that any wrappers created during frame construction (such as
for tables) might not be included in the ib-sibling chain depending on
when this wrapper creation takes place.
 
TODO: nsBox craziness from https://bugzilla.mozilla.org/show_bug.cgi?id=524925#c64
 
TODO: link to documentation of block and inline layout
 
TODO: link to documentation of scrollframes
 
TODO: link to documentation of XUL frame classes
 
Code (note that most files in base and generic have useful one line descriptions at the top that show up in DXR):
* [http://dxr.mozilla.org/mozilla-central/source/layout/base/ layout/base/] contains objects that coordinate everything and a bunch of other miscellaneous things
* [http://dxr.mozilla.org/mozilla-central/source/layout/generic/ layout/generic/] contains the basic frame classes as well as support code for their reflow methods (ReflowInput, ReflowOutput)
* [http://dxr.mozilla.org/mozilla-central/source/layout/forms/ layout/forms/] contains frame classes for HTML form controls
* [http://dxr.mozilla.org/mozilla-central/source/layout/tables/ layout/tables/] contains frame classes for CSS/HTML tables
* [http://dxr.mozilla.org/mozilla-central/source/layout/mathml/ layout/mathml/] contains frame classes for MathML
* [http://dxr.mozilla.org/mozilla-central/source/layout/svg/ layout/svg/] contains frame classes for SVG
* [http://dxr.mozilla.org/mozilla-central/source/layout/xul/ layout/xul/] contains frame classes for the XUL box model and for various XUL widgets
 
Bugzilla:
* All of the components whose names begin with "Layout" in the "Core" product
 
Further documentation:
* Talk: [https://air.mozilla.org/introduction-to-graphics-layout-architecture/ Introduction to graphics/layout architecture] (Robert O'Callahan, 2014-04-18)
* Talk: [https://air.mozilla.org/bz-layout-and-styles/ Layout and Styles] (Boris Zbarsky, 2014-10-14)
 
 
==== Frame Construction ====
 
Frame construction is the process of creating frames.  This is done when styles change in ways that require frames to be created or recreated or when nodes are inserted into the document.  The content tree and the frame tree don't have quite the same shape, and the frame construction process does some of the work of creating the right shape for the frame tree.  It handles the aspects of creating the right shape that don't depend on layout information.  So for example, frame construction handles the work needed to implement [http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes table anonymous objects] but does not handle frames that need to be created when an element is broken across lines or pages.
 
The basic unit of frame construction is a run of contiguous children of a single parent element.  When asked to construct frames for such a run of children, the frame constructor first determines, based on the siblings and parent of the nodes involved, where in the frame tree the new frames should be inserted.  Then the frame constructor walks through the list of content nodes involved and for each one creates a temporary data structure called a '''frame construction item'''.  The frame construction item encapsulates various information needed to create the frames for the content node: its style data, some metadata about how one would create a frame for this node based on its namespace, tag name, and styles, and some data about what sort of frame will be created.  This list of frame construction items is then analyzed to see whether constructing frames based on it and inserting them at the chosen insertion point will produce a valid frame tree.  If it will not, the frame constructor either fixes up the list of frame construction items so that the resulting frame tree would be valid or throws away the list of frame construction items and requests the destruction and re-creation of the frame for the parent element so that it has a chance to create a list of frame construction items that it <em>can</em> fix up.
 
Once the frame constructor has a list of frame construction items and an insertion point that would lead to a valid frame tree, it goes ahead and creates frames based on those items.  Creation of a non-leaf frame recursively attempts to create frames for the children of that frame's element, so in effect frames are created in a depth-first traversal of the content tree.
 
The vast majority of the code in the frame constructor, therefore, falls into one of these categories:
* Code to determine the correct insertion point in the frame tree for new frames.
* Code to create, for a given content node, frame construction items.  This involves some searches through static data tables for metadata about the frame to be created.
* Code to analyze the list of frame construction items.
* Code to fix up the list of frame construction items.
* Code to create frames from frame construction items.
 
Code: [http://dxr.mozilla.org/mozilla-central/source/layout/base/nsCSSFrameConstructor.h layout/base/nsCSSFrameConstructor.h] and [http://dxr.mozilla.org/mozilla-central/source/layout/base/nsCSSFrameConstructor.cpp layout/base/nsCSSFrameConstructor.cpp]
 
==== Physical Sizes vs. Logical Sizes ====
 
TODO: Discuss inline-size (typically width) and block size (typically height), writing modes, and the various logical vs. physical size/rect types.
 
==== Reflow ====
 
Reflow is the process of computing the positions and sizes of frames.  (After all,
frames represent rectangles, and at some point we need to figure out
exactly *what* rectangle.)  Reflow is done recursively, with each
frame's Reflow method calling the Reflow methods on that frame's
descendants.
 
In many cases, the correct results are defined by CSS specifications
(particularly [http://www.w3.org/TR/CSS21/visudet.html CSS 2.1]).  In some cases, the details are not defined by
CSS, though in some (but not all) of those cases we are constrained by
Web compatibility.  When the details are defined by CSS, however, the
code to compute the layout is generally structured somewhat differently
from the way it is described in the CSS specifications, since the CSS
specifications are generally written in terms of constraints, whereas
our layout code consists of algorithms optimized for incremental
recomputation.
 
The reflow generally starts from the root of the frame tree, though some other
types of frame can act as "reflow roots" and start a reflow from them
(nsTextControlFrame is one example; see the
[https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_REFLOW_ROOT&redirect=true NS_FRAME_REFLOW_ROOT] frame state bit).
Reflow roots must obey the invariant that a change inside one of their
descendants never changes their rect or overflow areas (though currently
scrollbars are reflow roots but don't quite obey this invariant).
 
In many cases, we want to reflow a part of the frame tree, and we want
this reflow to be efficient.  For example, when content is added or
removed from the document tree or when styles change, we want the amount
of work we need to redo to be proportional to the amount of content.  We
also want to efficiently handle a series of changes to the same content.
 
To do this, we maintain two bits on frames:
[https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_IS_DIRTY&redirect=true NS_FRAME_IS_DIRTY]
indicates that a frame and all of its descendants require reflow.
[https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_HAS_DIRTY_CHILDREN&redirect=true NS_FRAME_HAS_DIRTY_CHILDREN]
indicates that a frame has a descendant that
is dirty or has had a descendant removed (i.e., that it has a child that
has NS_FRAME_IS_DIRTY or NS_FRAME_HAS_DIRTY_CHILDREN or it had a child
removed).  These bits allow coalescing of multiple updates; this
coalescing is done in PresShell, which tracks the set of reflow roots
that require reflow.  The bits are set during calls to
[https://searchfox.org/mozilla-central/search?q=PresShell%3A%3AFrameNeedsReflow&path= PresShell::FrameNeedsReflow]
and are cleared during reflow.
 
The layout algorithms used by many of the frame classes are those
specified in CSS, which are based on the traditional document formatting
model, where widths are input and heights are output.
 
In some cases, however, widths need to be determined based on the
content.  This depends on two ''intrinsic widths'': the minimum
intrinsic width (see [https://searchfox.org/mozilla-central/search?q=nsIFrame%3A%3AGetMinISize&path= nsIFrame::GetMinISize]) and the preferred intrinsic
width (see [https://searchfox.org/mozilla-central/search?q=nsIFrame%3A%3AGetPrefISize&path= nsIFrame::GetPrefISize]).  The concept of what these widths
represent is best explained by describing what they are on a paragraph
containing only text:  in such a paragraph the minimum intrinsic width
is the width of the longest word, and the preferred intrinsic width is
the width of the entire paragraph laid out on one line.
 
Intrinsic widths are invalidated separately from the dirty bits
described above.  When a caller informs the pres shell that a frame
needs reflow (PresShell::FrameNeedsReflow), it passes one of three
options:
* eResize indicates that no intrinsic widths are dirty
* eTreeChange indicates that intrinsic widths on it and its ancestors are dirty (which happens, for example, if new children are added to it)
* eStyleChange indicates that intrinsic widths on it, its ancestors, and its descendants are dirty (for example, if the font-size changes)
 
Reflow is the area where the XUL frame classes (those that inherit from
nsBoxFrame or nsLeafBoxFrame) are most different from the rest.  Instead
of using nsIFrame::Reflow, they do their layout computations using
intrinsic size methods called GetMinSize, GetPrefSize, and GetMaxSize
(which report intrinsic sizes in two dimensions) and a final layout
method called Layout.  In many cases these methods defer some of the
computation to a separate object called a layout manager.
 
When an individual frame's Reflow method is called, most of the input is
provided on an object called ReflowInput and the output is filled
in to an object called ReflowOutput.  After reflow, the caller
(usually the parent) is responsible for setting the frame's size based
on the metrics reported.  (This can make some computations during reflow
difficult, since the new size is found in either the reflow state or the
metrics, but the frame's size is still the old size.  However, it's
useful for invalidating the correct areas that need to be repainted.)
 
One major difference worth noting is that in XUL layout, the size of the
child is set prior to its parent calling its Layout method.  (Once
invalidation uses display lists and is no longer tangled up in Reflow,
it may be worth switching non-XUL layout to work this way as well.)
 
==== Painting ====
 
TODO: display lists (and event handling)
 
TODO: layers
 
==== Pagination ====
 
The concepts behind pagination (also known as fragmentation) are a bit complicated, so for now we've split them off into a separate document: [[Gecko:Continuation_Model]].  This code is used for printing, print-preview, and multicolumn frames.


=== Dynamic change handling along the rendering pipeline ===
=== Dynamic change handling along the rendering pipeline ===


The ability to make changes to the DOM from script is a major feature of the Web platform.  Web authors rely on the concept (though there are a few exceptions, such as animations) that changing the DOM from script leads to the same rendering that would have resulted from starting from that DOM tree.  They also rely on the performance characteristics of these changes:  small changes to the DOM that have small effects should have proportionally small processing time.  This means that Gecko needs to efficiently propagate changes from the content tree to style, the frame tree, the geometry of the frame tree, and the screen.
The dynamic change handling section has been moved to https://firefox-source-docs.mozilla.org/layout/DynamicChangeHandling.html
 
For many types of changes, however, there is substantial overhead to processing a change, no matter how small.  For example, reflow must propagate from the top of the frame tree down to the frames that are dirty, no matter how small the change.  One very common way around this is to batch up changes.  We batch up changes in lots of ways, for example:
* The content sink adds multiple nodes to the DOM tree before notifying listeners that they've been added.  This allows notifying once about an ancestor rather than for each of its descendants, or notifying about a group of descendants all at once, which speeds up the processing of those notifications.
* We batch up nodes that require style reresolution (recomputation of selector matching and processing the resulting style changes).  This batching is tree based, so it not only merges multiple notifications on the same element, but also merges a notification on an ancestor with a notification on its descendant (since ''some'' of these notifications imply that style reresolution is required on all descendants).
* We wait to reconstruct frames that require reconstruction (after destroying frames eagerly).  This, like the tree-based style reresolution batching, avoids duplication both for same-element notifications and ancestor-descendant notifications, even though it doesn't actually do any tree-based caching.
* We postpone doing reflows until needed.  As for style reresolution, this maintains tree-based dirty bits (see the description of NS_FRAME_IS_DIRTY and NS_FRAME_HAS_DIRTY_CHILDREN under Reflow).
* We allow the OS to queue up multiple invalidates before repainting (though we will likely switch to controlling that ourselves).  This leads to a single repaint of some set of pixels where there might otherwise have been multiple (though it may also lead to more pixels being repainted if multiple rectangles are merged to a single one).
 
Having changes buffered up means, however, that various pieces of information (layout, style, etc.) may not be up-to-date.  Some things require up-to-date information:  for example, we don't want to expose the details of our buffering to Web page script since the programming model of Web page script assumes that DOM changes take effect "immediately", i.e., that the script shouldn't be able to detect any buffering.  Many Web pages depend on this.
 
We therefore have ways to flush these different sorts of buffers. There are methods called FlushPendingNotifications on nsIDocument and nsIPresShell, that take an argument of what things to flush:
* Flush_Content: create all the content nodes from data buffered in the parser
* Flush_ContentAndNotify: the above, plus notify document observers about the creation of all nodes created so far
* Flush_Style: the above, plus make sure style data are up-to-date
* Flush_Frames: the above, plus make sure all frame construction has happened (currently the same as Flush_Style)
* Flush_InterruptibleLayout: the above, plus perform layout (Reflow), but allow interrupting layout if it takes too long
* Flush_Layout: the above, plus ensure layout (Reflow) runs to completion
* Flush_Display (should never be used): the above, plus ensure repainting happens
 
The major way that notifications of changes propagate from the content code to layout and other areas of code is through the nsIDocumentObserver and nsIMutationObserver interfaces. Classes can implement this interface to listen to notifications of changes for an entire document or for a subtree of the content tree.
 
WRITE ME: ... layout document observer implementations
 
TODO: how style system optimizes away rerunning selector matching
 
TODO: style changes and nsChangeHint


=== Refresh driver ===
=== Refresh driver ===
Confirmed users
885

edits

Navigation menu