summaryrefslogtreecommitdiffstats
path: root/layout/docs/DynamicChangeHandling.md
blob: 50df613412c36580ee4f8eed84217f83c5222fe7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# 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.

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