tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DynamicChangeHandling.md (4516B)


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:

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.

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).

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.

this maintains tree-based dirty bits (see the description of NS\FRAME\IS\DIRTY and NS\FRAME\HAS\DIRTY\_CHILDREN under Reflow).

(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:

the parser

about the creation of all nodes created so far

happened (currently the same as Flush\_Style)

but allow interrupting layout if it takes too long

completion

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