CSS Style Invalidation in Blink
source link: https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/core/css/style-invalidation.md
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
CSS Style Invalidation in Blink
About this document
The doc gives a high-level overview of the style invalidation process. It does not cover sibling invalidation.
Overview of invalidation
Invalidation is the process of marking which elements need their style recalculated in response to a change in the DOM. The simplest possible approach is to invalidate everything in response to every change.
Invalidation sets give us a way to find a smaller set of elements which need recalculation They are not perfect, they err on the side of correctness, so we invalidate elements that do not need recalculation but this are significantly better than recalculating everything. An invalidation set represents
- criteria for matching against a node
- instructions for whether/how to descend the tree into the node's children
If we have a style rule ".c1 div.c2 { ... }"
then style recalculation is needed when a c1
-class is added or removed as an ancestor of a c2
-class or when a c2
-class is added or removed from a div that is a descendant of a c1
-class element (here adding/removing can be adding/removing an element or just adding/removing these classes on existing elements). We don't want to do full style recalc at the time of adding/removing because there may be more mutations coming. If we can tell immediately that a change forces style recalc then we mark the node as that, otherwise we collect everything as pending invalidation sets.
In the example, if a c1
-class is added to an element in the tree, we need to invalidate all of its descendants which have class c2
. Rather than perform a search right now, we just mark the element with a pending invalidation set that matches against c2
and descends into all light-descendants. (We won't invalidate all div descendants, as class c2
is more specific.)
If class c2
is added to an element in the tree, then it needs recalculation if it has a c1
-class ancestor. We never search up the tree at this point or during style invalidation, we only do that during recalculation, so this becomes an immediate invalidation, even though it may be unnecessary. Similarly, we don't check if the c2
-class element is a div.
Eventually all DOM changes have been turned into immediate invalidations or pending invalidation sets. At this point, we apply all the pending invalidations and then recalculate style for all of the invalidated elements.
For more details see the original invalidation sets design doc and the sibling invalidation design doc.
State involved
RuleFeatureSet
The data in RuleFeatureSet is built from the style rules and does not change unless the style rules change.
DOM Node's style states
DOM nodes have several bits of style-related state that control style invalidation and recalculation. These are accessed through:
PendingInvalidationsMap
This is a map from DOM Node to invalidation sets that should be applied due to updates to that node.
Processes
Overview
The overview of style invalidation and recalculation is that
- Style rules are compiled down to a collection of InvalidationSets and other data in
RuleFeatureSet
- The following process is then applied continuously
- Changes to the DOM cause nodes or subtrees to be immediately invalidated or to accumulate pending invalidations.
- A point is reached where style is being read (e.g. in order to render a new frame)
- Style invalidation process finds all pending invalidations and decides on what will actually be recalculated
- Style recalculation process recalculates style for all nodes that need it
Building the RuleFeatureSet
Each RuleSet
produces its own RuleFeatureSet
by calling CollectFeaturesFromRuleData
for each RuleData
. These contain several indexed collections of InvalidationSet
s and some miscellaneous properties.
All of these are merged together to form a final RuleFeatureSet
which used for style purposes.
Turning DOM changes into pending/immediate invalidations
Changes in the DOM that require updates to styles may get turned into either immediate invalidations or pending invalidations. When a DOM change that could impact style occurs inside a Node
(e.g. a change in class name) this leads to a call into StyleEngine
to record this style-impacting change via one of several FooChangedForElement
methods.
Depending on the type of change, StyleEngine
gathers the relevant InvalidationSet
s and calls PendingInvalidations::ScheduleInvalidationSetsForNode
which will do one or both of
- call
Node::SetNeedsStyleInvalidation
which ensures that the invalidation process will consider this node and add InvalidationSets for this node to the pending invalidation set map. - call
Node::SetNeedsStyleRecalc
with eitherkLocalStyleChange
orkSubtreeStyleChange
Pushing the pending invalidations
When style is about to be read, the map of pending invalidations which has been built up needs to be pushed. For each ContainerNode
in the DOM tree we have 0 or more descendant InvalidationSet
waiting to be applied. The invalidation process starts with a call to StyleInvalidator::Invalidate
which recurses down the tree, depth first. Read the method's inline documentation to understand more about the process.
See Also
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK