New Layout: Style SystemAuthor: Peter Linss
The NGLayout Style System was designed with
the goals of reasonable extensibility, high performance and a reasonable runtime
footprint. The current implementation
of the Style System is centered around mapping HTML Attributes and CSS2.
The central management object of the Style System is the StyleSet. The StyleSet is constructed by the UA and passed to the PresentationShell during initialization. The UA controls the presentation of the document by specifying which StyleSheets get applied to the document in that presentation. Typically, the StyleSet will contain references to the StyleSheets contained within, or linked to, the document, as well as a collection of UA override and backstop StyleSheets. The StyleSet also has the responsibility for creating, resolving and caching StyleContexts.
StyleSheets and StyleRulesStyleSheets are the objects that contain the specific style data that gets applied to the document, as well as the logic for applying the data. Generally, the actual style data is kept in a nsIStyleRule. The StyleSheet is responsible for determining the set of StyleRules to apply to a given piece of content in a given situation. The StyleRule will in turn, be told to apply its data to a given StyleContext.
StyleContextThe StyleContext is the sum total of style data that has been applied to a given piece of content in a given situation. StyleContexts are created and managed by the StyleSet. Only one StyleContext will be created for each unique stylistic situation. In other words, all content nodes that have the identical set of StyleRules applied to them, in the same parental context, will share one StyleContext instance. StyleContexts contain a reference to their parent StyleContext, a list of all the StyleRules that were applied to them, and a collection a data structs that hold the actual, resolved style data.
The NGLayout side of the Style System consists of the StyleSet, interface declarations for StyleSheets and StyleRules, the StyleContext, and specific style data structures contained within the StyleContext.
In addition to implementing the storage of StyleSheets (an ordered set). The StyleSet implements the basic StyleContext resolution algorithm.
To establish a StyleContext, the StyleSet is passed three items: a pointer to the current Presentation Context, a pointer to the Frame that will contain the StyleContext, and a pointer to the Content node (or pseudo content) that style is being mapped for. Given this data, the StyleSet follows the following algorithm: first the parent frame is given an opportunity to return a cached StyleContext for the Content. The implementation of that caching is Frame dependent and should be used carefully. Failing to obtain a cached StyleContext, the StyleSet then iterates all the StyleSheets, collecting from them a list of StyleRules to apply to that Content in that Frame. Determining what rules apply is a StyleSheet specific behavior, however, the rules are returned in order of precedence.
Once a set of StyleRules is established, the StyleSet attempts to find an already established StyleContext that uses the exact set of StyleRules with the same parent StyleContext (from the parent Frame). If an established StyleContext isn't found, a new instance is finally created. This instance then processes its set of StyleRules to determine the actual style data for that StyleContext.
StyleContextThe StyleContext contains a collection of StyleStructs. These structs hold the actual style data that is needed for the layout, rendering and operation of a NGLayout document. The collection of structs is extensible, and individual structs are queried for by ID. The set of structs implemented in NGLayout is a sum of that needed to handle HTML and XML documents with CSS applied.
When a StyleContext is created, first all style data is initialized to starting values. Inheritable attributes are copied from the parent context, then the StyleRules are iterated in reverse order (so that higher precedence data is set last). Each StyleRule gets passed the StyleContext and PresentationContext, and then maps its data into the StyleContext's data structs.
The handling of CSS data in NGLayout is
achieved by a custom parser, StyleSheet and StyleRule class. The parser is invoked
during document load for each CSS StyleSheet encountered, it produces a CSSStyleSheet
object that contains all the StyleRules and child StyleSheets (from @import
rules). The StyleSheet contains the StyleRules and sorts them according to CSS
cascading order. The StyleRules contain the Selectors and Declarations.
When the StyleSheet is asked for a list of StyleRules for a given Content node in a given Frame. It searches through its list of StyleRules applying the CSS Selector algorithm to determine which StyleRules apply.
The StyleRules, when asked to map their data into a StyleContext, simply convert from CSS data into the simplified NGLayout data stored in the StyleContext.
The HTML StyleSheet class in NGLayout serves as an adapter between HTML Attributes and the Style System. The StyleSheet contains no data, the actual Attributes are stored by each HTML Content node in a special class. This class, nsHTMLAttributes, contains a list of all the Attributes for a Content node, and also implements the StyleRule interface.
When a HTML StyleSheet is asked for a list of StyleRules for a given piece of Content, it simply asks the Content if it has any Attributes. If so, the Attribute class is returned as a StyleRule. If the Content has a STYLE attribute, then a second rule is returned for the contents of that Attribute.
When the Attributes are asked to map their
data into a StyleContext, a method of the Content, MapAttributesInto, is invoked
to allow the Content node to interpret its Attributes and convert them to NGLayout
- The set of style attributes implemented
so far has been driven by dependencies on the Style System from implementations
of Layout and Rendering behavior.
The short term goal is to flush out all the attributes that need to be stored in a StyleContext.
- Pseudo-elements will be implemented
by style support for Pseudo-Frames (see Layout docs). This will require
some extensions to the Style Resolution apis, since there won't be an actual
Content node to be mapped. Pseudo-class support will be implemented in
the CSS StyleSheet by extending the Selector match algorithm to account
for document state.
- Several performance aspects have
yet to be implemented: the first level cache of StyleContexts by Frames,
CSS Selector matching and possible special handling of the UA StyleSheet.
The CSS Selector matching algorithm currently searches through all StyleRules in the StyleSheet. This will be reduced by pre-sorting the StyleRules by Tag, Class and ID.
The UA StyleSheet used in NGLayout is currently a CSS StyleSheet. Since UA processing doesn't need full CSS support to implement backward compatible behavior, we may implement a third StyleSheet class to special case the UA behavior with increased performance.
- The CSS StyleSheet and StyleRules
classes need to be connected to the DOM implementation. This will involve
flushing out the DOM apis for CSS, as well as guaranteeing correct behavior
of the System when style data changes.
- At this point we'll be going through
the CSS2 spec with a fine-toothed comb and making sure that all desired
behaviors are implemented.
- Here we'll be going though the Content
model and ensuring that all Attributes are present and accounted for.
- CSS Selector matching performance is known to be an issue, but that's because we haven't gotten there yet.
- Many style attributes have only been implemented to a limited degree to date. Furthermore, layout and rendering code isn't completely implemented to interpret all possible values.
Feel free to send questions, comments or interest in helping to develop this system.