Package io.sf.carte.doc.style.css.nsac


package io.sf.carte.doc.style.css.nsac
NSAC: a non-standard extension to W3C's SAC api.

NSAC Base Extension

The base extension is intended to be an easy upgrade path for current SAC users, providing an API that is very similar to SAC but is able to process modern selectors, and supports recent syntax and units. The original SAC interfaces are on a package under the org.w3c hierarchy and cannot be modified directly, so a set of interfaces that inherit from SAC was created under a new package called nsac (for Non-Standard Api for Css) in the doc.style.css hierarchy of this project.

The New Interfaces

The modifications that the new interfaces introduce are basically the following:

  1. LexicalUnit: add new identifiers (constants) and the method getCssText(). (see below )
  2. Selector: add numeric identifiers for combinators SAC_SUBSEQUENT_SIBLING_SELECTOR and SAC_COLUMN_COMBINATOR_SELECTOR. Also add the SAC_SCOPE_SELECTOR pseudo-selector, intended to be a placeholder for scope in an selector argument (like in not() or has()).
  3. Condition: add numeric identifiers for SAC_BEGINS_ATTRIBUTE_CONDITION and others, including SAC_PSEUDO_ELEMENT_CONDITION. Pseudo-elements are handled as conditional selectors with this extension. Also, a new Condition.SAC_SELECTOR_ARGUMENT_CONDITION identifier is introduced to support the new ArgumentCondition.
  4. New ArgumentCondition (see below).
  5. New methods added to AttributeCondition and PositionalCondition (see below).

New Methods and Constants

Interface LexicalUnit

Constants
  • Add identifiers for level 3-4 units like SAC_CAP.
  • Add SAC_ELEMENT_REFERENCE for images by element reference.
  • For unicode range wildcards, add SAC_UNICODE_WILDCARD.
  • Also add the following identifiers for grid support: SAC_LEFT_BRACKET, SAC_RIGHT_BRACKET and SAC_FR (fr flexible length unit).
  • Finally, two values that are non-conformant and intended to be used for compatibility with the Internet Explorer browser: SAC_COMPAT_IDENT and SAC_COMPAT_PRIO values (see LexicalUnit Extensions).
Method
String getCssText()
Get a parsable representation of the unit. The serialization must only include this lexical unit, ignoring the next units if they exist.

Interface AttributeCondition

boolean hasFlag(Flag)
Check for the given flag. Currently supports CASE_I for the i flag (case insensitivity) and CASE_S for s.

Interface PositionalCondition

boolean isForwardCondition()
Is this a forward condition? return true if this is a forward condition like :nth-child (also true for :only-child), false otherwise (like in :nth-last-child).
boolean isOfType()
Is this an of-type selector? This method only returns true if the selector has been explicitly declared to apply to the same type, like in :first-of-type or :nth-of-type. It should return false otherwise, for example for selectors like div:nth-child(1 of div) despite being equivalent to div:first-of-type. This method is possibly the same as the old PositionalCondition.getType(), but with a potentially different specification.
int getFactor()
Get the An+B expression factor (i.e. 'A'). Zero if there is no factor (or no expression).
int getOffset()
Get the An+B expression offset (i.e. 'B'). If there is no expression, it must return the positive integer position value (e.g. 1 for :first-child or :last-child).
SelectorList getOfList()
Get the list of selectors that the child list have to match, or null if not specified.
boolean hasArgument()
Was the selector specified with an argument ?. Serves to tell apart selectors that have no functional notation from their functional equivalents (like :first-child and :nth-child(1).
boolean hasKeyword()
Get whether the AnB expression was specified as a keyword (like even).

New Interface ArgumentCondition

String getName()
Get the name of the condition, like not or has.
SelectorList getSelectors()
Get the selector list to which the condition has to be applied.

Other Changes to Current SAC Usage

Although the changes to SAC described so far are required to handle modern selectors, the NSAC API behaves differently in other aspects:

  • The names of pseudo-classes are retrieved with the AttributeCondition's getLocalName() method instead of getValue(). This leaves getValue() to retrieve the pseudo-class argument if there is any, like in :dir(ltr).
  • The identifier SAC_ANY_NODE_SELECTOR is used for the universal selector, albeit it is still implemented as an ElementSelector with the * local name.
  • Margin rules are handled through startPage and endPage, as nested page rules. Not very elegant, but allows the reuse of the old DocumentHandler interface.
  • Implementations of LexicalUnit must provide a serialization of the value, at least for SAC_IDENT and SAC_RGBCOLOR values, available through LexicalUnit2's new getCssText() method. That serialization should be close to how the value was specified (for example, preserving hex or functional notation in rgb colors) but must parse without errors (except for compatibility values like SAC_COMPAT_IDENT).

Selector Serialization

Implementations of the selector interfaces are not required to provide a toString() serialization, although the reference implementation (the doc.style.css.parser package) does. It is not recommended to use it for serialization, however, as it may not reflect namespace changes made after the parsing took place (i.e. changing the namespace prefix). The rule serialization in the Object Model implementation of css4j does account for that, and it does not use the selector's toString().

If you combine NSAC with your own Object Model code, you may want to follow the same approach and serialize the selectors yourself.

The Parser Extensions

The previously described base SAC extensions allowed to handle level 4 selectors and values. However, for the API to be of more general usefulness in real-world usage a few methods were added to the Parser interface.

Parser Flags

To let the parser be configurable, two methods were added to the Parser interface:

void setFlag(Flag)

void unsetFlag(Flag)

where Flag is a flag from an enumeration:

  • STARHACK. When STARHACK is set, the parser will handle asterisk-prefixed property names as accepted names. This hack (that targets old IE browsers) is ubiquitous in present-day websites, and in plain SAC parsers it was producing 'unexpected character' errors because the property names are not valid according to the specification. However, these declarations weren't real mistakes and the style authors wanted them to be there.
  • IEVALUES accepts values with some IE hacks like IE expressions (progid included), and also values ending with \9 and \0. The non-standard values produce LexicalUnit2.SAC_COMPAT_IDENT values as a result.
  • IEPRIO accepts values with the !ie priority hack, and again produces LexicalUnit2.SAC_COMPAT_IDENT values.
  • IEPRIOCHAR accepts values with the !important! priority hack, and instead produces LexicalUnit2.SAC_COMPAT_PRIO values.

Rule Parsing

The original SAC api includes this method:

void parseRule(InputSource)

The method can be used to parse individual rules, like those supplied to the CSSOM's CSSStyleSheet.insertRule method:

int insertRule(String, int)

However, when a rule that contains a namespace prefix is parsed, the style sheet may contain the appropriate CSSNamespaceRule for that prefix, but it is unclear why/how the Parser instance is going to know about it. To be able to handle that case, NSAC adds the following method to the Parser interface:

void parseRule(InputSource, NamespaceMap)

where NamespaceMap is a simple sub-interface that just gives the namespace URI associated to a prefix:

String getNamespaceURI(String)

LexicalUnit Extensions

Some of the above Internet Explorer compatibility flags require the use of two pseudo-values that do not follow standard CSS syntax:

  • SAC_COMPAT_IDENT values are produced only when the IEVALUES and IEPRIO flags are used, and contain ident-like values.
  • SAC_COMPAT_PRIO values are produced by the IEPRIOCHAR flag, representing values that its compatible browser interprets as being of !important priority.

Caution is advised when using these compatibility pseudo-values, as they may conflict with syntax-conformant values.

Bugs

While this API offers an useful improvement to SAC, that API is old and is showing its age; when it was written, CSS was simpler and smaller than it is today. As this API reuses from SAC as much as possible there are obvious limitations with this approach, like:

  • DocumentHandler.ignorableAtRule is a big hammer and not appropriate for today's variety of rules. For example, for @supports rules it would be better to have specialized startSupports and endSupports methods than going through ignorableAtRule.
  • Media queries are unparsed and passed as plain media declarations.
  • Combinator selector interfaces were reused, avoiding the creation of a new interface (like e.g. a plain CombinatorSelector interface). Again, this is not elegant but this API tries to depart minimally from SAC (and this kind of interface reuse was already being done by other SAC implementations).

W3C Copyright Notice

This software includes material derived from SAC (https://www.w3.org/TR/SAC/). Copyright © 1999,2000 W3C® (MIT, INRIA, Keio).