Content states are what Gecko uses to implement the various state-dependent in CSS (examples would be :hover, :active, :focus, :target, :checked). We will focus on describing how changes in content state are handled.
Generally, whenever a node's content state changes, style has to be reresolved (recomputed) for that node and all of its descendants. This is an expensive operation, however, so the style system tries to minimize the number of style reresolves it does. To this end, when a <code>ContentStatesChanged</code> notification is dispatched for a content node the first thing that's done is to is to check whether the content state change something could affect any styles.
This is done by walking the list of all CSS2.1 simple selectors in all style sheets applied to the page that have a state-dependent pseudo-class as part of the selector. This list is created during the parsing of the stylesheets involved. For each selector in this list we check whether it might have stopped matching the node or started matching it. If that has happened, then the style could depend on the state that changed and we have to reresolve style.
The way we determine whether the selector might have stopped or started matching the node is by just checking whether it matches with the caveat that all the state-dependent pseudo-classes corresponding to the states that changed must be treated as matching (whether they actually do and whether they're negated or not). This is needed to catch both selectors that now match and selectors that no longer match.
For example, say we have the selectors:
a:hover a:not(:hover) div:hover
and the hover state on some node changes. We then try matching the node against these selectors, with the assumption that both
:not(:hover) match the node. So the effect will be that of matching a node against the selectors:
a a div
The code that implements this is in the
SelectorMatches method, which is passed the list of states that changed in the