FileDocCategorySizeDatePackage
StyleSheet.javaAPI DocJava SE 6 API109134Tue Jun 10 00:27:00 BST 2008javax.swing.text.html

StyleSheet

public class StyleSheet extends StyleContext
Support for defining the visual characteristics of HTML views being rendered. The StyleSheet is used to translate the HTML model into visual characteristics. This enables views to be customized by a look-and-feel, multiple views over the same model can be rendered differently, etc. This can be thought of as a CSS rule repository. The key for CSS attributes is an object of type CSS.Attribute. The type of the value is up to the StyleSheet implementation, but the toString method is required to return a string representation of CSS value.

The primary entry point for HTML View implementations to get their attributes is the getViewAttributes method. This should be implemented to establish the desired policy used to associate attributes with the view. Each HTMLEditorKit (i.e. and therefore each associated JEditorPane) can have its own StyleSheet, but by default one sheet will be shared by all of the HTMLEditorKit instances. HTMLDocument instance can also have a StyleSheet, which holds the document-specific CSS specifications.

In order for Views to store less state and therefore be more lightweight, the StyleSheet can act as a factory for painters that handle some of the rendering tasks. This allows implementations to determine what they want to cache and have the sharing potentially at the level that a selector is common to multiple views. Since the StyleSheet may be used by views over multiple documents and typically the HTML attributes don't effect the selector being used, the potential for sharing is significant.

The rules are stored as named styles, and other information is stored to translate the context of an element to a rule quickly. The following code fragment will display the named styles, and therefore the CSS rules contained.

 
  import java.util.*;
  import javax.swing.text.*;
  import javax.swing.text.html.*;
 
  public class ShowStyles {
 
  public static void main(String[] args) {
  HTMLEditorKit kit = new HTMLEditorKit();
  HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument();
  StyleSheet styles = doc.getStyleSheet();
 
  Enumeration rules = styles.getStyleNames();
  while (rules.hasMoreElements()) {
  String name = (String) rules.nextElement();
  Style rule = styles.getStyle(name);
  System.out.println(rule.toString());
  }
  System.exit(0);
  }
  }
 

The semantics for when a CSS style should overide visual attributes defined by an element are not well defined. For example, the html <body bgcolor=red> makes the body have a red background. But if the html file also contains the CSS rule body { background: blue } it becomes less clear as to what color the background of the body should be. The current implemention gives visual attributes defined in the element the highest precedence, that is they are always checked before any styles. Therefore, in the previous example the background would have a red color as the body element defines the background color to be red.

As already mentioned this supports CSS. We don't support the full CSS spec. Refer to the javadoc of the CSS class to see what properties we support. The two major CSS parsing related concepts we do not currently support are pseudo selectors, such as A:link { color: red }, and the important modifier.

Note: This implementation is currently incomplete. It can be replaced with alternative implementations that are complete. Future versions of this class will provide better CSS support.

author
Timothy Prinzing
author
Sunita Mani
author
Sara Swanson
author
Jill Nakata
version
1.91 11/30/05

Fields Summary
static final Border
noBorder
static final int
DEFAULT_FONT_SIZE
private CSS
css
private SelectorMapping
selectorMapping
An inverted graph of the selectors.
private Hashtable
resolvedStyles
Maps from selector (as a string) to Style that includes all relevant styles.
private Vector
linkedStyleSheets
Vector of StyleSheets that the rules are to reference.
private URL
base
Where the style sheet was found. Used for relative imports.
static final int[]
sizeMapDefault
The HTML/CSS size model has seven slots that one can assign sizes to.
private int[]
sizeMap
private boolean
w3cLengthUnits
Constructors Summary
public StyleSheet()
Construct a StyleSheet

	super();
	selectorMapping = new SelectorMapping(0);
	resolvedStyles = new Hashtable();
	if (css == null) {
	    css = new CSS();
	}
    
Methods Summary
private java.lang.String_cleanSelectorString(java.lang.String selector)
Returns a new String that contains only one space between non white space characters.

	SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
	StringBuffer buff = sb.getStringBuffer();
	boolean lastWasSpace = true;
	int lastIndex = 0;
	char[] chars = selector.toCharArray();
	int numChars = chars.length;
	String retValue = null;
	try {
	    for (int counter = 0; counter < numChars; counter++) {
		switch(chars[counter]) {
		case ' ":
		    if (!lastWasSpace) {
			lastWasSpace = true;
			if (lastIndex < counter) {
			    buff.append(chars, lastIndex,
					1 + counter - lastIndex);
			}
		    }
		    lastIndex = counter + 1;
		    break;
		case '\n":
		case '\r":
		case '\t":
		    if (!lastWasSpace) {
			lastWasSpace = true;
			if (lastIndex < counter) {
			    buff.append(chars, lastIndex,
					counter - lastIndex);
			    buff.append(' ");
			}
		    }
		    lastIndex = counter + 1;
		    break;
		default:
		    lastWasSpace = false;
		    break;
		}
	    }
	    if (lastWasSpace && buff.length() > 0) {
		// Remove last space.
		buff.setLength(buff.length() - 1);
	    }
	    else if (lastIndex < numChars) {
		buff.append(chars, lastIndex, numChars - lastIndex);
	    }
	    retValue = buff.toString();
	}
	finally {
	    SearchBuffer.releaseSearchBuffer(sb);
	}
	return retValue;
    
public javax.swing.text.AttributeSetaddAttribute(javax.swing.text.AttributeSet old, java.lang.Object key, java.lang.Object value)
Adds an attribute to the given set, and returns the new representative set. This is reimplemented to convert StyleConstant attributes to CSS prior to forwarding to the superclass behavior. The StyleConstants attribute has no corresponding CSS entry, the StyleConstants attribute is stored (but will likely be unused).

param
old the old attribute set
param
key the non-null attribute key
param
value the attribute value
return
the updated attribute set
see
MutableAttributeSet#addAttribute

	if (css == null) {
	    // supers constructor will call this before returning,
	    // and we need to make sure CSS is non null.
	    css = new CSS();
	}
	if (key instanceof StyleConstants) {
            HTML.Tag tag = HTML.getTagForStyleConstantsKey(
                                (StyleConstants)key);

            if (tag != null && old.isDefined(tag)) {
                old = removeAttribute(old, tag);
            }

	    Object cssValue = css.styleConstantsValueToCSSValue
		              ((StyleConstants)key, value);
	    if (cssValue != null) {
		Object cssKey = css.styleConstantsKeyToCSSKey
		                    ((StyleConstants)key);
		if (cssKey != null) {
		    return super.addAttribute(old, cssKey, cssValue);
		}
	    }
	}
	return super.addAttribute(old, key, value);
    
public javax.swing.text.AttributeSetaddAttributes(javax.swing.text.AttributeSet old, javax.swing.text.AttributeSet attr)
Adds a set of attributes to the element. If any of these attributes are StyleConstants attributes, they will be converted to CSS prior to forwarding to the superclass behavior.

param
old the old attribute set
param
attr the attributes to add
return
the updated attribute set
see
MutableAttributeSet#addAttribute

        if (!(attr instanceof HTMLDocument.TaggedAttributeSet)) {
            old = removeHTMLTags(old, attr);
        }
	return super.addAttributes(old, convertAttributeSet(attr));
    
public voidaddCSSAttribute(javax.swing.text.MutableAttributeSet attr, javax.swing.text.html.CSS$Attribute key, java.lang.String value)
Adds a CSS attribute to the given set.

since
1.3

	css.addInternalCSSValue(attr, key, value);
    
public booleanaddCSSAttributeFromHTML(javax.swing.text.MutableAttributeSet attr, javax.swing.text.html.CSS$Attribute key, java.lang.String value)
Adds a CSS attribute to the given set.

since
1.3

	Object iValue = css.getCssValue(key, value);
	if (iValue != null) {
	    attr.addAttribute(key, iValue);
	    return true;
	}
	return false;
    
voidaddRule(java.lang.String[] selector, javax.swing.text.AttributeSet declaration, boolean isLinked)
Adds a rule into the StyleSheet.

param
selector the selector to use for the rule. This will be a set of simple selectors, and must be a length of 1 or greater.
param
declaration the set of CSS attributes that make up the rule.

	int n = selector.length;
	StringBuffer sb = new StringBuffer();
	sb.append(selector[0]);
	for (int counter = 1; counter < n; counter++) {
	    sb.append(' ");
	    sb.append(selector[counter]);
	}
	String selectorName = sb.toString();
	Style rule = getStyle(selectorName);
	if (rule == null) {
	    // Notice how the rule is first created, and it not part of
	    // the synchronized block. It is done like this as creating
	    // a new rule will fire a ChangeEvent. We do not want to be
	    // holding the lock when calling to other objects, it can
	    // result in deadlock.
	    Style altRule = addStyle(selectorName, null);
	    synchronized(this) {
		SelectorMapping mapping = getRootSelectorMapping();
		for (int i = n - 1; i >= 0; i--) {
		    mapping = mapping.getChildSelectorMapping
                                      (selector[i], true);
		}
		rule = mapping.getStyle();
		if (rule == null) {
                    rule = altRule;
                    mapping.setStyle(rule);
		    refreshResolvedRules(selectorName, selector, rule,
					 mapping.getSpecificity());
		}
	    }
	}
	if (isLinked) {
	    rule = getLinkedStyle(rule);
	}
	rule.addAttributes(declaration);
    
public voidaddRule(java.lang.String rule)
Adds a set of rules to the sheet. The rules are expected to be in valid CSS format. Typically this would be called as a result of parsing a <style> tag.

	if (rule != null) {
            //tweaks to control display properties
            //see BasicEditorPaneUI
            final String baseUnitsDisable = "BASE_SIZE_DISABLE";
            final String baseUnits = "BASE_SIZE ";
            final String w3cLengthUnitsEnable = "W3C_LENGTH_UNITS_ENABLE";
            final String w3cLengthUnitsDisable = "W3C_LENGTH_UNITS_DISABLE";
            if (rule == baseUnitsDisable) {
                sizeMap = sizeMapDefault;
            } else if (rule.startsWith(baseUnits)) {
                rebaseSizeMap(Integer.
                              parseInt(rule.substring(baseUnits.length())));
            } else if (rule == w3cLengthUnitsEnable) {
                w3cLengthUnits = true;
            } else if (rule == w3cLengthUnitsDisable) {
                w3cLengthUnits = false;
            } else {
                CssParser parser = new CssParser();
                try {
                    parser.parse(getBase(), new StringReader(rule), false, false);
                } catch (IOException ioe) { }
            }
	}
    
private voidaddSortedStyle(javax.swing.text.html.StyleSheet$SelectorMapping mapping, java.util.Vector elements)
Adds mapping to elements. It is added such that elements will remain ordered by specificity.

	int       size = elements.size();

	if (size > 0) {
	    int     specificity = mapping.getSpecificity();

	    for (int counter = 0; counter < size; counter++) {
		if (specificity >= ((SelectorMapping)elements.elementAt
                                    (counter)).getSpecificity()) {
		    elements.insertElementAt(mapping, counter);
		    return;
		}
	    }
	}
	elements.addElement(mapping);
    
public voidaddStyleSheet(javax.swing.text.html.StyleSheet ss)
Adds the rules from the StyleSheet ss to those of the receiver. ss's rules will override the rules of any previously added style sheets. An added StyleSheet will never override the rules of the receiving style sheet.

since
1.3

	synchronized(this) {
	    if (linkedStyleSheets == null) {
		linkedStyleSheets = new Vector();
	    }
	    if (!linkedStyleSheets.contains(ss)) {
                int index = 0;
                if (ss instanceof javax.swing.plaf.UIResource
                    && linkedStyleSheets.size() > 1) {
                    index = linkedStyleSheets.size() - 1;
                }
		linkedStyleSheets.insertElementAt(ss, index);
		linkStyleSheetAt(ss, index);
	    }
	}
    
java.lang.StringcleanSelectorString(java.lang.String selector)
Returns a string that only has one space between simple selectors, which may be the passed in String.

	boolean lastWasSpace = true;
	for (int counter = 0, maxCounter = selector.length();
	     counter < maxCounter; counter++) {
	    switch(selector.charAt(counter)) {
	    case ' ":
		if (lastWasSpace) {
		    return _cleanSelectorString(selector);
		}
		lastWasSpace = true;
		break;
	    case '\n":
	    case '\r":
	    case '\t":
		return _cleanSelectorString(selector);
	    default:
		lastWasSpace = false;
	    }
	}
	if (lastWasSpace) {
	    return _cleanSelectorString(selector);
	}
	// It was fine.
	return selector;
    
javax.swing.text.AttributeSetconvertAttributeSet(javax.swing.text.AttributeSet a)
Converts a set of attributes (if necessary) so that any attributes that were specified as StyleConstants attributes and have a CSS mapping, will be converted to CSS attributes.

	if ((a instanceof LargeConversionSet) || 
	    (a instanceof SmallConversionSet)) {
	    // known to be converted.
	    return a;
	}
	// in most cases, there are no StyleConstants attributes
	// so we iterate the collection of keys to avoid creating
	// a new set.
	Enumeration names = a.getAttributeNames();
	while (names.hasMoreElements()) {
	    Object name = names.nextElement();
	    if (name instanceof StyleConstants) {
		// we really need to do a conversion, iterate again
		// building a new set.
		MutableAttributeSet converted = new LargeConversionSet();
		Enumeration keys = a.getAttributeNames();
		while (keys.hasMoreElements()) {
		    Object key = keys.nextElement();
		    Object cssValue = null;
		    if (key instanceof StyleConstants) {
			// convert the StyleConstants attribute if possible
			Object cssKey = css.styleConstantsKeyToCSSKey
			                    ((StyleConstants)key);
			if (cssKey != null) {
			    Object value = a.getAttribute(key);
			    cssValue = css.styleConstantsValueToCSSValue
				           ((StyleConstants)key, value);
			    if (cssValue != null) {
				converted.addAttribute(cssKey, cssValue);
			    }
			}
		    }
		    if (cssValue == null) {
			converted.addAttribute(key, a.getAttribute(key));
		    }
		}
		return converted;
            }
	}
	return a;
    
protected javax.swing.text.MutableAttributeSetcreateLargeAttributeSet(javax.swing.text.AttributeSet a)
Creates a large set of attributes that should trade off space for time. This set will not be shared. This is a hook for subclasses that want to alter the behavior of the larger attribute storage format (which is SimpleAttributeSet by default). This can be reimplemented to return a MutableAttributeSet that provides some sort of attribute conversion.

param
a The set of attributes to be represented in the the larger form.

        return new LargeConversionSet(a);
    
private synchronized javax.swing.text.StylecreateResolvedStyle(java.lang.String selector, java.lang.String[] tags, java.lang.String[] ids, java.lang.String[] classes)
Creates and returns a Style containing all the rules that match selector.

	SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
	Vector tempVector = sb.getVector();
	Hashtable tempHashtable = sb.getHashtable();
	// Determine all the Styles that are appropriate, placing them
	// in tempVector
	try {
	    SelectorMapping mapping = getRootSelectorMapping();
	    int numElements = tags.length;
	    String tagString = tags[0];
	    SelectorMapping childMapping = mapping.getChildSelectorMapping(
                                                   tagString, false);
	    if (childMapping != null) {
		getStyles(childMapping, tempVector, tags, ids, classes, 1,
			  numElements, tempHashtable);
	    }
	    if (classes[0] != null) {
		String className = classes[0];
		childMapping = mapping.getChildSelectorMapping(
                                       tagString + "." + className, false);
		if (childMapping != null) {
		    getStyles(childMapping, tempVector, tags, ids, classes, 1,
			      numElements, tempHashtable);
		}
		childMapping = mapping.getChildSelectorMapping(
                                       "." + className, false);
		if (childMapping != null) {
		    getStyles(childMapping, tempVector, tags, ids, classes,
			      1, numElements, tempHashtable);
		}
	    }
	    if (ids[0] != null) {
		String idName = ids[0];
		childMapping = mapping.getChildSelectorMapping(
                                       tagString + "#" + idName, false);
		if (childMapping != null) {
		    getStyles(childMapping, tempVector, tags, ids, classes,
			      1, numElements, tempHashtable);
		}
		childMapping = mapping.getChildSelectorMapping(
                                       "#" + idName, false);
		if (childMapping != null) {
		    getStyles(childMapping, tempVector, tags, ids, classes,
			      1, numElements, tempHashtable);
		}
	    }
	    // Create a new Style that will delegate to all the matching
	    // Styles.
	    int numLinkedSS = (linkedStyleSheets != null) ?
		              linkedStyleSheets.size() : 0;
	    int numStyles = tempVector.size();
	    AttributeSet[] attrs = new AttributeSet[numStyles + numLinkedSS];
	    for (int counter = 0; counter < numStyles; counter++) {
		attrs[counter] = ((SelectorMapping)tempVector.
                                  elementAt(counter)).getStyle();
	    }
	    // Get the AttributeSet from linked style sheets.
	    for (int counter = 0; counter < numLinkedSS; counter++) {
		AttributeSet attr = ((StyleSheet)linkedStyleSheets.
				 elementAt(counter)).getRule(selector);
		if (attr == null) {
		    attrs[counter + numStyles] = SimpleAttributeSet.EMPTY;
		}
		else {
		    attrs[counter + numStyles] = attr;
		}
	    }
	    ResolvedStyle retStyle = new ResolvedStyle(selector, attrs,
						       numStyles);
	    resolvedStyles.put(selector, retStyle);
	    return retStyle;
	}
	finally {
	    SearchBuffer.releaseSearchBuffer(sb);
	}
    
private javax.swing.text.StylecreateResolvedStyle(java.lang.String selector, java.util.Vector elements, javax.swing.text.html.HTML$Tag t)
Creates and returns a Style containing all the rules that matches selector.

param
elements a Vector of all the Elements the style is being asked for. The first Element is the deepest Element, with the last Element representing the root.
param
t the Tag to use for the first Element in elements

	int numElements = elements.size();
        // Build three arrays, one for tags, one for class's, and one for
        // id's
        String tags[] = new String[numElements];
        String ids[] = new String[numElements];
        String classes[] = new String[numElements];
        for (int counter = 0; counter < numElements; counter++) {
            Element e = (Element)elements.elementAt(counter);
            AttributeSet attr = e.getAttributes();
	    if (counter == 0 && e.isLeaf()) {
		// For leafs, we use the second tier attributes.
		Object testAttr = attr.getAttribute(t);
		if (testAttr instanceof AttributeSet) {
		    attr = (AttributeSet)testAttr;
		}
		else {
		    attr = null;
		}
	    }
            if (attr != null) {
		HTML.Tag tag = (HTML.Tag)attr.getAttribute(StyleConstants.
							   NameAttribute);
                if (tag != null) {
                    tags[counter] = tag.toString();
                }
                else {
                    tags[counter] = null;
                }
		if (attr.isDefined(HTML.Attribute.CLASS)) {
                    classes[counter] = attr.getAttribute
			              (HTML.Attribute.CLASS).toString();
		}
                else {
                    classes[counter] = null;
                }
		if (attr.isDefined(HTML.Attribute.ID)) {
                    ids[counter] = attr.getAttribute(HTML.Attribute.ID).
			                toString();
                }
                else {
                    ids[counter] = null;
                }
            }
            else {
                tags[counter] = ids[counter] = classes[counter] = null;
            }
        }
        tags[0] = t.toString();
	return createResolvedStyle(selector, tags, ids, classes);
    
private javax.swing.text.StylecreateResolvedStyle(java.lang.String selector)
Creates and returns a Style containing all the rules that match selector. It is assumed that each simple selector in selector is separated by a space.

	SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
	// Will contain the tags, ids, and classes, in that order.
	Vector elements = sb.getVector();
	try {
	    boolean done;
	    int dotIndex = 0;
	    int spaceIndex = 0;
	    int poundIndex = 0;
	    int lastIndex = 0;
	    int length = selector.length();
	    while (lastIndex < length) {
		if (dotIndex == lastIndex) {
		    dotIndex = selector.indexOf('.", lastIndex);
		}
		if (poundIndex == lastIndex) {
		    poundIndex = selector.indexOf('#", lastIndex);
		}
		spaceIndex = selector.indexOf(' ", lastIndex);
		if (spaceIndex == -1) {
		    spaceIndex = length;
		}
		if (dotIndex != -1 && poundIndex != -1 &&
		    dotIndex < spaceIndex && poundIndex < spaceIndex) {
		    if (poundIndex < dotIndex) {
			// #.
			if (lastIndex == poundIndex) {
			    elements.addElement("");
			}
			else {
			    elements.addElement(selector.substring(lastIndex,
								  poundIndex));
			}
			if ((dotIndex + 1) < spaceIndex) {
			    elements.addElement(selector.substring
						(dotIndex + 1, spaceIndex));
			}
			else {
			    elements.addElement(null);
			}
			if ((poundIndex + 1) == dotIndex) {
			    elements.addElement(null);
			}
			else {
			    elements.addElement(selector.substring
						(poundIndex + 1, dotIndex));
			}
		    }
		    else if(poundIndex < spaceIndex) {
			// .#
			if (lastIndex == dotIndex) {
			    elements.addElement("");
			}
			else {
			    elements.addElement(selector.substring(lastIndex,
								  dotIndex));
			}
			if ((dotIndex + 1) < poundIndex) {
			    elements.addElement(selector.substring
						(dotIndex + 1, poundIndex));
			}
			else {
			    elements.addElement(null);
			}
			if ((poundIndex + 1) == spaceIndex) {
			    elements.addElement(null);
			}
			else {
			    elements.addElement(selector.substring
						(poundIndex + 1, spaceIndex));
			}
		    }
		    dotIndex = poundIndex = spaceIndex + 1;
		}
		else if (dotIndex != -1 && dotIndex < spaceIndex) {
		    // .
		    if (dotIndex == lastIndex) {
			elements.addElement("");
		    }
		    else {
			elements.addElement(selector.substring(lastIndex,
							       dotIndex));
		    }
		    if ((dotIndex + 1) == spaceIndex) {
			elements.addElement(null);
		    }
		    else {
			elements.addElement(selector.substring(dotIndex + 1,
							       spaceIndex));
		    }
		    elements.addElement(null);
		    dotIndex = spaceIndex + 1;
		}
		else if (poundIndex != -1 && poundIndex < spaceIndex) {
		    // #
		    if (poundIndex == lastIndex) {
			elements.addElement("");
		    }
		    else {
			elements.addElement(selector.substring(lastIndex,
							       poundIndex));
		    }
		    elements.addElement(null);
		    if ((poundIndex + 1) == spaceIndex) {
			elements.addElement(null);
		    }
		    else {
			elements.addElement(selector.substring(poundIndex + 1,
							       spaceIndex));
		    }
		    poundIndex = spaceIndex + 1;
		}
		else {
		    // id
		    elements.addElement(selector.substring(lastIndex,
							   spaceIndex));
		    elements.addElement(null);
		    elements.addElement(null);
		}
		lastIndex = spaceIndex + 1;
	    }
	    // Create the tag, id, and class arrays.
	    int total = elements.size();
	    int numTags = total / 3;
	    String[] tags = new String[numTags];
	    String[] ids = new String[numTags];
	    String[] classes = new String[numTags];
	    for (int index = 0, eIndex = total - 3; index < numTags;
		 index++, eIndex -= 3) {
		tags[index] = (String)elements.elementAt(eIndex);
		classes[index] = (String)elements.elementAt(eIndex + 1);
		ids[index] = (String)elements.elementAt(eIndex + 2);
	    }
	    return createResolvedStyle(selector, tags, ids, classes);
	}
	finally {
	    SearchBuffer.releaseSearchBuffer(sb);
	}
    
protected SmallAttributeSetcreateSmallAttributeSet(javax.swing.text.AttributeSet a)
Creates a compact set of attributes that might be shared. This is a hook for subclasses that want to alter the behavior of SmallAttributeSet. This can be reimplemented to return an AttributeSet that provides some sort of attribute conversion.

param
a The set of attributes to be represented in the the compact form.

	return new SmallConversionSet(a);
    
public java.awt.ColorgetBackground(javax.swing.text.AttributeSet a)
Takes a set of attributes and turn it into a background color specification. This might be used to specify things like brighter, more hue, etc.

param
a the set of attributes
return
the color

	return css.getColor(a, CSS.Attribute.BACKGROUND_COLOR);
    
javax.swing.ImageIcongetBackgroundImage(javax.swing.text.AttributeSet attr)
Returns the ImageIcon to draw in the background for attr.

	Object value = attr.getAttribute(CSS.Attribute.BACKGROUND_IMAGE);

	if (value != null) {
	    return ((CSS.BackgroundImage)value).getImage(getBase());
	}
	return null;
    
public java.net.URLgetBase()
Returns the base.

since
1.3

	return base;
    
public javax.swing.text.html.StyleSheet$BoxPaintergetBoxPainter(javax.swing.text.AttributeSet a)
Fetches the box formatter to use for the given set of CSS attributes.

	return new BoxPainter(a, css, this);
    
public javax.swing.text.AttributeSetgetDeclaration(java.lang.String decl)
Translates a CSS declaration to an AttributeSet that represents the CSS declaration. Typically this would be called as a result of encountering an HTML style attribute.

	if (decl == null) {
	    return SimpleAttributeSet.EMPTY;
	}
	CssParser parser = new CssParser();
	return parser.parseDeclaration(decl);
    
public java.awt.FontgetFont(javax.swing.text.AttributeSet a)
Fetches the font to use for the given set of attributes.

	return css.getFont(this, a, 12, this);
    
public java.awt.ColorgetForeground(javax.swing.text.AttributeSet a)
Takes a set of attributes and turn it into a foreground color specification. This might be used to specify things like brighter, more hue, etc.

param
a the set of attributes
return
the color

	Color c = css.getColor(a, CSS.Attribute.COLOR);
	if (c == null) {
	    return Color.black;
	}
	return c;
    
public static intgetIndexOfSize(float pt)

	return CSS.getIndexOfSize(pt, sizeMapDefault);
    
private javax.swing.text.StylegetLinkedStyle(javax.swing.text.Style localStyle)
Returns the style that linked attributes should be added to. This will create the style if necessary.

	// NOTE: This is not synchronized, and the caller of this does
	// not synchronize. There is the chance for one of the callers to
	// overwrite the existing resolved parent, but it is quite rare.
	// The reason this is left like this is because setResolveParent
	// will fire a ChangeEvent. It is really, REALLY bad for us to
	// hold a lock when calling outside of us, it may cause a deadlock.
	Style retStyle = (Style)localStyle.getResolveParent();
	if (retStyle == null) {
	    retStyle = addStyle(null, null);
	    localStyle.setResolveParent(retStyle);
	}
	return retStyle;
    
public javax.swing.text.html.StyleSheet$ListPaintergetListPainter(javax.swing.text.AttributeSet a)
Fetches the list formatter to use for the given set of CSS attributes.

	return new ListPainter(a, this);
    
public floatgetPointSize(int index)
Returns the point size, given a size index.

	return css.getPointSize(index, this);
    
public floatgetPointSize(java.lang.String size)
Given a string such as "+2", "-2", or "2", returns a point size value.

	return css.getPointSize(size, this);
    
private synchronized javax.swing.text.StylegetResolvedStyle(java.lang.String selector, java.util.Vector elements, javax.swing.text.html.HTML$Tag t)
Returns the resolved style for selector. This will create the resolved style, if necessary.

	Style retStyle = (Style)resolvedStyles.get(selector);
	if (retStyle == null) {
	    retStyle = createResolvedStyle(selector, elements, t);
	}
	return retStyle;
    
private synchronized javax.swing.text.StylegetResolvedStyle(java.lang.String selector)
Returns the resolved style for selector. This will create the resolved style, if necessary.

	Style retStyle = (Style)resolvedStyles.get(selector);
	if (retStyle == null) {
	    retStyle = createResolvedStyle(selector);
	}
	return retStyle;
    
private javax.swing.text.html.StyleSheet$SelectorMappinggetRootSelectorMapping()
Returns the root selector mapping that all selectors are relative to. This is an inverted graph of the selectors.

	return selectorMapping;
    
public javax.swing.text.StylegetRule(javax.swing.text.html.HTML$Tag t, javax.swing.text.Element e)
Fetches the style to use to render the given type of HTML tag. The element given is representing the tag and can be used to determine the nesting for situations where the attributes will differ if nesting inside of elements.

param
t the type to translate to visual attributes
param
e the element representing the tag; the element can be used to determine the nesting for situations where the attributes will differ if nested inside of other elements
return
the set of CSS attributes to use to render the tag

        SearchBuffer sb = SearchBuffer.obtainSearchBuffer();

        try {
            // Build an array of all the parent elements.
            Vector searchContext = sb.getVector();

            for (Element p = e; p != null; p = p.getParentElement()) {
                searchContext.addElement(p);
            }

            // Build a fully qualified selector.
            int              n = searchContext.size();
            StringBuffer     cacheLookup = sb.getStringBuffer();
            AttributeSet     attr;
            String           eName;
            Object           name;

            // >= 1 as the HTML.Tag for the 0th element is passed in.
            for (int counter = n - 1; counter >= 1; counter--) {
                e = (Element)searchContext.elementAt(counter);
                attr = e.getAttributes();
                name = attr.getAttribute(StyleConstants.NameAttribute);
		eName = name.toString();
                cacheLookup.append(eName);
                if (attr != null) {
                    if (attr.isDefined(HTML.Attribute.ID)) {
                        cacheLookup.append('#");
                        cacheLookup.append(attr.getAttribute
					   (HTML.Attribute.ID));
                    }
                    else if (attr.isDefined(HTML.Attribute.CLASS)) {
                        cacheLookup.append('.");
                        cacheLookup.append(attr.getAttribute
					   (HTML.Attribute.CLASS));
                    }
                }
                cacheLookup.append(' ");
            }
            cacheLookup.append(t.toString());
	    e = (Element)searchContext.elementAt(0);
	    attr = e.getAttributes();
	    if (e.isLeaf()) {
		// For leafs, we use the second tier attributes.
		Object testAttr = attr.getAttribute(t);
		if (testAttr instanceof AttributeSet) {
		    attr = (AttributeSet)testAttr;
		}
		else {
		    attr = null;
		}
	    }
            if (attr != null) {
                if (attr.isDefined(HTML.Attribute.ID)) {
                    cacheLookup.append('#");
                    cacheLookup.append(attr.getAttribute(HTML.Attribute.ID));
                }
                else if (attr.isDefined(HTML.Attribute.CLASS)) {
                    cacheLookup.append('.");
                    cacheLookup.append(attr.getAttribute
				       (HTML.Attribute.CLASS));
                }
            }

            Style style = getResolvedStyle(cacheLookup.toString(),
					   searchContext, t);
	    return style;
        }
        finally {
            SearchBuffer.releaseSearchBuffer(sb);
        }
    
public javax.swing.text.StylegetRule(java.lang.String selector)
Fetches the rule that best matches the selector given in string form. Where selector is a space separated String of the element names. For example, selector might be 'html body tr td''

The attributes of the returned Style will change as rules are added and removed. That is if you to ask for a rule with a selector "table p" and a new rule was added with a selector of "p" the returned Style would include the new attributes from the rule "p".

	selector = cleanSelectorString(selector);
	if (selector != null) {
	    Style style = getResolvedStyle(selector);
	    return style;
	}
	return null;
    
java.lang.String[]getSimpleSelectors(java.lang.String selector)
Returns the simple selectors that comprise selector.

	selector = cleanSelectorString(selector);
	SearchBuffer sb = SearchBuffer.obtainSearchBuffer();
	Vector selectors = sb.getVector();
	int lastIndex = 0;
	int length = selector.length();
	while (lastIndex != -1) {
	    int newIndex = selector.indexOf(' ", lastIndex);
	    if (newIndex != -1) {
		selectors.addElement(selector.substring(lastIndex, newIndex));
		if (++newIndex == length) {
		    lastIndex = -1;
		}
		else {
		    lastIndex = newIndex;
		}
	    }
	    else {
		selectors.addElement(selector.substring(lastIndex));
		lastIndex = -1;
	    }
	}
	String[] retValue = new String[selectors.size()];
	selectors.copyInto(retValue);
	SearchBuffer.releaseSearchBuffer(sb);
	return retValue;
    
int[]getSizeMap()

        return sizeMap;
    
static intgetSpecificity(java.lang.String selector)
Returns the specificity of the passed in String. It assumes the passed in string doesn't contain junk, that is each selector is separated by a space and each selector at most contains one . or one #. A simple selector has a weight of 1, an id selector has a weight of 100, and a class selector has a weight of 10000.

        int specificity = 0;
        boolean lastWasSpace = true;

        for (int counter = 0, maxCounter = selector.length();
             counter < maxCounter; counter++) {
            switch(selector.charAt(counter)) {
            case '.":
                specificity += 100;
                break;
            case '#":
                specificity += 10000;
                break;
            case ' ":
                lastWasSpace = true;
                break;
            default:
                if (lastWasSpace) {
                    lastWasSpace = false;
                    specificity += 1;
                }
            }
        }
        return specificity;
    
public javax.swing.text.html.StyleSheet[]getStyleSheets()
Returns an array of the linked StyleSheets. Will return null if there are no linked StyleSheets.

since
1.3

	StyleSheet[] retValue;

	synchronized(this) {
	    if (linkedStyleSheets != null) {
		retValue = new StyleSheet[linkedStyleSheets.size()];
		linkedStyleSheets.copyInto(retValue);
	    }
	    else {
		retValue = null;
	    }
	}
	return retValue;
    
private synchronized voidgetStyles(javax.swing.text.html.StyleSheet$SelectorMapping parentMapping, java.util.Vector styles, java.lang.String[] tags, java.lang.String[] ids, java.lang.String[] classes, int index, int numElements, java.util.Hashtable alreadyChecked)
Adds parentMapping to styles, and recursively calls this method if parentMapping has any child mappings for any of the Elements in elements.

	// Avoid desending the same mapping twice.
	if (alreadyChecked.contains(parentMapping)) {
	    return;
	}
	alreadyChecked.put(parentMapping, parentMapping);
	Style style = parentMapping.getStyle();
	if (style != null) {
	    addSortedStyle(parentMapping, styles);
	}
	for (int counter = index; counter < numElements; counter++) {
            String tagString = tags[counter];
            if (tagString != null) {
		SelectorMapping childMapping = parentMapping.
                                getChildSelectorMapping(tagString, false);
		if (childMapping != null) {
		    getStyles(childMapping, styles, tags, ids, classes,
                              counter + 1, numElements, alreadyChecked);
		}
		if (classes[counter] != null) {
		    String className = classes[counter];
		    childMapping = parentMapping.getChildSelectorMapping(
                                         tagString + "." + className, false);
		    if (childMapping != null) {
			getStyles(childMapping, styles, tags, ids, classes,
                                  counter + 1, numElements, alreadyChecked);
		    }
		    childMapping = parentMapping.getChildSelectorMapping(
                                         "." + className, false);
		    if (childMapping != null) {
			getStyles(childMapping, styles, tags, ids, classes,
                                  counter + 1, numElements, alreadyChecked);
		    }
		}
		if (ids[counter] != null) {
		    String idName = ids[counter];
		    childMapping = parentMapping.getChildSelectorMapping(
                                         tagString + "#" + idName, false);
		    if (childMapping != null) {
			getStyles(childMapping, styles, tags, ids, classes,
                                  counter + 1, numElements, alreadyChecked);
		    }
		    childMapping = parentMapping.getChildSelectorMapping(
                                   "#" + idName, false);
		    if (childMapping != null) {
			getStyles(childMapping, styles, tags, ids, classes,
                                  counter + 1, numElements, alreadyChecked);
		    }
		}
	    }
	}
    
public javax.swing.text.AttributeSetgetViewAttributes(javax.swing.text.View v)
Fetches a set of attributes to use in the view for displaying. This is basically a set of attributes that can be used for View.getAttributes.

	return new ViewAttributeSet(v);
    
public voidimportStyleSheet(java.net.URL url)
Imports a style sheet from url. The resulting rules are directly added to the receiver. If you do not want the rules to become part of the receiver, create a new StyleSheet and use addStyleSheet to link it in.

since
1.3

	try {
	    InputStream is;

	    is = url.openStream();
	    Reader r = new BufferedReader(new InputStreamReader(is));
	    CssParser parser = new CssParser();
	    parser.parse(url, r, false, true);
	    r.close();
	    is.close();
	} catch (Throwable e) {
	    // on error we simply have no styles... the html
	    // will look mighty wrong but still function.
	}
    
booleanisW3CLengthUnits()

        return w3cLengthUnits;
    
private synchronized voidlinkStyleSheetAt(javax.swing.text.html.StyleSheet ss, int index)
Updates the attributes of the rules to reference any related rules in ss.

	if (resolvedStyles.size() > 0) {
	    Enumeration values = resolvedStyles.elements();
	    while (values.hasMoreElements()) {
		ResolvedStyle rule = (ResolvedStyle)values.nextElement();
		rule.insertExtendedStyleAt(ss.getRule(rule.getName()),
					   index);
	    }
	}
    
public voidloadRules(java.io.Reader in, java.net.URL ref)
Loads a set of rules that have been specified in terms of CSS1 grammar. If there are collisions with existing rules, the newly specified rule will win.

param
in the stream to read the CSS grammar from
param
ref the reference URL. This value represents the location of the stream and may be null. All relative URLs specified in the stream will be based upon this parameter.

	CssParser parser = new CssParser();
	parser.parse(ref, in, false, false);
    
voidrebaseSizeMap(int base)

    

       
        final int minimalFontSize = 4;
        sizeMap = new int[sizeMapDefault.length];
        for (int i = 0; i < sizeMapDefault.length; i++) {
            sizeMap[i] = Math.max(base * sizeMapDefault[i] / 
                                  sizeMapDefault[CSS.baseFontSizeIndex],
                                  minimalFontSize);
        }

    
private synchronized voidrefreshResolvedRules(java.lang.String selectorName, java.lang.String[] selector, javax.swing.text.Style newStyle, int specificity)
Should be invoked when a new rule is added that did not previously exist. Goes through and refreshes the necessary resolved rules.

	if (resolvedStyles.size() > 0) {
	    Enumeration values = resolvedStyles.elements();
	    while (values.hasMoreElements()) {
		ResolvedStyle style = (ResolvedStyle)values.nextElement();
		if (style.matches(selectorName)) {
		    style.insertStyle(newStyle, specificity);
		}
	    }
	}
    
public javax.swing.text.AttributeSetremoveAttribute(javax.swing.text.AttributeSet old, java.lang.Object key)
Removes an attribute from the set. If the attribute is a StyleConstants attribute, the request will be converted to a CSS attribute prior to forwarding to the superclass behavior.

param
old the old set of attributes
param
key the non-null attribute name
return
the updated attribute set
see
MutableAttributeSet#removeAttribute

	if (key instanceof StyleConstants) {
            HTML.Tag tag = HTML.getTagForStyleConstantsKey(
                                   (StyleConstants)key);
            if (tag != null) {
                old = super.removeAttribute(old, tag);
            }

	    Object cssKey = css.styleConstantsKeyToCSSKey((StyleConstants)key);
	    if (cssKey != null) {
		return super.removeAttribute(old, cssKey);
	    }
	}
        return super.removeAttribute(old, key);
    
public javax.swing.text.AttributeSetremoveAttributes(javax.swing.text.AttributeSet old, java.util.Enumeration names)
Removes a set of attributes for the element. If any of the attributes is a StyleConstants attribute, the request will be converted to a CSS attribute prior to forwarding to the superclass behavior.

param
old the old attribute set
param
names the attribute names
return
the updated attribute set
see
MutableAttributeSet#removeAttributes

        // PENDING: Should really be doing something similar to 
        // removeHTMLTags here, but it is rather expensive to have to
        // clone names
        return super.removeAttributes(old, names);
    
public javax.swing.text.AttributeSetremoveAttributes(javax.swing.text.AttributeSet old, javax.swing.text.AttributeSet attrs)
Removes a set of attributes. If any of the attributes is a StyleConstants attribute, the request will be converted to a CSS attribute prior to forwarding to the superclass behavior.

param
old the old attribute set
param
attrs the attributes
return
the updated attribute set
see
MutableAttributeSet#removeAttributes

        if (old != attrs) {
            old = removeHTMLTags(old, attrs);
        }
	return super.removeAttributes(old, convertAttributeSet(attrs));
    
private javax.swing.text.AttributeSetremoveHTMLTags(javax.swing.text.AttributeSet old, javax.swing.text.AttributeSet attr)
For any StyleConstants key in attr that has an associated HTML.Tag, it is removed from old. The resulting AttributeSet is then returned.

        if (!(attr instanceof LargeConversionSet) &&
            !(attr instanceof SmallConversionSet)) {
            Enumeration names = attr.getAttributeNames();

            while (names.hasMoreElements()) {
                Object key = names.nextElement();

                if (key instanceof StyleConstants) {
                    HTML.Tag tag = HTML.getTagForStyleConstantsKey(
                        (StyleConstants)key);

                    if (tag != null && old.isDefined(tag)) {
                        old = super.removeAttribute(old, tag);
                    }
                }
            }
        }
	return old;
    
public voidremoveStyle(java.lang.String nm)
Removes a named style previously added to the document.

param
nm the name of the style to remove

	Style       aStyle = getStyle(nm);

	if (aStyle != null) {
	    String selector = cleanSelectorString(nm);
	    String[] selectors = getSimpleSelectors(selector);
	    synchronized(this) {
		SelectorMapping mapping = getRootSelectorMapping();
		for (int i = selectors.length - 1; i >= 0; i--) {
		    mapping = mapping.getChildSelectorMapping(selectors[i],
                                                              true);
		}
		Style rule = mapping.getStyle();
		if (rule != null) {
		    mapping.setStyle(null);
		    if (resolvedStyles.size() > 0) {
			Enumeration values = resolvedStyles.elements();
			while (values.hasMoreElements()) {
			    ResolvedStyle style = (ResolvedStyle)values.
				                    nextElement();
			    style.removeStyle(rule);
			}
		    }
		}
	    }
	}
	super.removeStyle(nm);
    
public voidremoveStyleSheet(javax.swing.text.html.StyleSheet ss)
Removes the StyleSheet ss from those of the receiver.

since
1.3

	synchronized(this) {
	    if (linkedStyleSheets != null) {
		int index = linkedStyleSheets.indexOf(ss);
		if (index != -1) {
		    linkedStyleSheets.removeElementAt(index);
		    unlinkStyleSheet(ss, index);
		    if (index == 0 && linkedStyleSheets.size() == 0) {
			linkedStyleSheets = null;
		    }
		}
	    }
	}
    
public voidsetBase(java.net.URL base)
Sets the base. All import statements that are relative, will be relative to base.

since
1.3

	this.base = base;
    
public voidsetBaseFontSize(int sz)
Sets the base font size, with valid values between 1 and 7.

	css.setBaseFontSize(sz);
    
public voidsetBaseFontSize(java.lang.String size)
Sets the base font size from the passed in String. The string can either identify a specific font size, with legal values between 1 and 7, or identifiy a relative font size such as +1 or -2.

	css.setBaseFontSize(size);
    
public java.awt.ColorstringToColor(java.lang.String string)
Converts a color string such as "RED" or "#NNNNNN" to a Color. Note: This will only convert the HTML3.2 color strings or a string of length 7; otherwise, it will return null.

	return CSS.stringToColor(string);
    
public javax.swing.text.AttributeSettranslateHTMLToCSS(javax.swing.text.AttributeSet htmlAttrSet)
Converts a set of HTML attributes to an equivalent set of CSS attributes.

param
htmlAttrSet AttributeSet containing the HTML attributes.

	AttributeSet cssAttrSet = css.translateHTMLToCSS(htmlAttrSet);

	MutableAttributeSet cssStyleSet = addStyle(null, null);
	cssStyleSet.addAttributes(cssAttrSet);

	return cssStyleSet;
    
private synchronized voidunlinkStyleSheet(javax.swing.text.html.StyleSheet ss, int index)
Removes references to the rules in ss. index gives the index the StyleSheet was at, that is how many StyleSheets had been added before it.

	if (resolvedStyles.size() > 0) {
	    Enumeration values = resolvedStyles.elements();
	    while (values.hasMoreElements()) {
		ResolvedStyle rule = (ResolvedStyle)values.nextElement();
		rule.removeExtendedStyleAt(index);
	    }
	}