Style System
|
nsIStyleRuleProcessor
and
nsIStyleSheet
describe in C++ what a CSS
stylesheet can donsIStyleRule
describes in C++ what a CSS
style rule can do@import
,
@media
, @namespace
, etc.
p { color: green; font-size: 12em; } |
selector { property: value; property: value; } |
What do style rules mean?
'font-size'
, 'color'
, etc.'border'
, 'background'
, etc.!important
),<doc> <title>A few quotes</title> <para class="emph"> Franklin said that <quote>"A penny saved is a penny earned."</quote> </para> <para> FDR said <quote>"We have nothing to fear but <span class="emph">fear itself.</span>"</quote> </para> </doc>
doc { display: block; text-indent: 1em; } title { display: block; font-size: 3em; } para { display: block; } [class="emph"] { font-style: italic; }
nsCSSDeclaration
CSSStyleRuleImpl
contains each selector
associated with that declaration, and the declaration, and is
the most important implementation of
nsIStyleRule
.nsCSS*
).:not()
is confusing).h1, h2 { color: green; text-align: right; text-indent: 0; }
CSSStyleRuleImpl | CSSStyleRuleImpl | |||||
↓ | ↓ | ↓ | ↓ | |||
h1 | nsCSSDeclaration | h2 | ||||
↙ | ↘ | |||||
nsCSSColor color: green | nsCSSText text-align: right text-indent: 0 |
!important
declarations cause an extra rule
object CSSImportantRule
to be created since they
are in a separate part of the cascadensIStyleRule
implementationsnsHTMLMappedAttributes
represents stylistic HTML
attributes turned into a style rule (one instance per unique set
of attributes)BodyRule
handles marginwidth/marginheight mixes on
BODY
and on FRAME
.nsHTMLStyleSheet.cpp
do other
things with presentational color-related attributes and with
tables.CSSStyleRuleImpl
objects that represent their
style
attributes.StyleSetImpl
manages the different origins of rules
in the cascade (UA, user, author)nsIStyleRuleProcessor
implementations
from the style sheets, and the CSS stylesheets force one
CSSRuleProcessor
per origin (rather than one per
stylesheet).HTMLStyleSheetImpl
(HTML attributes) and
HTMLCSSStyleSheet
(style attributes) also implement
nsIStyleRuleProcessor
.nsIStyleRuleProcessor
interfaceCSSRuleProcessor
,
HTMLStyleSheetImpl
, and
HTMLCSSStyleSheetImpl
RulesMatching
method, which is required to
call nsRuleWalker::Forward
on any rules that match
the element. (We'll see what this does later.)RulesMatching
is a structure
of enumeration data that implementations use to determine more
quickly which rules match.RulesMatching
method for
pseudo-elements.CSSRuleProcessor
per origin (UA, User, Author)RuleHash
, which remembers order and
then hashes by first of id, class, tag, namespace, or
unhashed.RuleHash
's
tables, remerge the lists of rules using stored indices, and
then call SelectorMatchesTree
to find which
selectors really match.class
and id
selectors is much faster than, say, attribute selectors.
(Important advice for chrome CSS authors.)nsStyleContext
),
which is the interface through which layout accesses the style
data for a given element, points to one rule node.nsStyleStruct.h
).nsIStyleContext::GetStyleData
.
nsIFrame::GetStyleData
does the same thing for the
frame's mStyleContext
member, and the global
::GetStyleData
is a typesafe helper that doesn't
require the style struct ID.const
, and should
always be declared as such (evil old-style casts often used with
the non-typesafe forms sometimes hide this error), since the
struct may be shared with other elements.
nsRuleWalker::Forward
on all the rules
that are matched, we build or walk along the rule tree.nsRuleNode
.nsRuleNode
objects to
speed up computation and reduce memory use.Rules:
/* rule 1 */ doc { display: block; text-indent: 1em; } /* rule 2 */ title { display: block; font-size: 3em; } /* rule 3 */ para { display: block; } /* rule 4 */ [class="emph"] { font-style: italic; } | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rule tree:
|
Style context tree:
|
inherit
value)inherit
)inherit
value).nsRuleNode::GetStyleData
to just get the struct
from the parent.nsStyleContext::GetStyleData
checks for
a cached struct on the style context, and returns it if
present.nsRuleNode::GetStyleData
checks for a cached
struct or a dependent bit on the rule node, and returns the
struct if present.nsRuleNode::GetStyleData
calls
nsRuleNode::Get*Data
, which initializes the correct
one of the data structs on the stack (the structs used by
nsCSSDeclaration
)Get*Data
calls
nsRuleNode::WalkRuleTree
, which walks from the
style context's rule node towards the root rule node.
nsIStyleRule::MapRuleInfoInto
on the rules.MapRuleInfoInto
implementations must
check that the property is not filled in before filling it in.WalkRuleTree
stops walking up when it finds either
a none bit, a cached struct, a dependent bit, or all the
properties have been filled in.WalkRuleTree
also remembers the first
rule that contributed non-empty data.WalkRuleTree
stops walking up, it calls
nsRuleNode::Compute*Data
to turn the specified
values into the mostly-computed style data in the style
struct.
Compute*Data
use either a default or a start
struct as the basis for the computation. A start struct
is a cached struct in the rule tree that we can just copy and
add to.
Compute*Data
used any data
from the parent style context, we cache the struct on the style
context.nsIStyleSet
, wrapped by similarly named ones on
nsIPresContext
:
ResolveStyleContextFor
: For elements.ResolvePseudoStyleContextFor
: for
pseudo-elements (:first-letter
,
:before
, etc.)ResolveStyleContextForNonElement
: skips rule
matching and uses root rule node (text frame optimization)StyleSetImpl::FileRules
, find the correct rule
node, and find a current child of the parent (“sibling
sharing”) or create a new child.FrameManager::ReResolveStyleContext
destroys and
recreates style contexts for existing frames (rule node pointer
immutable).ReResolveStyleContext
is messy because it needs to
create and parent style contexts correctly (sibling
sharing may not be the same) rather than just changing data.
[design flaw, again]nsIFrame::GetParentStyleContextFrame
.ReResolveStyleContext
calculates differences
(repaint, reflow, reframe, etc.) between style old and new style
contexts and does appropriate cleanupnsIStyleContext::CalcStyleDifference
, which
only computes differences for structs that have been
requested. (I'll call this the data-struct-based hint
mechanism.)nsIFrameManager::ComputeStyleChangeFor
processes the change list, which has been built to avoid
duplication.ReParentStyleContext
, used in a few
places (usually during frame construction), but it's broken (has
many bugs that ReResolveStyleContext
used
to have).ReResolveStyleContext
if the attribute has
an effect. nsIStyleSheet::AttributeAffectsStyle
(should be on nsIStyleRuleProcessor
).:hover
,
:active
, etc.) using
nsIStyleRuleProcessor::HasStateDependentStyle
,
which is much more accurate. The CSSRuleProcessor
implementation does a slightly modified form of selector
matching to implement it (includes matching on the middle of
selectors to catch p:hover a
).style
attribute (“inline
style”) changes in a different
way from other changes to style rules.nsIStyleRule
, since there could be an
!important
rule that overrides it, which would
allow dynamic changes to put the style attribute in multiple
places in the rule tree. However, we maintain a hashtable just
for inline style rules so that we don't have to walk the whole
tree to find the nodes.nsCSSFrameConstructor::AttributeChanged
only
reresolves style on the subtree of the element, just like other
attribute changes.AttributeChanged
just go straight to a
framechange, instead.nsIFrame::DidSetStyleContext
.PresShell::ReconstructStyleData
calls
FrameManager::ComputeStyleChangeFor
(ReResolve) and then processes the framechange list.O(rules *
rule-nodes)
).StyleSetImpl::ClearStyleData
) by walking
the rule tree and then the style context tree.
(could be handled by simultaneous clearing and
difference calculation of data (somewhat tricky))DidSetStyleContext
)